Re: Bluetooth audio via pulse doesn't function unless I chant the magic incantations

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Thu, 2009-11-05 at 02:49 +0000, Bastien Nocera wrote:
> On Wed, 2009-11-04 at 19:13 -0700, Russ Dill wrote:
> > On Wed, Nov 4, 2009 at 6:29 AM, Bastien Nocera <hadess@xxxxxxxxxx> wrote:
> > > On Wed, 2009-11-04 at 01:14 -0700, Russ Dill wrote:
> > >> I have ubuntu lucid (its just karmic+2.6.32-rc5) and I can only get
> > >> pulseaudio to detect my Sony DR-BT50 headset if I send some dbus
> > >> commands:
> > >>
> > >> addr=00:1a:80:67:63:2c
> > >> hci=$(dbus-send --print-reply --system --dest=org.bluez /
> > >> org.bluez.Manager.DefaultAdapter | tail -n 1 | cut -f 2 -d '"')
> > >> dev=$(dbus-send --print-reply --system --dest=org.bluez $hci
> > >> org.bluez.Adapter.FindDevice string:$addr | tail -n 1 | cut -f 2 -d
> > >> '"')
> > >> dbus-send --print-reply --system --dest=org.bluez $dev org.bluez.Audio.Connect
> > >>
> > >> Additionally, the device shows up under the gnome bluetooth-properties
> > >> applet under "Known devices" with the gold star and the keys. The
> > >> connected plug doesn't appear until I exec the above commands.
> > >> Clicking the plug without the above commands does nothing.
> > >
> > > You're using bluez-gnome (or possibly an old version of
> > > gnome-bluetooth). Make sure you use the latest version (2.28.3).
> > >
> > > Cheers
> > >
> > 
> > Thank you for the awesomeness.
> > 
> > Next question, I get events from keypresses on the headset via a
> > /dev/input/eventX file, but how do I do things with those events?
> 
> If you use GNOME, the buttons should be forwarded to X11, and to the
> desktop. So the volume buttons should already work. Check the Sound and
> Keyboard shortcuts preferences.
> 
> If you're using something else, I'm afraid I wouldn't know...
> 
> Cheers
> 

Looking at the spec, yes 0x7e is VENDOR_UNIQUE. It gives a operation
data field length of 5 as spelled out in the spec, it then gives a
company ID of 0x08 0x00 0x46 and then a vendor unique id of 0x00 0x01
for folder+ and 0x00 0x02 for folder -.

Ok, here is my quick and dirty patch for supporting VENDOR_UNIQUE.
audio/control.c doesn't seem to be the right place to store these
quirks. Can we somehow pass it as a uinput message and let some other
software stack layer that has policy files figure it out?

I also don't think KEY_PROG1 and KEY_PROG2 are the right choice, but I'm
not sure what is.

I also noticed that the spec includes info on how to tell the device
that audio is playing or audio is paused. I imagine if this was
implemented, my device would send the correct play/pause keycode.

The patch is mainly a request for comments. It is against bluez-4.51.

--- a/audio/control.c	2009-11-11 00:11:32.000000000 -0700
+++ b/audio/control.c	2009-11-11 01:29:22.000000000 -0700
@@ -193,6 +193,28 @@ static struct {
 	{ NULL }
 };
 
+struct vendor_keys {
+	const char *name;
+	uint16_t vendorid;
+	uint16_t uinput;
+};
+
+#define COMPANYID_SONY 0x080046
+static struct vendor_keys sony_vendor_keys[] = {
+	{ "FOLDER_NEXT",	0x0001,			KEY_PROG1 },
+	{ "FOLDER_PREV",	0x0002,			KEY_PROG2 },
+	{ NULL }
+};
+
+static struct {
+	const char *name;
+	uint32_t companyid;
+	struct vendor_keys *keys;
+} vendor_key_map[] = {
+	{ "Sony Corporation", COMPANYID_SONY, sony_vendor_keys },
+	{ NULL }
+};
+
 static GSList *avctp_callbacks = NULL;
 
 static sdp_record_t *avrcp_ct_record()
@@ -348,6 +370,8 @@ static void handle_panel_passthrough(str
 {
 	const char *status;
 	int pressed, i;
+	const char *name = NULL;
+	uint16_t uinput = 0;
 
 	if (operand_count == 0)
 		return;
@@ -360,17 +384,61 @@ static void handle_panel_passthrough(str
 		pressed = 1;
 	}
 
-	for (i = 0; key_map[i].name != NULL; i++) {
-		if ((operands[0] & 0x7F) == key_map[i].avrcp) {
-			debug("AVRCP: %s %s", key_map[i].name, status);
-			send_key(control->uinput, key_map[i].uinput, pressed);
-			break;
+	if ((operands[0] & 0x7f) == 0x7e) {
+		const struct vendor_keys *map = NULL;
+		const char *vendor_name = NULL;
+		uint32_t companyid = 0;
+		uint16_t vendorid = 0;
+
+		if (operand_count != 7) {
+			debug("AVRCP: Incorrect operand_count for "
+				"VENDOR_UNIQUE (%d) %s", operand_count, status);
+			return;
 		}
-	}
+		companyid = (operands[2] << 16) | (operands[3] << 8) |
+						operands[4];
+		vendorid = (operands[5] << 8) | operands[6];
+		for (i = 0; vendor_key_map[i].name != NULL; i++) {
+			if (companyid == vendor_key_map[i].companyid) {
+				map = vendor_key_map[i].keys;
+				vendor_name = vendor_key_map[i].name;
+				break;
+			}
+		}
+		if (map == NULL) {
+			debug("AVRCP: Unknown companyid (0x%06x) for "
+				"VENDOR_UNIQUE (%d) %s", companyid,
+				operand_count, status);
+			return;
+		}
+		for (i = 0; map[i].name != NULL; i++) {
+			if (vendorid == map[i].vendorid) {
+				name = map[i].name;
+				uinput = map[i].uinput;
+				break;
+			}
+		}
+		if (name == NULL)
+			debug("AVRCP: unknown vendor button %s 0x%04X %s",
+						vendor_name, vendorid, status);
 
-	if (key_map[i].name == NULL)
-		debug("AVRCP: unknown button 0x%02X %s",
+	} else {
+		for (i = 0; key_map[i].name != NULL; i++) {
+			if ((operands[0] & 0x7F) == key_map[i].avrcp) {
+				name = key_map[i].name;
+				uinput = key_map[i].uinput;
+				break;
+			}
+		}
+		if (name == NULL)
+			debug("AVRCP: unknown button 0x%02X %s",
 						operands[0] & 0x7F, status);
+	}
+
+	if (name) {
+		debug("AVRCP: %s %s", name, status);
+		send_key(control->uinput, uinput, pressed);
+	}
 }
 
 static void avctp_disconnected(struct audio_device *dev)
@@ -585,6 +653,12 @@ static int uinput_create(char *name)
 
 	for (i = 0; key_map[i].name != NULL; i++)
 		ioctl(fd, UI_SET_KEYBIT, key_map[i].uinput);
+	for (i = 0; vendor_key_map[i].name != NULL; i++) {
+		const struct vendor_keys *map = vendor_key_map[i].keys;
+		int j;
+		for (j = 0; map[j].name != NULL; j++)
+			ioctl(fd, UI_SET_KEYBIT, map[j].uinput);
+	}
 
 	if (ioctl(fd, UI_DEV_CREATE, NULL) < 0) {
 		err = errno;

Attachment: signature.asc
Description: This is a digitally signed message part


[Index of Archives]     [Bluez Devel]     [Linux Wireless Networking]     [Linux Wireless Personal Area Networking]     [Linux ATH6KL]     [Linux USB Devel]     [Linux Media Drivers]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Big List of Linux Books]

  Powered by Linux