summaryrefslogtreecommitdiffstats
path: root/plugins/alsa/alsa-core-ctl.c
diff options
context:
space:
mode:
authorThierry Bultel <thierry.bultel@iot.bzh>2018-12-04 23:11:20 +0100
committerThierry Bultel <thierry.bultel@iot.bzh>2018-12-19 23:09:21 +0100
commite0f57e523112e1bc73a04e8615d7a21355f0ce0e (patch)
tree19198c38d7433862cee733fde3efca8170228279 /plugins/alsa/alsa-core-ctl.c
parent7df040a3742af8d800852dd39f8e921cd82a4cf2 (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.c196
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(&registryEntry->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;
}