User avatar
Douglas6
Posts: 4472
Joined: Sat Mar 16, 2013 5:34 am
Location: Chicago, IL

[Guide] Pulseaudio 5 on Wheezy

Tue Sep 16, 2014 3:35 pm

[Edit: I've written up a detailed guide in this post later on in this thread: http://www.raspberrypi.org/forums/viewt ... 13#p619713]

In an unrelated post, I just found a great link with instructions for building Pulseaudio 5 on Wheezy. This is something I've wanted to try for some time, but I knew better than to attempt it myself. It's time now to brew a big pot of coffee and give it a try.

Does anyone in this forum have any experience, tips, advice on building PA5 for Raspbian?
Last edited by Douglas6 on Sun Sep 28, 2014 9:14 pm, edited 2 times in total.

pipimann
Posts: 22
Joined: Fri Mar 07, 2014 7:25 pm

Re: Pulseaudio 5 on Wheezy

Wed Sep 17, 2014 5:56 pm

I am just trying it, hoping that it will eventually work on a read only filesystem...

Raspbian standard PA2 needs to write to the filesystem and fails for read only.

User avatar
Douglas6
Posts: 4472
Joined: Sat Mar 16, 2013 5:34 am
Location: Chicago, IL

Re: Pulseaudio 5 on Wheezy

Wed Sep 17, 2014 6:07 pm

I tried to compile PA5 last night and it failed with missing dependencies and something about 'locked' packages. This was on an updated Raspian, but not the latest. I'm gonna first load up the newest image and see if I can resolve the dependency issues. Not sure I can.

pipimann
Posts: 22
Joined: Fri Mar 07, 2014 7:25 pm

Re: Pulseaudio 5 on Wheezy

Wed Sep 17, 2014 7:23 pm

I also had/have issues (I'm with an up to date Raspbian).

Needed to $ apt-get install libcap-dev before I could run ./configure

After making and installing I could not run it. It gave me an error:

Code: Select all

$ /usr/local/bin/pulseaudio -vvv --system --disallow-exit --disallow-module-loading=1 --high-priority
/usr/local/bin/pulseaudio: error while loading shared libraries: libpulsecore-5.0.so: cannot open shared object file: No such file or directory
I found out that it's possible to point to the right directory to look for libpulsecore-5.0.so:

Code: Select all

$ export LD_LIBRARY_PATH=/usr/local/lib
I still get an error, when NOT remounting the filesystem rw before starting... but when doing it

Code: Select all

[email protected] ~ $ sudo mount -o remount,rw /
[email protected] ~ $ /usr/local/bin/pulseaudio -vvv --system --disallow-exit --disallow-module-loading=1 --high-priority
N: [pulseaudio] main.c: System mode refused for non-root user. Only starting the D-Bus server lookup service.
I: [pulseaudio] main.c: setrlimit(RLIMIT_NICE, (31, 31)) failed: Operation not permitted
D: [pulseaudio] core-rtclock.c: Timer slack is set to 50 us.
I: [pulseaudio] core-util.c: Failed to acquire high-priority scheduling: Permission denied
I: [pulseaudio] main.c: This is PulseAudio 5.0
D: [pulseaudio] main.c: Compilation host: armv6l-unknown-linux-gnueabihf
D: [pulseaudio] main.c: Compilation CFLAGS: -g -O2 -Wall -W -Wextra -pipe -Wno-long-long -Wno-overlength-strings -Wunsafe-loop-optimizations -Wundef -Wformat=2 -Wlogical-op -Wsign-compare -Wformat-security -Wmissing-include-dirs -Wformat-nonliteral -Wpointer-arith -Winit-self -Wdeclaration-after-statement -Wfloat-equal -Wmissing-prototypes -Wredundant-decls -Wmissing-declarations -Wmissing-noreturn -Wshadow -Wendif-labels -Wcast-align -Wstrict-aliasing -Wwrite-strings -Wno-unused-parameter -ffast-math -fno-common -fdiagnostics-show-option
D: [pulseaudio] main.c: Running on host: Linux armv6l 3.12.28+ #710 PREEMPT Wed Sep 10 15:23:42 BST 2014
D: [pulseaudio] main.c: Found 1 CPUs.
I: [pulseaudio] main.c: Page size is 4096 bytes
D: [pulseaudio] main.c: Compiled with Valgrind support: no
D: [pulseaudio] main.c: Running in valgrind mode: no
D: [pulseaudio] main.c: Running in VM: no
D: [pulseaudio] main.c: Optimized build: yes
D: [pulseaudio] main.c: FASTPATH defined, only fast path asserts disabled.
I: [pulseaudio] main.c: Machine ID is raspberrypi.
I: [pulseaudio] main.c: Using runtime directory /home/pi/.config/pulse/raspberrypi-runtime.
I: [pulseaudio] main.c: Using state directory /home/pi/.config/pulse.
I: [pulseaudio] main.c: Using modules directory /usr/local/lib/pulse-5.0/modules.
I: [pulseaudio] main.c: Running in system mode: no
I: [pulseaudio] main.c: Fresh high-resolution timers available! Bon appetit!
D: [pulseaudio] memblock.c: Using shared memory pool with 1024 slots of size 64.0 KiB each, total size is 64.0 MiB, maximum usable slot size is 65496
I: [pulseaudio] cpu-arm.c: CPU flags: V6 V7 VFP EDSP 
I: [pulseaudio] svolume_arm.c: Initialising ARM optimized volume functions.
W: [pulseaudio] server-lookup.c: Unable to contact D-Bus: org.freedesktop.DBus.Error.NotSupported: Unable to autolaunch a dbus-daemon without a $DISPLAY for X11
I: [pulseaudio] main.c: Daemon startup complete.
Seems I need to start it with sudo appended — but:

Code: Select all

$ sudo /usr/local/bin/pulseaudio -vvv --system --disallow-exit --disallow-module-loading=1 --high-priority
/usr/local/bin/pulseaudio: error while loading shared libraries: libpulsecore-5.0.so: cannot open shared object file: No such file or directory
Why does my export of the library path does not work anymore, when using sudo?
Last edited by pipimann on Wed Sep 17, 2014 7:45 pm, edited 1 time in total.

User avatar
Douglas6
Posts: 4472
Joined: Sat Mar 16, 2013 5:34 am
Location: Chicago, IL

Re: Pulseaudio 5 on Wheezy

Wed Sep 17, 2014 7:34 pm

pipimann wrote:Needed to $ apt-get install libcap-dev before I could run ./configure
Great, thanks for that.
pipimann wrote:I found out that it's possible to point to the right directory to look for libpulsecore-5.0.so:

Code: Select all

$ export LD_LIBRARY_PATH=/usr/local/lib
Wonder if that could/should be changed with a ./configure parameter?
pipimann wrote:This helps but still I get some errors:

Code: Select all

$ /usr/local/bin/pulseaudio -vvv --system --disallow-exit --disallow-module-loading=1 --high-priority
N: [pulseaudio] main.c: Running in system mode, forcibly disabling SHM mode!
N: [pulseaudio] main.c: Running in system mode, forcibly disabling exit idle time!
D: [pulseaudio] core-rtclock.c: Timer slack is set to 50 us.
D: [pulseaudio] core-util.c: setpriority() worked.
I: [pulseaudio] core-util.c: Successfully gained nice level -11.
E: [pulseaudio] main.c: Failed to find user 'pulse'.
Maybe as simple as adding a pulse user? And possibly putting her in the audio group, I'll take a look at a PA2 pulse user tonight.

pipimann
Posts: 22
Joined: Fri Mar 07, 2014 7:25 pm

Re: Pulseaudio 5 on Wheezy

Wed Sep 17, 2014 7:49 pm

Hmm...

Code: Select all

$ adduser pulse
adduser: The group `pulse' already exists.
Now I have a problem :)

//edit

... problem from a previous installation: I added user pi to group pulse and pulse-access. Seems that the uninstallation of PA2 did NOT delete the groups because there were other users (pi) in there...

Deleting the groups allowed me to add new user pulse — new output now (Running in sudo bash now...):

Code: Select all

# /usr/local/bin/pulseaudio -vvv --system --disallow-exit --disallow-module-loading=1 --high-priority
N: [pulseaudio] main.c: Running in system mode, forcibly disabling SHM mode!
N: [pulseaudio] main.c: Running in system mode, forcibly disabling exit idle time!
D: [pulseaudio] core-rtclock.c: Timer slack is set to 50 us.
D: [pulseaudio] core-util.c: setpriority() worked.
I: [pulseaudio] core-util.c: Successfully gained nice level -11.
I: [pulseaudio] main.c: Found user 'pulse' (UID 1001) and group 'pulse' (GID 1004).
W: [pulseaudio] main.c: Home directory of user 'pulse' is not '/usr/local/var/run/pulse', ignoring.
I: [pulseaudio] main.c: Successfully changed user to "pulse".
I: [pulseaudio] main.c: This is PulseAudio 5.0
D: [pulseaudio] main.c: Compilation host: armv6l-unknown-linux-gnueabihf
D: [pulseaudio] main.c: Compilation CFLAGS: -g -O2 -Wall -W -Wextra -pipe -Wno-long-long -Wno-overlength-strings -Wunsafe-loop-optimizations -Wundef -Wformat=2 -Wlogical-op -Wsign-compare -Wformat-security -Wmissing-include-dirs -Wformat-nonliteral -Wpointer-arith -Winit-self -Wdeclaration-after-statement -Wfloat-equal -Wmissing-prototypes -Wredundant-decls -Wmissing-declarations -Wmissing-noreturn -Wshadow -Wendif-labels -Wcast-align -Wstrict-aliasing -Wwrite-strings -Wno-unused-parameter -ffast-math -fno-common -fdiagnostics-show-option
D: [pulseaudio] main.c: Running on host: Linux armv6l 3.12.28+ #710 PREEMPT Wed Sep 10 15:23:42 BST 2014
D: [pulseaudio] main.c: Found 1 CPUs.
I: [pulseaudio] main.c: Page size is 4096 bytes
D: [pulseaudio] main.c: Compiled with Valgrind support: no
D: [pulseaudio] main.c: Running in valgrind mode: no
D: [pulseaudio] main.c: Running in VM: no
D: [pulseaudio] main.c: Optimized build: yes
D: [pulseaudio] main.c: FASTPATH defined, only fast path asserts disabled.
I: [pulseaudio] main.c: Machine ID is raspberrypi.
I: [pulseaudio] main.c: Using runtime directory /usr/local/var/run/pulse.
E: [pulseaudio] core-util.c: Failed to create secure directory (/usr/local/var/lib/pulse): Permission denied
I'll try to install a RAMDISK for that path...

User avatar
Douglas6
Posts: 4472
Joined: Sat Mar 16, 2013 5:34 am
Location: Chicago, IL

Re: Pulseaudio 5 on Wheezy

Wed Sep 17, 2014 8:01 pm

pipimann wrote:Why does my export of the library path does not work anymore, when using sudo?
I suspect because you exported it into your own user environment, where sudo will not see it. This post has some ways to avoid the export altogether: http://ubuntuforums.org/showthread.php? ... 0#ldconfig

pipimann
Posts: 22
Joined: Fri Mar 07, 2014 7:25 pm

Re: Pulseaudio 5 on Wheezy

Wed Sep 17, 2014 8:33 pm

This helped! Also I set up a tmpfs for /usr/local/var and chmodded the lib folder with 777

Now I'm stuck again...

Code: Select all

$ sudo /usr/local/bin/pulseaudio -vvv --system --disallow-exit --disallow-module-loading=1 --high-priority
N: [pulseaudio] main.c: Running in system mode, forcibly disabling SHM mode!
N: [pulseaudio] main.c: Running in system mode, forcibly disabling exit idle time!
D: [pulseaudio] core-rtclock.c: Timer slack is set to 50 us.
D: [pulseaudio] core-util.c: setpriority() worked.
I: [pulseaudio] core-util.c: Successfully gained nice level -11.
I: [pulseaudio] main.c: Found user 'pulse' (UID 1001) and group 'pulse' (GID 1004).
W: [pulseaudio] main.c: Home directory of user 'pulse' is not '/usr/local/var/run/pulse', ignoring.
I: [pulseaudio] main.c: Successfully changed user to "pulse".
I: [pulseaudio] main.c: This is PulseAudio 5.0
D: [pulseaudio] main.c: Compilation host: armv6l-unknown-linux-gnueabihf
D: [pulseaudio] main.c: Compilation CFLAGS: -g -O2 -Wall -W -Wextra -pipe -Wno-long-long -Wno-overlength-strings -Wunsafe-loop-optimizations -Wundef -Wformat=2 -Wlogical-op -Wsign-compare -Wformat-security -Wmissing-include-dirs -Wformat-nonliteral -Wpointer-arith -Winit-self -Wdeclaration-after-statement -Wfloat-equal -Wmissing-prototypes -Wredundant-decls -Wmissing-declarations -Wmissing-noreturn -Wshadow -Wendif-labels -Wcast-align -Wstrict-aliasing -Wwrite-strings -Wno-unused-parameter -ffast-math -fno-common -fdiagnostics-show-option
D: [pulseaudio] main.c: Running on host: Linux armv6l 3.12.28+ #710 PREEMPT Wed Sep 10 15:23:42 BST 2014
D: [pulseaudio] main.c: Found 1 CPUs.
I: [pulseaudio] main.c: Page size is 4096 bytes
D: [pulseaudio] main.c: Compiled with Valgrind support: no
D: [pulseaudio] main.c: Running in valgrind mode: no
D: [pulseaudio] main.c: Running in VM: no
D: [pulseaudio] main.c: Optimized build: yes
D: [pulseaudio] main.c: FASTPATH defined, only fast path asserts disabled.
I: [pulseaudio] main.c: Machine ID is raspberrypi.
I: [pulseaudio] main.c: Using runtime directory /usr/local/var/run/pulse.
I: [pulseaudio] main.c: Using state directory /usr/local/var/lib/pulse.
I: [pulseaudio] main.c: Using modules directory /usr/local/lib/pulse-5.0/modules.
I: [pulseaudio] main.c: Running in system mode: yes
W: [pulseaudio] main.c: OK, so you are running PA in system mode. Please note that you most likely shouldn't be doing that.
W: [pulseaudio] main.c: If you do it nonetheless then it's your own fault if things don't work as expected.
W: [pulseaudio] main.c: Please read http://pulseaudio.org/wiki/WhatIsWrongWithSystemMode for an explanation why system mode is usually a bad idea.
I: [pulseaudio] main.c: Fresh high-resolution timers available! Bon appetit!
D: [pulseaudio] memblock.c: Using private memory pool with 1024 slots of size 64.0 KiB each, total size is 64.0 MiB, maximum usable slot size is 65496
I: [pulseaudio] cpu-arm.c: CPU flags: V6 V7 VFP EDSP 
I: [pulseaudio] svolume_arm.c: Initialising ARM optimized volume functions.
E: [pulseaudio] module-alsa-card.c: Card '0' doesn't exist: No such file or directory
E: [pulseaudio] module.c: Failed to load module "module-alsa-card" (argument: ""): initialization failed.
E: [pulseaudio] main.c: Module load failed.
E: [pulseaudio] main.c: Failed to initialize daemon.
I: [pulseaudio] main.c: Daemon terminated.
There is a card...

Code: Select all

$ aplay -l
**** List of PLAYBACK Hardware Devices ****
card 0: sndrpirpidac [snd_rpi_rpi_dac], device 0: RPi-DAC HiFi pcm1794a-hifi-0 []
  Subdevices: 1/1
  Subdevice #0: subdevice #0
// EDIT

When using the standard system.pa file it starts the daemon!

Code: Select all

$ sudo /usr/local/bin/pulseaudio -vvv --system --disallow-exit --disallow-module-loading=1 --high-priority
N: [pulseaudio] main.c: Running in system mode, forcibly disabling SHM mode!
N: [pulseaudio] main.c: Running in system mode, forcibly disabling exit idle time!
D: [pulseaudio] core-rtclock.c: Timer slack is set to 50 us.
D: [pulseaudio] core-util.c: setpriority() worked.
I: [pulseaudio] core-util.c: Successfully gained nice level -11.
I: [pulseaudio] main.c: Found user 'pulse' (UID 1001) and group 'pulse' (GID 1004).
W: [pulseaudio] main.c: Home directory of user 'pulse' is not '/usr/local/var/run/pulse', ignoring.
I: [pulseaudio] main.c: Successfully changed user to "pulse".
I: [pulseaudio] main.c: This is PulseAudio 5.0
D: [pulseaudio] main.c: Compilation host: armv6l-unknown-linux-gnueabihf
D: [pulseaudio] main.c: Compilation CFLAGS: -g -O2 -Wall -W -Wextra -pipe -Wno-long-long -Wno-overlength-strings -Wunsafe-loop-optimizations -Wundef -Wformat=2 -Wlogical-op -Wsign-compare -Wformat-security -Wmissing-include-dirs -Wformat-nonliteral -Wpointer-arith -Winit-self -Wdeclaration-after-statement -Wfloat-equal -Wmissing-prototypes -Wredundant-decls -Wmissing-declarations -Wmissing-noreturn -Wshadow -Wendif-labels -Wcast-align -Wstrict-aliasing -Wwrite-strings -Wno-unused-parameter -ffast-math -fno-common -fdiagnostics-show-option
D: [pulseaudio] main.c: Running on host: Linux armv6l 3.12.28+ #710 PREEMPT Wed Sep 10 15:23:42 BST 2014
D: [pulseaudio] main.c: Found 1 CPUs.
I: [pulseaudio] main.c: Page size is 4096 bytes
D: [pulseaudio] main.c: Compiled with Valgrind support: no
D: [pulseaudio] main.c: Running in valgrind mode: no
D: [pulseaudio] main.c: Running in VM: no
D: [pulseaudio] main.c: Optimized build: yes
D: [pulseaudio] main.c: FASTPATH defined, only fast path asserts disabled.
I: [pulseaudio] main.c: Machine ID is raspberrypi.
I: [pulseaudio] main.c: Using runtime directory /usr/local/var/run/pulse.
I: [pulseaudio] main.c: Using state directory /usr/local/var/lib/pulse.
I: [pulseaudio] main.c: Using modules directory /usr/local/lib/pulse-5.0/modules.
I: [pulseaudio] main.c: Running in system mode: yes
W: [pulseaudio] main.c: OK, so you are running PA in system mode. Please note that you most likely shouldn't be doing that.
W: [pulseaudio] main.c: If you do it nonetheless then it's your own fault if things don't work as expected.
W: [pulseaudio] main.c: Please read http://pulseaudio.org/wiki/WhatIsWrongWithSystemMode for an explanation why system mode is usually a bad idea.
I: [pulseaudio] main.c: Fresh high-resolution timers available! Bon appetit!
D: [pulseaudio] memblock.c: Using private memory pool with 1024 slots of size 64.0 KiB each, total size is 64.0 MiB, maximum usable slot size is 65496
I: [pulseaudio] cpu-arm.c: CPU flags: V6 V7 VFP EDSP 
I: [pulseaudio] svolume_arm.c: Initialising ARM optimized volume functions.
D: [pulseaudio] module.c: Checking for existence of '/usr/local/lib/pulse-5.0/modules/module-udev-detect.so': success
D: [pulseaudio] module-udev-detect.c: /dev/snd/controlC0 is accessible: no
I: [pulseaudio] module-udev-detect.c: Found 1 cards.
I: [pulseaudio] module.c: Loaded "module-udev-detect" (index: #0; argument: "").
D: [pulseaudio] module.c: Checking for existence of '/usr/local/lib/pulse-5.0/modules/module-esound-protocol-unix.so': success
D: [pulseaudio] authkey.c: Got 0 bytes from cookie file '/usr/local/var/run/pulse/.esd_auth', expected 16
I: [pulseaudio] module.c: Loaded "module-esound-protocol-unix" (index: #1; argument: "").
W: [pulseaudio] authkey.c: Failed to open cookie file '/usr/local/var/run/pulse/.config/pulse/cookie': No such file or directory
W: [pulseaudio] authkey.c: Failed to load authorization key '/usr/local/var/run/pulse/.config/pulse/cookie': No such file or directory
W: [pulseaudio] authkey.c: Failed to open cookie file '/usr/local/var/run/pulse/.pulse-cookie': No such file or directory
W: [pulseaudio] authkey.c: Failed to load authorization key '/usr/local/var/run/pulse/.pulse-cookie': No such file or directory
D: [pulseaudio] authkey.c: Got 0 bytes from cookie file '/usr/local/var/run/pulse/.config/pulse/cookie', expected 256
I: [pulseaudio] module.c: Loaded "module-native-protocol-unix" (index: #2; argument: "").
D: [pulseaudio] database-tdb.c: Opened TDB database '/usr/local/var/lib/pulse/raspberrypi-stream-volumes.tdb'
I: [pulseaudio] module-stream-restore.c: Successfully opened database file '/usr/local/var/lib/pulse/raspberrypi-stream-volumes'.
D: [pulseaudio] protocol-dbus.c: Interface org.PulseAudio.Ext.StreamRestore1 added for object /org/pulseaudio/stream_restore1
I: [pulseaudio] module.c: Loaded "module-stream-restore" (index: #3; argument: "").
D: [pulseaudio] database-tdb.c: Opened TDB database '/usr/local/var/lib/pulse/raspberrypi-device-volumes.tdb'
I: [pulseaudio] module-device-restore.c: Successfully opened database file '/usr/local/var/lib/pulse/raspberrypi-device-volumes'.
I: [pulseaudio] module.c: Loaded "module-device-restore" (index: #4; argument: "").
I: [pulseaudio] module.c: Loaded "module-default-device-restore" (index: #5; argument: "").
I: [pulseaudio] module.c: Loaded "module-rescue-streams" (index: #6; argument: "").
D: [pulseaudio] module-always-sink.c: Autoloading null-sink as no other sinks detected.
D: [pulseaudio] module-device-restore.c: Database contains invalid data for key: sink:auto_null (probably pre-v1.0 data)
D: [pulseaudio] module-device-restore.c: Attempting to load legacy (pre-v1.0) data for key: sink:auto_null
D: [pulseaudio] module-device-restore.c: Size does not match.
D: [pulseaudio] module-device-restore.c: Unable to load legacy (pre-v1.0) data for key: sink:auto_null. Ignoring.
D: [pulseaudio] module-device-restore.c: Database contains invalid data for key: sink:auto_null:null
I: [pulseaudio] sink.c: Created sink 0 "auto_null" with sample spec s16le 2ch 44100Hz and channel map front-left,front-right
I: [pulseaudio] sink.c:     device.description = "Dummy Output"
I: [pulseaudio] sink.c:     device.class = "abstract"
I: [pulseaudio] sink.c:     device.icon_name = "audio-card"
D: [pulseaudio] core-subscribe.c: Dropped redundant event due to change event.
D: [pulseaudio] module-device-restore.c: Database contains invalid data for key: source:auto_null.monitor (probably pre-v1.0 data)
D: [pulseaudio] module-device-restore.c: Attempting to load legacy (pre-v1.0) data for key: source:auto_null.monitor
D: [pulseaudio] module-device-restore.c: Size does not match.
D: [pulseaudio] module-device-restore.c: Unable to load legacy (pre-v1.0) data for key: source:auto_null.monitor. Ignoring.
D: [pulseaudio] module-device-restore.c: Database contains invalid data for key: source:auto_null.monitor:null
I: [pulseaudio] source.c: Created source 0 "auto_null.monitor" with sample spec s16le 2ch 44100Hz and channel map front-left,front-right
I: [pulseaudio] source.c:     device.description = "Monitor of Dummy Output"
I: [pulseaudio] source.c:     device.class = "monitor"
I: [pulseaudio] source.c:     device.icon_name = "audio-input-microphone"
D: [null-sink] module-null-sink.c: Thread starting up
D: [pulseaudio] module-device-restore.c: Database contains invalid data for key: sink:auto_null:null
I: [pulseaudio] module.c: Loaded "module-null-sink" (index: #8; argument: "sink_name=auto_null sink_properties='device.description="Dummy Output"'").
I: [pulseaudio] module.c: Loaded "module-always-sink" (index: #7; argument: "").
D: [pulseaudio] module-suspend-on-idle.c: Sink auto_null becomes idle, timeout in 5 seconds.
I: [pulseaudio] module.c: Loaded "module-suspend-on-idle" (index: #9; argument: "").
I: [pulseaudio] module.c: Loaded "module-position-event-sounds" (index: #10; argument: "").
D: [pulseaudio] dbus-util.c: Successfully connected to D-Bus system bus e880f84f89323cfcdd0e0b6b5419b549 as :1.10
E: [pulseaudio] main.c: Failed to acquire org.pulseaudio.Server: org.freedesktop.DBus.Error.AccessDenied: Connection ":1.10" is not allowed to own the service "org.pulseaudio.Server" due to security policies in the configuration file
I: [pulseaudio] main.c: Daemon startup complete.
D: [pulseaudio] module-device-restore.c: Database contains invalid data for key: sink:auto_null (probably pre-v1.0 data)
D: [pulseaudio] module-device-restore.c: Attempting to load legacy (pre-v1.0) data for key: sink:auto_null
D: [pulseaudio] module-device-restore.c: Size does not match.
D: [pulseaudio] module-device-restore.c: Unable to load legacy (pre-v1.0) data for key: sink:auto_null. Ignoring.
D: [pulseaudio] module-device-restore.c: Database contains invalid data for key: sink:auto_null:null
I: [pulseaudio] module-device-restore.c: Storing port for device sink:auto_null.
I: [pulseaudio] module-device-restore.c: Storing volume/mute for device+port sink:auto_null:null.
D: [pulseaudio] module-device-restore.c: Database contains invalid data for key: source:auto_null.monitor (probably pre-v1.0 data)
D: [pulseaudio] module-device-restore.c: Attempting to load legacy (pre-v1.0) data for key: source:auto_null.monitor
D: [pulseaudio] module-device-restore.c: Size does not match.
D: [pulseaudio] module-device-restore.c: Unable to load legacy (pre-v1.0) data for key: source:auto_null.monitor. Ignoring.
D: [pulseaudio] module-device-restore.c: Database contains invalid data for key: source:auto_null.monitor:null
I: [pulseaudio] module-device-restore.c: Storing port for device source:auto_null.monitor.
I: [pulseaudio] module-device-restore.c: Storing volume/mute for device+port source:auto_null.monitor:null.
I: [pulseaudio] module-suspend-on-idle.c: Sink auto_null idle for too long, suspending ...
D: [pulseaudio] sink.c: Suspend cause of sink auto_null is 0x0004, suspending
D: [pulseaudio] core.c: Hmm, no streams around, trying to vacuum.
I: [pulseaudio] module-device-restore.c: Synced.
Still — I cant play back any audio: mplayer complaints..

Code: Select all

...
AUDIO: 44100 Hz, 2 ch, floatle, 244.4 kbit/8.66% (ratio: 30546->352800)
Selected audio codec: [ffmp3float] afm: ffmpeg (FFmpeg MPEG layer-3 audio)
==========================================================================
Failed to create secure directory: Read-only file system
waitpid(): No child processes
AO: [pulse] Init failed: Internal error
Failed to initialize audio driver 'pulse'
[AO_ALSA] Format floatle is not supported by hardware, trying default.
AO: [alsa] 44100Hz 2ch s16le (2 bytes per sample)
...
Damn it! Maybe pulseaudio can't run on read only systems?!

User avatar
Douglas6
Posts: 4472
Joined: Sat Mar 16, 2013 5:34 am
Location: Chicago, IL

Re: Pulseaudio 5 on Wheezy

Thu Sep 18, 2014 3:18 am

I've started with the latest Raspian image from http://downloads.raspberrypi.org/raspbian_latest
With the addition of libcap-dev, I was able to build PA5, after

Code: Select all

sudo apt-get install -y libltdl-dev libsamplerate0-dev libsndfile1-dev libglib2.0-dev libasound2-dev libavahi-client-dev libspeexdsp-dev liborc-0.4-dev libbluetooth-dev intltool libtdb-dev libssl-dev libudev-dev libjson0-dev bluez-firmware bluez-utils  libbluetooth-dev bluez-alsa libsbc-dev libcap-dev
I'm also getting the

Code: Select all

E: [pulseaudio] main.c: Failed to find user 'pulse'.
error. Also, I can't find an init.d script for starting PA at boot. Clearly that link is seriously lacking. I'll keep pressing on and hopefully have a complete recipe for PA5 on Raspbian

User avatar
Douglas6
Posts: 4472
Joined: Sat Mar 16, 2013 5:34 am
Location: Chicago, IL

Re: Pulseaudio 5 on Wheezy

Mon Sep 22, 2014 6:58 pm

Forgive my noobness. I thought I had successfully built PA5, but just discovered that it seems to have been built with dependencies on libpulsecommon-2.0.so, which comes shipped with Raspian. This breaks PA5 in certain ways. So, can I
1. Uninstall these bits of PA2 ('sudo apt-get purge pulseaudio' just reports that it's not installed)?
2. Tell the PA5 build process not to use these shared objects?
3. Simply and safely delete them before building PA5?

The offending files seem to be these:

Code: Select all

[email protected] ~ $ sudo find / -name libpulse*
/usr/lib/arm-linux-gnueabihf/pulseaudio/libpulsecommon-2.0.so
/usr/lib/arm-linux-gnueabihf/libpulse-simple.so.0
/usr/lib/arm-linux-gnueabihf/libpulse-simple.so.0.0.3
/usr/lib/arm-linux-gnueabihf/libpulse.so.0
/usr/lib/arm-linux-gnueabihf/libpulse.so.0.14.2
/usr/share/doc/libpulse0
/var/lib/dpkg/info/libpulse0:armhf.shlibs
/var/lib/dpkg/info/libpulse0:armhf.conffiles
/var/lib/dpkg/info/libpulse0:armhf.md5sums
/var/lib/dpkg/info/libpulse0:armhf.postinst
/var/lib/dpkg/info/libpulse0:armhf.postrm
/var/lib/dpkg/info/libpulse0:armhf.list
/var/lib/dpkg/info/libpulse0:armhf.symbols

User avatar
Douglas6
Posts: 4472
Joined: Sat Mar 16, 2013 5:34 am
Location: Chicago, IL

Re: Pulseaudio 5 on Wheezy

Mon Sep 22, 2014 11:17 pm

And the answer is....

Code: Select all

sudo apt-get remove libpulse0

User avatar
Douglas6
Posts: 4472
Joined: Sat Mar 16, 2013 5:34 am
Location: Chicago, IL

Re: Pulseaudio 5 on Wheezy

Tue Sep 23, 2014 12:11 am

Hooray. Successfully streaming music from phone via A2DP using BlueZ 5.23 and PulseAudio 5 under Raspian Wheezy.

I'll write up a guide if anyone is interested.

pipimann
Posts: 22
Joined: Fri Mar 07, 2014 7:25 pm

Re: [Solved] Pulseaudio 5 on Wheezy

Wed Sep 24, 2014 9:38 pm

I would definitely be interested — good job!

User avatar
Douglas6
Posts: 4472
Joined: Sat Mar 16, 2013 5:34 am
Location: Chicago, IL

Re: [Solved] Pulseaudio 5 on Wheezy

Wed Sep 24, 2014 10:27 pm

Will do, this weekend if possible. As a bonus, last night I got AVRCP working (actually, it worked out of the box, I just had to access it), so I can display song title and artist, and play/pause/skip/stop the phone app (tested with Google Play Music and Pandora on an Android 4.4 phone)

User avatar
Douglas6
Posts: 4472
Joined: Sat Mar 16, 2013 5:34 am
Location: Chicago, IL

Re: [Solved] Pulseaudio 5 on Wheezy

Sun Sep 28, 2014 9:12 pm

I'm describing here the steps that worked for me to build (from source) PulseAudio 5.0 (PA5) and Bluez 5.23 (BlueZ5) on a fresh image of Raspiam Wheezy, and to stream audio from a mobile device to the Pi over Bluetooth. Note that BT streaming can be done without building packages from source (use one of the the several (not so good) guides already extant on the web). Attempt this guide only if you're comfortable with the Linux command line, and you REALLY want the latest Bluetooth stack.

1. Prepare the image
First, image an SD card with the latest Raspian image (I used 2014-09-09-wheezy-raspbian.img). Configure it with raspi-config, and set up networking. Leave the Buetooth dongle unattached until later. Then

Code: Select all

sudo apt-get update
sudo apt-get -y upgrade
Now install the dependencies for building PA5 and Bluez5

Code: Select all

sudo apt-get install -y libusb-dev libdbus-1-dev libglib2.0-dev libudev-dev libical-dev libreadline-dev libltdl-dev libsamplerate0-dev libsndfile1-dev libasound2-dev libavahi-client-dev libspeexdsp-dev liborc-0.4-dev intltool libtdb-dev libssl-dev libjson0-dev libsbc-dev libcap-dev
Raspian ships with the libpulse0 package which I've found conflicts with PA5. Removing it may have unwanted effects on other parts of the system (PyGame, GStreamer?), but it will allow PA5 and BlueZ5 to work. Remember, this was your decision. Don't blame me.

Code: Select all

sudo apt-get remove -y libpulse0
2. Build and Install PulseAudio 5.0
I got important information on building these packages from the Beyond Linux From Scratch site. For PA5, refer to this page

Download and unpack the PA5 source code. I do my building in the user home directory

Code: Select all

cd ~
wget : http://freedesktop.org/software/pulseaudio/releases/pulseaudio-5.0.tar.xz
tar xvf pulseaudio-5.0.tar.xz
Switch to the source directory and configure and build. The 'make' step took me about forty minutes, and 'sudo make install' another ten, so get a sandwich.

Code: Select all

cd pulseaudio-5.0/
./configure --prefix=/usr --sysconfdir=/etc --localstatedir=/var --disable-bluez4 --disable-rpath --with-module-dir=/usr/lib/pulse/modules
make
sudo make install
I like to run PA in 'system-wide' mode, which seems appropriate for a media-player appliance. We'll need to create a system user for PA

Code: Select all

sudo addgroup --system pulse
sudo adduser --system --ingroup pulse --home /var/run/pulse pulse
sudo addgroup --system pulse-access
sudo adduser pulse audio
It's convenient to be able to check things out, so let's give the root user access to Pulse commands

Code: Select all

sudo adduser root pulse-access
We'll need to change the PA resampling method for use on the Pi. I typically use 'speex-fixed-3', which gives a good compromise between quality and performance. By all means, experiment with the other options, just please don't use 'trivial', that's just stupid.

Code: Select all

sudo nano /etc/pulse/daemon.conf
Comment out the following line, and add the next

Code: Select all

; resample-method = speex-float-3
resample-method = speex-fixed-3
PulseAudio (both version 2 and 5) has a problem with the Pi's on-board sound driver. If you are not using a USB sound card, the following work-around helps to remove stuttering and other problems. We'll also want to load the bluetooth-discover module when the daemon starts. Edit the PA5 system configuration

Code: Select all

sudo nano /etc/pulse/system.pa
Find and comment out the first line and add the next

Code: Select all

#load-module module-udev-detect
load-module module-udev-detect tsched=0
Then at the end of system.pa, add the following lines

Code: Select all

### Automatically load driver modules for Bluetooth hardware
.ifexists module-bluetooth-discover.so
    load-module module-bluetooth-discover
.endif
3. Build and Install BlueZ 5.23
Refer to the Beyond Linux From Scratch page for details on building and configuring BlueZ 5.23. Change back to the home directory, and download and unpack the BlueZ5 source code.

Code: Select all

cd ~
wget www.kernel.org/pub/linux/bluetooth/bluez-5.23.tar.xz
tar xvf bluez-5.23.tar.xz
Drop into the source directory and configure, make and install BlueZ. Allow another 45 minutes or so for the 'make' step.

Code: Select all

cd bluez-5.23/
./configure --prefix=/usr --sysconfdir=/etc  --localstatedir=/var --enable-library --disable-systemd
make
sudo make install
sudo install -v -dm755 /etc/bluetooth
sudo install -v -m644 src/main.conf /etc/bluetooth/main.conf
Now allow the pulse daemon to integrate with Bluetooth

Code: Select all

sudo adduser pulse lp
We'll rename our Bluetooth adapter to be a little more descriptive

Code: Select all

sudo nano /etc/bluetooth/main.conf
And add the following line, or similar under the [General] section. For some reason, the substitution variables %h and %d don't seem to be working.

Code: Select all

Name = Raspberry-Pi
4. Verify Installation
At last, let's give it a go. Turn off the Pi, insert the Bluetooth dongle, and turn it back on. now let's fire up BlueZ and PulseAudio

Code: Select all

sudo /usr/libexec/bluetooth/bluetoothd &
sudo /usr/bin/pulseaudio --system --disallow-exit --disallow-module-loading=0 --daemonize --log-target=syslog --high-priority
Check that the PA is working and the modules have been loaded:

Code: Select all

sudo pactl list modules
This should list at the end

Code: Select all

Module #12
        Name: module-bluez5-discover
        Argument:
        Usage counter: n/a
        Properties:
                module.author = "João Paulo Rechi Vita"
                module.description = "Detect available BlueZ 5 Bluetooth audio devices and load BlueZ 5 Bluetooth audio drivers"
                module.version = "5.0"
Looks good. Let's go ahead and pair our Bluetooth-enabled mobile device. I've tested this set-up with a couple of Bluetooth dongles, and my Nexus 4 phone running Android 4.4. We'll use the CLI interface bluetoothctl. Start it with

Code: Select all

sudo bluetoothctl
Enter the following commands to bring up the adapter, make it discoverable (for three minutes), start a pairing agent, and make that agent the default

Code: Select all

power on
discoverable on
agent on
default-agent
Now, on your mobile device, search for devices, and initiate pairing. The paring process is slightly different depending on the dongle, so follow the directions on the Pi and on the phone. The phone may provide a random PIN, and bluethoothctl will ask you to confirm the PIN. Enter 'yes'. Then click 'pair' on the phone. Or, The phone will ask you to enter a PIN code. Enter '0000' on the phone, and bluetoothctl will ask you for a PIN code. Enter the same code. In either case, bluetoothctl should inform you that pairing was successful. It will then ask you to authorize the connection. Enter 'yes'.
Now trust the mobile device (notice that bluetoothctl features auto-complete, so you can type the first few characters of the device's bluetooth address (which was displayed a few lines previously) and hit <tab> to complete the address.

NOTE: Whenever you see 'AA:BB:CC:DD:EE:FF' or 'AA_BB_CC_DD_EE_FF' in this guide, replace it with the actual address of your mobile Bluetooth device, in the proper format (colons or underscores).

Code: Select all

trust AA:BB:CC:DD:EE:FF
Quit bluetoothctl with 'quit'. If all has gone well, we should see a PA module has been loaded for the device

Code: Select all

sudo pactl list modules
Should list the mobile device module

Code: Select all

Module #13
        Name: module-bluez5-device
        Argument: path=/org/bluez/hci0/dev_AA_BB_CC_DD_EE_FF
        Usage counter: 0
        Properties:
                module.author = "João Paulo Rechi Vita"
                module.description = "BlueZ 5 Bluetooth audio sink and source"
                module.version = "5.0"
Make sure there is a corresponding PA source:

Code: Select all

sudo pactl list sources
Source #1
        State: SUSPENDED
        Name: bluez_source.AA_BB_CC_DD_EE_FF
        Description: Nexus 4
        ....
Now it's simply a matter of connecting the new source to the default PA sink

Code: Select all

sudo -u pulse pactl load-module module-loopback source=bluez_source.AA_BB_CC_DD_EE_FF sink=0
That will return with the module number of the loopback module (14). You can verify this again with 'sudo pactl list modules'. Start playing music on your phone, and it will be streamed to the Pi's default output device. Use alsamixer to set the levels to maximum on the Pi, and use your phone to adjust the volume.

5. Automate the Process
We'll add two init scripts to start PA and bluetoothd at boot time. I've adapted the standard Raspian pulseaudio init script to use system-wide mode in all cases.

Code: Select all

sudo nano /etc/init.d/pulseaudio
And paste the following content

Code: Select all

#!/bin/sh -e
### BEGIN INIT INFO
# Provides:          pulseaudio esound
# Required-Start:    $remote_fs $syslog
# Required-Stop:     $remote_fs $syslog
# Should-Start:      udev network-manager
# Should-Stop:       udev network-manager
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: Start the PulseAudio sound server
# Description:       System mode startup script for
#                    the PulseAudio sound server.
### END INIT INFO

DAEMON=/usr/bin/pulseaudio
PIDDIR=/var/run/pulse
PIDFILE=$PIDDIR/pid
DAEMONUSER=pulse
PATH=/sbin:/bin:/usr/sbin:/usr/bin

test -x $DAEMON || exit 0

. /lib/lsb/init-functions

pulseaudio_start () {
        log_daemon_msg "Starting system PulseAudio Daemon"
        if [ ! -d $PIDDIR ]; then
                mkdir -p $PIDDIR
                chown $DAEMONUSER:$DAEMONUSER $PIDDIR
        fi
        start-stop-daemon -x $DAEMON -p $PIDFILE --start -- --system --disallow-exit --disallow-module-loading=0 --daemonize --log-target=syslog --high-priority
        status=$?
        if [ -e /var/run/pulse/.esd_auth ]; then
                chown pulse:pulse-access /var/run/pulse/.esd_auth
                chmod 640 /var/run/pulse/.esd_auth
        fi
        if [ -e /var/run/pulse/.pulse-cookie ]; then
                chown pulse:pulse-access /var/run/pulse/.pulse-cookie
                chmod 640 /var/run/pulse/.pulse-cookie
        fi
        log_end_msg ${status}
}

pulseaudio_stop () {
        log_daemon_msg "Stopping system PulseAudio Daemon"
        start-stop-daemon -p $PIDFILE --stop --retry 5 || echo -n "...which is not running"
        log_end_msg $?
}

case "$1" in
        start|stop)
                pulseaudio_${1}
                ;;
        restart|reload|force-reload)
                if [ -s $PIDFILE ] && kill -0 $(cat $PIDFILE) >/dev/null 2>&1; then
                        pulseaudio_stop
                        pulseaudio_start
                fi
                ;;
        force-stop)
                pulseaudio_stop
                killall pulseaudio || true
                sleep 2
                killall -9 pulseaudio || true
                ;;
        status)
                status_of_proc -p $PIDFILE "$DAEMON" "system-wide PulseAudio" && exit 0 || exit $?
                ;;
        *)
                echo "Usage: /etc/init.d/pulseaudio {start|stop|force-stop|restart|reload|force-reload|status}"
                exit 1
                ;;
esac

exit 0
Make the script executable and enable it.

Code: Select all

sudo chmod +x /etc/init.d/pulseaudio
sudo update-rc.d pulseaudio defaults
The bluetooth script is very basic, and does not support RFCOMM for example. This could use more work for a general solution, but it works for A2DP streaming.

Code: Select all

sudo nano /etc/init.d/bluetooth

Code: Select all

#!/bin/sh
### BEGIN INIT INFO
# Provides:            bluetooth
# Required-Start:      $local_fs $syslog dbus
# Required-Stop:       $local_fs $syslog
# Default-Start:       2 3 4 5
# Default-Stop:        0 1 6
# Short-Description:   Starts bluetooth daemons
### END INIT INFO

. /lib/lsb/init-functions

DESC=bluetoothd
DAEMON=/usr/libexec/bluetooth/bluetoothd
SSD_OPTIONS="--oknodo --quiet --exec $DAEMON"
HCI=hci0

case "${1}" in
    start)
       log_daemon_msg "Starting Bluetooth daemon bluetoothd..."
       start-stop-daemon --start --background $SSD_OPTIONS
       log_progress_msg "${DAEMON}"

       hciconfig $HCI up > /dev/null 2>&1
       log_end_msg 0
       ;;

    stop)
        log_daemon_msg "Stopping Bluetooth daemon bluetoothd..."
        start-stop-daemon --stop $SSD_OPTIONS
        log_progress_msg "${DAEMON}"
        log_end_msg 0
       ;;

    restart)
       ${0} stop
       sleep 1
       ${0} start
       ;;

    status)
        status_of_proc "$DAEMON" "$DESC" && exit 0 || exit $?
       ;;

    *)
         echo "Usage: ${0} {start|stop|restart|status}"
         exit 1
       ;;
esac

exit 0
Then

Code: Select all

sudo chmod +x /etc/init.d/bluetooth
sudo update-rc.d bluetooth defaults
Finally (finally!), we'll create a udev script to automatically loopback the PA bluetooth source to the default sink, and create a udev rule for it.

Code: Select all

sudo nano /usr/local/bin/bluez-udev
and add the following

Code: Select all

#!/bin/bash
audio_sink=0
name=$(sed 's/\"//g' <<< $NAME)
#exit if not a BT address
if [[ ! $name =~ ^([0-9A-F]{2}[:-]){5}([0-9A-F]{2})$ ]]; then exit 0;  fi

audio_source=bluez_source.$(sed 's/:/_/g' <<< $name)

action=$(expr "$ACTION" : "\([a-zA-Z]\+\).*")
if [ "$action" = "add" ]; then
    logger "[$(basename $0)] Bluetooth device is being added [$name]"
    logger "[$(basename $0)] Patching $audio_source into ALSA sink #$audio_sink"
    # loop back this source to the default sink
    handle=$(pactl load-module module-loopback source=$audio_source sink=$audio_sink)
    logger "[$(basename $0)] PulseAudio module-loopback returned handle [$handle]"
fi

if [ "$action" = "remove" ]; then
    logger "[$(basename $0)] Bluetooth device is being removed [$name]"
    # remove any loopback modules assigned to this source
    # only required for USB sound cards, which PulseAudio will not automatically remove
    for handle in $(pactl list short modules | grep module-loopback | grep source=$audio_source | cut -f 1); do
        logger "[$(basename $0)] Unloading module-loopback with handle [$handle]"
        pactl unload-module $handle
    done
fi
Make it executable

Code: Select all

sudo chmod +x /usr/local/bin/bluez-udev
Now edit the udev user input rules

Code: Select all

sudo nano /etc/udev/rules.d/99-input.rules
And add the following line at the bottom

Code: Select all

KERNEL=="input[0-9]*", RUN+="/usr/local/bin/bluez-udev"
Reboot, and everything should 'just work'!

Troubleshooting
Keep an eye on /var/log/syslog for various errors from PA or the udev script
My phone will frequently stop the audio stream when switching between outputs. If you're not hearing anything, make sure the phone is playing something.
Bluetooth is sometimes ornery. If the phone won't pair or connect on the first attempt, try again.

texy
Forum Moderator
Forum Moderator
Posts: 5146
Joined: Sat Mar 03, 2012 10:59 am
Location: Berkshire, England

Re: [Solved] Pulseaudio 5 on Wheezy

Mon Nov 03, 2014 5:47 pm

Douglas6 wrote:Will do, this weekend if possible. As a bonus, last night I got AVRCP working (actually, it worked out of the box, I just had to access it), so I can display song title and artist, and play/pause/skip/stop the phone app (tested with Google Play Music and Pandora on an Android 4.4 phone)
Very interested in this - could you please supply some Python code to display song title etc

Thanks
Texy
Various male/female 40- and 26-way GPIO header for sale here ( IDEAL FOR YOUR PiZero ):
https://www.raspberrypi.org/forums/viewtopic.php?f=93&t=147682#p971555

User avatar
Douglas6
Posts: 4472
Joined: Sat Mar 16, 2013 5:34 am
Location: Chicago, IL

Re: [Guide] Pulseaudio 5 on Wheezy

Tue Nov 04, 2014 2:46 am

Here's the Python code I have come up with. It's very much in the alpha stage, so I'll simply post it here; the next version I'll try and put on Github.

Some background: Since BlueZ 4, the recommended way to communicate with BlueZ is via D-Bus. This works quite well, and is easy to do in Python, so it's the approach I took. This code (blueplayer) connects to the system bus, and waits for propertyChanged 'signals' from BlueZ on the bus, signifying changes to the state of the BlueZ device; either status changes, or changes to the current track. It will update it's state, and then update the display. I'm using Adafruit's 16x2 RGB Pi plate with buttons; code changes will be needed for a different display and navigation buttons.

Blueplayer first checks if a MediaPlayer1 is active, if not, it waits for one. It also acts as a pairing agent so you can pair new devices (currently any pairing request is accepted; that's a to-do). Then it just waits on changes and reacts accordingly. Changes include a change to "Track", from which the "Title" and "Artist" are updated and displayed. Other changes to the device state (idle, disconnected) will turn off the display's backlight.

Dependencies: You'll probably need to

Code: Select all

sudo apt-get install python-gobject python-smbus
Usage: Run 'sudo blueplayer' (root permission is required to access the system bus). Press the 'Select' button (far left) to make the Pi discoverable. You should be able to pair from your device. Use the 'up' button to pause/unpause. Use the 'left' button for previous, and the 'right' button for next or skip.

The code follows. I hope it is useful.
blueplayer

Code: Select all

#!/usr/bin/env python

# Dependencies:
# sudo apt-get install -y python-gobject
# sudo apt-get install -y python-smbus

import time
import signal
import dbus
import dbus.service
import dbus.mainloop.glib
import gobject
import logging
from lcd import Lcd

SERVICE_NAME = "org.bluez"
AGENT_IFACE = SERVICE_NAME + '.Agent1'
ADAPTER_IFACE = SERVICE_NAME + ".Adapter1"
DEVICE_IFACE = SERVICE_NAME + ".Device1"
PLAYER_IFACE = SERVICE_NAME + '.MediaPlayer1'
TRANSPORT_IFACE = SERVICE_NAME + '.MediaTransport1'

#LOG_LEVEL = logging.INFO
LOG_LEVEL = logging.DEBUG
LOG_FILE = "/dev/stdout"
LOG_FORMAT = "%(asctime)s %(levelname)s %(message)s"

"""Utility functions from bluezutils.py"""
def getManagedObjects():
    bus = dbus.SystemBus()
    manager = dbus.Interface(bus.get_object("org.bluez", "/"), "org.freedesktop.DBus.ObjectManager")
    return manager.GetManagedObjects()

def findAdapter():
    objects = getManagedObjects();
    bus = dbus.SystemBus()
    for path, ifaces in objects.iteritems():
        adapter = ifaces.get(ADAPTER_IFACE)
        if adapter is None:
            continue
        obj = bus.get_object(SERVICE_NAME, path)
        return dbus.Interface(obj, ADAPTER_IFACE)
    raise Exception("Bluetooth adapter not found")

class BluePlayer(dbus.service.Object):
    AGENT_PATH = "/blueplayer/agent"
    CAPABILITY = "DisplayOnly"

    lcd = None
    bus = None
    adapter = None
    device = None
    deviceAlias = None
    player = None
    transport = None
    connected = None
    state = None
    status = None
    discoverable = None
    track = None

    def __init__(self, lcd):
        """Initialize gobject, start the LCD, and find any current media players"""
        self.lcd = lcd
        self.bus = dbus.SystemBus()

        dbus.service.Object.__init__(self, dbus.SystemBus(), BluePlayer.AGENT_PATH)

        self.bus.add_signal_receiver(self.playerHandler,
                bus_name="org.bluez",
                dbus_interface="org.freedesktop.DBus.Properties",
                signal_name="PropertiesChanged",
                path_keyword="path")

        self.registerAgent()

        adapter_path = findAdapter().object_path
        self.bus.add_signal_receiver(self.adapterHandler,
                bus_name = "org.bluez",
                path = adapter_path,
                dbus_interface = "org.freedesktop.DBus.Properties",
                signal_name = "PropertiesChanged",
                path_keyword = "path")


        self.findPlayer()
        self.updateDisplay()

    def start(self):
        """Start the BluePlayer by running the gobject mainloop()"""
        try:
            mainloop = gobject.MainLoop()
            mainloop.run()
        except:
            self.end()

    def findPlayer(self):
        """Find any current media players and associated device"""
        manager = dbus.Interface(self.bus.get_object("org.bluez", "/"), "org.freedesktop.DBus.ObjectManager")
        objects = manager.GetManagedObjects()

        player_path = None
        transport_path = None
        for path, interfaces in objects.iteritems():
            if PLAYER_IFACE in interfaces:
                player_path = path
            if TRANSPORT_IFACE in interfaces:
                transport_path = path

        if player_path:
            logging.debug("Found player on path [{}]".format(player_path))
            self.connected = True
            self.getPlayer(player_path)
            player_properties = self.player.GetAll(PLAYER_IFACE, dbus_interface="org.freedesktop.DBus.Properties")
            if "Status" in player_properties:
                self.status = player_properties["Status"]
            if "Track" in player_properties:
                self.track = player_properties["Track"]
        else:
            logging.debug("Could not find player")

        if transport_path:
            logging.debug("Found transport on path [{}]".format(player_path))
            self.transport = self.bus.get_object("org.bluez", transport_path)
            logging.debug("Transport [{}] has been set".format(transport_path))
            transport_properties = self.transport.GetAll(TRANSPORT_IFACE, dbus_interface="org.freedesktop.DBus.Properties")
            if "State" in transport_properties:
                self.state = transport_properties["State"]

    def getPlayer(self, path):
        """Get a media player from a dbus path, and the associated device"""
        self.player = self.bus.get_object("org.bluez", path)
        logging.debug("Player [{}] has been set".format(path))
        device_path = self.player.Get("org.bluez.MediaPlayer1", "Device", dbus_interface="org.freedesktop.DBus.Properties")
        self.getDevice(device_path)

    def getDevice(self, path):
        """Get a device from a dbus path"""
        self.device = self.bus.get_object("org.bluez", path)
        self.deviceAlias = self.device.Get(DEVICE_IFACE, "Alias", dbus_interface="org.freedesktop.DBus.Properties")

    def playerHandler(self, interface, changed, invalidated, path):
        """Handle relevant property change signals"""
        logging.debug("Interface [{}] changed [{}] on path [{}]".format(interface, changed, path))
        iface = interface[interface.rfind(".") + 1:]

        if iface == "Device1":
            if "Connected" in changed:
                self.connected = changed["Connected"]
        if iface == "MediaControl1":
            if "Connected" in changed:
                self.connected = changed["Connected"]
                if changed["Connected"]:
                    logging.debug("MediaControl is connected [{}] and interface [{}]".format(path, iface))
                    self.findPlayer()
        elif iface == "MediaTransport1":
            if "State" in changed:
                logging.debug("State has changed to [{}]".format(changed["State"]))
                self.state = (changed["State"])
            if "Connected" in changed:
                self.connected = changed["Connected"]
        elif iface == "MediaPlayer1":
            if "Track" in changed:
                logging.debug("Track has changed to [{}]".format(changed["Track"]))
                self.track = changed["Track"]
            if "Status" in changed:
                logging.debug("Status has changed to [{}]".format(changed["Status"]))
                self.status = (changed["Status"])

        self.updateDisplay()

    def updateDisplay(self):
        """Display the current status of the device on the LCD"""
        logging.debug("Updating display for connected: [{}]; state: [{}]; status: [{}]; discoverable [{}]".format(self.connected, self.state, self.status, self.discoverable))
        if self.discoverable:
            self.wake()
            self.showDiscoverable()
        else:
            if self.connected:
                if self.state == "idle":
                    self.sleep()
                else:
                    self.wake()
                    if self.status == "paused":
                        self.showPaused()
                    else:
                        self.showTrack()
            else:
                self.sleep()

    def showDevice(self):
        """Display the device connection info on the LCD"""
        self.lcd.clear()
        self.lcd.writeLn("Connected to:", 0)
        self.lcd.writeLn(self.deviceAlias, 1)
        time.sleep(2)

    def showTrack(self):
        """Display track info on the LCD"""
        lines = []
        if "Artist" in self.track:
                    lines.append(self.track["Artist"])
                    if self.track["Title"]:
                         lines.append(self.track["Title"])
        elif "Title" in self.track:
            lines = self.lcd.wrap(self.track["Title"])

        self.lcd.clear()
        for i, line in enumerate(lines):
            if i >= self.lcd.numlines: break
            self.lcd.writeLn(lines[i], i)

    def showPaused(self):
        self.lcd.clear()
        self.lcd.writeLn("Device is paused", 0)

    def showDiscoverable(self):
        self.lcd.clear()
        self.lcd.writeLn("Waiting to pair", 0)
        self.lcd.writeLn("with device", 1)


    def next(self):
        self.player.Next(dbus_interface=PLAYER_IFACE)

    def previous(self):
        self.player.Previous(dbus_interface=PLAYER_IFACE)

    def play(self):
        self.player.Play(dbus_interface=PLAYER_IFACE)

    def pause(self):
        self.player.Pause(dbus_interface=PLAYER_IFACE)

    def volumeUp(self):
        self.control.VolumeUp(dbus_interface=CONTROL_IFACE)
        self.transport.VolumeUp(dbus_interface=TRANSPORT_IFACE)

    def wake(self):
        """Wake up the LCD"""
        self.lcd.backlight(Lcd.TEAL)

    def shutdown(self):
        self.lcd.end()

    def sleep(self):
        """Put the LCD to sleep"""
        self.lcd.clear()
        self.lcd.backlight(Lcd.OFF)

    def getStatus(self):
        return self.status

    """Pairing agent methods"""
    @dbus.service.method(AGENT_IFACE, in_signature="ou", out_signature="")
    def RequestConfirmation(self, device, passkey):
        """Always confirm"""
        logging.debug("RequestConfirmation returns")
        self.trustDevice(device)
        return

    @dbus.service.method(AGENT_IFACE, in_signature="os", out_signature="")
    def AuthorizeService(self, device, uuid):
        """Always authorize"""
        logging.debug("Authorize service returns")
        return

    def trustDevice(self, path):
        """Set the device to trusted"""
        device_properties = dbus.Interface(self.bus.get_object(SERVICE_NAME, path), "org.freedesktop.DBus.Properties")
        device_properties.Set(DEVICE_IFACE, "Trusted", True)

    def registerAgent(self):
        """Register BluePlayer as the default agent"""
        manager = dbus.Interface(self.bus.get_object(SERVICE_NAME, "/org/bluez"), "org.bluez.AgentManager1")
        manager.RegisterAgent(BluePlayer.AGENT_PATH, BluePlayer.CAPABILITY)
        manager.RequestDefaultAgent(BluePlayer.AGENT_PATH)
        logging.debug("Blueplayer is registered as a default agent")

    def startPairing(self):
        logging.debug("Starting to pair")
        """Make the adpater discoverable"""
        adapter_path = findAdapter().object_path
        adapter = dbus.Interface(self.bus.get_object(SERVICE_NAME, adapter_path), "org.freedesktop.DBus.Properties")
        adapter.Set(ADAPTER_IFACE, "Discoverable", True)

def navHandler(buttons):
    logging.debug("Handling navigation for [{}]".format(buttons))
    """Handle the navigation buttons"""
    if buttons == Lcd.BUTTON_SELECT:
        player.startPairing()
    elif buttons == Lcd.BUTTON_LEFT:
        player.previous()
    elif buttons == Lcd.BUTTON_RIGHT:
        player.next()
    elif buttons == Lcd.BUTTON_UP:
        if player.getStatus() == "playing":
            player.pause()
        else:
            player.play()

logging.basicConfig(filename=LOG_FILE, format=LOG_FORMAT, level=LOG_LEVEL)
logging.info("Starting BluePlayer")

gobject.threads_init()
dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)

lcd = Lcd()
lcd.begin(16, 2, handler=navHandler)
lcd.backlight(Lcd.TEAL)
lcd.clear()
lcd.writeLn("Starting", 0)
lcd.writeLn("BluePlayer", 1)
time.sleep(2)

player = None
try:
    player = BluePlayer(lcd)
    mainloop = gobject.MainLoop()
    mainloop.run()
except KeyboardInterrupt as ex:
    logging.info("BluePlayer canceled by user")
except Exception as ex:
    logging.error("How embarrassing. The following error occurred {}".format(ex))
finally:
    if player:
        player.shutdown()
And here is the Lcd code that provides basic display functions based on the Adafruit LCD plate, and button polling:

Code: Select all

from threading import Thread
import time
from Adafruit_CharLCDPlate import Adafruit_CharLCDPlate

class Lcd(Adafruit_CharLCDPlate):
    BUTTON_SELECT = 1
    BUTTON_LEFT = 16
    BUTTON_RIGHT = 2
    BUTTON_UP = 8
    BUTTON_DOWN = 4

    worker = None
    polling = True
    handler = None

    def begin(self, cols, rows, handler=None):
        super(Lcd, self).begin(cols, rows)
        self.handler = handler
        if self.handler:
            self.worker = Thread(target=self.getButtons)
            self.worker.start()

    def end(self):
        self.polling = False;
        self.clear()
        self.backlight(Lcd.OFF)
        self.stop()

    def writeLn(self, str, row):
        self.setCursor(0, row)
        self.message(self.replaceAccents(str[:40].ljust(40)))

    def replaceAccents(self, str):
        return str.replace(u"\xe9", "e")

    def getButtons(self):
        button_cache = 0;
        while self.polling:
            test = self.buttons()
            buttons = test - button_cache;
            button_cache = test if test > 0 else 0
            if buttons > 0:
                self.handler(buttons)
            time.sleep(0.1)

    def wrap(self, str):
        lines = [];
        while len(str) > self.numcols:
            idx = str[:self.numcols+1].rfind(" ")
            if idx > 0:
                lines.append(str[:idx])
                str = str[idx+1:].lstrip()
            else:
                lines.append(str[:self.numcols])
                str = str[self.numcols:].lstrip()

        lines.append(str)

        return  lines



if __name__ == "__main__":
    def handleNav(buttons):
        print(buttons)

    try:
        lcd = Lcd()
        lcd.begin(16, 2, handler=handleNav)

        while True:
            time.sleep(1)
    except:
        lcd.end()
[EDIT: image removed]
Last edited by Douglas6 on Thu Sep 22, 2016 3:33 pm, edited 1 time in total.

texy
Forum Moderator
Forum Moderator
Posts: 5146
Joined: Sat Mar 03, 2012 10:59 am
Location: Berkshire, England

Re: [Guide] Pulseaudio 5 on Wheezy

Tue Nov 04, 2014 9:21 pm

Thanks for posting the code and method. It'll take me some time to get bare bones code working as I don't have an Adafruit LCD module. Currently trying to strip away all lcd related code - not an easy task for myself.
cheers,
Texy
Various male/female 40- and 26-way GPIO header for sale here ( IDEAL FOR YOUR PiZero ):
https://www.raspberrypi.org/forums/viewtopic.php?f=93&t=147682#p971555

User avatar
Douglas6
Posts: 4472
Joined: Sat Mar 16, 2013 5:34 am
Location: Chicago, IL

Re: [Guide] Pulseaudio 5 on Wheezy

Tue Nov 04, 2014 10:00 pm

Shouldn't be too hard. Start by replacing lcd.py with the following [untested]:

Code: Select all

from threading import Thread
import time

class Lcd(Object):
    BUTTON_SELECT = 1
    BUTTON_LEFT = 16
    BUTTON_RIGHT = 2
    BUTTON_UP = 8
    BUTTON_DOWN = 4

    worker = None
    polling = True
    handler = None

    def begin(self, cols, rows, handler=None):
        self.handler = handler
        if self.handler:
            self.worker = Thread(target=self.getButtons)
            self.worker.start()

    def end(self):
        self.polling = False;
        self.clear()
        self.backlight(Lcd.OFF)
        self.stop()

    def writeLn(self, str, row):
        self.setCursor(0, row)
        self.message(self.replaceAccents(str[:40].ljust(40)))

    def replaceAccents(self, str):
        return str.replace(u"\xe9", "e")

    def getButtons(self):
        button_cache = 0;
        while self.polling:
            test = self.buttons()
            buttons = test - button_cache;
            button_cache = test if test > 0 else 0
            if buttons > 0:
                self.handler(buttons)
            time.sleep(0.1)

    def wrap(self, str):
        lines = [];
        while len(str) > self.numcols:
            idx = str[:self.numcols+1].rfind(" ")
            if idx > 0:
                lines.append(str[:idx])
                str = str[idx+1:].lstrip()
            else:
                lines.append(str[:self.numcols])
                str = str[self.numcols:].lstrip()

        lines.append(str)

        return  lines
  
    #  
    # Adjust the following for your display
    #
    def clear(self):
        # clear the display
        pass

    def setCursor(self, col, row):
        # set the cursor position
        pass

    def backlight(self, col):
        # set the backlight color
        pass

    def stop(self):
        # clean up the display
        pass

    def message(self, str):
        # print a line
        print(str)

    def buttons(self):
        # return the button states
        return '0b00000'

And adjust the last few methods for your display (currently it will print to the terminal). Buttons will be a bit trickier, but basically just test them with RPi.GPIO or whatever.
Last edited by Douglas6 on Tue Nov 04, 2014 10:13 pm, edited 1 time in total.

deivid
Posts: 46
Joined: Thu Oct 23, 2014 7:08 am

Re: [Guide] Pulseaudio 5 on Wheezy

Tue Nov 04, 2014 10:02 pm

How is the CPU usage with pulse? Using the version on the repos I get like 40% cpu usage just to play a file. This doesn't happen with alsa (and the sound quality is the same, only thing alsa required was fiddling with configs)

User avatar
Douglas6
Posts: 4472
Joined: Sat Mar 16, 2013 5:34 am
Location: Chicago, IL

Re: [Guide] Pulseaudio 5 on Wheezy

Tue Nov 04, 2014 10:18 pm

deivid wrote:How is the CPU usage with pulse?
Using the the 'speex-fixed-3' resampling method, I hover around 35% CPU. 'trivial' lowers that to 20 or 25%, if I recall, but quality is noticeably worse. If you know how to do A2DP streaming without PA, I'd be more than happy to ditch it.

Were you using the ALSA dmix plug-in? I'd expect that would be a fairer comparison, since I don't think ALSA does resampling normally, like PA does.

texy
Forum Moderator
Forum Moderator
Posts: 5146
Joined: Sat Mar 03, 2012 10:59 am
Location: Berkshire, England

Re: [Guide] Pulseaudio 5 on Wheezy

Wed Nov 05, 2014 8:38 pm

Douglas6 wrote:Shouldn't be too hard. Start by replacing lcd.py with the following [untested]:

Code: Select all

from threading import Thread
import time

class Lcd(Object):
    BUTTON_SELECT = 1
    BUTTON_LEFT = 16
    BUTTON_RIGHT = 2
    BUTTON_UP = 8
    BUTTON_DOWN = 4

    worker = None
    polling = True
    handler = None

    def begin(self, cols, rows, handler=None):
        self.handler = handler
        if self.handler:
            self.worker = Thread(target=self.getButtons)
            self.worker.start()

    def end(self):
        self.polling = False;
        self.clear()
        self.backlight(Lcd.OFF)
        self.stop()

    def writeLn(self, str, row):
        self.setCursor(0, row)
        self.message(self.replaceAccents(str[:40].ljust(40)))

    def replaceAccents(self, str):
        return str.replace(u"\xe9", "e")

    def getButtons(self):
        button_cache = 0;
        while self.polling:
            test = self.buttons()
            buttons = test - button_cache;
            button_cache = test if test > 0 else 0
            if buttons > 0:
                self.handler(buttons)
            time.sleep(0.1)

    def wrap(self, str):
        lines = [];
        while len(str) > self.numcols:
            idx = str[:self.numcols+1].rfind(" ")
            if idx > 0:
                lines.append(str[:idx])
                str = str[idx+1:].lstrip()
            else:
                lines.append(str[:self.numcols])
                str = str[self.numcols:].lstrip()

        lines.append(str)

        return  lines
  
    #  
    # Adjust the following for your display
    #
    def clear(self):
        # clear the display
        pass

    def setCursor(self, col, row):
        # set the cursor position
        pass

    def backlight(self, col):
        # set the backlight color
        pass

    def stop(self):
        # clean up the display
        pass

    def message(self, str):
        # print a line
        print(str)

    def buttons(self):
        # return the button states
        return '0b00000'

And adjust the last few methods for your display (currently it will print to the terminal). Buttons will be a bit trickier, but basically just test them with RPi.GPIO or whatever.
Hmm, no that doesn't work. It's complaining about Object. If I make it object (ie no capital O), then it gets further, but then

Code: Select all

Traceback (most recent call last):
  File "blueplayer.py", line 310, in <module>
    lcd.backlight(Lcd.TEAL)
AttributeError: type object 'Lcd' has no attribute 'TEAL'
So I # out that line and it fails with

Code: Select all

Traceback (most recent call last):
  File "blueplayer.py", line 318, in <module>
    player = BluePlayer(lcd)
  File "blueplayer.py", line 78, in __init__
    self.bus.add_signal_receiver(self.adapterHandler,
AttributeError: 'BluePlayer' object has no attribute 'adapterHandler'
This is way above my python abilities. :(

Texy
Various male/female 40- and 26-way GPIO header for sale here ( IDEAL FOR YOUR PiZero ):
https://www.raspberrypi.org/forums/viewtopic.php?f=93&t=147682#p971555

User avatar
Douglas6
Posts: 4472
Joined: Sat Mar 16, 2013 5:34 am
Location: Chicago, IL

Re: [Guide] Pulseaudio 5 on Wheezy

Wed Nov 05, 2014 9:06 pm

texy wrote:Hmm, no that doesn't work.
My apologies, I should know better than to post untested code. Give me an evening or two to get it sorted, and I'll post a working version that does not depend on an LCD display or buttons (so will not have the pairing, pause, previous or next functions)

So, you managed to get Bluez 5.23 and PulseAudio 5.0 built and installed? No problems there?

deivid
Posts: 46
Joined: Thu Oct 23, 2014 7:08 am

Re: [Guide] Pulseaudio 5 on Wheezy

Wed Nov 05, 2014 9:28 pm

Douglas6 wrote:
deivid wrote:How is the CPU usage with pulse?
Using the the 'speex-fixed-3' resampling method, I hover around 35% CPU. 'trivial' lowers that to 20 or 25%, if I recall, but quality is noticeably worse. If you know how to do A2DP streaming without PA, I'd be more than happy to ditch it.

Were you using the ALSA dmix plug-in? I'd expect that would be a fairer comparison, since I don't think ALSA does resampling normally, like PA does.
A2DP is the bluetooth profile, and it has nothing to do with ALSA/Pulse, see here how to connect with ALSA.
Resampling is very expensive and should be avoided if possible(Unless your RPI is used for music only).
All that said, I have zero 'ear' for music, meaning that unless the sound is distorted as hell I won't notice it.

texy
Forum Moderator
Forum Moderator
Posts: 5146
Joined: Sat Mar 03, 2012 10:59 am
Location: Berkshire, England

Re: [Guide] Pulseaudio 5 on Wheezy

Wed Nov 05, 2014 9:31 pm

Firstly many thanks for sharing the guide - it is most appreciated.
Yes I have bluetooth audio streaming from my iPhone using your instructions.
So the compilation and configuration are working fine.
If the lcd code can be removed that'll be great. The method for skipping tracks and of course obtaining the artist and track names, etc, would be useful of course as this is what puts this apart from the other 'bog standard' bluetooth tutorials.
Thanks again
Texy
Various male/female 40- and 26-way GPIO header for sale here ( IDEAL FOR YOUR PiZero ):
https://www.raspberrypi.org/forums/viewtopic.php?f=93&t=147682#p971555

Return to “Advanced users”