[{"categories":[{"LinkTitle":"Radio","RelPermalink":"/categories/radio/"},{"LinkTitle":"Linux","RelPermalink":"/categories/linux/"}],"content":"Why Clone an Audio Stream? One of the reasons that Linux is such a great platform for playing with Amateur Radio is the unequaled flexibility PulseAudio (and PipeWire, more recently, which is drop-in compatible with PulseAudio) give you to send any audio anywhere you want. Since most Amateur Radio software uses audio signals to interface with your radio, this extra flexibility comes in quite handy. However, unless you know what you are looking for, the possibilities are not obvious.\nA trick that I find myself using often is to send the audio stream from one application to multiple outputs. That way you can listen on your speakers while the audio goes out to your radio through a different sound card.\nVirtual Devices This technique is made possible by the \u0026ldquo;null sink\u0026rdquo; and \u0026ldquo;loopback\u0026rdquo; devices in PulseAudio (again, this all works without changes in PipeWire as well). These devices are \u0026ldquo;virtual\u0026rdquo;; that is, they are not backed by any hardware. A null sink is a virtual device that does nothing but receive audio. A loopback copies the audio from a source to a sink. You can connect these devices is many different topologies. This is what we are going to set up in this post, using fldigi as an example application:\nLet\u0026rsquo;s Get Started We\u0026rsquo;ll need to create the virtual devices on the command line. After that, you can use pavucontrol to connect them together if you want, but I\u0026rsquo;ll show it on the command line. First we\u0026rsquo;ll create a null sink:\n$ pactl load-module module-null-sink sink_name=\u0026#34;NS1\u0026#34; 262 pactl will output a number, which is the module number that you just created. You can see all of the loaded modules with\n$ pactl list modules [...] Module #262 Name: module-null-sink Argument: sink_name=NS1 Usage counter: n/a Properties: module.author = \u0026#34;Wim Taymans \u0026lt;wim.taymans@gmail.com\u0026gt;\u0026#34; module.description = \u0026#34;A NULL sink\u0026#34; module.usage = \u0026#34;sink_name=\u0026lt;name of sink\u0026gt; sink_properties=\u0026lt;properties for the sink\u0026gt; format=\u0026lt;sample format\u0026gt; rate=\u0026lt;sample rate\u0026gt; channels=\u0026lt;number of channels\u0026gt; channel_map=\u0026lt;channel map\u0026gt;\u0026#34; module.version = \u0026#34;0.3.40\u0026#34; node.name = \u0026#34;NS1\u0026#34; audio.channels = \u0026#34;2\u0026#34; audio.position = \u0026#34;FL,FR\u0026#34; media.class = \u0026#34;Audio/Sink\u0026#34; device.description = \u0026#34;NS1 Audio/Sink sink\u0026#34; factory.name = \u0026#34;support.null-audio-sink\u0026#34; object.linger = \u0026#34;true\u0026#34; monitor.channel-volumes = \u0026#34;true\u0026#34; If you want to remove a module, substitute its module number for 262 in:\n$ pactl unload-module 262 Now that we have our virtual sink, we will use the loopbacks to connect it to both of our real outputs. We\u0026rsquo;ll get a list of all sinks, making note of the node.name property for the devices in question. I\u0026rsquo;ve trimmed the output quite a bit for clarity. Note that your sinks will probably be much different than mine depending on your hardware and what is currently running on your system.\n$ pactl list sinks Sink #49 State: IDLE Name: alsa_output.usb-C-Media_Electronics_Inc._USB_PnP_Sound_Device-00.analog-stereo Description: CM108 Audio Controller Analog Stereo Properties: node.nick = \u0026#34;USB PnP Sound Device\u0026#34; node.name = \u0026#34;alsa_output.usb-C-Media_Electronics_Inc._USB_PnP_Sound_Device-00.analog-stereo\u0026#34; device.description = \u0026#34;CM108 Audio Controller Analog Stereo\u0026#34; Sink #272 State: IDLE Name: NS1 Description: NS1 Audio/Sink sink Properties: node.name = \u0026#34;NS1\u0026#34; device.description = \u0026#34;NS1 Audio/Sink sink\u0026#34; Sink #293 State: RUNNING Name: bluez_output.00_42_79_E6_8A_9A.a2dp-sink Description: JBL BoomBox Properties: device.description = \u0026#34;JBL BoomBox\u0026#34; node.name = \u0026#34;bluez_output.00_42_79_E6_8A_9A.a2dp-sink\u0026#34; In my case, the \u0026ldquo;USB PnP Sound Device\u0026rdquo; is the output to my radio, \u0026ldquo;JBL BoomBox\u0026rdquo; is the device I want to listen on, and \u0026ldquo;NS1 Audio/Sink sink\u0026rdquo; is the null sync I created in the last step. Let\u0026rsquo;s connect them all together.\n$ pactl load-module module-loopback source=NS1 sink=\u0026#34;alsa_output.usb-C-Media_Electronics_Inc._USB_PnP_Sound_Device-00.analog-stereo\u0026#34; 262145 $ pactl load-module module-loopback source=NS1 sink=\u0026#34;bluez_output.00_42_79_E6_8A-9A.a2dp-sink\u0026#34; 262146 Now we have a virtual device that will send any audio we feed it to both our radio and our speakers. The last remaining step is to reroute fldigi\u0026rsquo;s output there. You can use pavucontrol to change the output if you prefer GUI, but where\u0026rsquo;s the fun in that? We need to find the \u0026ldquo;sink input\u0026rdquo; ID corresponding to fldigi. Once again, I\u0026rsquo;ve trimmed the output to only the relevant sections.\n$ pactl list sink-inputs Sink Input #233 Client: 181 Sink: 272 Properties: application.name = \u0026#34;ALSA plug-in [fldigi]\u0026#34; application.process.id = \u0026#34;972192\u0026#34; application.process.binary = \u0026#34;fldigi\u0026#34; node.name = \u0026#34;ALSA plug-in [fldigi]\u0026#34; And now to move it. Substitute your sink input number for 233.\n$ pactl move-sink-input 233 NS1 Summary Now the audio from our fldigi process is going into the null sink we created. When it plays some audio, the two loopback devices will copy it from the null sink, which does nothing on its own, to the two different audio devices we specified. As you can see, PulseAudio and PipeWire are extremely versatile tools for taking any audio you have any putting it where you want it to go. I hope you find this technique helpful.\n73 DE KZ3A\n","permalink":"https://kz3a.us/posts/2021-12-01-cloning-audio-stream/","tags":[],"title":"Cloning an Audio Stream in Linux"},{"categories":[],"content":" This is a static site, managed with Hugo, hosted on Cloudflare Pages.\n","permalink":"https://kz3a.us/about/","tags":[],"title":"About"},{"categories":[],"content":"","permalink":"https://kz3a.us/manifest.json","tags":[],"title":""},{"categories":[],"content":"","permalink":"https://kz3a.us/search/_index.de/","tags":[],"title":""},{"categories":[],"content":"","permalink":"https://kz3a.us/search/_index.es/","tags":[],"title":""},{"categories":[],"content":"","permalink":"https://kz3a.us/search/_index.fr/","tags":[],"title":""},{"categories":[],"content":"","permalink":"https://kz3a.us/search/_index.hi/","tags":[],"title":""},{"categories":[],"content":"","permalink":"https://kz3a.us/search/_index.jp/","tags":[],"title":""},{"categories":[],"content":"","permalink":"https://kz3a.us/search/_index.nl/","tags":[],"title":""},{"categories":[],"content":"","permalink":"https://kz3a.us/search/_index.pl/","tags":[],"title":""},{"categories":[],"content":"","permalink":"https://kz3a.us/search/_index.ru/","tags":[],"title":""},{"categories":[],"content":"","permalink":"https://kz3a.us/search/_index.zh-cn/","tags":[],"title":""}]