diff options
author | Thierry Bultel <thierry.bultel@iot.bzh> | 2018-12-04 23:11:20 +0100 |
---|---|---|
committer | Thierry Bultel <thierry.bultel@iot.bzh> | 2018-12-19 23:09:21 +0100 |
commit | e0f57e523112e1bc73a04e8615d7a21355f0ce0e (patch) | |
tree | 19198c38d7433862cee733fde3efca8170228279 /plugins/alsa/alsa-core-ctl.c | |
parent | 7df040a3742af8d800852dd39f8e921cd82a4cf2 (diff) |
Add support for bluetooth telephonyguppy_6.99.3guppy/6.99.36.99.3
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 <thierry.bultel@iot.bzh>
Diffstat (limited to 'plugins/alsa/alsa-core-ctl.c')
-rw-r--r-- | plugins/alsa/alsa-core-ctl.c | 196 |
1 files changed, 122 insertions, 74 deletions
diff --git a/plugins/alsa/alsa-core-ctl.c b/plugins/alsa/alsa-core-ctl.c index 7a0c476..dcfd860 100644 --- a/plugins/alsa/alsa-core-ctl.c +++ b/plugins/alsa/alsa-core-ctl.c @@ -25,12 +25,11 @@ for the specific language governing permissions and #define _GNU_SOURCE // needed for vasprintf #include "alsa-softmixer.h" -#include "alsa-bluez.h" #include <pthread.h> #include <sys/syscall.h> -typedef struct { +typedef struct SubscribeHandleT_ { SoftMixerT *mixer; sd_event_source* evtsrc; const char* uid; @@ -151,24 +150,6 @@ OnErrorExit: return NULL; } -PUBLIC snd_ctl_t *AlsaCtlOpenCtl(SoftMixerT *mixer, const char *cardid) { - int error; - snd_ctl_t *ctl; - - if (!cardid) goto OnErrorExit; - - if ((error = snd_ctl_open(&ctl, cardid, SND_CTL_READONLY)) < 0) { - cardid = "Not Defined"; - goto OnErrorExit; - } - - return ctl; - -OnErrorExit: - AFB_ApiError(mixer->api, "AlsaCtlOpenCtl: fail to find sndcard by id= %s", cardid); - return NULL; -} - STATIC void CtlElemIdDisplay(SoftMixerT *mixer, snd_ctl_elem_info_t *elemInfo, snd_ctl_elem_value_t *elemData) { @@ -275,7 +256,7 @@ PUBLIC int CtlElemIdSetLong(SoftMixerT *mixer, AlsaSndCtlT *sndcard, snd_ctl_ele OnErrorExit: numid = snd_ctl_elem_info_get_numid(elemInfo); name = snd_ctl_elem_info_get_name(elemInfo); - AFB_ApiError(mixer->api, "CtlElemIdSetInt: numid=%d name=%s not writable", numid, name); + AFB_ApiError(mixer->api, "%s: numid=%d name=%s not writable", __func__, numid, name); return -1; } @@ -290,26 +271,42 @@ PUBLIC snd_ctl_card_info_t *AlsaCtlGetCardInfo(SoftMixerT *mixer, const char *ca /* "bluealsa" is the name of the control external plugin * (https://www.alsa-project.org/alsa-doc/alsa-lib/ctl_external_plugins.html) */ + if (strstr(cardid, "bluealsa")) { - cardid="bluealsa"; - alsa_bluez_init(); + cardid = strdup("bluealsa"); + if (cardid == NULL) { + SOFTMIXER_NOMEM(mixer->api); + goto fail; + } } AFB_ApiNotice(mixer->api, "Opening card control '%s'", cardid); if ((error = snd_ctl_open(&ctl, cardid, SND_CTL_READONLY)) < 0) { cardid = "Not Defined"; - goto OnErrorExit; + goto fail; } snd_ctl_card_info_t *cardInfo = malloc(snd_ctl_card_info_sizeof()); + if (cardInfo == NULL) { + SOFTMIXER_NOMEM(mixer->api); + goto fail_ctl; + } + if ((error = snd_ctl_card_info(ctl, cardInfo)) < 0) { - goto OnErrorExit; + AFB_ApiError(mixer->api, "%s fail to find sndcard by id= %s", __func__, cardid); + goto fail_card_info; } + + snd_ctl_close(ctl); return cardInfo; -OnErrorExit: - AFB_ApiError(mixer->api, "AlsaCtlGetInfo: fail to find sndcard by id= %s", cardid); +fail_card_info: + free(cardInfo); +fail_ctl: + snd_ctl_close(ctl); +fail: + AFB_ApiError(mixer->api, "%s: fail to find sndcard by id= %s", __func__, cardid); return NULL; } @@ -495,50 +492,76 @@ STATIC int CtlSubscribeEventCB(sd_event_source* src, int fd, uint32_t revents, v snd_ctl_event_t *eventId; snd_ctl_elem_id_t *elemId; long value; - int index; + + AFB_ApiDebug(mixer->api, "%s event on card %s", __func__, sndcard->cid.cardid); if ((revents & EPOLLHUP) != 0) { AFB_ApiNotice(mixer->api, "%s hanghup [card:%s disconnected]", __func__, sHandle->uid); goto OnSuccessExit; } - if ((revents & EPOLLIN) == 0) goto OnSuccessExit; + if ((revents & EPOLLIN) == 0) { + AFB_ApiNotice(mixer->api, "%s: no events", __func__); + goto OnSuccessExit; + } // initialise event structure on stack snd_ctl_event_alloca(&eventId); snd_ctl_elem_id_alloca(&elemId); error = snd_ctl_read(sndcard->ctl, eventId); - if (error < 0) goto OnErrorExit; + if (error < 0) { + AFB_ApiDebug(mixer->api, "%s: failed to read control", __func__); + goto OnErrorExit; + } // we only process sndctrl element - if (snd_ctl_event_get_type(eventId) != SND_CTL_EVENT_ELEM) goto OnSuccessExit; + if (snd_ctl_event_get_type(eventId) != SND_CTL_EVENT_ELEM) { + AFB_ApiDebug(mixer->api, "%s: bad event type", __func__); + goto OnSuccessExit; + } // we only process value changed events unsigned int eventMask = snd_ctl_event_elem_get_mask(eventId); - if (!(eventMask & SND_CTL_EVENT_MASK_VALUE)) goto OnSuccessExit; + if (!(eventMask & SND_CTL_EVENT_MASK_VALUE)) { + goto OnSuccessExit; + } // extract element from event and get value snd_ctl_event_elem_get_id(eventId, elemId); error = CtlElemIdGetLong(mixer, sHandle->sndcard, elemId, &value); - if (error) goto OnErrorExit; + if (error) { + AFB_ApiDebug(mixer->api, "%s: failed to get elem id", __func__); + goto OnErrorExit; + } // get numdid and name from elemId snd_ctl_elem_info_t *elemInfo; snd_ctl_elem_info_alloca(&elemInfo); snd_ctl_elem_info_set_id(elemInfo, elemId); - if (snd_ctl_elem_info(sndcard->ctl, elemInfo) < 0) goto OnErrorExit; + if (snd_ctl_elem_info(sndcard->ctl, elemInfo) < 0) { + AFB_ApiDebug(mixer->api, "%s: failed to get elem info", __func__); + goto OnErrorExit; + } int numid = snd_ctl_elem_info_get_numid(elemInfo); + + AFB_ApiDebug(mixer->api, "%s: event on elem id %d", __func__, numid); + const char *name= snd_ctl_elem_info_get_name(elemInfo); - for (index = 0; sndcard->registry[index]; index++) { - RegistryEntryPcmT * reg = sndcard->registry[index]; - snd_pcm_t * pcm = reg->pcm->handle; - if (reg->numid == numid) { + RegistryEntryPcmT * registry = NULL; + + bool found = false; + + cds_list_for_each_entry(registry, &sndcard->registryList, cardListEntry) { + snd_pcm_t * pcm = registry->pcm->handle; + + if (registry->numid == numid) { + found = true; int ret; - switch (reg->type) { + switch (registry->type) { case FONTEND_NUMID_RUN: - AlsaPcmCopyMuteSignal(mixer, reg->pcm, !value); + AlsaPcmCopyMuteSignal(mixer, registry->pcm, !value); ret = snd_pcm_pause(pcm, (int) (!value)); AFB_ApiNotice(mixer->api, "%s:%s numid=%d name=%s active=%ld ret %d", __func__, sHandle->uid, numid, name, value, ret); @@ -548,8 +571,8 @@ STATIC int CtlSubscribeEventCB(sd_event_source* src, int fd, uint32_t revents, v break; case FONTEND_NUMID_PAUSE: - AlsaPcmCopyMuteSignal(mixer, reg->pcm, value); - ret = snd_pcm_pause(reg->pcm->handle, (int) value); + AlsaPcmCopyMuteSignal(mixer, registry->pcm, value); + ret = snd_pcm_pause(registry->pcm->handle, (int) value); AFB_ApiNotice(mixer->api, "%s:%s numid=%d name=%s pause=%ld ret %d", __func__, sHandle->uid, numid, name, value, ret); if (ret < 0) { @@ -558,53 +581,51 @@ STATIC int CtlSubscribeEventCB(sd_event_source* src, int fd, uint32_t revents, v break; case FONTEND_NUMID_IGNORE: default: - AFB_ApiInfo(mixer->api, + AFB_ApiDebug(mixer->api, "%s:%s numid=%d name=%s ignored=%ld", __func__, sHandle->uid, numid, name, value); } break; } } - if (index == sndcard->rcount) { - AFB_ApiNotice(mixer->api, "%s:%s numid=%d (unknown)", __func__, sHandle->uid, numid); + if (!found) { + AFB_ApiNotice(mixer->api, "%s:%s numid=%d is unknown", __func__, sHandle->uid, numid); } OnSuccessExit: return 0; OnErrorExit: - AFB_ApiInfo(mixer->api, "%s: ignored unsupported event", __func__); + AFB_ApiDebug(mixer->api, "%s: ignored unsupported event", __func__); return 0; } -PUBLIC snd_ctl_t* AlsaCrlFromPcm(SoftMixerT *mixer, snd_pcm_t *pcm) { - char buffer[32]; - int error; - snd_ctl_t *ctl; - snd_pcm_info_t *pcmInfo; - snd_pcm_info_alloca(&pcmInfo); - if ((error = snd_pcm_info(pcm, pcmInfo)) < 0) goto OnErrorExit; +PUBLIC int AlsaCtlUnSubscribe(SoftMixerT *mixer, AlsaSndCtlT *sndcard) { + SubscribeHandleT * handle = sndcard->eventSubscribeHandle; - int pcmCard = snd_pcm_info_get_card(pcmInfo); - snprintf(buffer, sizeof (buffer), "hw:%i", pcmCard); - if ((error = snd_ctl_open(&ctl, buffer, SND_CTL_READONLY)) < 0) goto OnErrorExit; + AFB_ApiDebug(mixer->api,"%s for card %s", __func__, sndcard->cid.cardid); - return ctl; - -OnErrorExit: - return NULL; + sd_event_source_unref(handle->evtsrc); + free(handle); + return 0; } PUBLIC int AlsaCtlSubscribe(SoftMixerT *mixer, const char *uid, AlsaSndCtlT *sndcard) { int error; char string [32]; struct pollfd pfds; - SubscribeHandleT *handle = malloc(sizeof (SubscribeHandleT)); + + SubscribeHandleT *handle = calloc(1, sizeof (SubscribeHandleT)); + if (handle == NULL) { + SOFTMIXER_NOMEM(mixer->api); + goto OnErrorExit; + } handle->mixer = mixer; handle->sndcard = sndcard; handle->uid = uid; + sndcard->eventSubscribeHandle = handle; // subscribe for sndctl events attached to cardid if ((error = snd_ctl_subscribe_events(handle->sndcard->ctl, 1)) < 0) { @@ -636,36 +657,63 @@ OnErrorExit: return -1; } -PUBLIC int AlsaCtlRegister(SoftMixerT *mixer, AlsaSndCtlT *sndcard, AlsaPcmCtlT *pcmdev, RegistryNumidT type, int numid) { - int index; - AFB_ApiInfo(mixer->api,"%s: registered ID %d.", __func__, numid); +PUBLIC void AlsaCtlUnregister(SoftMixerT* mixer, void * arg) { - for (index = 0; index < sndcard->rcount; index++) { - if (!sndcard->registry[index]) break; - } + RegistryEntryPcmT * registryEntry = (RegistryEntryPcmT*) arg; + + AFB_ApiDebug(mixer->api,"%s: card %s : Unregistering control ID %d (%ld in registry).", + __func__, registryEntry->sndcard->cid.cardid, registryEntry->numid, registryEntry->sndcard->nbRegistry); + AlsaSndCtlT * sndcard = registryEntry->sndcard; + + cds_list_del(®istryEntry->cardListEntry); + sndcard->nbRegistry--; - if (index == sndcard->rcount) { + if (sndcard->nbRegistry <= 0) + AlsaCtlUnSubscribe(mixer, sndcard); + + free(registryEntry); + AFB_ApiDebug(mixer->api,"%s: DONE", __func__); +} + + +PUBLIC int AlsaCtlRegister(SoftMixerT *mixer, AlsaSndCtlT *sndcard, AlsaPcmCtlT *pcmdev, RegistryNumidT type, int numid) { + + AFB_ApiDebug(mixer->api,"%s: registering control ID %d to %s", __func__, numid, sndcard->cid.cardid); + + if (sndcard->nbRegistry >= SMIXER_SUBDS_CTLS ) { AFB_ApiError(mixer->api, - "%s cardid=%s cardname=%s to many audio stream max=%ld", - __func__, sndcard->cid.cardid, sndcard->cid.longname, sndcard->rcount); - goto OnErrorExit; + "%s cardid='%s' cardname='%s' too many registered controls max=%ld", + __func__, sndcard->cid.cardid, sndcard->cid.longname, sndcard->nbRegistry); + goto fail; } // If 1st registration then register to card event - if (index == 0) { + if (sndcard->nbRegistry == 0) { AlsaCtlSubscribe(mixer, sndcard->cid.cardid, sndcard); } // store PCM in order to pause/resume depending on event RegistryEntryPcmT *entry = calloc(1, sizeof (RegistryEntryPcmT)); - sndcard->registry[index] = entry; + if (entry == NULL) { + SOFTMIXER_NOMEM(mixer->api); + goto fail; + } + CDS_INIT_LIST_HEAD(&entry->cardListEntry); + entry->pcm = pcmdev; entry->numid = numid; entry->type = type; + entry->sndcard = sndcard; + + sndcard->nbRegistry++; + + AlsaMixerTransactionObjectAdd(mixer->transaction, entry, AlsaCtlUnregister); + + cds_list_add_tail(&entry->cardListEntry, &sndcard->registryList); return 0; -OnErrorExit: +fail: return -1; } |