Play sound over standard java sinks via pulseaudio to bluetooth device

Hi, I would love to play sounds to my bluetooth speaker. As I managed to do so with Raspian, I struggled so far with Openhab.
E.g. the console command

smarthome:audio play enhancedjavasound doorbell.mp3

just directs to the standard Raspberry Pi audio outputs, while the linux console command

mpg321 doorbell.mp3

just works fine.

Since neither the Squeezebox nor the Pulseaudio binding seem to be so far valid audio sinks for OpenHAB2, I was hoping that there is a way to re-direkt the standard java OpenHAB sinks in a way to communicate with the pulseaudio server. Is this possible?

My current workaround ist using a Squeezelite instance and stream audio sources e.g. by the following statement

sendCommand(SqueezeLite_StreamURL, "http://www.some.url")

Any idea how to do it better, i.e. how to re-direkt the standard OpenHAB sinks to pulseaudio?

Thx,
Wartel

I tried doing the same quite a while back but never quite managed to get the BT part to work properly.

I remember it was essential to change /usr/lib/jvm/default-java/jre/lib/sound.properties.
(the default-java is actually just a link, depending on packages you have installed or not, multiple directories may exist with a sound.properties below each, so ensure you edit the one your java is actively using).
Mine reads

javax.sound.sampled.Clip=org.classpath.icedtea.pulseaudio.PulseAudioMixerProvider
javax.sound.sampled.Port=org.classpath.icedtea.pulseaudio.PulseAudioMixerProvider
javax.sound.sampled.SourceDataLine=org.classpath.icedtea.pulseaudio.PulseAudioMixerProvider
javax.sound.sampled.TargetDataLine=org.classpath.icedtea.pulseaudio.PulseAudioMixerProvider

#javax.sound.sampled.Clip=com.sun.media.sound.DirectAudioDeviceProvider
#javax.sound.sampled.Port=com.sun.media.sound.PortMixerProvider
#javax.sound.sampled.SourceDataLine=com.sun.media.sound.DirectAudioDeviceProvider
#javax.sound.sampled.TargetDataLine=com.sun.media.sound.DirectAudioDeviceProvider

so I guess I’m using PulseAudio right now …

Hm, sounds like the perfect solution and a clear spot where to solve the issue. Unfortunately I tried to do so with an Oracle JDK1.8 and unfortunately it did not change a bit - sound still comes through the 3.5mm jack…

However, regarding the bluetooth issue - this site helped me to get it up and running:
https://wiki.archlinux.org/index.php/Bluetooth_headset

Thx, nevertheless

@wartel
Hello Gerald!

Ever managed to output sound from openhab2 to a BT speaker?
I’m in the same spot as you were: mpg321 plays the file to the BT speaker, but no sound from openhab…

Well, I got it working… :smile:
Here’s what needs to be done to output the sound from openhab to pulseaudio (and a BT connected speaker in my case).
I got it working using oracle-java8-jdk (I also tried the same with Zulu, but no luck)

Install need packages

apt-get install libpulse-jni libpulse-java

Copy pulse-java files:

sudo cp /usr/lib/arm-linux-gnueabihf/jni/libpulse-java.so /usr/lib/jvm/jdk-8-oracle-arm32-vfp-hflt/jre/lib/arm/
sudo cp /usr/share/java/pulse-java* /usr/lib/jvm/jdk-8-oracle-arm32-vfp-hflt/jre/lib/ext/

Edit /usr/lib/jvm/jdk-8-oracle-arm32-vfp-hflt/jre/lib/sound.properties and add the following lines:

javax.sound.sampled.Clip=org.classpath.icedtea.pulseaudio.PulseAudioMixerProvider
javax.sound.sampled.Port=org.classpath.icedtea.pulseaudio.PulseAudioMixerProvider
javax.sound.sampled.SourceDataLine=org.classpath.icedtea.pulseaudio.PulseAudioMixerProvider
javax.sound.sampled.TargetDataLine=org.classpath.icedtea.pulseaudio.PulseAudioMixerProvider

And voila!, now smarthome:audio play doorbell.mp3 plays nicely on my BT speaker :smile:

Same approach didn’t work with Zulu :rage: :

# ls -la /opt/zulu/8u112/jre/lib/ext/
total 7716
drwxrwxr-x  2 root root    4096 Feb 13 11:50 .
drwxrwxr-x 10 root root    4096 Feb 13 11:41 ..
-rw-rw-r--  1 root root 3861228 Dec 23 12:56 cldrdata.jar
-rw-rw-r--  1 root root    8287 Dec 23 12:56 dnsns.jar
-rw-rw-r--  1 root root   44517 Dec 23 12:56 jaccess.jar
-rw-rw-r--  1 root root 1179094 Dec 23 12:56 localedata.jar
-rw-rw-r--  1 root root     617 Dec 23 12:56 meta-index
-rw-rw-r--  1 root root 2032277 Dec 23 12:56 nashorn.jar
-rw-r--r--  1 root root   69031 Feb 13 11:50 pulse-java-2.4.7.jar
-rw-r--r--  1 root root   69031 Feb 13 11:50 pulse-java.jar
-rw-rw-r--  1 root root   38163 Dec 23 12:56 sunec.jar
-rw-rw-r--  1 root root  261567 Dec 23 12:56 sunjce_provider.jar
-rw-rw-r--  1 root root  238950 Dec 23 12:56 sunpkcs11.jar
-rw-rw-r--  1 root root   68938 Dec 23 12:56 zipfs.jar
#~ $ ls -la /opt/zulu/8u112/jre/lib/arm/
total 60
drwxr-xr-x  2 root root  4096 Feb 13 11:42 .
drwxrwxr-x 10 root root  4096 Feb 13 11:41 ..
-rw-r--r--  1 root root 50772 Feb 13 11:42 libpulse-java.so
# cat cat /opt/zulu/8u112/jre/lib/sound.properties
javax.sound.sampled.Clip=org.classpath.icedtea.pulseaudio.PulseAudioMixerProvider
javax.sound.sampled.Port=org.classpath.icedtea.pulseaudio.PulseAudioMixerProvider
javax.sound.sampled.SourceDataLine=org.classpath.icedtea.pulseaudio.PulseAudioMixerProvider
javax.sound.sampled.TargetDataLine=org.classpath.icedtea.pulseaudio.PulseAudioMixerProvider

Runnin a java simple program to test the sound output gives:

Exception in thread "main" java.lang.UnsatisfiedLinkError: no pulse-java in java.library.path
        at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1867)
        at java.lang.Runtime.loadLibrary0(Runtime.java:870)
        at java.lang.System.loadLibrary(System.java:1122)
        at org.classpath.icedtea.pulseaudio.SecurityWrapper.loadNativeLibrary(SecurityWrapper.java:27)
        at org.classpath.icedtea.pulseaudio.EventLoop.<clinit>(EventLoop.java:97)
        at org.classpath.icedtea.pulseaudio.PulseAudioMixer.openImpl(PulseAudioMixer.java:654)
        at org.classpath.icedtea.pulseaudio.PulseAudioMixer.openLocal(PulseAudioMixer.java:588)
        at org.classpath.icedtea.pulseaudio.PulseAudioMixer.openLocal(PulseAudioMixer.java:584)
        at org.classpath.icedtea.pulseaudio.PulseAudioMixer.open(PulseAudioMixer.java:579)
        at org.classpath.icedtea.pulseaudio.PulseAudioDataLine.open(PulseAudioDataLine.java:94)
        at org.classpath.icedtea.pulseaudio.PulseAudioSourceDataLine.open(PulseAudioSourceDataLine.java:75)
        at org.classpath.icedtea.pulseaudio.PulseAudioSourceDataLine.open(PulseAudioSourceDataLine.java:90)
        at com.sun.media.sound.DataPusher.start(DataPusher.java:107)
        at com.sun.media.sound.DataPusher.start(DataPusher.java:91)
        at sun.audio.AudioDevice.startSampled(AudioDevice.java:118)
        at sun.audio.AudioDevice.openChannel(AudioDevice.java:190)
        at sun.audio.AudioPlayer.start(AudioPlayer.java:133)
        at PlaySound.main(PlaySound.java:26)

Anybody got a clue? I’d like to get rid of Oracle…

3 Likes

something missing in $CLASSPATH, probably …
But no you don’t really want to get rid of Oracle, there have been quite some issues with the non-Oracle Java and OH that you don’t want to hit. Not just about sound but on performance and other stuff.

Hi, so finally tried it out (had first to recovery my raspberry from a broken sdcard - now finally back on a HDD). Unfortunately, smarthome:audio play doorbell.mp3 still does not want to ring. :frowning:
Update: Gave up too early! Had a concurrent running pulseaudio - now it works! Thx!!!

Another new experience. I updated today to Java 8u121 (from 8u65) with the recommended instructions (http://docs.openhab.org/installation/linux.html which is currently) in order to be able to use myopenhab.org. After that new problems appeared. First everything works fine (maybe I should mention that I am using a headless system without a running X server). When I do a

openhab> smarthome:audio play doorbell.mp3

and afterwards for a

ps -aux | grep -i pulseaudio

the response looks first reasonable:

openhab   3003  2.5  0.6 101188  6628 ?        Sl   16:52   0:00 /usr/bin/pulseaudio --start --log-target=syslog

Also a look into syslog looks fine:

Mar  4 16:52:16 raspberrypi bluetoothd[816]: Endpoint registered: sender=:1.85 path=/MediaEndpoint/A2DPSource
Mar  4 16:52:16 raspberrypi bluetoothd[816]: Endpoint registered: sender=:1.85 path=/MediaEndpoint/A2DPSink

Then I am happy to establish the connection to my bluetooth device in bluetoothctl. And a

openhab> smarthome:audio play doorbell.mp3

does what it should for a while. However, after some period, pulseaudio got terminated again with the following messages in syslog:

Mar  4 16:52:49 raspberrypi bluetoothd[816]: Endpoint unregistered: sender=:1.85 path=/MediaEndpoint/A2DPSource
Mar  4 16:52:50 raspberrypi bluetoothd[816]: Endpoint unregistered: sender=:1.85 path=/MediaEndpoint/A2DPSink

and of course due to that, I am loosing also the connection to my bluetooth device.

This did not happen before the installation of 8u121. So I removed 8u121 again and everything (except of course myopenhab.org since it is not supported by 8u65) works fine again.

The interesting thing is that if I start the pulseaudio server with a local user such as pi, pulseaudio does not terminate, even if 8u121 is installed. However, openhab will start another instance of pulseaudio in parallel nevertheless, which is not connected to the bluetooth device (and terminates after a while as well).

Any ideas?

I’m using 8u121 and have no such problem:

 $ java -version
java version "1.8.0_121"
Java(TM) SE Runtime Environment (build 1.8.0_121-b13)
Java HotSpot(TM) Client VM (build 25.121-b13, mixed mode)

But I’m running pulseaudio in system mode…

Hm, it seems that the problem was a parallel installation of java 8u65 (Raspian dist) and 8u121. De-installing 8u65 helped.
However still problems that the sound output over pulseaudio stops after an hour or so to forward and sound to my bluetooth box (bluetooth connection not disconnected), despite that pulseaudio seems still up and running (but rather seems to be an bluetooth problem with my raspberry).

pulseaudio in system mode: do you mean you are running an X server or you started pulseaudio --system (which is not recommended for whatever reasons)?

Nope, no X as I’m running OH2 on a RPi3 headless…
For example, here is the command line I use to start pulseaudio (mine is in system mode)

/usr/bin/pulseaudio --system --realtime --disallow-exit --no-cpu-limit --exit-idle-time=-1
```
As a matter of fact, it could be a problem with bluetooth...
I have the following installed right now:
```
 $ apt list --installed | grep blue

WARNING: apt does not have a stable CLI interface yet. Use with caution in scripts.

bluetooth/testing,now 5.43-1 all [installed]
bluez/testing,now 5.43-1+b4 armhf [installed]
bluez-firmware/stable,now 1.2-3+rpi1 all [installed,automatic]
libbluetooth-dev/testing,now 5.43-1+b4 armhf [installed]
libbluetooth3/testing,now 5.43-1+b4 armhf [installed,automatic]
pi-bluetooth/stable,now 0.1.3 armhf [installed]
pulseaudio-module-bluetooth/stable,now 5.0-13 armhf [installed]
```
Not remember exactly WHY I did switch to bluez from the testing (stretch) branch - not necessarily for this pulseaudio thing... I do have some bluetooth sensors and I might upgraded bluez because of them - but you might want to give it a try, just follow the instructions from [StackExchange](http://raspberrypi.stackexchange.com/questions/39254/updating-bluez-5-23-5-36).

I just upgraded my java to 8u121. Hadn’t noticed yet standard Raspbian doesn’t do that for me.
Now that fixed a long standing problem of mine, I had sounds not playout at times, then overlapping sounds on next or next-but-one occasion. Now my doorbell is working properly. So thanks for the hint.
I also run pulseaudio in system mode (yes, --system - it’s alright to do that on single user systems).

Hm, I tried to run pulseaudio in system mode as suggested above. Furthermore I understand according to this that every user such as openhab has to be added to the group pulse-access. So far so fine.

However, I am not able to connect now to the bluetooth device:

Mar  8 18:58:20 raspberrypi bluetoothd[723]: a2dp-sink profile connect failed for FC:58:FA:A0:5E:EE: Protocol not available

I did everything, which is recommended here in order to get it running, however, I failed.

So, I assume that I have a kind of a access problem (starting pulse audio as root in system mode ends up in running pulseaudio as pulse user) although I run bluetoothctl as root.

Anything special beyond the two links above I have to consider when I am runnung pulseaudio in system mode?

My pulseaudio daemon also runs as user pulse and it’s working:

$ ps aux | grep pulseaudio
pulse      585  1.7  0.8 111440  8332 ?        S<sl 00:11  16:05 /usr/bin/pulseaudio --system --realtime --disallow-exit --no-cpu-limit --exit-idle-time=-1

So the problem lays elsewhere…
Did you add users to the needed group?
Here is my relevant part of /etc/group:

$ cat /etc/group
.........................
audio:x:29:pi,pulse,openhab
lp:x:7:pi,openhab,pulse
pulse:x:117:pi,openhab
pulse-access:x:118:pi,openhab,root
.........................

EDIT:
Also, here are the modules I load in /etc/pulse/system.pa:

load-module module-bluetooth-discover
load-module module-switch-on-connect
load-module module-bluetooth-policy
load-module module-cli-protocol-tcp
load-module module-zeroconf-publish

set-default-sink bluez_sink.88_C6_26_28_A4_B0

Hi,

what was missing was the zeroconf module (it seems they are not needed if pulseaudio is not in system mode). Thanks for the hint! Now pulseaudio works again. BTW What is the expected argument for set-default-sink? If a add the mac-address of my bluetooth speaker I got the message

E: [pulseaudio] main.c: Sink bluez_sink.FC:58:FA:A0:5E:EE does not exist.

Furthermore another message appears (which does not prevent the overall thing from working):

E: [pulseaudio] bluez4-util.c: org.bluez.Manager.GetProperties() failed: org.freedesktop.DBus.Error.UnknownMethod: Method "GetProperties" with signature "" on interface "org.bluez.Manager" doesn't exist

BUT: Then I test the whole stuff and played some music over the speaker via squeezelite. Again after one hour or so playing stopped and also a

/etc/init.d/bluetooth reboot

does not help. Got some timeouts in syslog:

Mar  9 19:39:40 raspberrypi kernel: [ 3244.103014] Bluetooth: hci0 command 0x1003 tx timeout
Mar  9 19:39:42 raspberrypi kernel: [ 3246.182964] Bluetooth: hci0 command 0x1001 tx timeout
Mar  9 19:39:44 raspberrypi kernel: [ 3248.262967] Bluetooth: hci0 command 0x1009 tx timeout

So I assume this is definitely a bluetooth problem now. I darkly remember it worked before my SD-Card vanished, since I uploaded the newest firmware on my raspberry with rpi-update. However, now I switched to USB boot mode on my raspberry and boot from USB hard drive (since I have enough from all this broken SD stuff). However, for USB boot mode a special firmware via

sudo BRANCH=next rpi-update

is necessary. It seems that this branch has not the latest bluetooth firmware inside… :frowning:

Nevertheless, Mihai thanks for your support so far - helped a lot!

Well, just use the name of the sink you want to use… pactl list sinks might be of help :smile:
Bear in mind that pulseaudio runs as user pulse so you’ll need the following:

sudo PULSE_RUNTIME_PATH=/var/run/pulse -u pulse pactl list sinks

This, and the rest of that post, might make a good addition to the openhab documentation. Did you consider writing it up and creating a PR on the documentation repo?