unpluggeduk
Posts: 3
Joined: Wed Oct 05, 2016 10:55 am

Bluetooth Audio Receiver - Pi3

Wed Oct 05, 2016 12:15 pm

Had trouble getting this working at pretty much every tutorial is for Wheezy and Pi1&2 which use older builds of Pulse Audio and Bluez and they don't translate easily to newer versions of Raspbian Jessie .

The idea was to setup a headless box that lets one device connect at a time and pipes the audio over the 3.5mm Jack for use in a car or other alternative to allow people to stream music easily using the Pis onboard Bluetooth.

I'm also a complete beginner so hopefully this will act as a starting point for someone to make improvements and suggestions. I used http://raspberrypi.stackexchange.com/qu ... th-speaker as a base guide

I started with the Raspbian Lite and updated it to the current build.

Step 1 - Setup

Code: Select all

sudo apt-get update

Code: Select all

sudo apt-get upgrade

Code: Select all

sudo apt-get install pi-bluetooth

Code: Select all

sudo apt-get install blueman pulseaudio pavucontrol pulseaudio-module-bluetooth
Some of these steps may be unnecessary ;)

Add the pi user to the Pulse Audio Group

Code: Select all

sudo usermod -a -G lp pi
Create a new config under /etc/bluetooth/audio.conf

Code: Select all

sudo nano /etc/bluetooth/audio.conf
And enter the following

Code: Select all

[General]:
Enable=Source,Sink,Media,Socket
Edit /etc/bluetooth/main.conf

Code: Select all

sudo nano /etc/bluetooth/main.conf
And set the the Name to what you want (Didn't have any affect for me)
and the Class to 0x200414

Edit /etc/pulse/daemon.conf

Code: Select all

sudo nano /etc/pulse/daemon.conf
Change resample-method = trivial


Step 2 - Name the Device

For some reason the only way you can effectively name the device is to edit the /etc/machine-info and add a line in here

Code: Select all

PRETTY_HOSTNAME=BeatingsByDre


Step 3 - Setup the Audio Hook

The next step is to setup a hook so that when a device connects it setups the Audio Hook.

Edit /etc/udev/rules.d/99-com.rules (might be 99-input.rules)

Code: Select all

/etc/udev/rules.d/99-com.rules
and add

Code: Select all

SUBSYSTEM="input", GROUP="input", MODE="0660"
KERNEL=="input[0-9]*", RUN+="/usr/lib/udev/bluetooth"
add folder udev to /usr/lib by using mkdir

Code: Select all

sudo mkdir /usr/lib/udev
and add this to the file bluetooth (credits to ragusa87) I had to modify this slightly.

Code: Select all

sudo nano /usr/lib/udev/bluetooth

Code: Select all

#!/bin/bash
# This script is called by udev when you link a bluetooth device with your comp$
# It's called to add or remove the device from pulseaudio
#
#

# Output to this file
LOGFILE="/var/log/bluetooth_dev"

# Name of the local sink in this computer
# You can get it by calling : pactl list short sinks
# AUDIOSINK="alsa_output.platform-bcm2835_AUD0.0.analog-stereo"
AUDIOSINK="alsa_output.0.analog-stereo"

# User used to execute pulseaudio, an active session must be open to avoid erro$
USER="pi"

# Audio Output for raspberry-pi
# 0=auto, 1=headphones, 2=hdmi.
AUDIO_OUTPUT=1

# If on, this computer is not discovearable when an audio device is connected
# 0=off, 1=on
ENABLE_BT_DISCOVER=1

echo "For output see $LOGFILE"

## This function add the pulseaudio loopback interface from source to sink
## The source is set by the bluetooth mac address using XX_XX_XX_XX_XX_XX forma$
## param: XX_XX_XX_XX_XX_XX
## return 0 on success
add_from_mac(){
  if [ -z "$1" ] # zero params
    then
        echo "Mac not found" >> $LOGFILE
    else
        mac=$1 # Mac is parameter-1

        # Setting source name
        bluez_dev=bluez_source.$mac
        echo "bluez source: $mac"  >> $LOGFILE

        # This script is called early, we just wait to be sure that pulseaudio $
        sleep 1
        # Very that the source is present
        CONFIRM=`sudo -u pi pactl list short | grep $bluez_dev`
        if [ ! -z "$CONFIRM" ]
        then
            echo "Adding the loopback interface:  $bluez_dev"  >> $LOGFILE
            echo "sudo -u $USER pactl load-module module-loopback source=$bluez$

            # This command route audio from bluetooth source to the local sink..
            # it's the main goal of this script
            sudo -u $USER pactl load-module module-loopback source=$bluez_dev s$
            return $?
        else
            echo "Unable to find a bluetooth device compatible with pulsaudio u$
            return -1
        fi
    fi
}

## This function will detect the bluetooth mac address from input device and co$
## Lots of devices are seen as input devices. But Mac OS X is not detected as i$
## return 0 on success
detect_mac_from_input(){
    ERRORCODE=-1

    echo "Detecting mac from input devices" >> $LOGFILE
    for dev in $(find /sys/devices/virtual/input/ -name input*)
    do
        if [ -f "$dev/name" ]
        then
            mac=$(cat "$dev/name" | sed 's/:/_/g')
            add_from_mac $mac

            # Endfor if the command is successfull
            ERRORCODE=$?
            if [ $ERRORCODE -eq 0]; then
                return 0
            fi
        fi
    done
    # Error
    return $ERRORCODE
}

## This function will detect the bt mac address from dev-path and configure it.
## Devpath is set by udev on device link
## return 0 on success
detect_mac_from_devpath(){
    ERRORCODE=-1
    if [ ! -z "$DEVPATH" ]; then
        echo "Detecting mac from DEVPATH"  >> $LOGFILE
        for dev in $(find /sys$DEVPATH -name address)
        do
            mac=$(cat "$dev" | sed 's/:/_/g')
            add_from_mac $mac

            # Endfor if the command is successfull
            ERRORCODE=$?
            if [ $ERRORCODE -eq 0]; then
                return 0
            fi

        done
        return $ERRORCODE;
    else
        echo "DEVPATH not set, wrong bluetooth device? " >> $LOGFILE
        return -2
    fi
    return $ERRORCODE
}

## Detecting if an action is set
if [ -z "$ACTION" ]; then
    echo "The script must be called from udev." >> $LOGFILE
    exit -1;
fi
## Getting the action
ACTION=$(expr "$ACTION" : "\([a-zA-Z]\+\).*")

# Switch case
case "$ACTION" in
"add")

        # Turn off bluetooth discovery before connecting existing BT device to $
        if [ $ENABLE_BT_DISCOVER == 1 ]
        then
                echo "Set computer as hidden" >> $LOGFILE
                hciconfig hci0 noscan
        else
            echo "Not setting computer as hidden" >> $LOGFILE
        fi


    # Turn volume to max
    volume_max

    # Detect BT Mac Address from input devices
    detect_mac_from_input
    OK=$?

    # Detect BT Mac address from device path on a bluetooth event
    if [ $OK != 0 ]; then
        if [ "$SUBSYSTEM" == "bluetooth" ]; then
            detect_mac_from_devpath
            OK=$?
        fi
    fi

    # Check if the add was successfull, otherwise display all available sources
    if [ $OK != 0 ]; then
        echo "Your bluetooth device is not detected !" >> $LOGFILE
        echo "Available sources are:" >> $LOGFILE
        sudo -u $USER pactl list short sources >> $LOGFILE
    else
        echo "Device successfully added " >> $LOGFILE
    fi
    ;;

"remove")

        # Turn off bluetooth discovery before connecting existing BT device to $
        if [ $ENABLE_BT_DISCOVER == 1 ]
        then
                echo "Set computer as visable" >> $LOGFILE
                sudo hciconfig hci0 piscan
        else
            echo "Not setting computer as visible" >> $LOGFILE
        fi

    echo "Removed Audio Device" >> $LOGFILE
    ;;

#
*)
    echo "Unsuported action $action" >> $LOGFILE
    ;;
esac
echo "--" >> $LOGFILE
PLEASE NOTE that your AUDIOSINK might different from mine, check it before using

Code: Select all

pactl list short sinks
and set this under AUDIOSINK=X

make the script executable by inputting this code

Code: Select all

sudo chmod 777 /usr/lib/udev/bluetooth
The above script should connect up the audio from connecting devices and turn on/off the bluetooth discovery as they connect and disconnect.


Step 4 - Setup the Bluetooth Client

If your pi already auto logs in then great if not set it to do so (I wont cover that here)

edit the ~/bashrc and add the following

Code: Select all

pulseaudio -D
sudo hciconfig hci0 class 0x200414
sudo hciconfig hci0 sspmode off
sudo hciconfig hci0 piscan
sudo /usr/bin/hacktooth/hacktooth &
The above starts the PulseAudio Daemon, sets the bluetooth class, turns off simple passcode sharing and turns discovery on when the pi user logs in.

You will need to download the source code for Bluez. I use version 5.42 and extracted the test folder from the tarball into the folder /usr/bin/hacktooth/ however you can put it anywhere you want.

create the file /usr/bin/hacktooth/hacktooth

And enter the following script

Code: Select all

#!/usr/bin/python

from __future__ import absolute_import, print_function, unicode_literals

from optparse import OptionParser
import sys
import dbus
import dbus.service
import dbus.mainloop.glib
try:
  from gi.repository import GObject
except ImportError:
  import gobject as GObject
import bluezutils

BUS_NAME = 'org.bluez'
AGENT_INTERFACE = 'org.bluez.Agent1'
AGENT_PATH = "/test/agent"

bus = None
device_obj = None
dev_path = None

def ask(prompt):
	try:
		return raw_input(prompt)
	except:
		return input(prompt)

def set_trusted(path):
	props = dbus.Interface(bus.get_object("org.bluez", path), "org.freedesktop.DBus.Properties")
	props.Set("org.bluez.Device1", "Trusted", True)

def dev_connect(path):
	dev = dbus.Interface(bus.get_object("org.bluez", path), "org.bluez.Device1")
	dev.Connect()

class Rejected(dbus.DBusException):
	_dbus_error_name = "org.bluez.Error.Rejected"

class Agent(dbus.service.Object):
	exit_on_release = True

	def set_exit_on_release(self, exit_on_release):
		self.exit_on_release = exit_on_release

	@dbus.service.method(AGENT_INTERFACE, in_signature="", out_signature="")
	def Release(self):
		print("Release")
		if self.exit_on_release:
			mainloop.quit()

	@dbus.service.method(AGENT_INTERFACE, in_signature="os", out_signature="")
	def AuthorizeService(self, device, uuid):
		print("DEVICE REQUESTED CONNECTION AUTHORISATION - ALLOWED")
                return
                
	@dbus.service.method(AGENT_INTERFACE, in_signature="o", out_signature="s")
	def RequestPinCode(self, device):
		print("BLUETOOTH PIN CODE REQUESTED - %s - 0000" % (device))
		set_trusted(device)
		return "0000"

	@dbus.service.method(AGENT_INTERFACE, in_signature="o", out_signature="u")
	def RequestPasskey(self, device):
		print("RequestPasskey (%s)" % (device))
		set_trusted(device)
		passkey = ask("Enter passkey: ")
		return dbus.UInt32(passkey)

	@dbus.service.method(AGENT_INTERFACE, in_signature="ouq", out_signature="")
	def DisplayPasskey(self, device, passkey, entered):
		print("DisplayPasskey (%s, %06u entered %u)" %	(device, passkey, entered))

	@dbus.service.method(AGENT_INTERFACE, in_signature="os", out_signature="")
	def DisplayPinCode(self, device, pincode):
		print("DisplayPinCode (%s, %s)" % (device, pincode))

	@dbus.service.method(AGENT_INTERFACE, in_signature="ou", out_signature="")
	def RequestConfirmation(self, device, passkey):
                print("DEVICE REQUESTED PAIRING - PASSKEY (%s, %06d) - ACCEPTED" % (device, passkey))
                set_trusted(device)
                return

	@dbus.service.method(AGENT_INTERFACE, in_signature="o", out_signature="")
	def RequestAuthorization(self, device):
                print("DEVICE REQUESTED SERVICE AUTHORISATION - ALLOWED")
                return

	@dbus.service.method(AGENT_INTERFACE, in_signature="", out_signature="")
	def Cancel(self):
		print("Cancel")

def pair_reply():
	print("Device paired")
	set_trusted(dev_path)
	dev_connect(dev_path)
	mainloop.quit()

def pair_error(error):
	err_name = error.get_dbus_name()
	if err_name == "org.freedesktop.DBus.Error.NoReply" and device_obj:
		print("Timed out. Cancelling pairing")
		device_obj.CancelPairing()
	else:
		print("Creating device failed: %s" % (error))


	mainloop.quit()

if __name__ == '__main__':
	dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)

	bus = dbus.SystemBus()

	capability = "KeyboardDisplay"

	parser = OptionParser()
	parser.add_option("-i", "--adapter", action="store",
					type="string",
					dest="adapter_pattern",
					default=None)
	parser.add_option("-c", "--capability", action="store",
					type="string", dest="capability")
	parser.add_option("-t", "--timeout", action="store",
					type="int", dest="timeout",
					default=60000)
	(options, args) = parser.parse_args()
	if options.capability:
		capability  = options.capability

	path = "/test/agent"
	agent = Agent(bus, path)

	mainloop = GObject.MainLoop()

	obj = bus.get_object(BUS_NAME, "/org/bluez");
	manager = dbus.Interface(obj, "org.bluez.AgentManager1")
	manager.RegisterAgent(path, capability)

	print("Agent registered")

	# Fix-up old style invocation (BlueZ 4)
	if len(args) > 0 and args[0].startswith("hci"):
		options.adapter_pattern = args[0]
		del args[:1]

	if len(args) > 0:
		device = bluezutils.find_device(args[0],
						options.adapter_pattern)
		dev_path = device.object_path
		agent.set_exit_on_release(False)
		device.Pair(reply_handler=pair_reply, error_handler=pair_error,
								timeout=60000)
		device_obj = device
	else:
		manager.RequestDefaultAgent(path)

	mainloop.run()

	#adapter.UnregisterAgent(path)
	#print("Agent unregistered")
Make this script executable

Code: Select all

sudo chmod 777 /usr/bin/hacktooth/hacktooth

This script suppresses any messages in the bluetooth paring process, auto accepts devices and generates no user input.

The above code (with SSP turned off) responds with a pairing code of 0000 and with it on will accept whatever pairing code is generated.

If anyone can suggest a way of doing away with the passcode requirement completely I would be grateful :)

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

Re: Bluetooth Audio Receiver - Pi3

Wed Oct 05, 2016 1:38 pm

That's something of a mix between old and new. I like to recommend this guide: https://github.com/davidedg/NAS-mod-con ... Audio5.txt

The need for the udev rule can be replaced by adding the PulseAudio module module-bluetooth-policy.

Adding the '-c NoInputNoOutput' option to your hacktooth command should replace the need for a PIN code on the Pi (you'll need to leave Secure Simple Pairing mode on).

unpluggeduk
Posts: 3
Joined: Wed Oct 05, 2016 10:55 am

Re: Bluetooth Audio Receiver - Pi3

Wed Oct 05, 2016 3:04 pm

Thanks :)

-c NoInputNoOutput seems to work with the bluetoothctl application. I tried for hours to use that app/command however the audio just wouldn't connect (or failed) I can only seem to get it to pair/connect if I explicitly said "Yes the pairing code is right" and and "Yes allow the service" which is what the hacktooth script does on your behalf.

Had a quick look at the link and tried it on a blank image and it looks promising. Getting the Audio Connected wasn't the problem it was more getting the devices paired.

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

Re: Bluetooth Audio Receiver - Pi3

Wed Oct 05, 2016 4:43 pm

To connect via A2DP, the devices need to be paired AND trusted. I'm not sure how your hacktooth script has been hacked, but you might want to make it trust the device, rather than authorizing it automatically (or trust it with bluetoothctl).

unpluggeduk
Posts: 3
Joined: Wed Oct 05, 2016 10:55 am

Re: Bluetooth Audio Receiver - Pi3

Wed Oct 05, 2016 5:08 pm

That's the problem.

The Pi is simply doing audio passthu emulating a bluetooth speaker or A2DP "dongle". We have tried several of these standalone hardware recievers and they require no passcodes. You simply click them on the phone and they sync with no code or confirmation so it's certainly possible in the bluetooth world. The problem is however that we can't change the name of these so if we have several in a building theirs ambiguity in which one your connecting to.

The PI will be replacing the function of these and has no KVM or network attached to it (headless) so using bluetoothctl to add and "trust" devices manually is not an option. I will appreciate the requirement for security however it's not a requirement here and many people seem to want similar setups in their cars to allow their friends to connect phones without the buggering about :)

The hacktooth script simply waits for a device pairing request and then adds (and trusts) the connecting device by either assuming the pairing code is "0000" or (if using SSP) whatever code is negotated between the devices. If the user enters anything else on their phone or says "no" to whatever arbitrary code is generated the pairing fails.

I currently have a usable solution I was just trying to remove the requirement for pairing codes even if it is only 4 zeros and the first thing everyone uses :)

tonythetiger6969
Posts: 1
Joined: Sun Nov 19, 2017 8:50 pm

Re: Bluetooth Audio Receiver - Pi3

Sun Nov 19, 2017 8:56 pm

I got through most of the tutorial but having issues on the final step. I am very new to this and cannot figure out the last steps involving the ~/bashrc and also i guess steps were skipped when showing to make folders for /usr/bin/hacktooth/hacktooth since they don't exist yet. Any help would be appreciated because not as familiar with all of this.

MarkusJ
Posts: 3
Joined: Mon Dec 04, 2017 4:13 pm
Location: Finland
Contact: Website

Re: Bluetooth Audio Receiver - Pi3

Mon Dec 04, 2017 4:34 pm

tonythetiger6969 wrote: I got through most of the tutorial but having issues on the final step. I am very new to this and cannot figure out the last steps involving the ~/bashrc and also i guess steps were skipped when showing to make folders for /usr/bin/hacktooth/hacktooth since they don't exist yet. Any help would be appreciated because not as familiar with all of this.
Hi, I just made my own instructions because these were not working for me either. Please visit http://markus.jarvisalo.dy.fi/2017/12/m ... -receiver/ and see if you can get it to work with those. I have also made a new post about the subject but the topic is pending admin approval.

bloxix
Posts: 1
Joined: Mon Jan 29, 2018 9:40 am

Re: Bluetooth Audio Receiver - Pi3

Tue Jan 30, 2018 10:24 am

Hi,
I've created a tutorial for a very simple, alternative way to turn your RPI 3 into a Bluetooth Audio receiver. Here's the link: https://www.youtube.com/watch?v=ECpT6lL3fwA.

This will also tell you a little bit about Bluetooth and some basic concepts used. Or otherwise you can simply download the instructions here: https://docs.google.com/document/d/12cK ... dX4qs-TJg/

m_ramone_m
Posts: 1
Joined: Sun Feb 04, 2018 2:42 pm

Re: Bluetooth Audio Receiver - Pi3

Sun Feb 04, 2018 2:50 pm

Works perfect when i connect a honor 6x or a samsung galaxy s8.
But when i connect a sony xperia z2 i can't adjust the volume.
It connects and i can play audio, but i can't control the volume - i can move the car on the display, but the music keeps playing at 100%. I can mute it, but i can't ajust it to anything between....
This seems to be a bug in Android 6, but as the sony phone won't get updates any longer, i am looking for a different solution... any ideas ?

i tried to use a different bluetooth dongle - no effect.
I tried to set the bluetooth class to diffent values (e.g. 0x70020c) - no effect

anyone any ideas ?

Luxxxa
Posts: 1
Joined: Fri Mar 09, 2018 7:09 pm

Re: Bluetooth Audio Receiver - Pi3

Fri Mar 09, 2018 7:12 pm

Does not work anymore... :(

"Traceback (most recent call last):
File "/usr/bin/hacktooth/hacktooth", line 14, in <module>
import bluezutils
ImportError: No module named bluezutils

[1]+ Exit 1 sudo /usr/bin/hacktooth/hacktooth"

My phone could not connect with pi.

drgeoff
Posts: 7996
Joined: Wed Jan 25, 2012 6:39 pm

Re: Bluetooth Audio Receiver - Pi3

Sat Mar 10, 2018 6:34 pm

Easier, cheaper and less power consuming to spend $10 or equivalent on ebay for a ready to use device. :)

User avatar
frankpintosr
Posts: 3
Joined: Fri Jan 22, 2016 7:30 pm
Location: Southern California

Re: Bluetooth Audio Receiver - Pi3

Mon Mar 12, 2018 8:06 pm

@bloxix Assuming I am able to get one of these solutions to work, a big assumption due to my complete lack of experience, what is displayed on the CarPC interface? Do I need to go to a specific app?

Then, I am hoping to find something like you would see in a car stereo deck that displays Song, Artist, albumn cover, etc. Thank you in advance!

AlexSchmitz
Posts: 1
Joined: Tue May 15, 2018 4:38 am

Re: Bluetooth Audio Receiver - Pi3

Tue May 15, 2018 4:46 am

Thanks for this intruction. It worked for me when i deleted the "import bluezutils" command in the hacktooth file, changed SSP to on and added the "sudo ifconfig wlan0 down" command to the ~/.bashrc file.

But I have one Problem left: I can't control the volume of the Sound over my Mobile Phone, and it's annoying to always have a Monitor connected to the Pi. Has anybody an Idea how to fix this Problem. Btw. It might not has something to do with the Android 6 Volume Controls Bug. I have Android 8.0.

But anyway thanks for this instructions.

Alex

Return to “Media centres”

Who is online

Users browsing this forum: No registered users and 5 guests