{"id":469,"date":"2024-05-11T18:51:07","date_gmt":"2024-05-12T02:51:07","guid":{"rendered":"https:\/\/nramkumar.org\/tech\/?p=469"},"modified":"2024-05-11T18:51:07","modified_gmt":"2024-05-12T02:51:07","slug":"linking-audio-input-and-output-from-applications-with-pipewire-pw-link","status":"publish","type":"post","link":"https:\/\/nramkumar.org\/tech\/blog\/2024\/05\/11\/linking-audio-input-and-output-from-applications-with-pipewire-pw-link\/","title":{"rendered":"Linking Audio Input and Output from Applications with Pipewire pw-link"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">If you are recording audio output from an application, one challenge is that recording the default output can mean you record all the sounds that are produced by all applications. In Linux, you can use pipewire command-line utility pw-link to create a dedicated and isolated link between the application producing the audio output and the application that will be recording the audio output. Below is a bash script that does this &#8211; the command-line flags -o and -i imply the only links for the output and input applications should be to each other (exclusive mode). Note that this script makes a few assumptions (outside of assumptions about the format of the output from pw-link itself but I consider that to be not as problematic) &#8211; it assumes the application names do not contain _ &#8211; a more robust version could probably split the port name on &#8216;:&#8217; and use the second field on split as channel.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>#!\/bin\/bash\n\noutput_exclusive=false\ninput_exclusive=false\noutput_application_name=\"Amazon Music\"\ninput_application_name=\"OBS\"\n\nwhile getopts \"oi\" opt; do\n    case $opt in\n        o)\n            output_exclusive=true\n            ;;\n        i)\n            input_exclusive=true\n            ;;\n        \\?)\n            echo \"Invalid Option: -$OPTARG\" >&amp;2\n            exit 1\n            ;;\n    esac\ndone\nshift $((OPTIND - 1))\n\ndeclare -A deleted_links\nnode_matched=false\n\nwhile IFS= read -r line1; do\n    if &#91;&#91; (\"$line1\" =~ \"&lt;\" || \"$line1\" =~ \">\") &amp;&amp; \"$node_matched\" = true ]]; then\n        link_id=$(echo $line1 | cut -d ' ' -f 1)\n        if &#91;&#91; -z \"${deleted_links&#91;$link_id]}\" ]]; then\n            deleted_links&#91;\"$link_id\"]=1\n            echo pw-link -d \"$link_id\"\n            pw-link -d \"$link_id\"\n        fi\n    else\n        node_matched=false\n        if &#91;&#91; \"$output_exclusive\" = true &amp;&amp; \"$line1\" =~ $output_application_name ]]; then\n            node_matched=true\n        elif &#91;&#91; \"$input_exclusive\" = true &amp;&amp; \"$line1\" =~ $input_application_name ]]; then\n            node_matched=true\n        fi\n    fi\ndone &lt; &lt;(pw-link -l -I)\n\n\ndeclare -a output_ports\ndeclare -a input_ports\n\nwhile IFS= read -r line1; do\n    if &#91;&#91; \"$line1\" =~ $output_application_name ]]; then\n        output_ports+=(\"$line1\")\n    fi\ndone &lt; &lt;(pw-link -o)\n\n\n\nwhile IFS= read -r line1; do\n    if &#91;&#91; \"$line1\" =~ $input_application_name ]]; then\n        input_ports+=(\"$line1\")\n    fi\ndone &lt; &lt;(pw-link -i)\n\n\nfor ((i = 0; i &lt; ${#output_ports&#91;@]}; i++)); do\n    for ((j = 0; j &lt; ${#input_ports&#91;@]}; j++)); do\n        output_channel=$(echo \"${output_ports&#91;i]}\" | cut -d '_' -f 2)\n        input_channel=$(echo \"${input_ports&#91;j]}\" | cut -d '_' -f 2)\n\n        if &#91;&#91; \"$output_channel\" == \"$input_channel\" ]]; then\n            echo pw-link \"${output_ports&#91;i]}\" \"${input_ports&#91;j]}\"\n            pw-link \"${output_ports&#91;i]}\" \"${input_ports&#91;j]}\"\n        fi\n    done\ndone\n<\/code><\/pre>\n","protected":false},"excerpt":{"rendered":"<p>If you are recording audio output from an application, one challenge is that recording the default output can mean you record all the sounds that are produced by all applications. In Linux, you can use pipewire command-line utility pw-link to create a dedicated and isolated link between the application producing the audio output and the&#8230;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-469","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"_links":{"self":[{"href":"https:\/\/nramkumar.org\/tech\/wp-json\/wp\/v2\/posts\/469","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/nramkumar.org\/tech\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/nramkumar.org\/tech\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/nramkumar.org\/tech\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/nramkumar.org\/tech\/wp-json\/wp\/v2\/comments?post=469"}],"version-history":[{"count":1,"href":"https:\/\/nramkumar.org\/tech\/wp-json\/wp\/v2\/posts\/469\/revisions"}],"predecessor-version":[{"id":470,"href":"https:\/\/nramkumar.org\/tech\/wp-json\/wp\/v2\/posts\/469\/revisions\/470"}],"wp:attachment":[{"href":"https:\/\/nramkumar.org\/tech\/wp-json\/wp\/v2\/media?parent=469"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/nramkumar.org\/tech\/wp-json\/wp\/v2\/categories?post=469"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/nramkumar.org\/tech\/wp-json\/wp\/v2\/tags?post=469"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}