Saturday, April 10, 2010

Linksys NSLU2 Utilizing Bluetooth Audio

I was posting on Twitter and got a request from @m1n1m3 to cover this topic. The requirements are a Linksys NSLU2, a linux compatible usb bluetooth adapter (I use IOGEAR GBU211 or GBU421), a bluetooth headset (any should do), and a usb thumb drive (4GB or higher). This is for mono audio on a bluetooth headset. This does not cover a stereo configuration, though it should be possible.


To get started, follow the directions at https://wiki.ubuntu.com/ARM/NSLU2 to get your base Ubuntu system installed on the NSLU2. I have used other alternative firmwares in the past, but not for this particular project. The Debian install should work, but I cannot verify it. Note that it will take a while to complete the install. Also, if your NSLU2 is of a certain manufacture date, I strongly suggest that you follow the overclocking hack here: http://www.nslu2-linux.org/wiki/HowTo/OverClockTheSlug I have only run the NSLU2 at 266Mhz.


Once you have installed Ubuntu, log in and update your packages:

sudo -i apt-get update

Then install the following packages:

sudo -i apt-get install linux-sound-base bluetooth bluez bluez-alsa bluez-btsco bluez-compat bluez-utils python python-bluez vlc

Note: I do alot of other development stuff on my unit. I may have left off something, and if so let me know if you try it and it doesn't work.


Now that the needed packages are installed, an .asoundrc needs to be created in your user home directory. An example:

pcm.bluetooth {
type bluetooth
device 00:00:00:00:00:00
}

Edit the device section with the MAC address of your bluetooth headset. To find this, issue a reset of the bluetooth adapter by issuing the command:

hciconfig hci0 reset

Then place your headset in pairing mode and issue the following command:

sdptool browse

Now copy the following python script into a file named pair.py:

#!/usr/bin/python

import gobject

import sys
import dbus
import dbus.service
import dbus.mainloop.glib

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("org.bluez.Agent",
in_signature="", out_signature="")
def Release(self):
print "Release"
if self.exit_on_release:
mainloop.quit()

@dbus.service.method("org.bluez.Agent",
in_signature="os", out_signature="")
def Authorize(self, device, uuid):
print "Authorize (%s, %s)" % (device, uuid)
authorize = raw_input("Authorize connection (yes/no): ")
if (authorize == "yes"):
return
raise Rejected("Connection rejected by user")

@dbus.service.method("org.bluez.Agent",
in_signature="o", out_signature="s")
def RequestPinCode(self, device):
print "RequestPinCode (%s)" % (device)
return raw_input("Enter PIN Code: ")

@dbus.service.method("org.bluez.Agent",
in_signature="o", out_signature="u")
def RequestPasskey(self, device):
print "RequestPasskey (%s)" % (device)
passkey = raw_input("Enter passkey: ")
return dbus.UInt32(passkey)

@dbus.service.method("org.bluez.Agent",
in_signature="ou", out_signature="")
def DisplayPasskey(self, device, passkey):
print "DisplayPasskey (%s, %d)" % (device, passkey)

@dbus.service.method("org.bluez.Agent",
in_signature="ou", out_signature="")
def RequestConfirmation(self, device, passkey):
print "RequestConfirmation (%s, %d)" % (device, passkey)
confirm = raw_input("Confirm passkey (yes/no): ")
if (confirm == "yes"):
return
raise Rejected("Passkey doesn't match")

@dbus.service.method("org.bluez.Agent",
in_signature="s", out_signature="")
def ConfirmModeChange(self, mode):
print "ConfirmModeChange (%s)" % (mode)

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

def create_device_reply(device):
print "New device (%s)" % (device)
mainloop.quit()

def create_device_error(error):
print "Creating device failed: %s" % (error)
mainloop.quit()

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

bus = dbus.SystemBus()
manager = dbus.Interface(bus.get_object("org.bluez", "/"),
"org.bluez.Manager")

if len(sys.argv) > 1:
path = manager.FindAdapter(sys.argv[1])
else:
path = manager.DefaultAdapter()

adapter = dbus.Interface(bus.get_object("org.bluez", path),
"org.bluez.Adapter")

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

mainloop = gobject.MainLoop()

if len(sys.argv) > 2:
if len(sys.argv) > 3:
device = adapter.FindDevice(sys.argv[2])
adapter.RemoveDevice(device)

agent.set_exit_on_release(False)
adapter.CreatePairedDevice(sys.argv[2], path, "DisplayYesNo",
reply_handler=create_device_reply,
error_handler=create_device_error)
else:
adapter.RegisterAgent(path, "DisplayYesNo")
print "Agent registered"

mainloop.run()

#adapter.UnregisterAgent(path)
#print "Agent unregistered"

Now place your headset into pairing mode again and issue the follow command:

sudo -i python pair.py hci0 00:00:00:00:00:00

Once again replacing the address above with your headsets MAC.


The last step involves editing the vlcrc. To do this, issue the command:

pico .vlc/vlcrc

Scroll to the end and edit the entry that says alsadev=(default soundcard) to:

alsadev=bluetooth

If it does not exist then create it.

Now you should be ready to listen to audio. To listen to the audio from NASA TV's online video stream, issue the command:

cvlc --aout-rate 8000 --novideo http://www.nasa.gov/55644main_NASATV_Windows.asx

If everything is working you should hear audio. Keep in mind that the sample rate needs to be 8000Hz since that is the sample rate the headset can handle.


To pair another headset, or to re-pair the current, the /var/lib/bluetooth/(your MAC)/linkkeys file must be deleted. It will regenerate once you have paired the devices. Also remember that the .asoundrc file must be edited to match a different headset as the MAC will be different.

Other things I have done in the way of bluetooth that have worked has been using a TCP/IP piconet using pand. Since I have been unable so far to get a Belkin 802.11 usb wireless adater to work, it is useful as a wireless connection. I have connected 2 GBU211 adapters to a Targus ACH7405US travel usb hub, with one connecting to a computer via pand and the other providing bluetooth audio. I tried for 3, but the power draw was too much. I have tried to use the NSLU2 as a bluetooth to cellular bridge via pand, ip forwarding, iptables, rfcomm, and wvdial, but the version of wvdial for NSLU2 Ubuntu (and I believe Debian) crashes when connecting. Linphonc will work if you use wav files as soundcards. I have been trying to get a bluetooth headset to work (which I have no issues with on x86), but I have been unable to make calls. I have yet to try a bluttooth hands free speaker phone, but I would imagine that it would work the same.

Information on bluez-audio can be found here: http://wiki.bluez.org/wiki/HOWTO/AudioDevices I can't remember where exactly I found the pairing script. Let me know where to find it and I will post a link. ( Update: It's called simple-agent and I found it here: http://git.kernel.org/?p=bluetooth/bluez.git;a=blob_plain;f=test/simple-agent;hb=HEAD ) If you would like more information on this project or others contact me via http://twitter.com/POTUSCamacho

No comments:

Post a Comment