roc-streaming / roc-toolkit

Real-time audio streaming over the network.
https://roc-streaming.org
Mozilla Public License 2.0
1.03k stars 205 forks source link

roc-send not working with pulseaudio source #499

Closed Ramblurr closed 1 year ago

Ramblurr commented 1 year ago

As discussed in matrix..

pi@dev1:~ $ pulseaudio --version
pulseaudio 14.2

pi@dev1:~ $ roc-send  --version
roc-send 0.2.0 (ed92e21e98)
pi@dev1:~ $ roc-send --list-supported
supported schemes for audio devices and files:
  pulse:// alsa:// oss:// file://

supported formats for audio files:
  .aifc .aiffc .aiff .aif .al .au .snd .avr .cdda .cdr .cvsd .cvs .cvu .dat
  .dvms .vms .f32 .f64 .gsrt .hcom .htk .ima .la .lu .maud .prc .s8 .s16
  .s24 .s32 .sf .ircam .sln .smp .sndr .sndt .sox .sph .nist .8svx .txw
  .u8 .sou .fssd .u16 .u24 .u32 .ul .voc .vox .wav .wavpcm .amb .wve .xa

pi@dev1:~ $ roc-send -vvvv --input pulse://alsa_input.usb-C-Media_Electronics_Inc._USB_Audio_Device-00.mono-fallback --source rtp+rs8m://10.9.6.96:10001 -
-repair rs8m://10.9.6.96:10002
14:52:31.481 [4967] [dbg] roc_core: [slab_pool.cpp:38] slab pool: initializing: object_size=672 min_slab=0B(1S) max_slab=0B(0S) poison=0
14:52:31.481 [4967] [dbg] roc_core: [slab_pool.cpp:38] slab pool: initializing: object_size=2064 min_slab=0B(1S) max_slab=0B(0S) poison=0
14:52:31.481 [4967] [dbg] roc_core: [slab_pool.cpp:38] slab pool: initializing: object_size=4112 min_slab=0B(1S) max_slab=0B(0S) poison=0
14:52:31.482 [4968] [dbg] roc_netio: [network_loop.cpp:278] network loop: starting event loop
14:52:31.482 [4967] [dbg] roc_peer: [context.cpp:25] context: initializing
14:52:31.482 [4967] [dbg] roc_sndio: [pulseaudio_backend.cpp:19] pulseaudio backend: initializing
14:52:31.482 [4967] [dbg] roc_sndio: [sox_backend.cpp:164] sox backend: initializing
14:52:31.482 [4969] [dbg] roc_ctl: [control_task_queue.cpp:95] control task queue: starting event loop
14:52:31.483 [4969] [trc] roc_ctl: [control_task_queue.cpp:706] control task queue: ready task queue is empty or being pushed
14:52:31.483 [4969] [trc] roc_ctl: [control_task_queue.cpp:839] control task queue: updating wakeup deadline: deadline=-1
14:52:31.483 [4967] [dbg] roc_sndio: [backend_map.cpp:20] backend map: initialized: n_backends=2 n_drivers=58
14:52:31.483 [4967] [err] roc_sndio: [backend_dispatcher.cpp:208] backend dispatcher: failed to open source: type=device driver=pulse path=alsa_input.usb-C-Media_Electronics_Inc._USB_Audio_Device-00.mono-fallback
14:52:31.483 [4967] [err] roc_send: [main.cpp:255] can't open input file or device: uri=pulse://alsa_input.usb-C-Media_Electronics_Inc._USB_Audio_Device-00.mono-fallback format=(null)
14:52:31.483 [4967] [dbg] roc_peer: [context.cpp:29] context: deinitializing
14:52:31.484 [4969] [trc] roc_ctl: [control_task_queue.cpp:706] control task queue: ready task queue is empty or being pushed
14:52:31.484 [4969] [trc] roc_ctl: [control_task_queue.cpp:839] control task queue: updating wakeup deadline: deadline=-1
14:52:31.484 [4969] [dbg] roc_ctl: [control_task_queue.cpp:105] control task queue: finishing event loop
14:52:31.484 [4968] [dbg] roc_netio: [network_loop.cpp:285] network loop: finishing event loop

pi@dev1:~ $ pactl list sources  short
3       alsa_output.usb-C-Media_Electronics_Inc._USB_Audio_Device-00.analog-stereo.monitor      module-alsa-card.c      s16le 2ch 44100Hz       SUSPENDED
4       alsa_input.usb-C-Media_Electronics_Inc._USB_Audio_Device-00.mono-fallback       module-alsa-card.c      s16le 1ch 44100Hz       SUSPENDED

gavv Thanks. I think I know where is the bug (in backrnd dispatching code).

As a temporary workaround, could you try to use -i alsa://pulse ?

gavv commented 1 year ago

PulseAudio backend provides only sink, and backend dispatcher fails to select sox backend when trying to use PulseAudio source.

As noted, temporary workaround is to use ALSA emulation using -i alsa://pulse (i.e. use ALSA backend with "pulse" ALSA device which internally connects to PulseAudio daemon).

A proper fix is to do one of the following:

zopieux commented 1 year ago

I can confirm this bug is still present in 0.2.2 (e575eaa126). While using the alsa://pulse backend works, it seems to only be able to use Pulse's "default source" (e.g. a microphone), but I would like to capture desktop audio instead. Is there a workaround available as well? Do I need to create some kind of loopback Pulse device and make it the default source?

gavv commented 1 year ago

@zopieux Hi,

You can try to set PULSE_SOURCE environment variable. Hopefully, ALSA pulse device will use it.

If not, I think after starting roc-send you can just open pavucontrol, open "recording" tab and connect roc-send to needed source:

image

You you can do the same using pactl move-source-output.

When you restart roc-send, pulseaudio should remember your last choice, however this functionality sometimes does not always behave as you can expect.

gavv commented 1 year ago

I've added pulseaudio source support to develop branch. It will be part of next release.

Example:

roc-send -vv -s rtp+rs8m://lo:10001 -r rs8m://lo:10002 -i pulse://<source_name>

You're welcome to test it :)

https://github.com/roc-streaming/roc-toolkit/issues/312

zopieux commented 1 year ago

Tested with the recent roc-droid demo app:

$ ./build/src/x86_64-unknown-linux-gnu/gcc-12.2.0-release/roc-send -vv -s rtp+rs8m://192.168.1.139:10001 -r rs8m://192.168.1.139:10002 -i pulse://garbage
21:52:32.714 [5161] [err] roc_sndio: backend dispatcher: failed to open source: type=device driver=pulse path=garbage
$ ./build/src/x86_64-unknown-linux-gnu/gcc-12.2.0-release/roc-send -vv -s rtp+rs8m://192.168.1.139:10001 -r rs8m://192.168.1.139:10002 -i pulse://alsa_output.usb-RODE_Microphones_RODE_AI-1_C164EE29-00.analog-stereo.monitor
21:58:25.548 [5520] [inf] roc_sndio: pulseaudio source: opening stream: device=alsa_output.usb-RODE_Microphones_RODE_AI-1_C164EE29-00.analog-stereo.monitor n_channels=2 sample_rate=48000
21:58:25.566 [5517] [dbg] roc_peer: sender peer: initializing
21:58:25.566 [5520] [dbg] roc_sndio: pulseaudio source: stream_latency=2
…
21:58:25.566 [5517] [dbg] roc_fec: openfec encoder: initializing: codec=rs m=8
21:58:25.566 [5517] [dbg] roc_fec: fec writer: update block size: cur_sbl=0 cur_rbl=0 new_sbl=20 new_rbl=10
21:58:25.566 [5517] [dbg] roc_audio: packetizer: initializing: n_channels=2 samples_per_packet=309
21:58:25.566 [5517] [dbg] roc_audio: speex resampler: initializing: quality=5 frame_size=672 channels_num=2
…
22:00:07.545 [5517] [dbg] roc_netio: udp sender: <udpsend 0x1508f8000b70 bind=0.0.0.0:60527>: total=21402 nb=21402 nb_ratio=1.00000
22:00:16.173 [5520] [dbg] roc_sndio: pulseaudio source: stream_latency=92162
22:00:26.679 [5520] [dbg] roc_sndio: pulseaudio source: stream_latency=88066
22:00:27.684 [5517] [dbg] roc_audio: speex resampler: ratio_num=50000 ratio_den=45937 in_rate=48000 out_rate=44100 in_latency=44 out_latency=40

Works like a charm! Awesome, thanks for the quick turnaround.

I do experience a whopping 3s+ of lag between the realtime speaker output (from the sending workstation) to the receiver, though, compared to sub-500ms I get using the alsa driver, with the exact same configuration. Is this expected?

zopieux commented 1 year ago

Forgot to mention, the pulse source selection works just as well, I can easily select my microphone or the stereo "monitor" (loopback).

gavv commented 1 year ago

Thanks for testing and report!

The high latency is not expected, it should be possible to set pulseaudio part of the latency from ~15s to ~60ms depending on device, and 60ms is expected to be default (since it works well for most devices).

I was able to reproduce it, looking into it.

gavv commented 1 year ago

@zopieux I've pushed a fix for the latency to develop branch (cafa5a49327763a4b7a3ab9e45e2a8fb22dbc7ec). Pulseaudio part of the latency by default is about 60ms now.

I also added --io-latency option to roc-send (d65cfbfa5d5ad853f0c07b1010137cb66304d610), which allows to set that part of the latency manually. In my experience, on many devices you can safely set it to 20-30 ms, and sometimes even lower. (but usually you need rtkit for that).

zopieux commented 1 year ago

Indeed, greatly reduced latency with develop HEAD, and I could reduce it further using --io-latency. Awesome thanks! Somehow it's still not going below 100ms on localhost but maybe I'm handling this wrong. I suppose we can consider this issue fixed!

gavv commented 1 year ago

Thanks for checking!

Somehow it's still not going below 100ms on localhost but maybe I'm handling this wrong.

If you mean overall latency from sender input to receiver output, you can:

gavv commented 1 year ago

More about latency: https://github.com/roc-streaming/roc-toolkit/discussions/255 More about FEC: https://roc-streaming.org/toolkit/docs/internals/fec.html

gavv commented 1 year ago

I also plan to add adaptive latency algorithm, so that all these parameters will be adjusting automatically on fly, depending on network characteristics. Who knows when I'll have time for it...

gavv commented 1 year ago

@zopieux @Ramblurr BTW what is your use-case for using pulseaudio input device? Just curious.

zopieux commented 1 year ago

As I mentioned in my previous comment, mostly being able to roc-send my puselaudio (well, pipewire really) output stereo mix to other devices, a bit like snapcast.

Thanks for the nice comment about all the parameters, I'd recommend putting the discussion page you wrote in the docs, it's quite helpful and would become more discoverable.

Edit: indeed, setting the receiver's --sess-latency was definitely what helped most getting in the sub-20ms realm. Thanks!

gavv commented 1 year ago

I see, thanks. I thought you're also streaming from mic.

BTW you can also use pipewire modules for roc.

I'd recommend putting the discussion page you wrote in the docs, it's quite helpful and would become more discoverable.

Definitely, it's on my TODO.

I'm closing this. @Ramblurr feel free to reopen if needed!