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-api-pcm.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-api-pcm.c')
-rw-r--r-- | plugins/alsa/alsa-api-pcm.c | 375 |
1 files changed, 281 insertions, 94 deletions
diff --git a/plugins/alsa/alsa-api-pcm.c b/plugins/alsa/alsa-api-pcm.c index 1bba75c..85e3c3a 100644 --- a/plugins/alsa/alsa-api-pcm.c +++ b/plugins/alsa/alsa-api-pcm.c @@ -51,17 +51,31 @@ typedef struct { AlsaSndPcmT* pcm; } apiVerbHandleT; -STATIC AlsaPcmChannelT *ProcessOneChannel(SoftMixerT *mixer, const char *uid, json_object *argsJ) { +STATIC AlsaPcmChannelT * ProcessOneChannel(SoftMixerT *mixer, const char *uid, json_object *argsJ) { AlsaPcmChannelT *channel = calloc(1, sizeof (AlsaPcmChannelT)); + if (channel == NULL) { + SOFTMIXER_NOMEM(mixer->api); + goto fail; + } int error = wrap_json_unpack(argsJ, "{ss,si !}", "uid", &channel->uid, "port", &channel->port); - if (error) goto OnErrorExit; + if (error) { + AFB_ApiError(mixer->api, "%s: sndcard=%s channel: missing (uid||port) error=%s json=%s", + __func__, uid, wrap_json_get_error_string(error), json_object_get_string(argsJ)); + goto fail_channel; + } + + CDS_INIT_LIST_HEAD(&channel->list); channel->uid = strdup(channel->uid); + if (channel->uid == NULL) { + SOFTMIXER_NOMEM(mixer->api); + goto fail_channel; + } return channel; -OnErrorExit: - AFB_ApiError(mixer->api, "ProcessOneChannel: sndcard=%s channel: missing (uid||port) error=%s json=%s", uid, wrap_json_get_error_string(error), json_object_get_string(argsJ)); +fail_channel: free(channel); +fail: return NULL; } @@ -81,37 +95,45 @@ STATIC int PcmAttachOneCtl(SoftMixerT *mixer, AlsaSndCtlT *sndcard, json_object AFB_ApiError(mixer->api, "%s: cardid=%s channel: missing (numid|name|value) error=%s json=%s", __func__, sndcard->cid.name, wrap_json_get_error_string(error), json_object_get_string(argsJ)); - goto OnErrorExit; + goto fail; } if (numid > 0) { elemId = AlsaCtlGetNumidElemId(mixer, sndcard, numid); if (!elemId) { - AFB_ApiError(mixer->api, "PcmAttachOneCtl sndard=%s fail to find control numid=%d", sndcard->cid.cardid, numid); - goto OnErrorExit; + AFB_ApiError(mixer->api, "%s sndard=%s fail to find control numid=%d", + __func__, sndcard->cid.cardid, numid); + goto fail; } } else { elemId = AlsaCtlGetNameElemId(mixer, sndcard, name); if (!elemId) { - AFB_ApiError(mixer->api, "PcmAttachOneCtl sndard=%s fail to find control name=%s", sndcard->cid.cardid, name); - goto OnErrorExit; + AFB_ApiError(mixer->api, "%s sndard=%s fail to find control name=%s", + __func__, sndcard->cid.cardid, name); + goto fail; } } snd_ctl_elem_info_alloca(&elemInfo); snd_ctl_elem_info_set_id(elemInfo, elemId); control->name = strdup(snd_ctl_elem_info_get_name(elemInfo)); + if (!control->name) { + SOFTMIXER_NOMEM(mixer->api); + goto fail_elemId; + } control->numid = snd_ctl_elem_info_get_numid(elemInfo); if (snd_ctl_elem_info(sndcard->ctl, elemInfo) < 0) { - AFB_ApiError(mixer->api, "PcmAttachOneCtl: sndard=%s numid=%d name='%s' not loadable", sndcard->cid.cardid, control->numid, control->name); - goto OnErrorExit; + AFB_ApiError(mixer->api, "%s: sndard=%s numid=%d name='%s' not loadable", + __func__, sndcard->cid.cardid, control->numid, control->name); + goto fail_control_name; } if (!snd_ctl_elem_info_is_writable(elemInfo)) { - AFB_ApiError(mixer->api, "PcmAttachOneCtl: sndard=%s numid=%d name='%s' not writable", sndcard->cid.cardid, control->numid, control->name); - goto OnErrorExit; + AFB_ApiError(mixer->api, "%s: sndard=%s numid=%d name='%s' not writable", + __func__, sndcard->cid.cardid, control->numid, control->name); + goto fail_control_name; } control->count = snd_ctl_elem_info_get_count(elemInfo); @@ -132,22 +154,25 @@ STATIC int PcmAttachOneCtl(SoftMixerT *mixer, AlsaSndCtlT *sndcard, json_object break; default: - AFB_ApiError(mixer->api, "PcmAttachOneCtl: sndard=%s numid=%d name='%s' invalid/unsupported type=%d", - sndcard->cid.cardid, control->numid, control->name, snd_ctl_elem_info_get_type(elemInfo)); - goto OnErrorExit; + AFB_ApiError(mixer->api, "%s: sndard=%s numid=%d name='%s' invalid/unsupported type=%d", + __func__, sndcard->cid.cardid, control->numid, control->name, snd_ctl_elem_info_get_type(elemInfo)); + goto fail_control_name; } if (error) { - AFB_ApiError(mixer->api, "PcmAttachOneCtl: sndard=%s numid=%d name='%s' not writable", sndcard->cid.cardid, control->numid, control->name); - goto OnErrorExit; + AFB_ApiError(mixer->api, "%s: sndard=%s numid=%d name='%s' not writable", + __func__, sndcard->cid.cardid, control->numid, control->name); + goto fail_control_name; } free(elemId); - return 0; -OnErrorExit: - if (elemId)free(elemId); +fail_control_name: + free((char*)control->name); +fail_elemId: + free(elemId); +fail: return -1; } @@ -161,7 +186,7 @@ STATIC int PcmSetControl(SoftMixerT *mixer, AlsaSndCtlT *sndcard, AlsaSndControl elemId = AlsaCtlGetNumidElemId(mixer, sndcard, control->numid); if (!elemId) { - AFB_ApiError(mixer->api, "PcmSetControl sndard=%s fail to find control numid=%d", sndcard->cid.cardid, control->numid); + AFB_ApiError(mixer->api, "%s sndard=%s fail to find control numid=%d", __func__, sndcard->cid.cardid, control->numid); goto OnErrorExit; } @@ -169,18 +194,18 @@ STATIC int PcmSetControl(SoftMixerT *mixer, AlsaSndCtlT *sndcard, AlsaSndControl snd_ctl_elem_info_set_id(elemInfo, elemId); if (snd_ctl_elem_info(sndcard->ctl, elemInfo) < 0) { - AFB_ApiError(mixer->api, "PcmSetControl: sndard=%s numid=%d name='%s' not loadable", sndcard->cid.cardid, control->numid, control->name); + AFB_ApiError(mixer->api, "%s: sndard=%s numid=%d name='%s' not loadable", __func__, sndcard->cid.cardid, control->numid, control->name); goto OnErrorExit; } if (!snd_ctl_elem_info_is_writable(elemInfo)) { - AFB_ApiError(mixer->api, "PcmSetControl: sndard=%s numid=%d name='%s' not writable", sndcard->cid.cardid, control->numid, control->name); + AFB_ApiError(mixer->api, "%s: sndard=%s numid=%d name='%s' not writable", __func__, sndcard->cid.cardid, control->numid, control->name); goto OnErrorExit; } error = CtlElemIdGetLong(mixer, sndcard, elemId, &curval); if (error) { - AFB_ApiError(mixer->api, "PcmSetControl sndard=%s fail to read control numid=%d", sndcard->cid.cardid, control->numid); + AFB_ApiError(mixer->api, "%s sndcard=%s fail to read control numid=%d", __func__, sndcard->cid.cardid, control->numid); goto OnErrorExit; } @@ -347,9 +372,19 @@ OnErrorExit: return; } +PUBLIC void ApiPcmDelParams(SoftMixerT* mixer, AlsaPcmHwInfoT* params) { + free((char*)params->formatS); + free(params); +} + PUBLIC AlsaPcmHwInfoT * ApiPcmSetParams(SoftMixerT *mixer, const char *uid, json_object * paramsJ) { - AlsaPcmHwInfoT *params = calloc(1, sizeof (AlsaPcmHwInfoT)); + const char *format = NULL, *access = NULL; + AlsaPcmHwInfoT *params = calloc(1, sizeof (AlsaPcmHwInfoT)); + if (params == NULL) { + SOFTMIXER_NOMEM(mixer->api); + goto fail; + } // some default values params->rate = ALSA_DEFAULT_PCM_RATE; @@ -358,23 +393,31 @@ PUBLIC AlsaPcmHwInfoT * ApiPcmSetParams(SoftMixerT *mixer, const char *uid, json if (paramsJ) { int error = - wrap_json_unpack(paramsJ, "{s?i,s?i, s?s, s?s !}", - "rate", ¶ms->rate, - "channels",¶ms->channels, - "format", &format, + wrap_json_unpack(paramsJ, "{s?i,s?s,s?s !}", + "rate", ¶ms->rate, + "format", &format, "access", &access); if (error) { - AFB_ApiError(mixer->api, "ApiPcmSetParams: sndcard=%s invalid params=%s", uid, json_object_get_string(paramsJ)); - goto OnErrorExit; + AFB_ApiError(mixer->api, "%s: sndcard=%s invalid params=%s", + __func__, uid, json_object_get_string(paramsJ)); + goto fail_params; } } - if (!format) { + if (!format) { params->format = SND_PCM_FORMAT_S16_LE; - params->formatS = "S16_LE"; + params->formatS = strdup("S16_LE"); + if (params->formatS == NULL) { + SOFTMIXER_NOMEM(mixer->api); + goto fail_params; + } goto check_access; } params->formatS = strdup(format); + if (params->formatS == NULL) { + SOFTMIXER_NOMEM(mixer->api); + goto fail_params; + } #define FORMAT_CHECK(arg) if (!strcmp(format,#arg)) { params->format = SND_PCM_FORMAT_##arg; goto check_access; } FORMAT_CHECK(S16_LE); @@ -394,11 +437,11 @@ PUBLIC AlsaPcmHwInfoT * ApiPcmSetParams(SoftMixerT *mixer, const char *uid, json FORMAT_CHECK(FLOAT_LE); FORMAT_CHECK(FLOAT_BE); - AFB_ApiError(mixer->api, "ApiPcmSetParams:%s(params) unsupported format 'S16_LE|S32_L|...' format=%s", uid, format); - goto OnErrorExit; + AFB_ApiError(mixer->api, "%s: %s(params) unsupported format 'S16_LE|S32_L|...' format=%s", __func__, uid, format); + goto fail_params; check_access: - AFB_ApiNotice(mixer->api, "ApiPcmSetParams:%s format set to SND_PCM_FORMAT_%s", uid, params->formatS); + AFB_ApiNotice(mixer->api, "%s: %s format set to SND_PCM_FORMAT_%s", __func__, uid, params->formatS); #define ACCESS_CHECK(arg) if (!strcmp(access,#arg)) { params->access = SND_PCM_ACCESS_##arg; goto success;} @@ -413,25 +456,97 @@ check_access: ACCESS_CHECK(RW_INTERLEAVED); ACCESS_CHECK(RW_NONINTERLEAVED); - AFB_ApiNotice(mixer->api, "ApiPcmSetParams:%s(params) unsupported access 'RW_INTERLEAVED|MMAP_INTERLEAVED|MMAP_COMPLEX' access=%s", uid, access); - goto OnErrorExit; + AFB_ApiNotice(mixer->api, + "%s:%s(params) unsupported access 'RW_INTERLEAVED|MMAP_INTERLEAVED|MMAP_COMPLEX' access=%s", + __func__,uid, access); + goto fail_params; success: - AFB_ApiNotice(mixer->api, "ApiPcmSetParams:%s access set to %s", uid, access); + AFB_ApiNotice(mixer->api, "%s:%s access set to %s", __func__, uid, access); return params; -OnErrorExit: +fail_params: free(params); +fail: return NULL; } -PUBLIC AlsaSndPcmT * ApiPcmAttachOne(SoftMixerT *mixer, const char *uid, snd_pcm_stream_t direction, json_object * argsJ) { + +static void pcmChannelsDestroy(SoftMixerT * mixer, AlsaSndPcmT * pcm) { + AFB_ApiDebug(mixer->api, "%s: pcm %s (%d channels)", __func__, pcm->uid, pcm->nbChannels); + + AlsaPcmChannelT * channel, *tmp; + cds_list_for_each_entry_safe(channel, tmp, &pcm->channels.list, list) { + cds_list_del(&channel->list); + AFB_ApiDebug(mixer->api, "%s: del channel %s", __func__, channel->uid); + free((char *)channel->uid); + free(channel); + } + AFB_ApiDebug(mixer->api, "%s: pcm %s DONE", __func__, pcm->uid); +} + +PUBLIC void ApiPcmDelete(SoftMixerT * mixer, AlsaSndPcmT * pcm) { + + AFB_ApiDebug(mixer->api, "%s: pcm %s", __func__, pcm->uid); + + free(pcm->apiVerbHandle); + AlsaSndCtlT * card = pcm->sndcard; + if (card->cid.pcmplug_params) + free((char*)card->cid.pcmplug_params); + + pcmChannelsDestroy(mixer, pcm); + + snd_ctl_close(card->ctl); + free(card); + free ((char*)pcm->mute.name); + free ((char*)pcm->volume.name); + + if (pcm->verb && + (strcmp(pcm->verb, SOFTMIXER_VERB_NONE)!=0)) { + int error = afb_api_del_verb(mixer->api, pcm->verb, (void**)&pcm->apiVerbHandle); + if (error) { + AFB_ApiError(mixer->api, "Failed to remove verb %s", pcm->verb); + } + } + + free((char*)pcm->uid); + free(pcm); + AFB_ApiDebug(mixer->api, "%s: done", __func__); +} + +PUBLIC AlsaSndPcmT * ApiPcmNew(SoftMixerT* mixer) { AlsaSndPcmT *pcm = calloc(1, sizeof (AlsaSndPcmT)); + if (pcm == NULL) { + SOFTMIXER_NOMEM(mixer->api); + goto fail; + } + + CDS_INIT_LIST_HEAD(&pcm->list); + CDS_INIT_LIST_HEAD(&pcm->channels.list); +fail: + return pcm; +} + +PUBLIC AlsaSndPcmT * ApiPcmAttachOne(SoftMixerT *mixer, const char *uid, snd_pcm_stream_t direction, json_object * argsJ) { + json_object *sourceJ = NULL, *paramsJ = NULL, *sinkJ = NULL, *targetJ = NULL; char *apiVerb = NULL, *apiInfo = NULL; + apiVerbHandleT *handle = NULL; int error; + AlsaSndPcmT *pcm = ApiPcmNew(mixer); + if (pcm == NULL) { + SOFTMIXER_NOMEM(mixer->api); + goto fail; + } + pcm->sndcard = (AlsaSndCtlT*) calloc(1, sizeof (AlsaSndCtlT)); + if (pcm->sndcard == NULL) { + SOFTMIXER_NOMEM(mixer->api); + goto fail_pcm; + } + CDS_INIT_LIST_HEAD(&pcm->sndcard->registryList); + error = wrap_json_unpack(argsJ, "{ss,s?s,s?s,s?s,s?i,s?i,s?o,s?o,s?o !}" , "uid", &pcm->uid , "pcmplug_params", &pcm->sndcard->cid.pcmplug_params @@ -444,42 +559,40 @@ PUBLIC AlsaSndPcmT * ApiPcmAttachOne(SoftMixerT *mixer, const char *uid, snd_pcm , "params", ¶msJ ); if (error) { - AFB_ApiError(mixer->api, "ApiPcmAttachOne: hal=%s missing 'uid|path|cardid|device|sink|source|params' error=%s args=%s", uid, wrap_json_get_error_string(error), json_object_get_string(argsJ)); - goto OnErrorExit; + AFB_ApiError(mixer->api, "%s: hal=%s missing 'uid|path|cardid|device|sink|source|params' error=%s args=%s", + __func__, uid, wrap_json_get_error_string(error), json_object_get_string(argsJ)); + goto fail_pcm_sndcard; } + if (pcm->sndcard->cid.pcmplug_params) + pcm->isPcmPlug = true; + else + pcm->isPcmPlug = false; + // try to open sound card control interface pcm->sndcard->ctl = AlsaByPathOpenCtl(mixer, pcm->uid, pcm->sndcard); if (!pcm->sndcard->ctl) { - AFB_ApiError(mixer->api, "ApiPcmAttachOne: hal=%s Fail to open sndcard uid=%s devpath=%s cardid=%s", uid, pcm->uid, pcm->sndcard->cid.devpath, pcm->sndcard->cid.cardid); - goto OnErrorExit; - } - - // check sndcard accepts params - pcm->sndcard->params = ApiPcmSetParams(mixer, pcm->uid, paramsJ); - if (!pcm->sndcard->params) { - AFB_ApiError(mixer->api, "ApiPcmAttachOne: hal=%s Fail to set params sndcard uid=%s params=%s", uid, pcm->uid, json_object_get_string(paramsJ)); - goto OnErrorExit; + AFB_ApiError(mixer->api, "%s: hal=%s Fail to open sndcard uid=%s devpath=%s cardid=%s", + __func__, uid, pcm->uid, pcm->sndcard->cid.devpath, pcm->sndcard->cid.cardid); + goto fail_pcm_sndcard; } if (direction == SND_PCM_STREAM_PLAYBACK) { if (!sinkJ) { - AFB_ApiError(mixer->api, "ApiPcmAttachOne: hal=%s SND_PCM_STREAM_PLAYBACK require sinks args=%s", uid, json_object_get_string(argsJ)); - goto OnErrorExit; + AFB_ApiError(mixer->api, "%s: hal=%s SND_PCM_STREAM_PLAYBACK require sinks args=%s", + __func__, uid, json_object_get_string(argsJ)); + goto fail_pcm_sndcard_ctl; } targetJ = sinkJ; } if (direction == SND_PCM_STREAM_CAPTURE) { if (!sourceJ) { - AFB_ApiError(mixer->api, "ApiPcmAttachOne: hal=%s SND_PCM_STREAM_CAPTURE require sources args=%s", uid, json_object_get_string(argsJ)); - goto OnErrorExit; + AFB_ApiError(mixer->api, "%s: hal=%s SND_PCM_STREAM_CAPTURE require sources args=%s", + __func__, uid, json_object_get_string(argsJ)); + goto fail_pcm_sndcard_ctl; } targetJ = sourceJ; - - // we may have to register SMIXER_SUBDS_CTLS per subdev (Fulup ToBeDone when sndcard get multiple device/subdev) - pcm->sndcard->registry = calloc(SMIXER_SUBDS_CTLS + 1, sizeof (RegistryEntryPcmT)); - pcm->sndcard->rcount = SMIXER_SUBDS_CTLS; } json_object *channelsJ = NULL, *controlsJ = NULL; @@ -488,33 +601,56 @@ PUBLIC AlsaSndPcmT * ApiPcmAttachOne(SoftMixerT *mixer, const char *uid, snd_pcm , "controls", &controlsJ ); if (error) { - AFB_ApiNotice(mixer->api, "ApiPcmAttachOne: hal=%s pcms missing channels|[controls] error=%s paybacks=%s", uid, wrap_json_get_error_string(error), json_object_get_string(argsJ)); - goto OnErrorExit; + AFB_ApiNotice(mixer->api, "%s: hal=%s pcms missing channels|[controls] error=%s (%s)", + __func__, uid, wrap_json_get_error_string(error), json_object_get_string(argsJ)); + goto fail_pcm_sndcard_ctl; } + + AlsaPcmChannelT * channel = NULL; + if (channelsJ) { switch (json_object_get_type(channelsJ)) { case json_type_object: - pcm->ccount = 1; - pcm->channels = calloc(2, sizeof (void*)); - pcm->channels[0] = ProcessOneChannel(mixer, pcm->uid, channelsJ); - if (!pcm->channels[0]) goto OnErrorExit; + channel = ProcessOneChannel(mixer, pcm->uid, channelsJ); + if (channel == NULL) { + goto fail_pcm_channels; + } + + pcm->nbChannels++; + cds_list_add_tail(&channel->list, &pcm->channels.list); + break; - case json_type_array: - pcm->ccount = (int) json_object_array_length(channelsJ); - pcm->channels = calloc(pcm->ccount + 1, sizeof (void*)); - for (int idx = 0; idx < pcm->ccount; idx++) { + case json_type_array: { + int nbChannels = (int) json_object_array_length(channelsJ); + + for (int idx = 0; idx < nbChannels; idx++) { json_object *channelJ = json_object_array_get_idx(channelsJ, idx); - pcm->channels[idx] = ProcessOneChannel(mixer, pcm->uid, channelJ); - if (!pcm->channels[idx]) goto OnErrorExit; + channel = ProcessOneChannel(mixer, pcm->uid, channelJ); + if (!channel) + goto fail_pcm_channels; + + pcm->nbChannels++; + cds_list_add_tail(&channel->list, &pcm->channels.list); } break; + } default: - AFB_ApiError(mixer->api, "ApiPcmAttachOne:%s invalid pcm=%s", pcm->uid, json_object_get_string(channelsJ)); - goto OnErrorExit; + AFB_ApiError(mixer->api, "%s:%s invalid pcm=%s", pcm->uid, __func__, json_object_get_string(channelsJ)); + goto fail_pcm_sndcard_ctl; } } + // check sndcard accepts params + pcm->sndcard->params = ApiPcmSetParams(mixer, pcm->uid, paramsJ); + if (!pcm->sndcard->params) { + AFB_ApiError(mixer->api, "%s: hal=%s Fail to set params sndcard uid=%s params=%s", + __func__, uid, pcm->uid, json_object_get_string(paramsJ)); + goto fail_pcm_sndcard_ctl; + } + + pcm->sndcard->params->channels = pcm->nbChannels; + if (controlsJ) { json_object *volJ = NULL, *muteJ = NULL; error = wrap_json_unpack(controlsJ, "{s?o,s?o !}" @@ -525,50 +661,101 @@ PUBLIC AlsaSndPcmT * ApiPcmAttachOne(SoftMixerT *mixer, const char *uid, snd_pcm AFB_ApiNotice(mixer->api, "%s: source missing [volume]|[mute] error=%s control=%s", __func__, wrap_json_get_error_string(error), json_object_get_string(controlsJ)); - goto OnErrorExit; + goto fail_pcm_channels; } - if (volJ) error += PcmAttachOneCtl(mixer, pcm->sndcard, volJ, &pcm->volume); - if (muteJ) error += PcmAttachOneCtl(mixer, pcm->sndcard, muteJ, &pcm->mute); - if (error) goto OnErrorExit; + if (volJ) { + error = PcmAttachOneCtl(mixer, pcm->sndcard, volJ, &pcm->volume); + if (error) + goto fail_pcm_channels; + } + if (muteJ) { + error = PcmAttachOneCtl(mixer, pcm->sndcard, muteJ, &pcm->mute); + if (error) + goto fail_pcm_channels; + } // create master control for this sink if (direction == SND_PCM_STREAM_PLAYBACK) { - if (asprintf(&apiVerb, "%s:playback", pcm->uid) == -1) - goto OnErrorExit; - if (asprintf(&apiInfo, "HAL:%s SND_PCM_STREAM_PLAYBACK", uid) == -1) - goto OnErrorExit; + if (asprintf(&apiVerb, "%s:playback", pcm->uid) == -1) { + SOFTMIXER_NOMEM(mixer->api); + goto fail_pcm_channels; + } + if (asprintf(&apiInfo, "HAL:%s SND_PCM_STREAM_PLAYBACK", uid) == -1) { + SOFTMIXER_NOMEM(mixer->api); + goto fail_verb_name; + } + } else { - if (asprintf(&apiVerb, "%s:capture", pcm->uid) == -1) - goto OnErrorExit; - if (asprintf(&apiInfo, "HAL:%s SND_PCM_STREAM_PLAYBACK", uid) == -1) - goto OnErrorExit; + if (asprintf(&apiVerb, "%s:capture", pcm->uid) == -1) { + SOFTMIXER_NOMEM(mixer->api); + goto fail_pcm_channels; + } + if (asprintf(&apiInfo, "HAL:%s SND_PCM_STREAM_PLAYBACK", uid) == -1) { + SOFTMIXER_NOMEM(mixer->api); + goto fail_verb_name; + } } apiVerbHandleT *handle = calloc(1, sizeof (apiVerbHandleT)); + if (handle == NULL) { + SOFTMIXER_NOMEM(mixer->api); + goto fail_api_info; + } + handle->uid = uid; handle->pcm = pcm; handle->mixer = mixer; pcm->verb=apiVerb; + pcm->apiVerbHandle = handle; + error = afb_api_add_verb(mixer->api, apiVerb, apiInfo, ApiPcmVerbCB, handle, NULL, 0, 0); if (error) { - AFB_ApiError(mixer->api, "ApiPcmAttachOne mixer=%s verb=%s fail to Register Master control ", mixer->uid, apiVerb); - goto OnErrorExit; + AFB_ApiError(mixer->api, "%s mixer=%s verb=%s fail to Register Master control ", + __func__, mixer->uid, apiVerb); + goto fail_handle; } } else { /* no controls -> put dummy verb */ - pcm->verb = "none"; + pcm->verb = SOFTMIXER_VERB_NONE; } // free useless resource and secure others pcm->uid = strdup(pcm->uid); + if (pcm->uid == NULL) { + SOFTMIXER_NOMEM(mixer->api); + goto fail_handle; + } + const char ** ppcmplug = &(pcm->sndcard->cid.pcmplug_params); + if (*ppcmplug) { + *ppcmplug = strdup(*ppcmplug); + if (*ppcmplug == NULL) { + SOFTMIXER_NOMEM(mixer->api); + goto fail_pcm_uid; + } + } return pcm; -OnErrorExit: - free(pcm); - free(apiVerb); - free(apiInfo); +fail_pcm_uid: + free((char*)pcm->uid); +fail_handle: + free(handle); +fail_api_info: + free(apiInfo); +fail_verb_name: + free(apiVerb); +fail_pcm_channels: + pcmChannelsDestroy(mixer, pcm); +fail_pcm_sndcard_ctl: + free(pcm->sndcard->ctl); +fail_pcm_sndcard: + free(pcm->sndcard); +fail_pcm: + free ((char*)pcm->mute.name); + free ((char*)pcm->volume.name); + free(pcm); +fail: return NULL; } |