Linux Embedded

Le blog des technologies libres et embarquées

La Raspberry, Android et l’USB (1/3) : rediriger les flux Audio

La raspberry-pi est une jolie petite plateforme pour mettre une petite touche d’informatique dans un produit ou dans la maison. Elle est bon marché, facile à développer et à adapter mais elle n’a ni écran ni clavier permettant de la commander.

Nous allons voire dans cette série d’articles les différentes façons de faire communiquer une carte Raspberry pi et un téléphone Android via une connexion USB entre ces deux éléments.

Ce premier article présentera la gestion de l’USB sur android et vous expliquera comment rediriger le flux audio de votre téléphone vers votre carte Raspberry-pi.

Le deuxième article vous apprendra à rediriger un périphérique USB HID (souris ou clavier) branché sur votre raspberry-pi vers votre téléphone Android

Enfin, le dernier article vous montrera comment transmettre des données quelconques entre votre raspberry-pi et une application Android que nous développerons spécifiquement.

Android et l’USB

Maîtres et esclaves

L’USB est un protocole qui a été conçu pour connecter des périphériques à un ordinateur. Le protocole est donc prévue pour avoir un maître et des esclaves. Typiquement le PC est maître et les périphériques sont esclaves. Le maître décide qui parle sur le bus et les périphériques ne peuvent pas dialoguer entre eux.  Le maître est également le seul à pouvoir fournir de la puissance électrique sur le bus USB. A l’exceptions des téléphones les plus récents, les téléphones Android ne peuvent être qu’esclaves. C’est assez logique puisqu’il est souhaitable de pouvoir fournir de la puissance au téléphone (pour le charger par exemple)  et de pouvoir communiquer avec un PC (le téléphone se faisant passer pour une clé USB ).  Notre Raspberry sera donc le maître USB et le téléphone l’esclave USB.

La connexion d’un périphérique Android

Si vous branchez un téléphone android sur votre PC linux et que vous utilisez la commande suivante :

lsusb

vous remarquerez que votre téléphone n’indique d’aucune manière qu’il est équipé du système Android. Typiquement il vous donnera un nom de fabriquant et un nom de modèle différent pour chaque télépone

Bus 002 Device 126: ID 0bb4:0cac HTC (High Tech Computer Corp.)

Nous verrons lors de l’intégration sur la raspberry pi comment reconnaître le périphérique. Les grandes étapes de la connexion sont les suivantes :

  • Interroger le téléphone pour connaitre la version du protocole AOA (android open accessory) à utiliser.
  • Envoyer au téléphone des identifiants et des informations de configuration.
  • Demander au téléphone de passer en mode connecté USB.
  • Le téléphone se déconnecte du bus USB puis se reconnecte avec de nouveaux identifiants.
  • Utiliser les identifiants pour vérifier les capacités du téléphone.
  • Utiliser les capacités du téléphone.

Pour communiquer avec un périphérique Android nous utilisons simplement libusb. Vous trouverez à la fin de cet article le code source complet des applications de configuration et de communication avec le périphérique android.

Le premier programme à étudier est le programme usbAccConfig. Ce programme est appelé par udev à la connexion du téléphone et enverra les paramètres de configuration avant de demander au téléphone de basculer en mode accessoire.

Pour tester usbAccConfig il suffit de le compiler puis de le lancer en lui passant les identifiants du télépone:

sudo ./usbAccConfig s 0x0bb4 0x0cac

Le programme peut être testé sur votre PC de bureau. Il n’y a rien de spécifique à la raspberry-pi. Les identifiants à utiliser sont ceux de votre téléphone tels qu’ils sont indiqués par lsusb

Nous ne commenterons ici que les grandes lignes du code source.  La gestion d’erreur et la mise en place détaillée peut être trouvée dans le code source.

Tout d’abord ouvrons le périphérique

handle = libusb_open_device_with_vid_pid(NULL, vid, pid))

le VendorID et le ProductID sont obtenu depuis la ligne de commande.

Ensuite il faut envoyer un paquet spécial permettant de vérifier la version du protocole à utiliser ( les valeurs transmise viennent de la description du protocole AOA)

 response = libusb_control_transfer( handle, 0xC0, 51, 0, 0, ioBuffer, 2, 0);

La réponse arrive sous forme de deux octets que nous remettons dans le bon ordre

devVersion = ioBuffer[1] << 8 | ioBuffer[0];

devVersion doit être égal à 1 ou 2. Une autre valeur indique un périphérique qui n’est pas un périphérique Android.

Nous devons ensuite envoyer au téléphone une série de commandes pour lui dire quel type de périphérique l’hôte souhaite voir émulé par le téléphone.

  • Dock audio (les flux sonores du téléphone sont redirigés vers l’hôte).
  • Périphérique spécifique (le téléphone cherche une application capable de gérer le périphérique et laisse ensuite celle-ci gérer les communications).

Les détails des commandes de configuration à envoyer seront détaillés dans les différents articles de cette série.

Enfin, La dernière commande demande au téléphone de passer en mode gestion de périphérique.

 response = libusb_control_transfer(handle,0x40,53,0,0,NULL,0,0);

Le téléphone se déconnectera du bus USB puis se reconnectera avec des identifiants fixés par le protocole AOA. (Le vendorID sera celui de google, quel que soit le constructeur du téléphone et le productID dépendra de la configuration demandée.)

La commande lsusb devrait désormais afficher quelque chose de similaire à ceci :

Bus 002 Device 006: ID 18d1:2d00 Google Inc. Android-powered device in accessory mode

notez le 18d1 qui est le vendorId de google. La seconde valeur dépend de la configuration exacte qui a été demandée au téléphone.

Intégration dans buildroot

Nous voulons que tout périphérique USB branché sur la raspberry soit testé par notre programme. Pour cela le programme usbAccConfig commence par vérifier une liste d’identifiants correspondant aux périphériques USB embarqués sur la raspberry pi. Pour tout autre identifiant il enverra la séquence de commandes décrite plus haut.

Pour que usbAccConfig soit lancé automatiquement à chaque connexion USB nous devons ajouter une règle udev. Pour cela nous ajoutons un fichier /etc/udev/rules.d/dock.rules avec le contenu suivant

ACTION=="add",SUBSYSTEM=="usb",RUN+="/usbAccConfig  s 0x%s{idVendor} 0x%s{idProduct}"

Le premier paramètre (le s) indique que nous voulons utiliser notre device en mode audio. Lorsque vous voudrez tester le mode accessoire, il faudra le remplacer par un a.

Udev appellera ainsi le programme à chaque connexion USB. Nous pouvons vérifier que tout cela fonctionne correctement en branchant un téléphone sur la raspberry pi et en observant la déconnexion et reconnexion du téléphone.

Transformer notre Raspberry en dock Audio

Cette partie n’est possible que si votre téléphone gère la version 2.0 du protocole AOA, c’est à dire qu’il intègre Android 4.1 (i.e API 16) ou une version plus récente.

Nous avons vu dans le paragraphe précédant que le téléphone nous indique la version du protocole AOA qu’il utilise. Si notre téléphone utilise la version 2.0 nous pouvons lui passer une commande de configuration pour lui indiquer que nous souhaitons gérer les flux audio et que le téléphone doit se configurer en tant que périphérique Audio (le téléphone se présentera sur le bus comme une carte son USB avec une source sonore correspondante aux sons du téléphone).  La ligne suivante sert à indiquer au téléphone qu’il doit passer en mode dock :

 response = libusb_control_transfer(handle,0x40,58,1,0,NULL,0,0);

Après la configuration le téléphone devrait apparaître comme une carte son sur le bus USB et être reconnu comme tel par ALSA. un simple ls /proc/asound nous permet de vérifier que tout cela fonctionne… Notre raspberry a donc une nouvelle entrée son qui corresponds au périphérique Android, mais nous devons encore rediriger le son vers la véritable carte son de la raspberry pi. Pour cela il faut utiliser pulseaudio.

La configuration par défaut de pulseaudio est presque parfaite pour notre utilisation. Il lui manque juste quelques options.  Dans le ficher /etc/pulse/daemon.conf il faut changer la methode de resampling vers la méthode trivial, la méthode par défaut étant trop gourmande en CPU. Dans l’exemple buildroot fourni à la fin de l’article nous utilisons les overlay pour configurer le fichier. Ensuite, il faut lancer la commande suivante après que pulseaudio ait détecté le téléphone Android

pactl load-module module-loopback source=`pactl list sources short | grep alsa_input.usb | cut -f 1

Une fois cette commande executée vous pouvez lancer n’importe quelle application audio sur le téléphone et  le son sera redirigé vers le port jack de la carte raspberry pi.

Sur une véritable application l’api de la librairie pulseaudio permet de détecter l’ajout et de réagir mais, dans le cadre de cet article, nous nous contenterons de lancer la commande manuellement.

Code source, exemples et limitation

Vous trouverez le code source ci-dessous

usbAccConfig

Cette application prend trois paramètres, un action (a ou s),  le vendor-id et product-id d’un périphérique USB. elle enverra les commandes de configuration au périphérique pour le mettre en mode dock audio ou en mode accessoire. Ce programme doit être lancé en tant que root pour avoir les droits d’accès sur le périphérique USB.

Le mode accessoire sera utilisé dans un des futurs articles de cette série.

buildroot Bundle

Cette archive contient les bases pour construire votre propre projet buildroot

  • un defconfig pour la raspberry pi
  • un répertoire overlay contenant les fichiers modifiés

Notez que ce tutoriel utilise buildroot comme exemple mais que les techniques et logiciels utilisés sont communs sur toutes les distributions linux et qu’il est très facile d’adapter cela à d’autres distributions que ce soient des distributions embarquées ou bureautiques…

Lors de l’écriture de cet article nous avons rencontré quelques limitations du système et  des applications qu’il est utile de mentionner :

  • Un bug Android empêche d’utiliser simultanément le mode Audio et le mode Accessoire. Si on tente de le faire, Alsa ne reconnaîtra pas correctement le périphérique Audio. Il s’agit d’un bug Android que vous pouvez suivre ici une analyse du bug sur la mailing list Alsa contient un patch kernel permettant de contourner le bug (le thread commence ici) Ce patch a été intégré dans le kernel 3.9 ainsi que dans les dernières mises à jour des kernels 3.0 et 3.4.
  • Les applications de test ne gèrent pas pulseaudio (il faut lancer la commande manuellement). L’intégration de pulseaudio est possible dans une application réelle mais n’a pas été traitée ici.

Bibliographie

  • La documentation du protocole USB Android Open Accessory se trouve ici et .
  • La documentation de libusb se trouve ici.

5 commentaires sur “ La Raspberry, Android et l’USB (1/3) : rediriger les flux Audio ”

  1. Mathieu
    le 28 août 2013 à 16 h 05 min

    Ca serait pas plutot
    sudo ./usbAccConfig s 0x0bb4 0x0cac
    à la place de :
    sudo ./usbAccConfig s 0x0bb4 0xcaac

    • Jérémy Rosen
      le 2 septembre 2013 à 17 h 30 min

      Bien vu…

      c’est corrigé dans l’article.

  2. Omerlin
    le 26 décembre 2013 à 20 h 22 min

    Bonjour, je suis novice et je me demandais si il était possible et si oui arriverait on à afficher le bureau du RasPi en le branchant par micro hdmi à un telephone android?

    • Jérémy Rosen
      le 2 janvier 2014 à 9 h 34 min

      hmm, ce n’est pas vraiment le sujet de l’article mais je vais répondre rapidement quand même…

      malgré les apparences, les ports HDMI ne sont pas symétriques. Il y a des ports hdmi de sortie (raspberry pi, téléphones Android, PC) et des ports hdmi d’entrée (écran, télé…)

      ces ports ne sont pas interchangeables et si on connecte un port hdmi de sortie sur un autre port hdmi de sortie (ce qui est proposé ici) il ne se passera rien. c’est comme brancher une sortie vga de PC sur la carte vidéo d’un autre PC… je ne sais pas si on peut véritablement parler de “limitation” de la norme hdmi ou si c’est simplement pas prévu pour, mais en tout cas non. ce n’est pas possible.

      désolé

Répondre à Mathieu Annuler la réponse.

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *