Tips en Trucs 2024

Netwerkaudio

Als stereo-installatie gebruik ik een Raspberry Pi die eveneens als domotica-controller dienst doet, uitgebreid met een DigiAMP+ eindversterker. Radio luisteren we nu via internet. En TV kijken we al lang via internet op de monitor van de computer. Maar hoe koppel je alles aan elkaar, jawel via het netwerk.

Roc streaming

Er bestaat verschillende software om geluid via een netwerk naar andere apparaten te sturen. Maar bij het kijken naar TV en/of video moet je letten op latency (vertraging). Een te hoge latency zorgt dat de lippen van sprekende mensen reeds bewegen voor je het geluid hoort. M.a.w. het geluid loopt niet synchroon met het beeld, het geluid loopt namelijk achter op de beelden.

Na lang zoeken kon enkel Roc streaming de latency zo laag houden dat het niet meer opvalt.

Raspberry Pi

Eerst werd de versterker uitbreiding (HAT) op de Raspberry Pi geïnstalleerd. De luidsprekers aangesloten. Raspberry Pi OS geconfigureerd om de versterker te gebruiken. MPD software geïnstalleerd en geconfigureerd om radio te beluisteren. De Raspberry Pi kan dus al als radiotuner en versterker fungeren.

Debian 12 Bookworm

Computers met eenvoudige audio hardware hebben meestal geen mogelijkheid om het geproduceerde geluid op te nemen. En dus ook niet de mogelijkheid om geluid via het netwerk om te leiden naar een ander apparaat. Gelukkig bestaat er een software oplossing.

Met behulp van een kernel module (systeemuitbreiding) wordt een virtueel audio apparaat aangemaakt met zowel afspeel en opname mogelijkheden. De huidige afspeelapparaten kan je opvragen met de opdracht:

dany@pindabook:~$ aplay -l
**** List of PLAYBACK Hardware Devices ****
card 0: HDMI [HDA Intel HDMI], device 3: HDMI 0 [HDMI 0]
  Subdevices: 1/1
  Subdevice #0: subdevice #0
card 0: HDMI [HDA Intel HDMI], device 7: HDMI 1 [HDMI 1]
  Subdevices: 1/1
  Subdevice #0: subdevice #0
card 0: HDMI [HDA Intel HDMI], device 8: HDMI 2 [HDMI 2]
  Subdevices: 1/1
  Subdevice #0: subdevice #0
card 1: PCH [HDA Intel PCH], device 0: CX20751/2 Analog [CX20751/2 Analog]
  Subdevices: 1/1
  Subdevice #0: subdevice #0

Het virtuele audioapparaat voeg je aan de kernel toe met de opdracht:

dany@pindabook:~$ sudo modprobe snd-aloop
[sudo] wachtwoord voor root:

Waardoor de volgende afspeelapparaten beschikbaar zijn:

dany@pindabook:~$ aplay -l
**** List of PLAYBACK Hardware Devices ****
card 0: HDMI [HDA Intel HDMI], device 3: HDMI 0 [HDMI 0]
  Subdevices: 1/1
  Subdevice #0: subdevice #0
card 0: HDMI [HDA Intel HDMI], device 7: HDMI 1 [HDMI 1]
  Subdevices: 1/1
  Subdevice #0: subdevice #0
card 0: HDMI [HDA Intel HDMI], device 8: HDMI 2 [HDMI 2]
  Subdevices: 1/1
  Subdevice #0: subdevice #0
card 1: PCH [HDA Intel PCH], device 0: CX20751/2 Analog [CX20751/2 Analog]
  Subdevices: 1/1
  Subdevice #0: subdevice #0
card 2: Loopback [Loopback], device 0: Loopback PCM [Loopback PCM]
  Subdevices: 8/8
  Subdevice #0: subdevice #0
  Subdevice #1: subdevice #1
  Subdevice #2: subdevice #2
  Subdevice #3: subdevice #3
  Subdevice #4: subdevice #4
  Subdevice #5: subdevice #5
  Subdevice #6: subdevice #6
  Subdevice #7: subdevice #7
card 2: Loopback [Loopback], device 1: Loopback PCM [Loopback PCM]
  Subdevices: 8/8
  Subdevice #0: subdevice #0
  Subdevice #1: subdevice #1
  Subdevice #2: subdevice #2
  Subdevice #3: subdevice #3
  Subdevice #4: subdevice #4
  Subdevice #5: subdevice #5
  Subdevice #6: subdevice #6
  Subdevice #7: subdevice #7

Zorg ervoor dat het toegevoegde virtuele audio apparaat het standaard afspeelapparaat wordt.

Standaard afspeelapparaat

Bij het afspelen van audio hoor je nu niets, dit is normaal. Om het virtuele audio apparaat bij elke systeemstart automatisch aan te maken, voer je de volgende opdracht uit:

dany@pindabook:~$ echo "snd-aloop" | sudo tee /etc/modules-load.d/snd-aloop.conf
snd-aloop

Let op: na een herstart zullen de audio apparaten hoogstwaarschijnlijk een andere volgorde hebben. Je kunt dit nagaan met de aplay -l opdracht.

Roc streaming tools installeren

De Roc streaming tools zijn in geen enkele softwarebron te vinden, m.a.w. we zullen de broncode zelf moeten compileren. We beginnen met het installeren van de voor het compileren van Roc noodzakelijke softwarepakketten:

dany@pindabook:~$ sudo apt install libuv1-dev libunwind-dev libssl-dev libspeexdsp-dev libsox-dev ragel gengetopt  libpulse-dev scons g++ cmake
Pakketlijsten worden ingelezen... Klaar
Boom van vereisten wordt opgebouwd... Klaar
De statusinformatie wordt gelezen... Klaar 
De volgende extra pakketten zullen geïnstalleerd worden:
  binutils binutils-common binutils-x86-64-linux-gnu cmake-data g++-12 gcc gcc-12 libasan8 libatomic1 libbinutils
  libblkid-dev libc-dev-bin libc-devtools libc6-dev libcc1-0 libcrypt-dev libctf-nobfd0 libctf0 libffi-dev
  libgcc-12-dev libglib2.0-dev libglib2.0-dev-bin libgprofng0 libid3tag0 libitm1 libjsoncpp25 liblsan0 liblzma-dev
  libmount-dev libnsl-dev libpcre2-32-0 libpcre2-dev libpcre2-posix3 libpkgconf3 librhash0 libselinux1-dev
  libsepol-dev libsox-fmt-all libsox-fmt-alsa libsox-fmt-ao libsox-fmt-base libsox-fmt-mp3 libsox-fmt-oss
  libsox-fmt-pulse libsox3 libstdc++-12-dev libtirpc-dev libtsan2 libubsan1 linux-libc-dev make manpages-dev
  pkg-config pkgconf pkgconf-bin python3-distutils python3-lib2to3 rpcsvc-proto uuid-dev zlib1g-dev
Voorgestelde pakketten:
  binutils-doc cmake-doc cmake-format elpa-cmake-mode ninja-build g++-multilib g++-12-multilib gcc-12-doc
  gcc-multilib autoconf automake libtool flex bison gcc-doc gcc-12-multilib gcc-12-locales glibc-doc
  libgirepository1.0-dev libglib2.0-doc liblzma-doc libspeex-dev speex-doc libssl-doc libstdc++-12-doc make-doc
  scons-doc
De volgende NIEUWE pakketten zullen geïnstalleerd worden:
  binutils binutils-common binutils-x86-64-linux-gnu cmake cmake-data g++ g++-12 gcc gcc-12 gengetopt libasan8
  libatomic1 libbinutils libblkid-dev libc-dev-bin libc-devtools libc6-dev libcc1-0 libcrypt-dev libctf-nobfd0
  libctf0 libffi-dev libgcc-12-dev libglib2.0-dev libglib2.0-dev-bin libgprofng0 libid3tag0 libitm1 libjsoncpp25
  liblsan0 liblzma-dev libmount-dev libnsl-dev libpcre2-32-0 libpcre2-dev libpcre2-posix3 libpkgconf3 libpulse-dev
  librhash0 libselinux1-dev libsepol-dev libsox-dev libsox-fmt-all libsox-fmt-alsa libsox-fmt-ao libsox-fmt-base
  libsox-fmt-mp3 libsox-fmt-oss libsox-fmt-pulse libsox3 libspeexdsp-dev libssl-dev libstdc++-12-dev libtirpc-dev
  libtsan2 libubsan1 libunwind-dev libuv1-dev linux-libc-dev make manpages-dev pkg-config pkgconf pkgconf-bin
  python3-distutils python3-lib2to3 ragel rpcsvc-proto scons uuid-dev zlib1g-dev
0 opgewaardeerd, 71 nieuw geïnstalleerd, 0 te verwijderen en 0 niet opgewaardeerd.
Er moeten 76,1 MB aan archieven opgehaald worden.
Na deze bewerking zal er 313 MB extra schijfruimte gebruikt worden.
Wilt u doorgaan? [J/n] 
Ophalen:1 http://deb.debian.org/debian bookworm/main amd64 binutils-common amd64 2.40-2 [2.487 kB]
Ophalen:2 http://deb.debian.org/debian bookworm/main amd64 libbinutils amd64 2.40-2 [572 kB]
Ophalen:3 http://deb.debian.org/debian bookworm/main amd64 libctf-nobfd0 amd64 2.40-2 [153 kB]
...
Ophalen:69 http://deb.debian.org/debian bookworm/main amd64 manpages-dev all 6.03-2 [2.030 kB]                     
Ophalen:70 http://deb.debian.org/debian bookworm/main amd64 ragel amd64 6.10-4 [1.078 kB]                          
Ophalen:71 http://deb.debian.org/debian bookworm/main amd64 scons all 4.4.0+dfsg-1 [663 kB]                        
76,1 MB opgehaald in 7s (11,5 MB/s)                                                                                
Extraheren van sjablonen uit pakketten: 100%
Voorheen niet geselecteerd pakket binutils-common:amd64 wordt geselecteerd.
(Database wordt ingelezen ... 173853 bestanden en mappen momenteel geïnstalleerd.)
Uitpakken van .../00-binutils-common_2.40-2_amd64.deb wordt voorbereid...
Bezig met uitpakken van binutils-common:amd64 (2.40-2) ...
...
Voorheen niet geselecteerd pakket scons wordt geselecteerd.
Uitpakken van .../70-scons_4.4.0+dfsg-1_all.deb wordt voorbereid...
Bezig met uitpakken van scons (4.4.0+dfsg-1) ...
Instellen van libuv1-dev:amd64 (1.44.2-1) ...
Instellen van manpages-dev (6.03-2) ...
Instellen van gengetopt (2.23+dfsg1-1) ...
...
Instellen van libblkid-dev:amd64 (2.38.1-5+b1) ...
Instellen van gcc (4:12.2.0-3) ...
Instellen van g++ (4:12.2.0-3) ...
update-alternatives: /usr/bin/g++ wordt gebruikt om in de automatische modus in /usr/bin/c++ (c++) te voorzien
Instellen van libmount-dev:amd64 (2.38.1-5+b1) ...
Instellen van libglib2.0-dev:amd64 (2.74.6-2) ...
Bezig met afhandelen van triggers voor install-info (6.8-6+b1) ...
Bezig met afhandelen van triggers voor libglib2.0-0:amd64 (2.74.6-2) ...
Bezig met afhandelen van triggers voor libc-bin (2.36-9+deb12u4) ...
Bezig met afhandelen van triggers voor man-db (2.11.2-2) ...
Instellen van libpulse-dev:amd64 (16.1+dfsg1-2+b1) ...

Daarna downloaden we de broncode:

dany@pindabook:~$ git clone https://github.com/roc-streaming/roc-toolkit.git
Cloning into 'roc-toolkit'...
remote: Enumerating objects: 27984, done.
remote: Counting objects: 100% (1691/1691), done.
remote: Compressing objects: 100% (528/528), done.
remote: Total 27984 (delta 1178), reused 1601 (delta 1138), pack-reused 26293
Receiving objects: 100% (27984/27984), 9.41 MiB | 10.22 MiB/s, done.
Resolving deltas: 100% (19889/19889), done.

En kunnen we de Roc streaming tools compileren (wees geduldig):

dany@pindabook:~$ cd roc-toolkit/
dany@pindabook:~/roc-toolkit$ scons -Q --build-3rdparty=openfec
    BUILD   build/3rdparty/x86_64-pc-linux-gnu/gcc-12.2.0-release/openfec-1.4.2.7
[download] https://github.com/roc-streaming/openfec/archive/v1.4.2.7.tar.gz
[unpack] openfec_v1.4.2.7.tar.gz
[execute] cmake .. -DBUILD_STATIC_LIBS=ON -DDEBUG:STRING=OFF -DCMAKE_C_COMPILER=/usr/bin/gcc-12 -DCMAKE_LINKER=/usr/bin/gcc-12 -DCMAKE_AR=/usr/bin/ar -DCMAKE_RANLIB=/usr/bin/ranlib -DCMAKE_POSITION_INDEPENDENT_CODE=ON -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_FLAGS_RELEASE:STRING=-fPIC
[execute] cmake --build . -- VERBOSE=1 -j4
[install] build/3rdparty/x86_64-pc-linux-gnu/gcc-12.2.0-release/openfec-1.4.2.7/include
[install] build/3rdparty/x86_64-pc-linux-gnu/gcc-12.2.0-release/openfec-1.4.2.7/lib/libopenfec.a
      CXX   src/public_api/src/adapters.cpp
      CXX   src/public_api/src/arena.cpp
      CXX   src/public_api/src/context.cpp
...
      CXX   src/internal_modules/roc_core/target_posix/roc_core/time.cpp
      CXX   src/internal_modules/roc_core/target_posix_ext/roc_core/semaphore.cpp
      CXX   src/internal_modules/roc_core/target_posix_pc/roc_core/console.cpp
      GGO   src/tools/roc_copy/cmdline.ggo
      CXX   src/tools/roc_copy/main.cpp
       CC   build/src/x86_64-pc-linux-gnu/gcc-12.2.0-release/tools/roc_copy/cmdline.c
       AR   build/src/x86_64-pc-linux-gnu/gcc-12.2.0-release/internal_modules/libroc_core.a
   RANLIB   build/src/x86_64-pc-linux-gnu/gcc-12.2.0-release/internal_modules/libroc_core.a
      GGO   src/tools/roc_recv/cmdline.ggo
      CXX   src/tools/roc_recv/main.cpp
       CC   build/src/x86_64-pc-linux-gnu/gcc-12.2.0-release/tools/roc_recv/cmdline.c
      GGO   src/tools/roc_send/cmdline.ggo
      CXX   src/tools/roc_send/main.cpp
       CC   build/src/x86_64-pc-linux-gnu/gcc-12.2.0-release/tools/roc_send/cmdline.c
      ART   build/src/x86_64-pc-linux-gnu/gcc-12.2.0-release/compile_commands.json
      GEN   build/src/x86_64-pc-linux-gnu/gcc-12.2.0-release/roc.pc
  INSTALL   compile_commands.json
       AR   build/src/x86_64-pc-linux-gnu/gcc-12.2.0-release/internal_modules/libroc_audio.a
   RANLIB   build/src/x86_64-pc-linux-gnu/gcc-12.2.0-release/internal_modules/libroc_audio.a
       LD   build/src/x86_64-pc-linux-gnu/gcc-12.2.0-release/roc-recv
       LD   build/src/x86_64-pc-linux-gnu/gcc-12.2.0-release/libroc_unstripped.so.0.3
       LD   build/src/x86_64-pc-linux-gnu/gcc-12.2.0-release/roc-send
       LD   build/src/x86_64-pc-linux-gnu/gcc-12.2.0-release/roc-copy
  INSTALL   bin/x86_64-pc-linux-gnu/roc-copy
       CP   build/src/x86_64-pc-linux-gnu/gcc-12.2.0-release/libroc.so.0.3
    STRIP   build/src/x86_64-pc-linux-gnu/gcc-12.2.0-release/libroc.so.0.3
  INSTALL   bin/x86_64-pc-linux-gnu/libroc.so.0.3
       LN   bin/x86_64-pc-linux-gnu/libroc.so.0
       LN   bin/x86_64-pc-linux-gnu/libroc.so
  INSTALL   bin/x86_64-pc-linux-gnu/roc-send
  INSTALL   bin/x86_64-pc-linux-gnu/roc-recv

Nu de software gecompileerd is kunnen we ze installeren:

dany@pindabook:~/roc-toolkit$ sudo scons -Q --build-3rdparty=openfec install
[sudo] wachtwoord voor root: 
  INSTALL   /usr/share/man/man1/roc-copy.1
  INSTALL   /usr/share/man/man1/roc-recv.1
  INSTALL   /usr/share/man/man1/roc-send.1
  INSTALL   /usr/lib/x86_64-linux-gnu/libroc.so.0.3
  INSTALL   /usr/lib/x86_64-linux-gnu/libroc.so.0
  INSTALL   /usr/lib/x86_64-linux-gnu/libroc.so
  INSTALL   /usr/include/roc
  INSTALL   /usr/lib/x86_64-linux-gnu/pkgconfig/roc.pc
  INSTALL   /usr/bin/roc-copy
  INSTALL   /usr/bin/roc-recv
  INSTALL   /usr/bin/roc-send

Audio streamen met Roc

Om de Roc streaming tools te testen, gebruiken we één computer. M.a.w. we sturen het geluid het netwerk op en terug naar dezelfde computer (localhost met het ip adres 127.0.0.1). Het geluid wordt door Roc ontvangen en afgespeeld op de fysieke geluidskaart.

Eerst starten we de ontvanger met de opdracht:

dany@pindabook:~/roc-toolkit$ roc-recv -vv -s rtp+rs8m://0.0.0.0:10001 -r rs8m://0.0.0.0:10002 -c rtcp://0.0.0.0:10003 -o alsa://plughw:CARD=PCH,DEV=0
16:41:08.015 [4197] [dbg] roc_core: [slab_pool_impl.cpp:56] pool: initializing: name=packet_pool object_size=704 min_slab=8B(1S) max_slab=0B(0S)
16:41:08.015 [4197] [dbg] roc_core: [slab_pool_impl.cpp:56] pool: initializing: name=buffer_pool object_size=2096 min_slab=8B(1S) max_slab=0B(0S)
16:41:08.015 [4197] [dbg] roc_core: [slab_pool_impl.cpp:56] pool: initializing: name=buffer_pool object_size=4144 min_slab=8B(1S) max_slab=0B(0S)
16:41:08.015 [4197] [dbg] roc_core: [slab_pool_impl.cpp:56] pool: initializing: name=format_pool object_size=280 min_slab=4480B(16S) max_slab=0B(0S)
16:41:08.015 [4198] [dbg] roc_netio: [network_loop.cpp:278] network loop: starting event loop
16:41:08.015 [4199] [dbg] roc_ctl: [control_task_queue.cpp:95] control task queue: starting event loop
16:41:08.015 [4197] [dbg] roc_node: [context.cpp:24] context: initializing
16:41:08.015 [4197] [dbg] roc_sndio: [pulseaudio_backend.cpp:21] pulseaudio backend: initializing
16:41:08.015 [4197] [dbg] roc_sndio: [sox_backend.cpp:164] sox backend: initializing
16:41:08.022 [4197] [dbg] roc_sndio: [backend_map.cpp:19] backend map: initialized: n_backends=2 n_drivers=82
16:41:08.022 [4197] [dbg] roc_sndio: [sox_sink.cpp:62] sox sink: opening: driver=alsa path=plughw:CARD=PCH,DEV=0
16:41:08.065 [4197] [inf] roc_sndio: [sox_sink.cpp:215] sox sink: opened: bits=32 out_rate=48000 in_rate=0 ch=2 is_file=0
16:41:08.065 [4197] [dbg] roc_core: [slab_pool_impl.cpp:56] pool: initializing: name=slot_pool object_size=632 min_slab=8B(1S) max_slab=0B(0S)
16:41:08.065 [4197] [dbg] roc_node: [receiver.cpp:34] receiver node: initializing
16:41:08.065 [4197] [dbg] roc_node: [receiver.cpp:74] receiver node: configuring audiosrc interface of slot 0
16:41:08.065 [4197] [inf] roc_pipeline: [receiver_source.cpp:64] receiver source: adding slot
16:41:08.065 [4197] [dbg] roc_pipeline: [receiver_slot.cpp:36] receiver slot: initializing
16:41:08.065 [4197] [inf] roc_node: [receiver.cpp:121] receiver node: binding audiosrc interface of slot 0 to rtp+rs8m://0.0.0.0:10001
16:41:08.066 [4197] [dbg] roc_pipeline: [receiver_slot.cpp:41] receiver slot: adding audiosrc endpoint rtp+rs8m
16:41:08.066 [4198] [dbg] roc_netio: [udp_receiver_port.cpp:116] udp receiver: : opened port
16:41:08.066 [4197] [dbg] roc_node: [receiver.cpp:74] receiver node: configuring audiorpr interface of slot 0
16:41:08.066 [4197] [inf] roc_node: [receiver.cpp:121] receiver node: binding audiorpr interface of slot 0 to rs8m://0.0.0.0:10002
16:41:08.066 [4197] [dbg] roc_pipeline: [receiver_slot.cpp:41] receiver slot: adding audiorpr endpoint rs8m
16:41:08.066 [4198] [dbg] roc_netio: [udp_receiver_port.cpp:116] udp receiver: : opened port
16:41:08.066 [4197] [dbg] roc_node: [receiver.cpp:74] receiver node: configuring audioctl interface of slot 0
16:41:08.066 [4197] [inf] roc_node: [receiver.cpp:121] receiver node: binding audioctl interface of slot 0 to rtcp://0.0.0.0:10003
16:41:08.066 [4197] [dbg] roc_pipeline: [receiver_slot.cpp:41] receiver slot: adding audioctl endpoint rtcp
16:41:08.066 [4198] [dbg] roc_netio: [udp_receiver_port.cpp:116] udp receiver: : opened port
16:41:08.066 [4197] [dbg] roc_sndio: [pump.cpp:55] pump: starting main loop
16:41:08.066 [4197] [dbg] roc_pipeline: [pipeline_loop.cpp:456] pipeline loop: tasks=4 in_place=1.00 in_frame=0.00 preempts=0 sched=0/0
...

Deze opdracht blijft luisteren naar te ontvangen geluid op het netwerk. We moeten dus een tweede terminal starten om geluid het netwerk op te sturen.

Nu kunnen we met de volgende opdracht het geluid uit een stereo wav bestand (gebruikt testbestand: speakertest.wav) naar de computer met het ip adres 127.0.0.1 (localhost of zoals in het voorbeeld de hostnaam van de computer - pindabook.local) sturen:

dany@pindabook:~$ roc-send -vv -s rtp+rs8m://pindabook.local:10001 -r rs8m://pindabook.local:10002 -c rtcp://pindabook.local:10003 -i file:Muziek/speakertest.wav
16:51:40.552 [4354] [dbg] roc_core: [slab_pool_impl.cpp:56] pool: initializing: name=packet_pool object_size=704 min_slab=8B(1S) max_slab=0B(0S)
16:51:40.552 [4354] [dbg] roc_core: [slab_pool_impl.cpp:56] pool: initializing: name=buffer_pool object_size=2096 min_slab=8B(1S) max_slab=0B(0S)
16:51:40.552 [4354] [dbg] roc_core: [slab_pool_impl.cpp:56] pool: initializing: name=buffer_pool object_size=4144 min_slab=8B(1S) max_slab=0B(0S)
16:51:40.552 [4354] [dbg] roc_core: [slab_pool_impl.cpp:56] pool: initializing: name=format_pool object_size=280 min_slab=4480B(16S) max_slab=0B(0S)
16:51:40.552 [4355] [dbg] roc_netio: [network_loop.cpp:278] network loop: starting event loop
16:51:40.552 [4354] [dbg] roc_node: [context.cpp:24] context: initializing
16:51:40.552 [4356] [dbg] roc_ctl: [control_task_queue.cpp:95] control task queue: starting event loop
16:51:40.552 [4354] [dbg] roc_sndio: [pulseaudio_backend.cpp:21] pulseaudio backend: initializing
16:51:40.552 [4354] [dbg] roc_sndio: [sox_backend.cpp:164] sox backend: initializing
16:51:40.559 [4354] [dbg] roc_sndio: [backend_map.cpp:19] backend map: initialized: n_backends=2 n_drivers=82
16:51:40.559 [4354] [inf] roc_sndio: [sox_source.cpp:65] sox source: opening: driver=(null) path=Muziek/speakertest.wav
16:51:40.559 [4354] [dbg] roc_sndio: [sox_backend.cpp:157] sox: formats.c: detected file format type `wav'
16:51:40.559 [4354] [inf] roc_sndio: [sox_source.cpp:363] sox source: in_bits=16 out_bits=32 in_rate=48000 out_rate=0 in_ch=2 out_ch=0 is_file=1
16:51:40.559 [4354] [dbg] roc_core: [slab_pool_impl.cpp:56] pool: initializing: name=slot_pool object_size=512 min_slab=8B(1S) max_slab=0B(0S)
16:51:40.559 [4354] [dbg] roc_node: [sender.cpp:32] sender node: initializing
16:51:40.559 [4354] [dbg] roc_node: [sender.cpp:72] sender node: configuring audiosrc interface of slot 0
16:51:40.559 [4354] [inf] roc_pipeline: [sender_sink.cpp:53] sender sink: adding slot
16:51:40.559 [4354] [inf] roc_node: [sender.cpp:119] sender node: connecting audiosrc interface of slot 0 to rtp+rs8m://pindabook.local:10001
16:51:40.560 [4355] [dbg] roc_netio: [udp_sender_port.cpp:130] udp sender: : opened port
16:51:40.560 [4354] [inf] roc_node: [sender.cpp:472] sender node: bound audiosrc interface to 0.0.0.0:43178
16:51:40.560 [4354] [dbg] roc_pipeline: [sender_slot.cpp:45] sender slot: adding audiosrc endpoint rtp+rs8m
16:51:40.560 [4354] [dbg] roc_node: [sender.cpp:72] sender node: configuring audiorpr interface of slot 0
16:51:40.560 [4354] [inf] roc_node: [sender.cpp:119] sender node: connecting audiorpr interface of slot 0 to rs8m://pindabook.local:10002
16:51:40.560 [4354] [dbg] roc_node: [sender.cpp:415] sender node: sharing audiosrc interface port with audiorpr interface
16:51:40.560 [4354] [dbg] roc_pipeline: [sender_slot.cpp:45] sender slot: adding audiorpr endpoint rs8m
16:51:40.560 [4354] [dbg] roc_fec: [openfec_encoder.cpp:27] openfec encoder: initializing: codec=rs m=8
16:51:40.560 [4354] [dbg] roc_fec: [writer.cpp:84] fec writer: update block size: cur_sbl=0 cur_rbl=0 new_sbl=18 new_rbl=10
16:51:40.560 [4354] [dbg] roc_audio: [packetizer.cpp:49] packetizer: initializing: n_channels=2 samples_per_packet=221
16:51:40.560 [4354] [dbg] roc_audio: [speex_resampler.cpp:99] speex resampler: initializing: quality=5 frame_size=80 channels_num=2
16:51:40.561 [4354] [dbg] roc_node: [sender.cpp:72] sender node: configuring audioctl interface of slot 0
16:51:40.561 [4354] [inf] roc_node: [sender.cpp:119] sender node: connecting audioctl interface of slot 0 to rtcp://pindabook.local:10003
16:51:40.561 [4355] [dbg] roc_netio: [udp_sender_port.cpp:130] udp sender: : opened port
16:51:40.561 [4354] [inf] roc_node: [sender.cpp:472] sender node: bound audioctl interface to 0.0.0.0:58337
16:51:40.561 [4354] [dbg] roc_pipeline: [sender_slot.cpp:45] sender slot: adding audioctl endpoint rtcp
16:51:40.561 [4354] [dbg] roc_rtcp: [session.cpp:40] rtcp session: initialized: is_sender=1 is_receiver=0 ssrc=2928049869 cname=TODO
16:51:40.561 [4354] [dbg] roc_sndio: [pump.cpp:55] pump: starting main loop
16:51:40.561 [4354] [dbg] roc_audio: [speex_resampler.cpp:287] speex resampler: ratio=160/147 rates=48000/44100 latency=44 latency_diff=4
16:51:40.561 [4354] [dbg] roc_packet: [router.cpp:62] router: detected new stream: source=359590135 flags=0x10
16:51:40.561 [4354] [dbg] roc_netio: [udp_sender_port.cpp:355] udp sender: : total=1 nb=1 nb_ratio=1.00000
16:51:40.561 [4354] [dbg] roc_rtp: [timestamp_extractor.cpp:81] timestamp extractor: returning mapping: cts:1710085900561732027/sts:100226189
16:51:40.561 [4354] [dbg] roc_netio: [udp_sender_port.cpp:355] udp sender: : total=1 nb=1 nb_ratio=1.00000
16:51:40.561 [4354] [dbg] roc_pipeline: [pipeline_loop.cpp:456] pipeline loop: tasks=5 in_place=1.00 in_frame=0.00 preempts=0 sched=0/0
16:51:40.651 [4354] [dbg] roc_packet: [router.cpp:62] router: detected new stream: source=0 flags=0x20
16:51:43.562 [4354] [dbg] roc_sndio: [sox_source.cpp:258] sox source: got eof from sox
16:51:43.571 [4354] [dbg] roc_sndio: [pump.cpp:92] pump: got eof from source
16:51:43.571 [4354] [dbg] roc_sndio: [pump.cpp:107] pump: exiting main loop, wrote 302 buffers from main source
16:51:43.571 [4354] [dbg] roc_node: [sender.cpp:45] sender node: deinitializing
16:51:43.571 [4354] [inf] roc_pipeline: [sender_sink.cpp:72] sender sink: removing slot
16:51:43.571 [4355] [dbg] roc_netio: [network_loop.cpp:559] network loop: removing port 
16:51:43.571 [4355] [dbg] roc_netio: [udp_sender_port.cpp:312] udp sender: : initiating asynchronous close
16:51:43.572 [4355] [dbg] roc_netio: [udp_sender_port.cpp:214] udp sender: : closed port
16:51:43.572 [4355] [dbg] roc_netio: [network_loop.cpp:263] network loop: asynchronous close finished: port 
16:51:43.572 [4355] [dbg] roc_netio: [network_loop.cpp:559] network loop: removing port 
16:51:43.572 [4355] [dbg] roc_netio: [udp_sender_port.cpp:312] udp sender: : initiating asynchronous close
16:51:43.572 [4355] [dbg] roc_netio: [udp_sender_port.cpp:214] udp sender: : closed port
16:51:43.572 [4355] [dbg] roc_netio: [network_loop.cpp:263] network loop: asynchronous close finished: port 
16:51:43.572 [4354] [inf] roc_sndio: [sox_source.cpp:380] sox source: closing input
16:51:43.572 [4354] [dbg] roc_node: [context.cpp:28] context: deinitializing
16:51:43.572 [4356] [dbg] roc_ctl: [control_task_queue.cpp:105] control task queue: finishing event loop
16:51:43.572 [4355] [dbg] roc_netio: [network_loop.cpp:285] network loop: finishing event loop

Je moet nu geluid horen en de terminal met de ontvanger geeft extra meldingen weer:

...
16:51:13.150 [4351] [dbg] roc_pipeline: [receiver_slot.cpp:41] receiver slot: adding audioctl endpoint rtcp
16:51:13.150 [4352] [dbg] roc_netio: [udp_receiver_port.cpp:116] udp receiver: : opened port
16:51:13.150 [4351] [dbg] roc_sndio: [pump.cpp:55] pump: starting main loop
16:51:13.150 [4351] [dbg] roc_pipeline: [pipeline_loop.cpp:456] pipeline loop: tasks=4 in_place=1.00 in_frame=0.00 preempts=0 sched=0/0
16:51:40.575 [4351] [inf] roc_pipeline: [receiver_session_group.cpp:226] session group: creating session: src_addr=127.0.0.1:43178 dst_addr=0.0.0.0:10001
16:51:40.575 [4351] [dbg] roc_packet: [delayed_reader.cpp:25] delayed reader: initializing: delay=8820
16:51:40.575 [4351] [dbg] roc_fec: [openfec_decoder.cpp:40] openfec decoder: initializing: codec=rs m=8
16:51:40.575 [4351] [dbg] roc_audio: [depacketizer.cpp:55] depacketizer: initializing: n_channels=2
16:51:40.575 [4351] [dbg] roc_audio: [watchdog.cpp:67] watchdog: initializing: max_blank_duration=11760 max_drops_duration=88200 drop_detection_window=13230
16:51:40.575 [4351] [dbg] roc_audio: [speex_resampler.cpp:99] speex resampler: initializing: quality=5 frame_size=80 channels_num=2
16:51:40.575 [4351] [dbg] roc_audio: [latency_monitor.cpp:65] latency monitor: initializing: target=8820(200.000ms) min=0(0.000ms) max=17640(400.000ms) in_rate=44100 out_rate=48000 fe_enable=1 fe_profile=gradual fe_interval=5.011ms
16:51:40.575 [4351] [dbg] roc_audio: [freq_estimator.cpp:73] freq estimator: initializing: P=1.000000e-06 I=5.000000e-09 dc1=10 dc2=10
16:51:40.576 [4351] [dbg] roc_packet: [router.cpp:62] router: detected new stream: source=359590135 flags=0x10
16:51:40.576 [4351] [dbg] roc_rtcp: [session.cpp:40] rtcp session: initialized: is_sender=0 is_receiver=1 ssrc=2212033198 cname=TODO
16:51:40.576 [4351] [dbg] roc_rtp: [timestamp_injector.cpp:66] timestamp injector: received mapping: old=cts:0/sts:0 new=cts:1710085900561732026/sts:100226189 has_ts=0 n_drops=0
16:51:40.576 [4351] [dbg] roc_audio: [speex_resampler.cpp:287] speex resampler: ratio=147/160 rates=44100/48000 latency=40 latency_diff=0
16:51:40.576 [4351] [dbg] roc_audio: [depacketizer.cpp:332] depacketizer: ts=40 loss_ratio=0.00000
16:51:40.584 [4351] [dbg] roc_audio: [watchdog.cpp:241] watchdog: status: bbbbbbbbbbbbbbbbbbbb
16:51:40.603 [4351] [dbg] roc_audio: [watchdog.cpp:241] watchdog: status: bbbbbbbbbbbbbbbbbbbb
16:51:40.621 [4351] [dbg] roc_audio: [watchdog.cpp:241] watchdog: status: bbbbbbbbbbbbbbbbbbbb
16:51:40.639 [4351] [dbg] roc_audio: [watchdog.cpp:241] watchdog: status: bbbbbbbbbbbbbbbbbbbb
16:51:40.649 [4351] [dbg] roc_audio: [watchdog.cpp:241] watchdog: status: bbbbbbbbbbbbbbbbbbbb
16:51:40.657 [4351] [dbg] roc_packet: [router.cpp:62] router: detected new stream: source=0 flags=0x20
16:51:40.667 [4351] [dbg] roc_audio: [watchdog.cpp:241] watchdog: status: bbbbbbbbbbbbbbbbbbbb
16:51:40.694 [4351] [dbg] roc_audio: [watchdog.cpp:241] watchdog: status: bbbbbbbbbbbbbbbbbbbb
16:51:40.712 [4351] [dbg] roc_audio: [watchdog.cpp:241] watchdog: status: bbbbbbbbbbbbbbbbbbbb
16:51:40.731 [4351] [dbg] roc_audio: [watchdog.cpp:241] watchdog: status: bbbbbbbbbbbbbbbbbbbb
16:51:40.740 [4351] [dbg] roc_audio: [watchdog.cpp:241] watchdog: status: bbbbbbbbbbbbbbbbbbbb
16:51:40.758 [4351] [dbg] roc_audio: [watchdog.cpp:241] watchdog: status: bbbbbbbbbbbbbbbbbbbb
16:51:40.768 [4351] [dbg] roc_packet: [delayed_reader.cpp:66] delayed reader: initial queue: delay=8820 queue=9061 packets=41
16:51:40.768 [4351] [dbg] roc_packet: [delayed_reader.cpp:90] delayed reader: trimmed queue: delay=8820 queue=8840 packets=40
16:51:40.768 [4351] [dbg] roc_fec: [reader.cpp:631] fec reader: update payload size: next_esi=0 cur_size=0 new_size=896
16:51:40.768 [4351] [dbg] roc_fec: [reader.cpp:686] fec reader: update source block size: cur_sblen=0 cur_rblen=0 new_sblen=18
16:51:40.768 [4351] [dbg] roc_audio: [depacketizer.cpp:257] depacketizer: got first packet: zero_samples=8880
16:51:40.768 [4351] [dbg] roc_audio: [latency_monitor.cpp:325] latency monitor: e2e_latency=0(0.000ms) niq_latency=8800(199.546ms) target_latency=8820(200.000ms) fe=1.000000 trim_fe=1.000000
16:51:40.777 [4351] [dbg] roc_audio: [watchdog.cpp:241] watchdog: status: bb..................
16:51:40.851 [4351] [dbg] roc_fec: [reader.cpp:788] fec reader: repair queue: dropped=10
16:51:40.851 [4351] [dbg] roc_fec: [reader.cpp:128] fec reader: got first packet in a block, start decoding: n_packets_before=17 sbn=44516
16:51:40.851 [4351] [dbg] roc_fec: [reader.cpp:749] fec reader: update repair block size: cur_sblen=18 cur_rblen=0 new_rblen=237
16:51:43.791 [4351] [dbg] roc_audio: [watchdog.cpp:241] watchdog: status: ..ibbbbbbbbbbbbbbbbb
16:51:43.809 [4351] [dbg] roc_audio: [watchdog.cpp:241] watchdog: status: bbbbbbbbbbbbbbbbbbbb
16:51:43.827 [4351] [dbg] roc_audio: [watchdog.cpp:241] watchdog: status: bbbbbbbbbbbbbbbbbbbb
16:51:43.855 [4351] [dbg] roc_audio: [watchdog.cpp:241] watchdog: status: bbbbbbbbbbbbbbbbbbbb
16:51:43.864 [4351] [dbg] roc_audio: [watchdog.cpp:241] watchdog: status: bbbbbbbbbbbbbbbbbbbb
16:51:43.883 [4351] [dbg] roc_audio: [watchdog.cpp:241] watchdog: status: bbbbbbbbbbbbbbbbbbbb
16:51:43.901 [4351] [dbg] roc_audio: [watchdog.cpp:241] watchdog: status: bbbbbbbbbbbbbbbbbbbb
16:51:43.919 [4351] [dbg] roc_audio: [watchdog.cpp:241] watchdog: status: bbbbbbbbbbbbbbbbbbbb
16:51:43.938 [4351] [dbg] roc_audio: [watchdog.cpp:241] watchdog: status: bbbbbbbbbbbbbbbbbbbb
16:51:43.965 [4351] [dbg] roc_audio: [watchdog.cpp:241] watchdog: status: bbbbbbbbbbbbbbbbbbbb
16:51:43.975 [4351] [dbg] roc_audio: [watchdog.cpp:241] watchdog: status: bbbbbbbbbbbbbbbbbbbb
16:51:43.993 [4351] [dbg] roc_audio: [watchdog.cpp:241] watchdog: status: bbbbbbbbbbbbbbbbbbbb
16:51:44.011 [4351] [dbg] roc_audio: [watchdog.cpp:241] watchdog: status: bbbbbbbbbbbbbbbbbbbb
16:51:44.030 [4351] [dbg] roc_audio: [watchdog.cpp:241] watchdog: status: bbbbbbbbbbbbbbbbbbbb
16:51:44.039 [4351] [dbg] roc_audio: [watchdog.cpp:142] watchdog: blank timeout reached: every frame was blank during timeout: curr_read_pos=153480 last_pos_before_blank=141720 max_blank_duration=11760
16:51:44.039 [4351] [dbg] roc_audio: [watchdog.cpp:241] watchdog: status: bbbbbbbbbbbbbbbbb
16:51:44.039 [4351] [inf] roc_pipeline: [receiver_session_group.cpp:259] session group: removing session
16:52:13.154 [4351] [dbg] roc_pipeline: [pipeline_loop.cpp:456] pipeline loop: tasks=4 in_place=1.00 in_frame=0.00 preempts=0 sched=0/0
16:53:13.158 [4351] [dbg] roc_pipeline: [pipeline_loop.cpp:456] pipeline loop: tasks=4 in_place=1.00 in_frame=0.00 preempts=0 sched=0/0
16:54:13.153 [4351] [dbg] roc_pipeline: [pipeline_loop.cpp:456] pipeline loop: tasks=4 in_place=1.00 in_frame=0.00 preempts=0 sched=0/0
16:55:13.167 [4351] [dbg] roc_pipeline: [pipeline_loop.cpp:456] pipeline loop: tasks=4 in_place=1.00 in_frame=0.00 preempts=0 sched=0/0
16:56:13.153 [4351] [dbg] roc_pipeline: [pipeline_loop.cpp:456] pipeline loop: tasks=4 in_place=1.00 in_frame=0.00 preempts=0 sched=0/0
16:57:13.158 [4351] [dbg] roc_pipeline: [pipeline_loop.cpp:456] pipeline loop: tasks=4 in_place=1.00 in_frame=0.00 preempts=0 sched=0/0
16:58:13.153 [4351] [dbg] roc_pipeline: [pipeline_loop.cpp:456] pipeline loop: tasks=4 in_place=1.00 in_frame=0.00 preempts=0 sched=0/0
16:59:13.157 [4351] [dbg] roc_pipeline: [pipeline_loop.cpp:456] pipeline loop: tasks=4 in_place=1.00 in_frame=0.00 preempts=0 sched=0/0
^C

Zowel de zender als de ontvanger kan je onderbreken door Ctrl+c te drukken.

Mocht het streamen mislukken, controleer dan zeker het volgende:

  1. De opdracht om een audio netwerkstream te ontvangen (roc-recv) en let op de gebruikte audio-uitgang (op mijn computer: -o alsa://plughw:CARD=PCH,DEV=0).
  2. De opdracht om een audio netwerkstream te verzenden (roc-send) en let daarbij op eventuele typfouten.

Roc Toolkit installeren op een Raspberry Pi

Om geluid via het netwerk te streamen, moeten we op een tweede apparaat de Roc Toolkit installeren. Wie van plan is de Roc streaming tools op een Raspberry Pi te gebruiken, moet deze ook zelf compileren. Ik gebruik als besturingssysteem op de Raspberry Pi de moderne 64 bits versie. Daar een Raspberry Pi minder krachtig is dan een standaard computer, heb je bij het compileren nog meer geduld nodig. Opnieuw beginnen we met het installeren van de software die we nodig hebben om de Roc Toolkit te compileren.

pi@raspberrypi:~ $ sudo apt install scons automake libtool cmake
Pakketlijsten worden ingelezen... Klaar
Boom van vereisten wordt opgebouwd... Klaar
De statusinformatie wordt gelezen... Klaar 
De volgende extra pakketten zullen geïnstalleerd worden:
  autoconf autotools-dev cmake-data libjsoncpp25 libltdl-dev librhash0 libuv1 m4
Voorgestelde pakketten:
  autoconf-archive gnu-standards autoconf-doc gettext cmake-doc cmake-format elpa-cmake-mode ninja-build
  libtool-doc gfortran | fortran95-compiler gcj-jdk m4-doc scons-doc
De volgende NIEUWE pakketten zullen geïnstalleerd worden:
  autoconf automake autotools-dev cmake cmake-data libjsoncpp25 libltdl-dev librhash0 libtool libuv1 m4 scons
0 opgewaardeerd, 12 nieuw geïnstalleerd, 0 te verwijderen en 14 niet opgewaardeerd.
Er moeten 12,0 MB aan archieven opgehaald worden.
Na deze bewerking zal er 46,9 MB extra schijfruimte gebruikt worden.
Wilt u doorgaan? [J/n] 
Ophalen:1 http://deb.debian.org/debian bookworm/main arm64 m4 arm64 1.4.19-3 [276 kB]
Ophalen:2 http://deb.debian.org/debian bookworm/main arm64 autoconf all 2.71-3 [332 kB]
Ophalen:3 http://deb.debian.org/debian bookworm/main arm64 autotools-dev all 20220109.1 [51,6 kB]
...
Ophalen:10 http://deb.debian.org/debian bookworm/main arm64 libltdl-dev arm64 2.4.7-5 [165 kB]
Ophalen:11 http://deb.debian.org/debian bookworm/main arm64 libtool all 2.4.7-5 [517 kB]
Ophalen:12 http://deb.debian.org/debian bookworm/main arm64 scons all 4.4.0+dfsg-1 [663 kB]
12,0 MB opgehaald in 1s (11,0 MB/s)
Voorheen niet geselecteerd pakket m4 wordt geselecteerd.
(Database wordt ingelezen ... 144989 bestanden en mappen momenteel geïnstalleerd.)
Uitpakken van .../00-m4_1.4.19-3_arm64.deb wordt voorbereid...
Bezig met uitpakken van m4 (1.4.19-3) ...
...
Voorheen niet geselecteerd pakket scons wordt geselecteerd.
Uitpakken van .../11-scons_4.4.0+dfsg-1_all.deb wordt voorbereid...
Bezig met uitpakken van scons (4.4.0+dfsg-1) ...
Instellen van m4 (1.4.19-3) ...
Instellen van autotools-dev (20220109.1) ...
Instellen van libuv1:arm64 (1.44.2-1) ...
...
Instellen van libtool (2.4.7-5) ...
Instellen van libltdl-dev:arm64 (2.4.7-5) ...
Instellen van cmake (3.25.1-1) ...
Bezig met afhandelen van triggers voor man-db (2.11.2-2) ...
Bezig met afhandelen van triggers voor libc-bin (2.36-9+rpt2+deb12u4) ...

Daarna downloaden we de broncode:

pi@raspberrypi:~ $ git clone https://github.com/roc-streaming/roc-toolkit.git
Cloning into 'roc-toolkit'...
remote: Enumerating objects: 27984, done.
remote: Counting objects: 100% (1691/1691), done.
remote: Compressing objects: 100% (526/526), done.
remote: Total 27984 (delta 1178), reused 1601 (delta 1140), pack-reused 26293
Receiving objects: 100% (27984/27984), 9.40 MiB | 9.26 MiB/s, done.
Resolving deltas: 100% (19897/19897), done.

Waarna we de Roc Toolkit kunnen compileren. Let op de --host parameter waarmee we meegeven dat we een 64 bits arm versie willen bekomen.

pi@raspberrypi:~ $ cd roc-toolkit/
pi@raspberrypi:~/roc-toolkit $ scons -Q --host=aarch64-linux-gnu --build-3rdparty=all --disable-pulseaudio
    BUILD   build/3rdparty/aarch64-linux-gnu/gcc-12.2.0-release/libuv-1.35.0
[download] https://dist.libuv.org/dist/v1.35.0/libuv-v1.35.0.tar.gz
[unpack] libuv-v1.35.0.tar.gz
[execute] ./autogen.sh
[execute] ./configure --host=aarch64-linux-gnu CXX=/usr/bin/aarch64-linux-gnu-g++-12 CXXLD=/usr/bin/aarch64-linux-gnu-g++-12 CC=/usr/bin/aarch64-linux-gnu-gcc-12 CCLD=/usr/bin/aarch64-linux-gnu-gcc-12 AR=/usr/bin/aarch64-linux-gnu-ar RANLIB=/usr/bin/aarch64-linux-gnu-ranlib PKG_CONFIG=/usr/bin/aarch64-linux-gnu-pkg-config CXXFLAGS=-O2 CFLAGS=-O2 LDFLAGS='' --with-pic --enable-static
[execute] make -j4
[install] build/3rdparty/aarch64-linux-gnu/gcc-12.2.0-release/libuv-1.35.0/include
[install] build/3rdparty/aarch64-linux-gnu/gcc-12.2.0-release/libuv-1.35.0/lib/libuv.a
...
    BUILD   build/3rdparty/aarch64-linux-gnu/gcc-12.2.0-release/gengetopt-2.22.6
[download] ftp://ftp.gnu.org/gnu/gengetopt/gengetopt-2.22.6.tar.gz
[unpack] gengetopt-2.22.6.tar.gz
[execute] ./configure
[execute] make
[install] build/3rdparty/aarch64-linux-gnu/gcc-12.2.0-release/gengetopt-2.22.6/bin/gengetopt
      CXX   src/public_api/src/adapters.cpp
      CXX   src/public_api/src/arena.cpp
      CXX   src/public_api/src/context.cpp
...
      CXX   src/internal_modules/roc_core/target_posix/roc_core/time.cpp
      CXX   src/internal_modules/roc_core/target_posix_ext/roc_core/semaphore.cpp
      CXX   src/internal_modules/roc_core/target_posix_pc/roc_core/console.cpp
      GGO   src/tools/roc_copy/cmdline.ggo
      CXX   src/tools/roc_copy/main.cpp
       CC   build/src/aarch64-linux-gnu/gcc-12.2.0-release/tools/roc_copy/cmdline.c
       AR   build/src/aarch64-linux-gnu/gcc-12.2.0-release/internal_modules/libroc_core.a
   RANLIB   build/src/aarch64-linux-gnu/gcc-12.2.0-release/internal_modules/libroc_core.a
      GGO   src/tools/roc_recv/cmdline.ggo
      CXX   src/tools/roc_recv/main.cpp
       CC   build/src/aarch64-linux-gnu/gcc-12.2.0-release/tools/roc_recv/cmdline.c
      GGO   src/tools/roc_send/cmdline.ggo
      CXX   src/tools/roc_send/main.cpp
       CC   build/src/aarch64-linux-gnu/gcc-12.2.0-release/tools/roc_send/cmdline.c
      ART   build/src/aarch64-linux-gnu/gcc-12.2.0-release/compile_commands.json
      GEN   build/src/aarch64-linux-gnu/gcc-12.2.0-release/roc.pc
  INSTALL   compile_commands.json
       AR   build/src/aarch64-linux-gnu/gcc-12.2.0-release/internal_modules/libroc_audio.a
   RANLIB   build/src/aarch64-linux-gnu/gcc-12.2.0-release/internal_modules/libroc_audio.a
       LD   build/src/aarch64-linux-gnu/gcc-12.2.0-release/roc-send
       LD   build/src/aarch64-linux-gnu/gcc-12.2.0-release/roc-copy
       LD   build/src/aarch64-linux-gnu/gcc-12.2.0-release/roc-recv
       LD   build/src/aarch64-linux-gnu/gcc-12.2.0-release/libroc_unstripped.so.0.3
  INSTALL   bin/aarch64-linux-gnu/roc-copy
  INSTALL   bin/aarch64-linux-gnu/roc-send
       CP   build/src/aarch64-linux-gnu/gcc-12.2.0-release/libroc.so.0.3
  INSTALL   bin/aarch64-linux-gnu/roc-recv
    STRIP   build/src/aarch64-linux-gnu/gcc-12.2.0-release/libroc.so.0.3
  INSTALL   bin/aarch64-linux-gnu/libroc.so.0.3
       LN   bin/aarch64-linux-gnu/libroc.so.0
       LN   bin/aarch64-linux-gnu/libroc.so

Na het compileren, kunnen we de Roc Toolkit programma's installeren:

pi@raspberrypi:~/roc-toolkit $ sudo scons -Q --host=aarch64-linux-gnu --build-3rdparty=all --disable-pulseaudio install
  INSTALL   /usr/share/man/man1/roc-copy.1
  INSTALL   /usr/share/man/man1/roc-recv.1
  INSTALL   /usr/share/man/man1/roc-send.1
  INSTALL   /usr/lib/aarch64-linux-gnu/libroc.so.0.3
  INSTALL   /usr/lib/aarch64-linux-gnu/libroc.so.0
  INSTALL   /usr/lib/aarch64-linux-gnu/libroc.so
  INSTALL   /usr/include/roc
  INSTALL   /usr/lib/aarch64-linux-gnu/pkgconfig/roc.pc
  INSTALL   /usr/bin/roc-copy
  INSTALL   /usr/bin/roc-recv
  INSTALL   /usr/bin/roc-send

Naar een ander apparaat streamen

Installeer de Roc streaming tools op een andere computer zoals hierboven besproken. Voor het afspelen van geluid start je eerst de ontvanger op de andere computer:

pi@raspberrypi:~ $ roc-recv -vv -s rtp+rs8m://0.0.0.0:10001 -r rs8m://0.0.0.0:10002 -c rtcp://0.0.0.0:10003 -o alsa://plughw:CARD=Headphones,DEV=0

Indien je geen afspeelapparaat opgeeft, wordt het standaard afspeelapparaat gebruikt. Start een programma op dat geluid produceert en deze naar de virtuele geluidskaart stuurt. Daarna zend je het geproduceerde geluid via het netwerk naar de computer die het moet weergeven:

dany@pindabook:~$ roc-send -vv -s rtp+rs8m://raspberrypi.local:10001 -r rs8m://raspberrypi.local:10002 -c rtcp://raspberrypi.local:10003 -i alsa://plughw:CARD=Loopback,DEV=1

Video en audio synchroniseren

Hoewel de latenty (vertraging) van de Roc tools nog meevalt, valt deze bij het afspelen van video's met gesprekken wel degelijk op. Via allerlei opties kan je de Roc tools echter zo instellen dat deze optimaal werkt met de mogelijkheden van jouw hardware en de snelheid van jouw netwerk. Opnieuw kan je op de online documentatie pagina's (bv.:roc_recv) van de ontwikkelaar lezen met welke opties je een minimale latentie kunt bereiken. Ik bereikte uitstekende resultaten zonder foutmeldingen met de volgende opties voor de ontvanger op een bekabeld netwerk:

pi@raspberrypi:~ $ roc-recv -vv -s rtp+rs8m://0.0.0.0:10001 -r rs8m://0.0.0.0:10002 -c rtcp://0.0.0.0:10003 -o alsa://plughw:CARD=Headphones,DEV=0 --sess-latency=25ms

Automatiseren

De Roc streaming tools stellen hun eisen:

Om deze obstakels uit de weg te gaan, gebruik ik een script om de ontvanger enkel te starten als dit nodig is. De ontvanger terug af te sluiten als we er geen gebruik meer van willen maken, zodat de versterker vrij komt voor andere geluidsbronnen (MPD Radio). Onderstaande script maakt gebruik van SSH (geconfigureerd zonder wachtwoorden, maar met Public Key Authentification) om opdrachten zoals het opstarten en afsluiten van de ontvanger vanaf de gebruikers PC uit te voeren. In het kort: op de audio zender maken we authentificatie sleutels aan met de opdracht:

dany@pindabook:~$ ssh-keygen
Generating public/private rsa key pair.
Enter file in which to save the key (/home/dany/.ssh/id_rsa): 
Enter passphrase (empty for no passphrase): 
Enter same passphrase again: 
Your identification has been saved in /home/dany/.ssh/id_rsa
Your public key has been saved in /home/dany/.ssh/id_rsa.pub
The key fingerprint is:
SHA256:PZ69wapta3qbDlgvte1WPZeWRsv2eOfT2L/pau4ppa4 dany@pindabook
The key's randomart image is:
+---[RSA 3072]----+
|                 |
|                 |
|                 |
|         .     . |
|        S +   o.+|
|       o + B ..Xo|
|      . o = B.++=|
|         ++*.++.B|
|        oEX=B=o*B|
+----[SHA256]-----+

Op de audio ontvanger passen we de configuratie van de SSH server aan met:

pi@raspberrypi:~ $ sudo sed -i '/PubkeyAuthentication yes/s/^#//g' /etc/ssh/sshd_config

Om de aanpassingen te activeren, herstarten we de SSH server:

pi@raspberrypi:~ $ sudo systemctl restart sshd.service

Terug op de audio zender sturen we de publieke SSH authentificatie sleutel door naar de audio ontvanger:

dany@pindabook:~$ ssh-copy-id pi@raspberrypi.local
/usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/home/dany/.ssh/id_rsa.pub"
The authenticity of host 'raspberrypi.local (192.168.129.37)' can't be established.
ED25519 key fingerprint is SHA256:YqQQurKHguItzFFEsVeeJMfpGgRcpbhcpxn3JbtLrKs.
This key is not known by any other names.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes     
/usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed
/usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys
pi@raspberrypi.local's password: 

Number of key(s) added: 1

Now try logging into the machine, with:   "ssh 'pi@raspberrypi.local'"
and check to make sure that only the key(s) you wanted were added.

Nog een laatste test:

dany@pindabook:~$ ssh 'pi@raspberrypi.local'
Linux raspberrypi 6.1.0-rpi8-rpi-v8 #1 SMP PREEMPT Debian 1:6.1.73-1+rpt1 (2024-01-25) aarch64

The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
Last login: Sun Mar 10 18:02:28 2024 from 192.168.129.37
pi@raspberrypi:~ $ exit

Om de audio uitvoer om te schakelen, hebben we de identificaties nodig, die we opvragen met:

dany@pindabook:~$ pactl list sinks short
0       alsa_output.pci-0000_00_1b.0.analog-stereo      module-alsa-card.c      s16le 2ch 44100Hz       SUSPENDED
1       alsa_output.platform-snd_aloop.0.analog-stereo  module-alsa-card.c      s16le 2ch 44100Hz       SUSPENDED

Om opdrachten gelijktijdig uit te voeren, bijvoorbeeld bij het starten van de ontvanger, wordt gebruik gemaakt van opdrachten die op de achtergrond worden uitgevoerd (eindigen op &).

#!/usr/bin/bash
# HiFi.sh
# De URL van de ontvanger
ontvanger="raspberrypi.local"

if pgrep -x roc-send >/dev/null
then
  # activeer de originele audio-uitgang op de computer
  pactl set-default-sink alsa_output.pci-0000_00_1b.0.analog-stereo

  # stop zender
  killall roc-send
  # stop ontvanger
  ssh -o StrictHostKeyChecking=no pi@$ontvanger 'killall roc-recv'
else
  # activeer ontvanger
  (ssh -o StrictHostKeyChecking=no pi@$ontvanger 'roc-recv -vv -s rtp+rs8m://0.0.0.0:10001 -r rs8m://0.0.0.0:10002 -c rtcp://0.0.0.0:10003 --sess-latency=25ms') &

  # activeer zender
  roc-send -vv -s rtp+rs8m://$ontvanger:10001 -r rs8m://$ontvanger:10002 -c rtcp://$ontvanger:10003 -i alsa://plughw:CARD=Loopback,DEV=1 &

  # Activeer netwerk audio-uitgang
  # pactl list sinks short # lijst audio uitvoerkaarten
  pactl set-default-sink alsa_output.platform-snd_aloop.0.analog-stereo
fi

De opdrachtten om de geluidkaart om te schakelen werkt niet op alle systemen, waardoor je op de zender de geluidsuitvoer zelf moet omschakelen.

Roc streaming tools verwijderen

Deïnstalleer de Roc streaming tools vanuit de broncode map met de volgende opdracht:

dany@pindabook:~$ cd roc-toolkit/
dany@pindabook:~/roc-toolkit$ sudo scons -Q --build-3rdparty=openfec uninstall
[sudo] wachtwoord voor root: 
 UNINSTALL   /usr/share/man/man1/roc-copy.1
 UNINSTALL   /usr/share/man/man1/roc-recv.1
 UNINSTALL   /usr/share/man/man1/roc-send.1
 UNINSTALL   /usr/lib/x86_64-linux-gnu/libroc.so.0.3
 UNINSTALL   /usr/lib/x86_64-linux-gnu/libroc.so.0
 UNINSTALL   /usr/lib/x86_64-linux-gnu/libroc.so
 UNINSTALL   /usr/include/roc
 UNINSTALL   /usr/lib/x86_64-linux-gnu/pkgconfig/roc.pc
 UNINSTALL   /usr/bin/roc-copy
 UNINSTALL   /usr/bin/roc-recv
 UNINSTALL   /usr/bin/roc-send

Verwijder de pakketten om de Roc streaming tools te compileren met de opdracht:

dany@pindabook:~/roc-toolkit$ sudo apt remove libuv1-dev libunwind-dev libssl-dev libspeexdsp-dev libsox-dev ragel gengetopt  libpulse-dev scons g++ cmake
Pakketlijsten worden ingelezen... Klaar
Boom van vereisten wordt opgebouwd... Klaar
De statusinformatie wordt gelezen... Klaar 
De volgende pakketten zijn automatisch geïnstalleerd en zijn niet langer nodig:
  cmake-data g++-12 gcc gcc-12 libasan8 libatomic1 libblkid-dev libc-dev-bin libc-devtools libc6-dev libcc1-0
  libcrypt-dev libffi-dev libgcc-12-dev libglib2.0-dev libglib2.0-dev-bin libitm1 libjsoncpp25 liblsan0
  liblzma-dev libmount-dev libnsl-dev libpcre2-dev libpcre2-posix3 libpkgconf3 librhash0 libselinux1-dev
  libsepol-dev libsox-fmt-all libsox-fmt-alsa libsox-fmt-ao libsox-fmt-base libsox-fmt-mp3 libsox-fmt-oss
  libsox-fmt-pulse libsox3 libstdc++-12-dev libtirpc-dev libtsan2 libubsan1 linux-libc-dev manpages-dev pkg-config
  pkgconf pkgconf-bin python3-distutils python3-lib2to3 rpcsvc-proto uuid-dev zlib1g-dev
Gebruik 'sudo apt autoremove' om ze te verwijderen.
De volgende pakketten zullen VERWIJDERD worden:
  cmake g++ gengetopt libpulse-dev libsox-dev libspeexdsp-dev libssl-dev libunwind-dev libuv1-dev ragel scons
0 opgewaardeerd, 0 nieuw geïnstalleerd, 11 te verwijderen en 0 niet opgewaardeerd.
Na deze bewerking zal er 54,5 MB schijfruimte vrijkomen.
Wilt u doorgaan? [J/n] 
(Database wordt ingelezen ... 184986 bestanden en mappen momenteel geïnstalleerd.)
cmake (3.25.1-1) wordt verwijderd ...
g++ (4:12.2.0-3) wordt verwijderd ...
gengetopt (2.23+dfsg1-1) wordt verwijderd ...
libpulse-dev:amd64 (16.1+dfsg1-2+b1) wordt verwijderd ...
libsox-dev:amd64 (14.4.2+git20190427-3.5) wordt verwijderd ...
libspeexdsp-dev:amd64 (1.2.1-1) wordt verwijderd ...
libssl-dev:amd64 (3.0.11-1~deb12u2) wordt verwijderd ...
libunwind-dev:amd64 (1.6.2-3) wordt verwijderd ...
libuv1-dev:amd64 (1.44.2-1+deb12u1) wordt verwijderd ...
ragel (6.10-4) wordt verwijderd ...
scons (4.4.0+dfsg-1) wordt verwijderd ...
Bezig met afhandelen van triggers voor man-db (2.11.2-2) ...

Om ook de niet meer gebruikte afhankelijke pakketten te verwijderen, voer je de volgende opdracht uit:

dany@pindabook:~/roc-toolkit$ sudo apt autoremove
Pakketlijsten worden ingelezen... Klaar
Boom van vereisten wordt opgebouwd... Klaar
De statusinformatie wordt gelezen... Klaar 
De volgende pakketten zullen VERWIJDERD worden:
  cmake-data g++-12 gcc gcc-12 libasan8 libatomic1 libblkid-dev libc-dev-bin libc-devtools libc6-dev libcc1-0
  libcrypt-dev libffi-dev libgcc-12-dev libglib2.0-dev libglib2.0-dev-bin libitm1 libjsoncpp25 liblsan0
  liblzma-dev libmount-dev libnsl-dev libpcre2-dev libpcre2-posix3 libpkgconf3 librhash0 libselinux1-dev
  libsepol-dev libsox-fmt-all libsox-fmt-alsa libsox-fmt-ao libsox-fmt-base libsox-fmt-mp3 libsox-fmt-oss
  libsox-fmt-pulse libsox3 libstdc++-12-dev libtirpc-dev libtsan2 libubsan1 linux-libc-dev manpages-dev pkg-config
  pkgconf pkgconf-bin python3-distutils python3-lib2to3 rpcsvc-proto uuid-dev zlib1g-dev
0 opgewaardeerd, 0 nieuw geïnstalleerd, 50 te verwijderen en 0 niet opgewaardeerd.
Na deze bewerking zal er 222 MB schijfruimte vrijkomen.
Wilt u doorgaan? [J/n] 
(Database wordt ingelezen ... 184314 bestanden en mappen momenteel geïnstalleerd.)
cmake-data (3.25.1-1) wordt verwijderd ...
g++-12 (12.2.0-14) wordt verwijderd ...
gcc (4:12.2.0-3) wordt verwijderd ...
...
python3-distutils (3.11.2-3) wordt verwijderd ...
python3-lib2to3 (3.11.2-3) wordt verwijderd ...
rpcsvc-proto (1.4.3-1) wordt verwijderd ...
Bezig met afhandelen van triggers voor libc-bin (2.36-9+deb12u4) ...
Bezig met afhandelen van triggers voor man-db (2.11.2-2) ...
Bezig met afhandelen van triggers voor install-info (6.8-6+b1) ...
Bezig met afhandelen van triggers voor libglib2.0-0:amd64 (2.74.6-2) ...

Verwijder de automatische aanmaak van de virtuele geluidskaart met de opdracht:

dany@pindabook:~/roc-toolkit$ sudo rm /etc/modules-load.d/snd-aloop.conf

Bij de volgende systeemstart zal de virtuele geluidskaart verdwenen zijn. Stel dan ook terug een standaard geluidskaart naar voorkeur in. Ook de map met de broncode kan dan verwijderd worden:

dany@pindabook:~/roc-toolkit$ cd
dany@pindabook:~$ sudo rm -r roc-toolkit/