From e0f57e523112e1bc73a04e8615d7a21355f0ce0e Mon Sep 17 00:00:00 2001 From: Thierry Bultel Date: Tue, 4 Dec 2018 23:11:20 +0100 Subject: Add support for bluetooth telephony This adds support for bluetooth telephony. A big rework in the softmixer internals has been mandatory, in order to support dynamic streams creation and deletions. Bluetooth telephony relies on the recent evolutions of bluez-alsa, the most important one being the support of HFP over Ofono. The softmixer opens PCM ioplugs provided by bluez-alsa. Bluetooth SCO needs 2 streams, one for listening and the other for talking. These streams are created upon requests sent by the hal-manager. The hal manager subscribes for bluez-alsa events and request the list of availalble transports. For each "attach" transaction verb, the softmixer maintains a list of the all created objects (sources, sinks, zones, ramps, streams, and more) Additionnally, it creates a new verb when the attach succeeds, that verb is typically something like "sco_XX:XX:XX:XX:XX:XX", and the only supported action at the present time is {"action":"remove"}, that performs all the cleanup of the registered objects. Change-Id: I1b119e6c079e60daf771e63c083a1ef33a39f379 Signed-off-by: Thierry Bultel --- plugins/alsa/alsa-utils-bypath.c | 155 +++++++++++++++++++++++++++++++-------- 1 file changed, 125 insertions(+), 30 deletions(-) (limited to 'plugins/alsa/alsa-utils-bypath.c') diff --git a/plugins/alsa/alsa-utils-bypath.c b/plugins/alsa/alsa-utils-bypath.c index 2427e9f..908d247 100644 --- a/plugins/alsa/alsa-utils-bypath.c +++ b/plugins/alsa/alsa-utils-bypath.c @@ -27,7 +27,6 @@ #include #include "alsa-softmixer.h" -#include "alsa-bluez.h" // extracted IOCTLs from #define _IOR_HACKED(type,nr,size) _IOC(_IOC_READ,(type),(nr),size) @@ -38,52 +37,126 @@ PUBLIC snd_ctl_card_info_t *AlsaByPathInfo(SoftMixerT *mixer, const char *devpath) { int open_dev; - snd_ctl_card_info_t *cardInfo = malloc(snd_ctl_card_info_sizeof()); - - if (!devpath) goto OnErrorExit; + snd_ctl_card_info_t *cardInfo = (snd_ctl_card_info_t *) malloc(snd_ctl_card_info_sizeof()); + if (!devpath) { + SOFTMIXER_NOMEM(mixer->api); + goto fail; + } open_dev = open(devpath, O_RDONLY); - if (open_dev < 0) goto OnErrorExit; + if (open_dev < 0) { + AFB_ApiError(mixer->api, "%s: Unable to open %s", __func__, devpath); + goto fail_cardinfo; + } int rc = ioctl(open_dev, SNDRV_CTL_IOCTL_CARD_INFO(snd_ctl_card_info_sizeof()), cardInfo); if (rc < 0) { - close(open_dev); - goto OnErrorExit; + AFB_ApiError(mixer->api, "%s: ioctl on %s failed", __func__, devpath); + goto fail_dev; } close(open_dev); return cardInfo; -OnErrorExit: - AFB_ApiError(mixer->api, "AlsaCardInfoByPath: fail to find sndcard by path= %s", devpath); + +fail_dev: + close(open_dev); +fail_cardinfo: + free(cardInfo); +fail: return NULL; } -PUBLIC AlsaPcmCtlT *AlsaByPathOpenPcm(SoftMixerT *mixer, AlsaDevInfoT *pcmDev, snd_pcm_stream_t direction) { +PUBLIC AlsaPcmCtlT * AlsaPcmCtlNew(SoftMixerT* mixer, const char * name) { + + AFB_ApiDebug(mixer->api, "%s: NEW %s",__func__, name); + + AlsaPcmCtlT *pcmCtl = calloc(1, sizeof (AlsaPcmCtlT)); + if (pcmCtl == NULL) { + SOFTMIXER_NOMEM(mixer->api); + goto fail; + } + + pcmCtl->name = name; + pcmCtl->closeAtDeletion = false; + + AlsaMixerTransactionObjectAdd(mixer->transaction, pcmCtl, AlsaPcmCtlDelete); + +fail: + return pcmCtl; +} + +PUBLIC void AlsaPcmCtlDelete(SoftMixerT* mixer, void * arg) { + int error = 0; + + AlsaPcmCtlT * pcmCtl = (AlsaPcmCtlT *) arg; + + if (!pcmCtl->closeAtDeletion) + goto done; + + if (pcmCtl->isPcmPlug) { + AFB_ApiDebug(mixer->api, "%s: Wont' close '%s' PCM, its slave is a plug", __func__, pcmCtl->cid.cardid); + goto done; + } + + AFB_ApiDebug(mixer->api, "%s: Closing %s",__func__, pcmCtl->cid.cardid); + error = snd_pcm_close(pcmCtl->handle); + if (error) { + // It's safe to ignore this error. In case of ioplug PCM, the device may have already disappeared + AFB_ApiDebug(mixer->api, + "%s: failed to close capture PCM %s: err=%s", __func__, pcmCtl->cid.cardid, snd_strerror(error)); + } + +done: + + free((char*) pcmCtl->cid.cardid); + free(pcmCtl); +} + +PUBLIC AlsaPcmCtlT *AlsaByPathOpenPcmCtl(SoftMixerT *mixer, AlsaDevInfoT *pcmDev, snd_pcm_stream_t direction) { int error; - AlsaPcmCtlT *pcmCtl = calloc(1, sizeof (AlsaPcmCtlT)); char *cardid = NULL; + AlsaPcmCtlT *pcmCtl = NULL; + if (pcmDev->pcmplug_params) { - pcmDev->cardid = pcmDev->pcmplug_params; + pcmDev->cardid = strdup(pcmDev->pcmplug_params); + if (pcmDev->cardid == NULL) { + SOFTMIXER_NOMEM(mixer->api); + goto fail; + } } if (!pcmDev->cardid) { if (pcmDev->subdev) { - if (asprintf(&cardid, "hw:%i,%i,%i", pcmDev->cardidx, pcmDev->device, pcmDev->subdev) == -1) - goto OnErrorExit; + if (asprintf(&cardid, "hw:%i,%i,%i", pcmDev->cardidx, pcmDev->device, pcmDev->subdev) == -1) { + SOFTMIXER_NOMEM(mixer->api); + goto fail; + } } else if (pcmDev->device) { - if (asprintf(&cardid, "hw:%i,%i", pcmDev->cardidx, pcmDev->device) == -1) - goto OnErrorExit; + if (asprintf(&cardid, "hw:%i,%i", pcmDev->cardidx, pcmDev->device) == -1) { + SOFTMIXER_NOMEM(mixer->api); + goto fail; + } } else { - if (asprintf(&cardid, "hw:%i", pcmDev->cardidx) == -1) - goto OnErrorExit; + if (asprintf(&cardid, "hw:%i", pcmDev->cardidx) == -1) { + SOFTMIXER_NOMEM(mixer->api); + goto fail; + } } + pcmDev->cardid = (const char*)cardid; } + pcmCtl = AlsaPcmCtlNew(mixer, pcmDev->cardid); + if (pcmCtl == NULL) { + SOFTMIXER_NOMEM(mixer->api); + goto fail_cardid; + } + + // inherit CID from pcmDev pcmCtl->cid.cardid = pcmDev->cardid; pcmCtl->cid.cardidx = pcmDev->cardidx; @@ -92,21 +165,23 @@ PUBLIC AlsaPcmCtlT *AlsaByPathOpenPcm(SoftMixerT *mixer, AlsaDevInfoT *pcmDev, s pcmCtl->cid.name=NULL; pcmCtl->cid.longname=NULL; - AFB_ApiInfo(mixer->api, + AFB_ApiDebug(mixer->api, "%s OPEN PCM '%s', direction %s", __func__, pcmDev->cardid, direction==SND_PCM_STREAM_PLAYBACK?"playback":"capture"); error = snd_pcm_open(&pcmCtl->handle, pcmCtl->cid.cardid, direction, SND_PCM_NONBLOCK); if (error < 0) { AFB_ApiError(mixer->api, "%s: fail openpcm cardid=%s error=%s", __func__, pcmCtl->cid.cardid, snd_strerror(error)); - goto OnErrorExit; + goto fail_pcmctl; } return pcmCtl; -OnErrorExit: +fail_pcmctl: free(pcmCtl); - free(cardid); +fail_cardid: + free((char*)pcmDev->cardid); +fail: return NULL; } @@ -117,43 +192,63 @@ PUBLIC snd_ctl_t *AlsaByPathOpenCtl(SoftMixerT *mixer, const char *uid, AlsaSndC // get card info from /dev/snd/xxx if not use hw:x,x,x snd_ctl_card_info_t *cardInfo = NULL; + AFB_ApiDebug(mixer->api, "%s: devpath %s, cardid %s, plug %s", __func__, dev->cid.devpath, dev->cid.cardid, dev->cid.pcmplug_params); + if (dev->cid.devpath) cardInfo = AlsaByPathInfo(mixer, dev->cid.devpath); else if (dev->cid.cardid) cardInfo = AlsaCtlGetCardInfo(mixer, dev->cid.cardid); - else if (dev->cid.pcmplug_params) + else if (dev->cid.pcmplug_params) { + AFB_ApiDebug(mixer->api, "Get card info from plug params %s", dev->cid.pcmplug_params); cardInfo = AlsaCtlGetCardInfo(mixer, dev->cid.pcmplug_params); + } if (!cardInfo) { AFB_ApiError(mixer->api, "%s: uid=%s fail to find sndcard by path=%s id=%s", __func__, uid, dev->cid.devpath, dev->cid.cardid); - goto OnErrorExit; + goto fail; } // extract useful info from cardInfo handle dev->cid.devpath = NULL; dev->cid.cardidx = snd_ctl_card_info_get_card(cardInfo); dev->cid.name = strdup(snd_ctl_card_info_get_name(cardInfo)); + if (dev->cid.name == NULL) { + SOFTMIXER_NOMEM(mixer->api); + goto fail; + } dev->cid.longname = strdup(snd_ctl_card_info_get_longname(cardInfo)); + if (dev->cid.longname == NULL) { + SOFTMIXER_NOMEM(mixer->api); + goto fail_cid_name; + } // build a valid name and open sndcard - if (asprintf((char**) &dev->cid.cardid, "hw:%i", dev->cid.cardidx) == -1) - goto OnErrorExit; + if (asprintf((char**) &dev->cid.cardid, "hw:%i", dev->cid.cardidx) == -1) { + SOFTMIXER_NOMEM(mixer->api); + goto fail_cid_longname; + } if ((err = snd_ctl_open(&handle, dev->cid.cardid, 0)) < 0) { AFB_ApiError(mixer->api, "%s uid=%s sndcard open fail cardid=%s longname=%s error=%s", __func__, uid, dev->cid.cardid, dev->cid.longname, snd_strerror(err)); - goto OnErrorExit; + goto fail_cardid; } AFB_ApiNotice(mixer->api, - "%s: uid=%s cardid=%s cardname=%s", - __func__, uid, dev->cid.cardid, dev->cid.longname); + "%s: uid=%s cardid=%s cardname=%s pcmplug %s", + __func__, uid, dev->cid.cardid, dev->cid.longname, dev->cid.pcmplug_params); free(cardInfo); return handle; -OnErrorExit: +fail_cid_longname: + free((char*)dev->cid.longname); +fail_cid_name: + free((char*)dev->cid.name); +fail_cardid: + free((char*)dev->cid.cardid); +fail: return NULL; } -- cgit 1.2.3-korg