4

I am streaming music from a single controlling PC ("sender") to multiple PCs (receivers) on my LAN as described here:

https://www.freedesktop.org/wiki/Software/PulseAudio/Documentation/User/Network/#index2h3

How do I also get the same music to play on the controlling PC (sender)?

My current setup is very simple for testing right now:

sender

pactl load-module module-null-sink sink_name=rtpsink1
pactl load-module module-rtp-send source=rtpsink1.monitor

receivers

pactl load-module module-rtp-recv
6
  • Assuming you stream to a multicast address: Did you try to load module-rtp-recv on the sender, too?
    – dirkt
    Sep 25, 2018 at 6:13
  • @dirkt - I am streaming to a multicast address (because I just left the default). I did not try to load module-rtp-recv on the sender. I'll try that. Thanks. However, my bigger problem now is that each receiver is out of sync by a full second or more.
    – MountainX
    Sep 25, 2018 at 6:16
  • Yes, I read and upvoted the other question...
    – dirkt
    Sep 25, 2018 at 6:19
  • @dirkt - thank you for all your recent help regarding sound!
    – MountainX
    Sep 25, 2018 at 6:22
  • @dirkt - loading module-rtp-recv on the sender did not solve the issue for me. Is that something that you have used? If you are sure it works, I'll keep trying with that method.
    – MountainX
    Sep 26, 2018 at 5:02

2 Answers 2

3

This is my preferred, working solution. It is based on: pulsertp-multiroom
https://github.com/mada3k/pulsertp-multiroom/blob/master/scripts/pulsertpm-start.sh

I am using this to send audio to multiple receivers (different rooms). There are two lines, noted below, which make the sender a receiver too and solve this question. They are:

  • module-rtp-send with the sender's only IP address
  • module-rtp-recv with the sender's only IP address

The advantage of this approach is that all receivers (including the one on the sender) stay in sync. That was not the case when combining syncs as in my other answer.

After editing to enter the correct IP addresses, I run this script on the sender when ready to start up RTP unicasting:

#!/bin/bash
#
# PulseRTP-multiroom
#   Loads RTP sender modules to setup multiroom audio at request
#
#   Notes
#     * If you have issues, and have multiple network interfaces, add source_ip= with you prefered local IP
#     * mtu=1408 is good initial value. It makes room for 352 PCM frames in 16/44.1k.
#
pa_rtp_mtu=1408
pa_sink="rtpsink1"

echo "timedatectl status:"
timedatectl status --no-pager | grep 'NTP service: active'
if [[ $? -ne 0 ]]; then
    timedatectl set-ntp true
    sleep 2
    timedatectl status --no-pager | grep 'NTP service: active'
    if [[ $? -ne 0 ]]; then
        echo "WARNING: NTP service not active"
    else
        echo "timedatectl status OK"
    fi
fi

pacmd list-modules | grep module-native-protocol-unix
if [ $? -ne 0 ]; then
    pactl load-module module-native-protocol-unix
fi
pacmd list-modules | grep module-default-device-restore
if [ $? -ne 0 ]; then
    pactl load-module module-default-device-restore
fi
pacmd list-modules | grep module-rescue-streams
if [ $? -ne 0 ]; then
    pactl load-module module-rescue-streams
fi
pacmd list-modules | grep module-always-sink
if [ $? -ne 0 ]; then
    pactl load-module module-always-sink
fi
pacmd list-modules | grep module-intended-roles
if [ $? -ne 0 ]; then
    pactl load-module module-intended-roles
fi
pacmd list-modules | grep module-suspend-on-idle
if [ $? -ne 0 ]; then
    load-module module-suspend-on-idle
fi

#hardcoded addresses of each receiver:
pactl load-module module-rtp-send source=${pa_sink}.monitor mtu=${pa_rtp_mtu} destination_ip=192.168.0.1 #this is the sender's IP address (see below)
pactl load-module module-rtp-send source=${pa_sink}.monitor mtu=${pa_rtp_mtu} destination_ip=192.168.0.2
pactl load-module module-rtp-send source=${pa_sink}.monitor mtu=${pa_rtp_mtu} destination_ip=192.168.0.3
pactl load-module module-rtp-send source=${pa_sink}.monitor mtu=${pa_rtp_mtu} destination_ip=192.168.0.4
pactl load-module module-rtp-send source=${pa_sink}.monitor mtu=${pa_rtp_mtu} destination_ip=192.168.0.5

On each receiver:

pactl load-module module-rtp-recv sap_address=192.168.0.X

Use the receiver's actual IP address, e.g., 192.168.0.2

Finally, on the sender, make it a receiver too:

pactl load-module module-rtp-recv sap_address=192.168.0.1

You can make the configuration on the receivers permanent by editing /etc/pulse/default.pa

To stop RTP casting to the receivers, run this script on the sender:

#!/bin/bash
#
# PulseRTP-Multiroom
#   Unloads RTP sender modules to avoid unnecessary bandwidth hogging
#

pa_sink="rtpsink1"

IFS=$'\n'
for rtpn in `pactl list modules short|grep ${pa_sink}`; do
    PAM_ID=`echo $rtpn|awk '{print $1}'`
    pactl unload-module $PAM_ID
    echo " * unload-module id $PAM_ID done"
done

For starting and stopping music play, no changes are needed on the receivers. Their config can be made permanent. I did not have the need to make any permanent config changes on the sender with my modified version of the start script above.

7
  • but this is completely unicast, which not corespond to your initial question
    – dmnc
    Mar 10, 2020 at 12:07
  • @dmnc - multicasting isn't practical in my situation. One reason (there are more) is that it creates too much traffic. In my research I learned that unicasting to multiple devices, which achieves the end result I desired, is a much better solution. That's why I implemented it the way I did. Hope it helps.
    – MountainX
    Mar 10, 2020 at 18:53
  • okay, I can believe that ... but question is about RTP Multicast and if (your own) answer is about unicast then it can't be considered as best answer to the question ... I think you should update the question, at least topic name. No offense, I was just looking for some multicast solutions and nothing more, so I even didn't read your answer just saw unicast a lost interest. I hope you can understand me.
    – dmnc
    Mar 10, 2020 at 19:07
  • @dmnc - I was looking for a multicast solution when I asked the question. I found out that it is possible to unicast to multiple clients. This has the same end result as multicast. If you didn't even read or try the solution, how can you say it isn't an appropriate solution? I suggest you ask your own specific question for your situation. For my situation, this was and still is the best answer.
    – MountainX
    Mar 11, 2020 at 17:40
  • yes, it is good that you found the solution and we're getting close to our consensus because whole my point is that you should edit the question topic to match the answer. Because if anybody will search for Multicast (ONLY!) solution, this will not help but it solved your multicast-not-really-required solution.
    – dmnc
    Mar 11, 2020 at 18:00
2

Use module-combine-sink.

On the sender:

pacmd list-sinks

Use the values of the of each sink to be combined in slaves list below:

pactl load-module module-combine-sink sink_name=rtp1combined slaves=abcd,wxyz

where abcd and wxyz would be the names of the two sinks to combine. In my case, that would be slaves=rtpsink1,alsa_output.pci-0000_02_00.1.hdmi-stereo

UPDATE: this method apparently has the disadvantage that the sender is not synchronized with the nodes.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .