Just a quick review on how to get Bluetooth Audio working with ev3dev.
This is based on the method explained here. It was tested with a snapshot image (“snapshot-ev3dev-stretch-ev3-generic-2017-06-27.img”) but it should work with the latest stable image from the ev3dev downloads page.
Even with a snapshot image, that already includes many updates released after the stable version, it’s a good practice to update everything before start:
sudo apt update sudo apt upgrade sudo apt dist-upgrade
On my case one of the updates available is for the “libpulse0” package, used by pulseaudio (and Bluetooth Audio uses pulseaudio).
As of today I ended up with a 4.9.34 kernel:
robot@ev3dev:~$ uname -a Linux ev3dev 4.9.34-ev3dev-1.2.0-ev3 #1 PREEMPT Mon Jun 26 20:45:12 CDT 2017 armv5tejl GNU/Linux
Now we install some packages needed:
sudo apt-get install --no-install-recommends pulseaudio pulseaudio-module-bluetooth
This will in fact install much more than just those 2 packages:
... 0 upgraded, 33 newly installed, 0 to remove and 0 not upgraded. Need to get 9587 kB of archives.
Now we should enable Bluetooth. The easy way is by using ‘brickman’ – the text based User Interface that runs on ev3dev after boot: on the ‘Wireless’ menu, choose ‘Bluetooth’ then ‘Powered’ and ‘Visible’. After EV3 finds our BT audio device (a speaker or an headset) we can pair with it.
In my case I’m using a BT speaker named “BS-400” and EV3 shows something like this:
BS-400 C7:B5:42:B4:72:EC connect remove
After connecting (sometimes I need to try it a second time) we need to go to the command line:
pactl list sinks
This will show two audio devices – the EV3 speaker and my BT speaker:
Sink #0 State: SUSPENDED Name: alsa_output.platform-sound.analog-mono Description: LEGO MINDSTORMS EV3 Speaker Analog Mono ... Sink #1 State: SUSPENDED Name: bluez_sink.C7_B5_42_B4_72_EC.a2dp_sink Description: BS-400 ...
As far as I know the name of the second device always includes the BT address of our device, it can be useful if we have several devices of the same type.
Now we can test it using one of the audio samples available at ‘/usr/share/sounds/alsa/’:
paplay -d bluez_sink.C7_B5_42_B4_72_EC.a2dp_sink /usr/share/sounds/alsa/Front_Center.wav
We can control the volume with ‘–volume=x’ where x is an integer up to 65536.
Instead of using a wav file we can also redirect the output of ‘espeak’ to convert text to speech:
espeak "Hello" --stdout | paplay -d bluez_sink.C7_B5_42_B4_72_EC.a2dp_sink
(Note: this is a one-line command)
This is great for shell scripts but for python it poses a problem – how to access PulseAudio?
Will post about that later on but for now I show a simple way to use applications that expect ALSA to seamless work with our BT device by activating the PulseAudio plugin for alsalibs:
sudo nano /etc/asound.conf
The asound.conf file should contain just this 6 lines:
pcm.pulse { type pulse } ctl.pulse { type pulse }
This redirects ALSA to the default PulseAudio device. So we can now use ‘aplay’ instead of ‘paplay’:
aplay -Dpulse /usr/share/sounds/alsa/Front_Center.wav
and we can control the volume with ‘alsamixer’. But better yet, we can use python with the ev3.Sound methods like play or speak:
#!/usr/bin/env python3 from time import sleep import ev3dev.ev3 as ev3 ev3.Sound.speak('Hello').wait() sleep(1) ev3.Sound.play('/usr/share/sounds/alsa/Front_Center.wav')
There are however two methods that will not work with BT: tone and beep. That’s because instead of using ALSA they are hardwired to the onboard EV3 speaker.
And finally we can also play MIDI files locally on the EV3 through BT:
sudo apt install timidity
Timidity++ is a soft synth that allows us to play MIDI without a MIDI card:
timidity brahms_waltz.mid -Os
It works through BT but takes about 30 seconds to start playing and the sound is very poor, mostly glitches:
Requested buffer size 32768, fragment size 8192 ALSA pcm 'default' set buffer size 32768, period size 8192 bytes Playing brahms_waltz.mid MIDI file: brahms_waltz.mid Format: 1 Tracks: 2 Divisions: 256 Sequence: Waltz Text: Brahms Track name: Harp Playing time: ~57 seconds Notes cut: 86 Notes lost totally: 141
We can tune timidity to use less CPU resources by adding arguments (see the output of ‘timidity –help’) or by editing the configuration file:
sudo nano /etc/timidity/timidity.cfg
We uncomment all options recommended for a slow CPU except the default sample frequency:
... ## If you have a slow CPU, uncomment these: opt EFresamp=d #disable resampling opt EFvlpf=d #disable VLPF opt EFreverb=d #disable reverb opt EFchorus=d #disable chorus opt EFdelay=d #disable delay opt anti-alias=d #disable sample anti-aliasing opt EWPVSETOZ #disable all Midi Controls opt p32a #default to 32 voices with auto reduction #opt s32kHz #default sample frequency to 32kHz opt fast-decay #fast decay notes ...
Now the same command takes about 13 seconds to start playing and the music is played correctly (although with some white noise background).
We can reduce start time a bit more by using Timidity in server mode – it takes a few seconds to start completely:
robot@ev3dev:~$ timidity -iA -Os & [1] 8527 robot@ev3dev:~$ Requested buffer size 32768, fragment size 8192 ALSA pcm 'default' set buffer size 32768, period size 8192 bytes TiMidity starting in ALSA server mode Opening sequencer port: 128:0 128:1 128:2 128:3
if we now press ENTER we get back to the shell and Timidity keeps running:
robot@ev3dev:~$ pgrep timidity 8527
so now we can use our own MIDI programs to play MIDI through one of the 4 MIDI ports that Timidity created:
aplaymidi -p 128:0 brahms_waltz.mid
It starts playing after 6 seconds.
Not great but at least we can now use one of the several python libraries that can play MIDI music – perhaps after loading the library in memory this initial delay doesn’t happen when playing individal notes instead of a full music.