summaryrefslogtreecommitdiffstats
path: root/plugins/alsa/alsa-api-mixer.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-api-mixer.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-api-mixer.c')
-rw-r--r--plugins/alsa/alsa-api-mixer.c342
1 files changed, 170 insertions, 172 deletions
diff --git a/plugins/alsa/alsa-api-mixer.c b/plugins/alsa/alsa-api-mixer.c
index 171046b..ae08461 100644
--- a/plugins/alsa/alsa-api-mixer.c
+++ b/plugins/alsa/alsa-api-mixer.c
@@ -19,58 +19,15 @@
#define _GNU_SOURCE // needed for vasprintf
#include "alsa-softmixer.h"
-#include "alsa-bluez.h"
#include <string.h>
#include <pthread.h>
-extern Lua2cWrapperT Lua2cWrap;
static void MixerRemoveVerb(AFB_ReqT request) {
- SoftMixerT *mixer = (SoftMixerT*) afb_req_get_vcbdata(request);
- int error;
-
- for (int idx = 0; mixer->streams[idx]->uid; idx++) {
- AlsaStreamAudioT *stream = mixer->streams[idx];
- AlsaPcmCopyHandleT * copy = stream->copy;
-
- AFB_ApiNotice(mixer->api, "cleaning mixer=%s stream=%s", mixer->uid, stream->uid);
-
- error = pthread_cancel(stream->copy->rthread);
- if (error) {
- AFB_ReqFailF(request, "internal-error", "Fail to kill audio-stream threads mixer=%s", mixer->uid);
- goto OnErrorExit;
- }
-
- error = afb_api_del_verb(mixer->api, stream->uid, (void**)&mixer);
- if (error) {
- AFB_ReqFailF(request, "internal-error", "Mixer=%s fail to remove verb=%s error=%s", mixer->uid, stream->uid, strerror(error));
- goto OnErrorExit;
- }
-
- // free audio-stream dynamic structures
- snd_pcm_close(copy->pcmIn->handle);
- snd_pcm_close(copy->pcmOut->handle);
- if (copy->evtsrc) sd_event_source_unref(copy->evtsrc);
- if (copy->sdLoop) sd_event_unref(copy->sdLoop);
- }
-
- // // (Fulup to be Done) registry is attached to source
- // if (mixer->sources) ApiSourcFree (mixer);
- // if (mixer->sinks) ApiSinkFree (mixer);
- // if (mixer->loops) ApiLoopFree (mixer);
- // if (mixer->ramps) ApiRampFree (mixer);
- // if (mixer->zones) ApiZoneFree (mixer);
-
- // finally free mixer handle
- free(mixer);
- AFB_ReqSuccess(request, NULL, "Fulup: delete might not clean everything properly");
-
+ AFB_ReqFailF(request, "internal-error", "Function not implemented");
return;
-
-OnErrorExit:
- AFB_ReqFail(request, "internal-error", "fail to delete mixer");
}
STATIC json_object *MixerInfoOneStream(AlsaStreamAudioT *stream, int verbose) {
@@ -100,8 +57,7 @@ STATIC json_object * MixerInfoStreams(SoftMixerT *mixer, json_object *streamsJ,
const char * key;
json_object *valueJ;
json_object *responseJ = NULL;
- AlsaStreamAudioT **streams = mixer->streams;
-
+ AlsaStreamAudioT * stream;
switch (json_object_get_type(streamsJ)) {
@@ -109,17 +65,18 @@ STATIC json_object * MixerInfoStreams(SoftMixerT *mixer, json_object *streamsJ,
case json_type_boolean:
// list every existing stream
responseJ = json_object_new_array();
- for (int idx = 0; streams[idx]; idx++) {
- valueJ = MixerInfoOneStream(streams[idx], verbose);
+ cds_list_for_each_entry(stream, &mixer->streams.list, list) {
+ valueJ = MixerInfoOneStream(stream, verbose);
json_object_array_add(responseJ, valueJ);
}
break;
case json_type_string:
key = json_object_get_string(streamsJ);
- for (int idx = 0; streams[idx]; idx++) {
- if (strcasecmp(streams[idx]->uid, key)) continue;
- responseJ = MixerInfoOneStream(streams[idx], verbose);
+ cds_list_for_each_entry(stream, &mixer->streams.list, list) {
+ if (strcasecmp(stream->uid, key))
+ continue;
+ responseJ = MixerInfoOneStream(stream, verbose);
break;
}
break;
@@ -132,9 +89,10 @@ STATIC json_object * MixerInfoStreams(SoftMixerT *mixer, json_object *streamsJ,
__func__, json_object_get_string(streamsJ), wrap_json_get_error_string(error), wrap_json_get_error_position(error));
goto OnErrorExit;
}
- for (int idx = 0; streams[idx]; idx++) {
- if (strcasecmp(streams[idx]->uid, key)) continue;
- responseJ = MixerInfoOneStream(streams[idx], verbose);
+ cds_list_for_each_entry(stream, &mixer->streams.list, list) {
+ if (strcasecmp(stream->uid, key))
+ continue;
+ responseJ = MixerInfoOneStream(stream, verbose);
break;
}
break;
@@ -147,8 +105,8 @@ STATIC json_object * MixerInfoStreams(SoftMixerT *mixer, json_object *streamsJ,
valueJ = MixerInfoStreams(mixer, streamJ, verbose);
if (!valueJ) {
AFB_ApiError(mixer->api,
- "%s: fail to find stream=%s",
- __func__, json_object_get_string(streamsJ));
+ "%s: failed to find stream=%s",
+ __func__, json_object_get_string(streamJ));
goto OnErrorExit;
}
json_object_array_add(responseJ, valueJ);
@@ -156,7 +114,7 @@ STATIC json_object * MixerInfoStreams(SoftMixerT *mixer, json_object *streamsJ,
break;
default:
- AFB_ApiError(mixer->api, "MixerInfoStreams: unsupported json type streamsJ=%s", json_object_get_string(streamsJ));
+ AFB_ApiError(mixer->api, "%s: unsupported json type streamsJ=%s", __func__, json_object_get_string(streamsJ));
goto OnErrorExit;
}
@@ -187,7 +145,7 @@ STATIC json_object *MixerInfoRamps(SoftMixerT *mixer, json_object *rampsJ, int v
const char * key;
json_object *valueJ;
json_object *responseJ = NULL;
- AlsaVolRampT **ramps = mixer->ramps;
+ AlsaVolRampT * ramp;
switch (json_object_get_type(rampsJ)) {
@@ -195,18 +153,18 @@ STATIC json_object *MixerInfoRamps(SoftMixerT *mixer, json_object *rampsJ, int v
case json_type_boolean:
// list every existing ramp
responseJ = json_object_new_array();
- for (int idx = 0; ramps[idx]; idx++) {
+ cds_list_for_each_entry(ramp, &mixer->ramps.list, list) {
- valueJ = MixerInfoOneRamp(ramps[idx], verbose);
+ valueJ = MixerInfoOneRamp(ramp, verbose);
json_object_array_add(responseJ, valueJ);
}
break;
case json_type_string:
key = json_object_get_string(rampsJ);
- for (int idx = 0; ramps[idx]; idx++) {
- if (strcasecmp(ramps[idx]->uid, key)) continue;
- responseJ = MixerInfoOneRamp(ramps[idx], verbose);
+ cds_list_for_each_entry(ramp, &mixer->ramps.list, list) {
+ if (strcasecmp(ramp->uid, key)) continue;
+ responseJ = MixerInfoOneRamp(ramp, verbose);
break;
}
break;
@@ -214,12 +172,13 @@ STATIC json_object *MixerInfoRamps(SoftMixerT *mixer, json_object *rampsJ, int v
case json_type_object:
error = wrap_json_unpack(rampsJ, "{ss}", "uid", &key);
if (error) {
- AFB_ApiError(mixer->api, "MixerInfoRamps: missing 'uid' request rampJ=%s error=%s position=%d", json_object_get_string(rampsJ), wrap_json_get_error_string(error), wrap_json_get_error_position(error));
+ AFB_ApiError(mixer->api, "%s: missing 'uid' request rampJ=%s error=%s position=%d",
+ __func__, json_object_get_string(rampsJ), wrap_json_get_error_string(error), wrap_json_get_error_position(error));
goto OnErrorExit;
}
- for (int idx = 0; ramps[idx]; idx++) {
- if (strcasecmp(ramps[idx]->uid, key)) continue;
- responseJ = MixerInfoOneRamp(ramps[idx], verbose);
+ cds_list_for_each_entry(ramp, &mixer->ramps.list, list) {
+ if (strcasecmp(ramp->uid, key)) continue;
+ responseJ = MixerInfoOneRamp(ramp, verbose);
break;
}
break;
@@ -231,7 +190,7 @@ STATIC json_object *MixerInfoRamps(SoftMixerT *mixer, json_object *rampsJ, int v
valueJ = MixerInfoRamps(mixer, rampJ, verbose);
if (!valueJ) {
- AFB_ApiError(mixer->api, "MixerInfoRamps: fail to find ramp=%s", json_object_get_string(rampsJ));
+ AFB_ApiError(mixer->api, "%s: fail to find ramp=%s", __func__, json_object_get_string(rampsJ));
goto OnErrorExit;
}
json_object_array_add(responseJ, valueJ);
@@ -239,7 +198,7 @@ STATIC json_object *MixerInfoRamps(SoftMixerT *mixer, json_object *rampsJ, int v
break;
default:
- AFB_ApiError(mixer->api, "MixerInfoRamps: unsupported json type rampsJ=%s", json_object_get_string(rampsJ));
+ AFB_ApiError(mixer->api, "%s: unsupported json type rampsJ=%s", __func__, json_object_get_string(rampsJ));
goto OnErrorExit;
}
@@ -252,30 +211,34 @@ OnErrorExit:
STATIC json_object *MixerInfoOneZone(AlsaSndZoneT *zone, int verbose) {
json_object *responseJ;
+ AlsaPcmChannelT * channel;
+
if (!verbose) {
wrap_json_pack(&responseJ, "{ss}", "uid", zone->uid);
} else {
json_object *responseJ = json_object_new_object();
- if (zone->sinks) {
+ if (zone->nbSinks > 0) {
json_object *sinksJ = json_object_new_array();
- for (int jdx = 0; zone->sinks[jdx]; jdx++) {
+
+ cds_list_for_each_entry(channel, &zone->sinks.list, list) {
json_object *channelJ;
wrap_json_pack(&channelJ, "{ss,si}"
- , "uid", zone->sinks[jdx]->uid
- , "port", zone->sinks[jdx]->port
+ , "uid", channel->uid
+ , "port", channel->port
);
json_object_array_add(sinksJ, channelJ);
}
json_object_object_add(responseJ, "sinks", sinksJ);
}
- if (zone->sources) {
+ if (zone->nbSources > 0) {
json_object *sourcesJ = json_object_new_array();
- for (int jdx = 0; zone->sources[jdx]; jdx++) {
+
+ cds_list_for_each_entry(channel, &zone->sources.list, list) {
json_object *channelJ;
wrap_json_pack(&channelJ, "{ss,si}"
- , "uid", zone->sources[jdx]->uid
- , "port", zone->sources[jdx]->port
+ , "uid", channel->uid
+ , "port", channel->port
);
json_object_array_add(sourcesJ, channelJ);
}
@@ -300,7 +263,8 @@ STATIC json_object *MixerInfoZones(SoftMixerT *mixer, json_object *zonesJ, int v
const char * key;
json_object *valueJ;
json_object *responseJ = NULL;
- AlsaSndZoneT **zones = mixer->zones;
+
+ AlsaSndZoneT *zone;
switch (json_object_get_type(zonesJ)) {
@@ -308,18 +272,18 @@ STATIC json_object *MixerInfoZones(SoftMixerT *mixer, json_object *zonesJ, int v
case json_type_boolean:
// list every existing zone
responseJ = json_object_new_array();
- for (int idx = 0; zones[idx]; idx++) {
-
- valueJ = MixerInfoOneZone(zones[idx], verbose);
+ cds_list_for_each_entry(zone, &mixer->zones.list, list) {
+ valueJ = MixerInfoOneZone(zone, verbose);
json_object_array_add(responseJ, valueJ);
}
break;
case json_type_string:
key = json_object_get_string(zonesJ);
- for (int idx = 0; zones[idx]; idx++) {
- if (strcasecmp(zones[idx]->uid, key)) continue;
- responseJ = MixerInfoOneZone(zones[idx], verbose);
+ cds_list_for_each_entry(zone, &mixer->zones.list, list) {
+ if (strcasecmp(zone->uid, key))
+ continue;
+ responseJ = MixerInfoOneZone(zone, verbose);
break;
}
break;
@@ -332,9 +296,9 @@ STATIC json_object *MixerInfoZones(SoftMixerT *mixer, json_object *zonesJ, int v
__func__ ,json_object_get_string(zonesJ), wrap_json_get_error_string(error), wrap_json_get_error_position(error));
goto OnErrorExit;
}
- for (int idx = 0; zones[idx]; idx++) {
- if (strcasecmp(zones[idx]->uid, key)) continue;
- responseJ = MixerInfoOneZone(zones[idx], verbose);
+ cds_list_for_each_entry(zone, &mixer->zones.list, list) {
+ if (strcasecmp(zone->uid, key)) continue;
+ responseJ = MixerInfoOneZone(zone, verbose);
break;
}
break;
@@ -346,7 +310,7 @@ STATIC json_object *MixerInfoZones(SoftMixerT *mixer, json_object *zonesJ, int v
valueJ = MixerInfoZones(mixer, zoneJ, verbose);
if (!valueJ) {
- AFB_ApiError(mixer->api, "MixerInfoZones: fail to find zone=%s", json_object_get_string(zonesJ));
+ AFB_ApiError(mixer->api, "%s: fail to find zone=%s", __func__, json_object_get_string(zonesJ));
goto OnErrorExit;
}
json_object_array_add(responseJ, valueJ);
@@ -354,11 +318,11 @@ STATIC json_object *MixerInfoZones(SoftMixerT *mixer, json_object *zonesJ, int v
break;
default:
- AFB_ApiError(mixer->api, "MixerInfoZones: unsupported json type zonesJ=%s", json_object_get_string(zonesJ));
+ AFB_ApiError(mixer->api, "%s: unsupported json type zonesJ=%s", __func__, json_object_get_string(zonesJ));
goto OnErrorExit;
}
- AFB_ApiNotice(mixer->api, "MixerInfoZones: response=%s", json_object_get_string(responseJ));
+ AFB_ApiNotice(mixer->api, "%s: response=%s", __func__, json_object_get_string(responseJ));
return (responseJ);
OnErrorExit:
@@ -384,7 +348,7 @@ STATIC json_object *MixerInfoOnePcm(AlsaSndPcmT *pcm, int verbose) {
wrap_json_pack(&alsaJ, "{ss,ss,so}"
, "volume", pcm->volume
, "mute", pcm->mute
- , "ccount", pcm->ccount
+ , "ccount", pcm->nbChannels
);
wrap_json_pack(&responseJ, "{ss,ss,so,so}"
, "uid", pcm->uid
@@ -401,18 +365,18 @@ STATIC json_object *MixerInfoPcms(SoftMixerT *mixer, json_object *pcmsJ, snd_pcm
const char * key;
json_object *valueJ;
json_object *responseJ = NULL;
- AlsaSndPcmT **pcms;
+ AlsaSndPcmT * pcms = NULL, *pcm;
switch (direction) {
case SND_PCM_STREAM_PLAYBACK:
- pcms = mixer->sinks;
+ pcms = &mixer->sinks;
break;
case SND_PCM_STREAM_CAPTURE:
- pcms = mixer->sources;
+ pcms = &mixer->sources;
break;
default:
- AFB_ApiError(mixer->api, "MixerInfoPcms: invalid Direction should be SND_PCM_STREAM_PLAYBACK|SND_PCM_STREAM_capture");
+ AFB_ApiError(mixer->api, "%s: invalid Direction should be SND_PCM_STREAM_PLAYBACK|SND_PCM_STREAM_capture", __func__);
goto OnErrorExit;
}
@@ -422,18 +386,18 @@ STATIC json_object *MixerInfoPcms(SoftMixerT *mixer, json_object *pcmsJ, snd_pcm
case json_type_boolean:
// list every existing pcm
responseJ = json_object_new_array();
- for (int idx = 0; pcms[idx]; idx++) {
-
- valueJ = MixerInfoOnePcm(pcms[idx], verbose);
+ cds_list_for_each_entry(pcm, &pcms->list, list) {
+ valueJ = MixerInfoOnePcm(pcm, verbose);
json_object_array_add(responseJ, valueJ);
}
break;
case json_type_string:
key = json_object_get_string(pcmsJ);
- for (int idx = 0; pcms[idx]; idx++) {
- if (strcasecmp(pcms[idx]->uid, key)) continue;
- responseJ = MixerInfoOnePcm(pcms[idx], verbose);
+ cds_list_for_each_entry(pcm, &pcms->list, list) {
+ if (strcasecmp(pcm->uid, key))
+ continue;
+ responseJ = MixerInfoOnePcm(pcm, verbose);
break;
}
break;
@@ -446,9 +410,10 @@ STATIC json_object *MixerInfoPcms(SoftMixerT *mixer, json_object *pcmsJ, snd_pcm
__func__, json_object_get_string(pcmsJ), wrap_json_get_error_string(error), wrap_json_get_error_position(error));
goto OnErrorExit;
}
- for (int idx = 0; pcms[idx]; idx++) {
- if (strcasecmp(pcms[idx]->uid, key)) continue;
- responseJ = MixerInfoOnePcm(pcms[idx], verbose);
+ cds_list_for_each_entry(pcm, &pcms->list, list) {
+ if (strcasecmp(pcm->uid, key))
+ continue;
+ responseJ = MixerInfoOnePcm(pcm, verbose);
break;
}
break;
@@ -547,6 +512,7 @@ STATIC void MixerAttachVerb(AFB_ReqT request) {
json_object *argsJ = afb_req_json(request);
json_object *responseJ = json_object_new_object();
int error;
+ AlsaMixerTransaction * transaction = NULL;
error = wrap_json_unpack(argsJ, "{ss,s?s,s?s,s?o,s?o,s?o,s?o,s?o,s?o !}"
, "uid", &uid
@@ -562,35 +528,43 @@ STATIC void MixerAttachVerb(AFB_ReqT request) {
if (error) {
AFB_ReqFailF(request,
"invalid-syntax",
- "mixer=%s missing 'uid|ramps|playbacks|captures|zones|streams' error=%s args=%s",
- mixer->uid, wrap_json_get_error_string(error), json_object_get_string(argsJ));
- goto OnErrorExit;
+ "%s mixer=%s missing 'uid|ramps|playbacks|captures|zones|streams' error=%s args=%s",
+ __func__, mixer->uid, wrap_json_get_error_string(error), json_object_get_string(argsJ));
+ goto fail;
+ }
+
+ transaction = AlsaMixerTransactionNew(mixer, uid);
+ if (transaction == NULL) {
+ SOFTMIXER_NOMEM(mixer->api);
+ goto fail;
}
+ mixer->transaction = transaction;
+
AFB_ApiInfo(mixer->api, "%s set LOOPS", __func__);
if (loopsJ) {
error = ApiLoopAttach(mixer, request, uid, loopsJ);
- if (error) goto OnErrorExit;
+ if (error) goto fail;
}
- AFB_ApiInfo(mixer->api, "%s set PLAYBACK", __func__);
+ AFB_ApiInfo(mixer->api, "%s set PLAYBACKS", __func__);
if (playbacksJ) {
error = ApiSinkAttach(mixer, request, uid, playbacksJ);
- if (error) goto OnErrorExit;
+ if (error) goto fail_loop;
json_object *resultJ = MixerInfoPcms(mixer, playbacksJ, SND_PCM_STREAM_PLAYBACK, 0);
json_object_object_add(responseJ, "playbacks", resultJ);
}
- AFB_ApiInfo(mixer->api, "%s set CAPTURE", __func__);
+ AFB_ApiInfo(mixer->api, "%s set CAPTURES", __func__);
if (capturesJ) {
error = ApiSourceAttach(mixer, request, uid, capturesJ);
if (error) {
AFB_ApiError(mixer->api,"%s: source attach failed", __func__);
- goto OnErrorExit;
+ goto fail_sink;
}
json_object *resultJ = MixerInfoPcms(mixer, capturesJ, SND_PCM_STREAM_CAPTURE, 0);
@@ -601,7 +575,8 @@ STATIC void MixerAttachVerb(AFB_ReqT request) {
if (zonesJ) {
error = ApiZoneAttach(mixer, request, uid, zonesJ);
- if (error) goto OnErrorExit;
+ if (error)
+ goto fail_source;
json_object *resultJ = MixerInfoZones(mixer, zonesJ, 0);
json_object_object_add(responseJ, "zone", resultJ);
@@ -611,7 +586,8 @@ STATIC void MixerAttachVerb(AFB_ReqT request) {
if (rampsJ) {
error = ApiRampAttach(mixer, request, uid, rampsJ);
- if (error) goto OnErrorExit;
+ if (error)
+ goto fail_zone;
json_object *resultJ = MixerInfoRamps(mixer, rampsJ, 0);
json_object_object_add(responseJ, "ramps", resultJ);
@@ -621,71 +597,54 @@ STATIC void MixerAttachVerb(AFB_ReqT request) {
if (streamsJ) {
error = ApiStreamAttach(mixer, request, uid, prefix, streamsJ);
- if (error) goto OnErrorExit;
+ if (error)
+ goto fail_ramp;
json_object *resultJ = MixerInfoStreams(mixer, streamsJ, 0);
json_object_object_add(responseJ, "streams", resultJ);
}
+ error = afb_api_add_verb(mixer->api, uid, "Post Attach API", AlsaMixerTransactionVerbCB, transaction, NULL, 0, 0);
+ if (error) {
+ AFB_ApiError(mixer->api, "%s mixer=%s verb=%s fail to register post attach Verb ",
+ __func__, mixer->uid, uid);
+ goto fail_stream;
+ }
+
AFB_ApiNotice(mixer->api, "%s responseJ=%s", __func__, json_object_get_string(responseJ));
AFB_ReqSuccess(request, responseJ, NULL);
AFB_ApiInfo(mixer->api,"%s DONE", __func__);
return;
-OnErrorExit:
+fail_stream:
+ // TODO remove created streams
+fail_ramp:
+ // TODO remove created ramps
+fail_zone:
+ // TODO remove created zone
+fail_source:
+ // TODO remove created sources
+fail_sink:
+ // TODO remove created sinks
+fail_loop:
+ // TODO remove created loops
+fail:
+
+ if (mixer->transaction)
+ free(mixer->transaction);
+
AFB_ApiError(mixer->api,"%s FAILED", __func__);
return;
}
-static void MixerBluezAlsaDevVerb(AFB_ReqT request) {
- SoftMixerT *mixer = (SoftMixerT*) afb_req_get_vcbdata(request);
- char * interface = NULL, *device = NULL, *profile = NULL;
- json_object *argsJ = afb_req_json(request);
- int error;
-
- if (json_object_is_type(argsJ,json_type_null)) {
- goto parsed;
- }
-
- error = wrap_json_unpack(argsJ, "{ss,ss,ss !}"
- , "interface", &interface
- , "device", &device
- , "profile", &profile
- );
-
- if (error) {
- AFB_ReqFailF(request,
- "invalid-syntax",
- "mixer=%s missing 'interface|device|profile' error=%s args=%s",
- mixer->uid, wrap_json_get_error_string(error), json_object_get_string(argsJ));
- goto OnErrorExit;
- }
-
-parsed:
- AFB_ApiNotice(mixer->api, "%s: interface %s, device %s, profile %s\n", __func__, interface, device, profile);
- error = alsa_bluez_set_remote_device(interface, device, profile);
- if (error) {
- AFB_ReqFailF(request,
- "runtime error",
- "Unable to set device , err %d", error);
- goto OnErrorExit;
- }
-
- AFB_ReqSuccess(request, NULL, NULL);
-
-OnErrorExit:
- return;
-}
-
// Every HAL export the same API & Interface Mapping from SndCard to AudioLogic is done through alsaHalSndCardT
STATIC AFB_ApiVerbs CtrlApiVerbs[] = {
/* VERB'S NAME FUNCTION TO CALL SHORT DESCRIPTION */
{ .verb = "attach", .callback = MixerAttachVerb, .info = "attach resources to mixer"},
{ .verb = "remove", .callback = MixerRemoveVerb, .info = "remove existing mixer streams, zones, ..."},
{ .verb = "info", .callback = MixerInfoVerb, .info = "list existing mixer streams, zones, ..."},
- { .verb = "bluezalsa_dev", .callback = MixerBluezAlsaDevVerb, .info = "set bluez alsa device"},
{ .verb = NULL} /* marker for end of the array */
};
@@ -704,6 +663,8 @@ CTLP_CAPI(MixerAttach, source, argsJ, responseJ) {
json_object *playbackJ = NULL, *captureJ = NULL, *zonesJ = NULL, *streamsJ = NULL, *rampsJ = NULL, *loopsJ = NULL;
const char* uid = source->uid, *prefix = NULL;
+ AlsaMixerTransaction * transaction = NULL;
+
int error;
error = wrap_json_unpack(argsJ, "{s?s, s?o,s?o,s?o,s?o,s?o,s?o !}"
@@ -716,10 +677,17 @@ CTLP_CAPI(MixerAttach, source, argsJ, responseJ) {
, "streams", &streamsJ
);
if (error) {
- AFB_ApiError(mixer->api, "MixerAttachVerb: invalid-syntax mixer=%s error=%s args=%s", mixer->uid, wrap_json_get_error_string(error), json_object_get_string(argsJ));
+ AFB_ApiError(mixer->api, "%s: invalid-syntax mixer=%s error=%s args=%s",
+ __func__, mixer->uid, wrap_json_get_error_string(error), json_object_get_string(argsJ));
goto OnErrorExit;
}
+ transaction = AlsaMixerTransactionNew(mixer, uid);
+ if (transaction == NULL) {
+ SOFTMIXER_NOMEM(mixer->api);
+ goto OnErrorExit;
+ }
+
if (playbackJ) {
error = ApiSinkAttach(mixer, NULL, uid, playbackJ);
if (error) goto OnErrorExit;
@@ -759,6 +727,10 @@ OnErrorExit:
CTLP_CAPI(MixerCreate, source, argsJ, responseJ) {
SoftMixerT *mixer = calloc(1, sizeof (SoftMixerT));
+ if (mixer == NULL) {
+ SOFTMIXER_NOMEM(source->api);
+ goto fail;
+ }
source->context = mixer;
int error;
@@ -770,8 +742,8 @@ CTLP_CAPI(MixerCreate, source, argsJ, responseJ) {
mixer->max.ramps = SMIXER_DEFLT_RAMPS;
if (json_object_get_type(argsJ) != json_type_object) {
- AFB_ApiError(source->api, "_mixer_new_: invalid object type= %s", json_object_get_string(argsJ));
- goto OnErrorExit;
+ AFB_ApiError(source->api, "%s: invalid object type= %s", __func__, json_object_get_string(argsJ));
+ goto fail;
}
error = wrap_json_unpack(argsJ, "{ss,s?s,s?i,s?i,s?i,s?i,s?i,s?i !}"
@@ -785,31 +757,57 @@ CTLP_CAPI(MixerCreate, source, argsJ, responseJ) {
, "max_ramp", &mixer->max.ramps
);
if (error) {
- AFB_ApiNotice(source->api, "_mixer_new_ missing 'uid|max_loop|max_sink|max_source|max_zone|max_stream|max_ramp' error=%s mixer=%s", wrap_json_get_error_string(error), json_object_get_string(argsJ));
- goto OnErrorExit;
+ AFB_ApiNotice(source->api,
+ "%s missing 'uid|max_loop|max_sink|max_source|max_zone|max_stream|max_ramp' error=%s mixer=%s",
+ __func__, wrap_json_get_error_string(error), json_object_get_string(argsJ));
+ goto fail_mixer;
}
// make sure string do not get deleted
mixer->uid = strdup(mixer->uid);
- if (mixer->info)mixer->info = strdup(mixer->info);
-
- mixer->loops = calloc(mixer->max.loops + 1, sizeof (void*));
- mixer->sinks = calloc(mixer->max.sinks + 1, sizeof (void*));
- mixer->sources = calloc(mixer->max.sources + 1, sizeof (void*));
- mixer->zones = calloc(mixer->max.zones + 1, sizeof (void*));
- mixer->streams = calloc(mixer->max.streams + 1, sizeof (void*));
- mixer->ramps = calloc(mixer->max.ramps + 1, sizeof (void*));
+ if (mixer->uid == NULL) {
+ SOFTMIXER_NOMEM(source->api);
+ goto fail_mixer;
+ }
+ if (mixer->info) {
+ mixer->info = strdup(mixer->info);
+ if (mixer->info == NULL) {
+ SOFTMIXER_NOMEM(source->api);
+ goto fail_uid;
+ }
+ }
+
+ mixer->nbLoops = 0;
+ mixer->nbSinks = 0;
+ mixer->nbSources = 0;
+ mixer->nbZones = 0;
+ mixer->nbStreams = 0;
+ mixer->nbZones = 0;
+
+ CDS_INIT_LIST_HEAD(&mixer->loops.list);
+ CDS_INIT_LIST_HEAD(&mixer->sinks.list);
+ CDS_INIT_LIST_HEAD(&mixer->sources.list);
+ CDS_INIT_LIST_HEAD(&mixer->zones.list);
+ CDS_INIT_LIST_HEAD(&mixer->streams.list);
+ CDS_INIT_LIST_HEAD(&mixer->ramps.list);
mixer->sdLoop = AFB_GetEventLoop(source->api);
mixer->api = source->api;
afb_api_set_userdata(source->api, mixer);
error = LoadStaticVerbs(mixer, CtrlApiVerbs);
- if (error) goto OnErrorExit;
+ if (error)
+ goto fail_info;
return 0;
-OnErrorExit:
+fail_info:
+ free((char*)mixer->info);
+fail_uid:
+ free((char*)mixer->uid);
+fail_mixer:
+ free(mixer);
+fail:
return -1;
}