[alsa-devel] Problem using alsa to implement an Android dock
Hello everybody
I am trying to implement an android dock on linux, and there is some cases where alsa seems to not properly recognise the Android phone as a USB sound device...
First a little bit of context
since Android 4.1 it is possible to put an android phone (connected to a PC via USB) in "dock mode" Basically you send a couple of special USB packet to the phone and the phone will disconnect from the USB bus then reconnect as a USB sound device. You can then use any tool to handle it as an audio source and redirct the sound to your speaker.
For those intereset the details can be found at
http://source.android.com/tech/accessories/aoap/aoa2.html
This works really well, no problem with that...
However Android also has something called "accessory mode" which is used to create custom apps that communicate in "raw" mode with the host
my problems arrive when both the dock mode and the accessory mode are enabled. in that case Alsa will not recognise the usb sound device exposed by android. It will create an entry for it in /proc/asound but there are no mixer or input stream
I attach the output of lsusb -v in both cases and a small C program that I use to put the phone in the proper modes
(there is a small section of code to (un)comment to en/disable accessory mode, it uses libusb for usb access and should be trivial to compile with it)
At this point I am not sure how to proceed, is this a real bug or something not implemented ? what extra info do I need to provide ? any help would be welcome
Regards
Jérémy Rosen
fight key loggers : write some perl using vim
Jeremy Rosen wrote:
my problems arrive when both the dock mode and the accessory mode are enabled. in that case Alsa will not recognise the usb sound device exposed by android.
bInterfaceNumber 1 bInterfaceSubClass Control Device AudioControl Interface Descriptor: baInterfaceNr 0 baInterfaceNr 1 bInterfaceNumber 2 bInterfaceSubClass Streaming
This is a bug in the Android firmware: it says that the audio driver should look at interfaces 0 and 1, but the actual audio interfaces are 1 and 2.
I'll look into this ...
Regards, Clemens
This is a bug in the Android firmware: it says that the audio driver should look at interfaces 0 and 1, but the actual audio interfaces are 1 and 2.
I'll look into this ...
hmmm
interesting, i'll wait for you to investigate what you want to investigate and then i'll look into how to open a bug report on the android side...
I have to admit my knowledge is not sufficiant to diagnose that sort of problems myself, thx for the help
Please try this patch:
ALSA: usb-audio: work around Anroid accessory firmware bug
When the Android firmware enables the audio interfaces in accessory mode, it always declares in the control interface's baInterfaceNr array that interfaces 0 and 1 belong to the audio function. However, the accessory interface itself, if also enabled, already is at index 0 and shifts the actual audio interface numbers to 1 and 2, which prevents the PCM streaming interface from being seen by the host driver.
To get the PCM interface interface to work, detect when the descriptors point to the (for this driver useless) accessory interface, and redirect to the correct one.
Reported-by: Jeremy Rosen jeremy.rosen@openwide.fr Not-yet-tested-by: Jeremy Rosen jeremy.rosen@openwide.fr Cc: stable@vger.kernel.org Signed-off-by: Clemens Ladisch clemens@ladisch.de --- sound/usb/card.c | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-)
diff --git a/sound/usb/card.c b/sound/usb/card.c index 563854a..f7a38ec 100644 --- a/sound/usb/card.c +++ b/sound/usb/card.c @@ -148,14 +148,31 @@ static int snd_usb_create_stream(struct snd_usb_audio *chip, int ctrlif, int int return -EINVAL; }
+ alts = &iface->altsetting[0]; + altsd = get_iface_desc(alts); + + /* + * Android with both accessory and audio interfaces enabled gets the + * interface numbers wrong. + */ + if ((chip->usb_id == USB_ID(0x18d1, 0x2d04) || + chip->usb_id == USB_ID(0x18d1, 0x2d05)) && + interface == 0 && + altsd->bInterfaceClass == USB_CLASS_VENDOR_SPEC && + altsd->bInterfaceSubClass == USB_SUBCLASS_VENDOR_SPEC) { + iface = usb_ifnum_to_if(dev, 2); + if (!iface) + return -EINVAL; + alts = &iface->altsetting[0]; + altsd = get_iface_desc(alts); + } + if (usb_interface_claimed(iface)) { snd_printdd(KERN_INFO "%d:%d:%d: skipping, already claimed\n", dev->devnum, ctrlif, interface); return -EINVAL; }
- alts = &iface->altsetting[0]; - altsd = get_iface_desc(alts); if ((altsd->bInterfaceClass == USB_CLASS_AUDIO || altsd->bInterfaceClass == USB_CLASS_VENDOR_SPEC) && altsd->bInterfaceSubClass == USB_SUBCLASS_MIDISTREAMING) {
Ok I tested on my raspberry card (the card where I can easily test it) and it didn't seem to work
I did some printk around and I do go correctly into the added code, but it doesn't seem to change anything
the card still has no control according to amixer...
I used a raspberry-pi kernel from https://github.com/raspberrypi/linux (branch rpi_3.9.y)
the port didn't apply correctly there but I managed to get it in
I'm quite new to this stuff. I am pretty sure I tested correctly, but appology if I didn't...
any hint on what I can do to help is welcome at this point
Cordialement
Jérémy Rosen
fight key loggers : write some perl using vim
ok, bad success criteria, I'm a bit walking blind here...
however it is not working
ls /proc/asound/N4 in audio only mode give
# ls /proc/asound/N4/ id pcm0c stream0 usbbus usbid usbmixer
and in audio+acc mode
# ls /proc/asound/N4/ id usbbus usbid usbmixer
is there anything else I can do to help ?
Cordialement
Jérémy Rosen
fight key loggers : write some perl using vim
----- Mail original -----
Jeremy Rosen wrote:
Ok I tested on my raspberry card (the card where I can easily test it) and it didn't seem to work
the card still has no control according to amixer...
Why should there be a mixer control?
Does the PCM device exist now?
Regards, Clemens
Jeremy Rosen wrote:
it didn't seem to work
Because the important code uses 'interface', not 'iface'. Try this one:
ALSA: usb-audio: work around Anroid accessory firmware bug
When the Android firmware enables the audio interfaces in accessory mode, it always declares in the control interface's baInterfaceNr array that interfaces 0 and 1 belong to the audio function. However, the accessory interface itself, if also enabled, already is at index 0 and shifts the actual audio interface numbers to 1 and 2, which prevents the PCM streaming interface from being seen by the host driver.
To get the PCM interface interface to work, detect when the descriptors point to the (for this driver useless) accessory interface, and redirect to the correct one.
Reported-by: Jeremy Rosen jeremy.rosen@openwide.fr Not-yet-tested-by: Jeremy Rosen jeremy.rosen@openwide.fr Cc: stable@vger.kernel.org Signed-off-by: Clemens Ladisch clemens@ladisch.de --- sound/usb/card.c | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-)
diff --git a/sound/usb/card.c b/sound/usb/card.c index 563854a..5a5153c 100644 --- a/sound/usb/card.c +++ b/sound/usb/card.c @@ -148,14 +148,32 @@ static int snd_usb_create_stream(struct snd_usb_audio *chip, int ctrlif, int int return -EINVAL; }
+ alts = &iface->altsetting[0]; + altsd = get_iface_desc(alts); + + /* + * Android with both accessory and audio interfaces enabled gets the + * interface numbers wrong. + */ + if ((chip->usb_id == USB_ID(0x18d1, 0x2d04) || + chip->usb_id == USB_ID(0x18d1, 0x2d05)) && + interface == 0 && + altsd->bInterfaceClass == USB_CLASS_VENDOR_SPEC && + altsd->bInterfaceSubClass == USB_SUBCLASS_VENDOR_SPEC) { + interface = 2; + iface = usb_ifnum_to_if(dev, interface); + if (!iface) + return -EINVAL; + alts = &iface->altsetting[0]; + altsd = get_iface_desc(alts); + } + if (usb_interface_claimed(iface)) { snd_printdd(KERN_INFO "%d:%d:%d: skipping, already claimed\n", dev->devnum, ctrlif, interface); return -EINVAL; }
- alts = &iface->altsetting[0]; - altsd = get_iface_desc(alts); if ((altsd->bInterfaceClass == USB_CLASS_AUDIO || altsd->bInterfaceClass == USB_CLASS_VENDOR_SPEC) && altsd->bInterfaceSubClass == USB_SUBCLASS_MIDISTREAMING) {
Awesome, this works perfectly, thx a lot
tested-by: Jeremy Rosen jeremy.rosen@openwide.fr
Is there anything I need to do for the upstreaming ?
I will still open a bug on the android side, though...
Cordialement
Jérémy Rosen
fight key loggers : write some perl using vim
----- Mail original -----
Jeremy Rosen wrote:
it didn't seem to work
Because the important code uses 'interface', not 'iface'. Try this one:
ALSA: usb-audio: work around Anroid accessory firmware bug
When the Android firmware enables the audio interfaces in accessory mode, it always declares in the control interface's baInterfaceNr array that interfaces 0 and 1 belong to the audio function. However, the accessory interface itself, if also enabled, already is at index 0 and shifts the actual audio interface numbers to 1 and 2, which prevents the PCM streaming interface from being seen by the host driver.
To get the PCM interface interface to work, detect when the descriptors point to the (for this driver useless) accessory interface, and redirect to the correct one.
Reported-by: Jeremy Rosen jeremy.rosen@openwide.fr Not-yet-tested-by: Jeremy Rosen jeremy.rosen@openwide.fr Cc: stable@vger.kernel.org Signed-off-by: Clemens Ladisch clemens@ladisch.de
sound/usb/card.c | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-)
diff --git a/sound/usb/card.c b/sound/usb/card.c index 563854a..5a5153c 100644 --- a/sound/usb/card.c +++ b/sound/usb/card.c @@ -148,14 +148,32 @@ static int snd_usb_create_stream(struct snd_usb_audio *chip, int ctrlif, int int return -EINVAL; }
- alts = &iface->altsetting[0];
- altsd = get_iface_desc(alts);
- /*
* Android with both accessory and audio interfaces enabled gets
the
* interface numbers wrong.
*/
- if ((chip->usb_id == USB_ID(0x18d1, 0x2d04) ||
chip->usb_id == USB_ID(0x18d1, 0x2d05)) &&
interface == 0 &&
altsd->bInterfaceClass == USB_CLASS_VENDOR_SPEC &&
altsd->bInterfaceSubClass == USB_SUBCLASS_VENDOR_SPEC) {
interface = 2;
iface = usb_ifnum_to_if(dev, interface);
if (!iface)
return -EINVAL;
alts = &iface->altsetting[0];
altsd = get_iface_desc(alts);
- }
- if (usb_interface_claimed(iface)) { snd_printdd(KERN_INFO "%d:%d:%d: skipping, already claimed\n", dev->devnum, ctrlif, interface); return -EINVAL; }
- alts = &iface->altsetting[0];
- altsd = get_iface_desc(alts); if ((altsd->bInterfaceClass == USB_CLASS_AUDIO || altsd->bInterfaceClass == USB_CLASS_VENDOR_SPEC) && altsd->bInterfaceSubClass == USB_SUBCLASS_MIDISTREAMING) {
participants (2)
-
Clemens Ladisch
-
Jeremy Rosen