{"id":2503,"date":"2016-05-05T14:28:44","date_gmt":"2016-05-05T14:28:44","guid":{"rendered":"http:\/\/blog.designed79.co.uk\/?p=2503"},"modified":"2016-05-11T13:38:48","modified_gmt":"2016-05-11T13:38:48","slug":"raspberry-pi-bluetooth-speaker","status":"publish","type":"post","link":"https:\/\/blog.designed79.co.uk\/?p=2503","title":{"rendered":"Raspberry Pi Bluetooth Speaker"},"content":{"rendered":"<p>Raspbian Wheezy Installation Guide<\/p>\n<p>From a fresh installation of Wheezyrun the following as the default user pi:<\/p>\n<div class=\"codecolorer-container text default\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"text codecolorer\">pi@raspberrypi ~ $ sudo apt-get install bluez pulseaudio-module-bluetooth python-gobject python-gobject-2 alsa-utils<\/div><\/div>\n<p>Add the user pi to the group lp. This is so the user pi can get access to the bluetooth daemon. If this isn&#8217;t done, the bluez source will not show up in pulse audio.<\/p>\n<div class=\"codecolorer-container text default\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"text codecolorer\">pi@raspberrypi ~ $ sudo usermod -a -G lp pi<\/div><\/div>\n<p>The bluetooth stack has to be configured for A2DP.<\/p>\n<div class=\"codecolorer-container text default\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"text codecolorer\">pi@raspberrypi ~ $ sudo nano \/etc\/bluetooth\/audio.conf<\/div><\/div>\n<p>Add the following line after [General]:<\/p>\n<div class=\"codecolorer-container text default\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"text codecolorer\">Enable=Source,Sink,Media,Socket<\/div><\/div>\n<p>Change the resampling algorithm for pulse audio<\/p>\n<div class=\"codecolorer-container text default\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"text codecolorer\">pi@raspberrypi ~ $ sudo nano \/etc\/pulse\/daemon.conf<\/div><\/div>\n<div class=\"codecolorer-container text default\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"text codecolorer\">; resample-method = speex-float-3 <br \/>\nresample-method = trivial ; ADD THIS LINE<\/div><\/div>\n<p>Reboot at this point!<\/p>\n<div class=\"codecolorer-container text default\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"text codecolorer\">pi@raspberrypi ~ $ sudo reboot<\/div><\/div>\n<p>NOTE: Do not run these with sudo&#8230; Run as pi! <\/p>\n<p>Boot up, log-in, and run:<\/p>\n<div class=\"codecolorer-container text default\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"text codecolorer\">pi@raspberrypi ~ $ sudo hciconfig hci0 piscan<\/div><\/div>\n<p>Makes the Pi BT discoverable<\/p>\n<div class=\"codecolorer-container text default\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"text codecolorer\">pi@raspberrypi ~ $ bluez-simple-agent<\/div><\/div>\n<p>Connect with your smart phone and enter pin \/ authorize.<br \/>\nAfter authorization is complete, CTRL-C out.<\/p>\n<p>You can then trust the phone by using the command:<\/p>\n<div class=\"codecolorer-container text default\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"text codecolorer\">pi@raspberrypi ~ $ bluez-test-device trusted B8:C6:8E:52:E8:CA yes<\/div><\/div>\n<p>It shouldn&#8217;t ask for a pin in the future&#8230;<\/p>\n<p>After the phone is connected, list the sources. A bluez source should show up:<br \/>\nNote: This command will start the PulseAudio daemon in per-user mode if it is not already running!<\/p>\n<div class=\"codecolorer-container text default\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"text codecolorer\">pi@raspberrypi ~ $ pactl list sources short<br \/>\n<br \/>\n0 &nbsp; &nbsp;alsa_output.platform-bcm2835_AUD0.0.analog-stereo.monitor &nbsp; &nbsp;module-alsa-card.c &nbsp; &nbsp;s16le 2ch 44100Hz &nbsp; &nbsp;SUSPENDED<br \/>\n1 &nbsp; &nbsp;bluez_source.B8_C6_8E_52_E8_CA &nbsp; &nbsp;module-bluetooth-device.c &nbsp; &nbsp;s16le 2ch 44100Hz &nbsp; &nbsp;SUSPENDED<\/div><\/div>\n<p>List the sinks. An ALSA sink for the BCM codec should show up:<\/p>\n<div class=\"codecolorer-container text default\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"text codecolorer\">pi@raspberrypi ~ $ pactl list sinks short<br \/>\n<br \/>\n0 &nbsp; &nbsp;alsa_output.platform-bcm2835_AUD0.0.analog-stereo &nbsp; &nbsp;module-alsa-card.c &nbsp; &nbsp;s16le 2ch 44100Hz &nbsp; &nbsp;SUSPENDED<\/div><\/div>\n<p>Connect the source to the sink manaual as a test:<\/p>\n<div class=\"codecolorer-container text default\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"text codecolorer\">pi@raspberrypi ~ $ pactl load-module module-loopback source=bluez_source.B8_C6_8E_52_E8_CA sink=alsa_output.platform-bcm2835_AUD0.0.analog-stereo<\/div><\/div>\n<p>If you play the song on the phone, it should be played on the connected speakers. If not, maybe the default output isn&#8217;t the line out jack or the volume is muted or too low.<\/p>\n<p>The audio defaults to the HDMI output. I wanted it to play over the headphone jack.<br \/>\nHere is the command to set the source to headphone jack:<\/p>\n<div class=\"codecolorer-container text default\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"text codecolorer\">pi@raspberrypi ~ $ amixer cset numid=3 1<\/div><\/div>\n<p>turn up the ALSA volume:<\/p>\n<div class=\"codecolorer-container text default\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"text codecolorer\">pi@raspberrypi ~ $ amixer set Master 100%<\/div><\/div>\n<p>Also turn up the PulseAudio volume:<\/p>\n<div class=\"codecolorer-container text default\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"text codecolorer\">pi@raspberrypi ~ $ pacmd set-sink-volume 0 65537<\/div><\/div>\n<p>The 0 is the sink channel number for alsa_output.platform-bcm2835_AUD0.0.analog-stereo as found with the command: &#8220;pactl list sinks short&#8221;.<\/p>\n<p>Script to automate this when a bluetooth device attaches<\/p>\n<p>To trigger the udev script when a new device connects create (or modify) an even handler in \/etc\/udev\/rules.d\/99-input.rules adding the following content rules<\/p>\n<div class=\"codecolorer-container text default\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"text codecolorer\">SUBSYSTEM=&quot;input&quot;, GROUP=&quot;input&quot;, MODE=&quot;0660&quot;<br \/>\nKERNEL==&quot;input[0-9]*&quot;, RUN+=&quot;\/usr\/lib\/udev\/bluetooth&quot;<\/div><\/div>\n<p>Now let\u2019s actually save that script that the above rule file is referencing. First check to see if a udev\/ directory exists. Do sudo ls \u2013la \/usr\/lib\/udev . If it doesn\u2019t exist go ahead and create it like so: sudo mkdir \/usr\/lib\/udev<\/p>\n<div class=\"codecolorer-container text default\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"text codecolorer\">sudo nano \/usr\/lib\/udev\/bluetooth<\/div><\/div>\n<div class=\"codecolorer-container bash default\" style=\"overflow:auto;white-space:nowrap;height:300px;\"><table cellspacing=\"0\" cellpadding=\"0\"><tbody><tr><td class=\"line-numbers\"><div>1<br \/>2<br \/>3<br \/>4<br \/>5<br \/>6<br \/>7<br \/>8<br \/>9<br \/>10<br \/>11<br \/>12<br \/>13<br \/>14<br \/>15<br \/>16<br \/>17<br \/>18<br \/>19<br \/>20<br \/>21<br \/>22<br \/>23<br \/>24<br \/>25<br \/>26<br \/>27<br \/>28<br \/>29<br \/>30<br \/>31<br \/>32<br \/>33<br \/>34<br \/>35<br \/>36<br \/>37<br \/>38<br \/>39<br \/>40<br \/>41<br \/>42<br \/>43<br \/>44<br \/>45<br \/>46<br \/><\/div><\/td><td><div class=\"bash codecolorer\"><span class=\"co0\">#!\/bin\/bash<\/span><br \/>\n<span class=\"co0\"># This script belongs in \/usr\/lib\/udev\/bluetooth and should be executable<\/span><br \/>\n<br \/>\n<span class=\"co0\">#PA_SINK='alsa_output.platform-bcm2835_AUD0.0.analog-stereo'<\/span><br \/>\n<span class=\"co0\">#Change SINK to 0 as name of sink changes on hardware change. 0 Is default<\/span><br \/>\n<span class=\"re2\">PA_SINK<\/span>=<span class=\"nu0\">0<\/span><br \/>\n<span class=\"re2\">LOG_FILE<\/span>=<span class=\"sy0\">\/<\/span>var<span class=\"sy0\">\/<\/span>log<span class=\"sy0\">\/<\/span>bluetooth_a2dp<br \/>\n<span class=\"re2\">MAC<\/span>=$<span class=\"br0\">&#40;<\/span><span class=\"kw3\">echo<\/span> <span class=\"st0\">&quot;<span class=\"es2\">$NAME<\/span>&quot;<\/span> <span class=\"sy0\">|<\/span> <span class=\"kw2\">sed<\/span> <span class=\"st_h\">'s\/:\/_\/g'<\/span> <span class=\"sy0\">|<\/span> <span class=\"kw2\">sed<\/span> <span class=\"st_h\">'s\/&quot;\/\/g'<\/span><span class=\"br0\">&#41;<\/span><br \/>\n<br \/>\n<span class=\"co0\"># Set the user you want to run as, 'pi' would be fine for most.<\/span><br \/>\n<span class=\"re2\">BT_USER<\/span>=pi <br \/>\n<br \/>\n<span class=\"kw1\">function<\/span> checkSource <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"co0\"># Get the current sources<\/span><br \/>\n&nbsp; &nbsp; <span class=\"kw3\">local<\/span> <span class=\"re2\">_sources<\/span>=$<span class=\"br0\">&#40;<\/span><span class=\"kw2\">sudo<\/span> <span class=\"re5\">-u<\/span> <span class=\"st0\">&quot;<span class=\"es2\">$BT_USER<\/span>&quot;<\/span> pactl list sources short<span class=\"br0\">&#41;<\/span><br \/>\n<br \/>\n&nbsp; &nbsp; <span class=\"co0\"># Check if any sources are currently running <\/span><br \/>\n&nbsp; &nbsp; <span class=\"co0\"># and that our new device is valid.<\/span><br \/>\n&nbsp; &nbsp; <span class=\"kw1\">if<\/span> <span class=\"br0\">&#91;<\/span><span class=\"br0\">&#91;<\/span> <span class=\"sy0\">!<\/span> <span class=\"st0\">&quot;<span class=\"es2\">$_sources<\/span>&quot;<\/span> =~ RUNIING <span class=\"br0\">&#93;<\/span><span class=\"br0\">&#93;<\/span> <span class=\"sy0\">&amp;&amp;<\/span> <span class=\"br0\">&#91;<\/span><span class=\"br0\">&#91;<\/span> <span class=\"st0\">&quot;<span class=\"es2\">$_sources<\/span>&quot;<\/span> =~ <span class=\"st0\">&quot;$1&quot;<\/span> <span class=\"br0\">&#93;<\/span><span class=\"br0\">&#93;<\/span> ; <span class=\"kw1\">then<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; <span class=\"kw3\">echo<\/span> <span class=\"st0\">&quot;Validated new source: $1&quot;<\/span> <span class=\"sy0\">&gt;&gt;<\/span> <span class=\"st0\">&quot;<span class=\"es2\">$LOG_FILE<\/span>&quot;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; <span class=\"kw3\">echo<\/span> <span class=\"st0\">&quot;$1&quot;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"kw1\">fi<\/span><br \/>\n<span class=\"br0\">&#125;<\/span><br \/>\n<br \/>\n<span class=\"kw1\">function<\/span> setVolume <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"co0\"># Set our volume to max<\/span><br \/>\n&nbsp; &nbsp; <span class=\"kw2\">sudo<\/span> <span class=\"re5\">-u<\/span> <span class=\"st0\">&quot;<span class=\"es2\">$BT_USER<\/span>&quot;<\/span> pacmd set-sink-volume <span class=\"nu0\">0<\/span> <span class=\"nu0\">65537<\/span><br \/>\n&nbsp; &nbsp; <span class=\"kw2\">sudo<\/span> <span class=\"re5\">-u<\/span> <span class=\"st0\">&quot;<span class=\"es2\">$BT_USER<\/span>&quot;<\/span> amixer <span class=\"kw1\">set<\/span> Master <span class=\"nu0\">100<\/span><span class=\"sy0\">%<\/span><br \/>\n<span class=\"br0\">&#125;<\/span><br \/>\n<br \/>\n<span class=\"kw1\">function<\/span> connect <span class=\"br0\">&#123;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"co0\"># Connect source to sink<\/span><br \/>\n&nbsp; &nbsp; <span class=\"kw2\">sudo<\/span> <span class=\"re5\">-u<\/span> <span class=\"st0\">&quot;<span class=\"es2\">$BT_USER<\/span>&quot;<\/span> pactl load-module module-loopback \\<br \/>\n&nbsp; &nbsp; <span class=\"re2\">source<\/span>=<span class=\"st0\">&quot;$1&quot;<\/span> <span class=\"re2\">sink<\/span>=<span class=\"st0\">&quot;<span class=\"es2\">$PA_SINK<\/span>&quot;<\/span> <span class=\"re2\">rate<\/span>=<span class=\"nu0\">44100<\/span> <span class=\"re2\">adjust_time<\/span>=<span class=\"nu0\">0<\/span><br \/>\n<span class=\"br0\">&#125;<\/span><br \/>\n<br \/>\n<span class=\"kw3\">echo<\/span> <span class=\"st0\">&quot;Change for device <span class=\"es2\">$MAC<\/span> detected, running <span class=\"es2\">$ACTION<\/span>&quot;<\/span> <span class=\"sy0\">&gt;&gt;<\/span> <span class=\"st0\">&quot;<span class=\"es2\">$LOG_FILE<\/span>&quot;<\/span><br \/>\n<br \/>\n<span class=\"kw1\">if<\/span> <span class=\"br0\">&#91;<\/span> <span class=\"st0\">&quot;<span class=\"es2\">$ACTION<\/span>&quot;<\/span> = <span class=\"st0\">&quot;add&quot;<\/span> <span class=\"br0\">&#93;<\/span><br \/>\n<span class=\"kw1\">then<\/span><br \/>\n&nbsp; &nbsp; <span class=\"re2\">incoming<\/span>=bluez_source.<span class=\"st0\">&quot;<span class=\"es2\">$MAC<\/span>&quot;<\/span><br \/>\n&nbsp; &nbsp; <span class=\"kw1\">if<\/span> <span class=\"br0\">&#91;<\/span> <span class=\"sy0\">!<\/span> <span class=\"re5\">-z<\/span> $<span class=\"br0\">&#40;<\/span>checkSource <span class=\"st0\">&quot;<span class=\"es2\">$incoming<\/span>&quot;<\/span><span class=\"br0\">&#41;<\/span> <span class=\"br0\">&#93;<\/span> ; <span class=\"kw1\">then<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; connect <span class=\"st0\">&quot;<span class=\"es2\">$incoming<\/span>&quot;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; setVolume<br \/>\n&nbsp; &nbsp; <span class=\"kw1\">fi<\/span><br \/>\n<span class=\"kw1\">fi<\/span><\/div><\/td><\/tr><\/tbody><\/table><\/div>\n<p>disable timeouts by adding a line in &#8216;\/etc\/pulse\/client.conf&#8217;<\/p>\n<div class=\"codecolorer-container text default\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"text codecolorer\">extra-arguments = --exit-idle-time=-1 --log-target=syslog<\/div><\/div>\n<p>The Pi User has to be logged in for this to work.  In a headless setup you can get the Pi to auto login by editing the \/etc\/inittab file and replacing the line<\/p>\n<div class=\"codecolorer-container text default\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"text codecolorer\">1:2345:respawn:\/sbin\/getty 115200 tty1<\/div><\/div>\n<p>with<\/p>\n<div class=\"codecolorer-container text default\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"text codecolorer\">1:2345:respawn:\/bin\/login -f pi tty1 \/dev\/tty1 2&gt;&amp;1<\/div><\/div>\n<p>Also forget about auto pairing, not going to happen.  BLUEZ 4 onwards disabled this as a security measure.  Your gonna have to SSH in and pair your devices<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Raspbian Wheezy Installation Guide From a fresh installation of Wheezyrun the following as the default user pi: pi@raspberrypi ~ $ sudo apt-get [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-2503","post","type-post","status-publish","format-standard","hentry","category-info-on-tech"],"_links":{"self":[{"href":"https:\/\/blog.designed79.co.uk\/index.php?rest_route=\/wp\/v2\/posts\/2503","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blog.designed79.co.uk\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.designed79.co.uk\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.designed79.co.uk\/index.php?rest_route=\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.designed79.co.uk\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=2503"}],"version-history":[{"count":0,"href":"https:\/\/blog.designed79.co.uk\/index.php?rest_route=\/wp\/v2\/posts\/2503\/revisions"}],"wp:attachment":[{"href":"https:\/\/blog.designed79.co.uk\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=2503"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.designed79.co.uk\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=2503"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.designed79.co.uk\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=2503"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}