aboutsummaryrefslogtreecommitdiffstats
path: root/plugins/alsa/alsa-api-frontend.c
diff options
context:
space:
mode:
authorFulup Ar Foll <fulup@iot.bzh>2018-05-18 13:31:36 +0200
committerFulup Ar Foll <fulup@iot.bzh>2018-05-18 13:31:36 +0200
commit7454d66bb47349418f8f65b8d7bec79039a2be32 (patch)
tree9816b7c9d213c890adfcde58646e50e6545ebb70 /plugins/alsa/alsa-api-frontend.c
parent3fd11a5eb799a391351334b3580c5582a065f780 (diff)
Implements volume ramping
Diffstat (limited to 'plugins/alsa/alsa-api-frontend.c')
-rw-r--r--plugins/alsa/alsa-api-frontend.c121
1 files changed, 87 insertions, 34 deletions
diff --git a/plugins/alsa/alsa-api-frontend.c b/plugins/alsa/alsa-api-frontend.c
index 91ce63f..d39c92e 100644
--- a/plugins/alsa/alsa-api-frontend.c
+++ b/plugins/alsa/alsa-api-frontend.c
@@ -24,9 +24,29 @@
// Fulup need to be cleanup with new controller version
extern Lua2cWrapperT Lua2cWrap;
-STATIC int ProcessOneSubdev(CtlSourceT *source, AlsaSndLoopT *loop, json_object *subdevJ, AlsaPcmHwInfoT *loopDefParams,AlsaPcmInfoT *subdev) {
+STATIC int ProcessOneRamp(CtlSourceT *source, const char* uid, json_object *rampJ, AlsaVolRampT *ramp) {
+ const char*rampUid;
+
+ int error = wrap_json_unpack(rampJ, "{ss,si,si,si !}"
+ , "uid", &rampUid
+ , "delay", &ramp->delay
+ , "up", &ramp->stepUp
+ , "down", &ramp->stepDown
+ );
+ if (error) goto OnErrorExit;
+
+ ramp->delay=ramp->delay*100; // move from ms to us
+ ramp->uid = strdup(rampUid);
+ return 0;
+
+OnErrorExit:
+ AFB_ApiError(source->api, "ProcessOneRamp: sndcard=%s ramps: missing (uid||delay|up|down) json=%s", uid, json_object_get_string(rampJ));
+ return -1;
+}
+
+STATIC int ProcessOneSubdev(CtlSourceT *source, AlsaSndLoopT *loop, json_object *subdevJ, AlsaPcmHwInfoT *loopDefParams, AlsaPcmInfoT *subdev) {
json_object *paramsJ = NULL;
-
+
int error = wrap_json_unpack(subdevJ, "{si,si,s?o !}", "subdev", &subdev->subdev, "numid", &subdev->numid, "params", &paramsJ);
if (error) {
AFB_ApiError(source->api, "ProcessOneSubdev: loop=%s missing (uid|subdev|numid) json=%s", loop->uid, json_object_get_string(subdevJ));
@@ -41,7 +61,7 @@ STATIC int ProcessOneSubdev(CtlSourceT *source, AlsaSndLoopT *loop, json_object
}
} else {
// use global loop params definition as default
- memcpy (&subdev->params, loopDefParams, sizeof(AlsaPcmHwInfoT));
+ memcpy(&subdev->params, loopDefParams, sizeof (AlsaPcmHwInfoT));
}
// create a fake uid and complete subdev info from loop handle
char subuid[30];
@@ -66,17 +86,25 @@ OnErrorExit:
}
STATIC int ProcessOneLoop(CtlSourceT *source, json_object *loopJ, AlsaSndLoopT *loop) {
- json_object *subdevsJ = NULL, *devicesJ = NULL, *paramsJ = NULL;
+ json_object *subdevsJ = NULL, *devicesJ = NULL, *paramsJ = NULL, *rampsJ = NULL;
int error;
- error = wrap_json_unpack(loopJ, "{ss,s?s,s?s,s?i,s?o,so,s?o !}", "uid", &loop->uid, "devpath", &loop->devpath, "cardid", &loop->cardid
- , "cardidx", &loop->cardidx, "devices", &devicesJ, "subdevs", &subdevsJ, "params", &paramsJ);
+ error = wrap_json_unpack(loopJ, "{ss,s?s,s?s,s?i,s?o,so,s?o,s?o !}"
+ , "uid", &loop->uid
+ , "devpath", &loop->devpath
+ , "cardid", &loop->cardid
+ , "cardidx", &loop->cardidx
+ , "devices", &devicesJ
+ , "subdevs", &subdevsJ
+ , "params", &paramsJ
+ , "ramps", &rampsJ
+ );
if (error || !loop->uid || !subdevsJ || (!loop->devpath && !loop->cardid && loop->cardidx)) {
AFB_ApiNotice(source->api, "ProcessOneLoop missing 'uid|devpath|cardid|cardidx|devices|subdevs' loop=%s", json_object_get_string(loopJ));
goto OnErrorExit;
}
- AlsaPcmHwInfoT *loopDefParams =alloca(sizeof(AlsaPcmHwInfoT));
+ AlsaPcmHwInfoT *loopDefParams = alloca(sizeof (AlsaPcmHwInfoT));
if (paramsJ) {
error = ProcessSndParams(source, loop->uid, paramsJ, loopDefParams);
if (error) {
@@ -85,11 +113,11 @@ STATIC int ProcessOneLoop(CtlSourceT *source, json_object *loopJ, AlsaSndLoopT *
}
} else {
loopDefParams->rate = ALSA_DEFAULT_PCM_RATE;
- loopDefParams->rate= ALSA_DEFAULT_PCM_RATE;
- loopDefParams->access=SND_PCM_ACCESS_RW_INTERLEAVED;
- loopDefParams->format=SND_PCM_FORMAT_S16_LE;
- loopDefParams->channels=2;
- loopDefParams->sampleSize=0;
+ loopDefParams->rate = ALSA_DEFAULT_PCM_RATE;
+ loopDefParams->access = SND_PCM_ACCESS_RW_INTERLEAVED;
+ loopDefParams->format = SND_PCM_FORMAT_S16_LE;
+ loopDefParams->channels = 2;
+ loopDefParams->sampleSize = 0;
}
// Fake a sound card to check if loop is a valid Alsa snd driver
@@ -104,11 +132,36 @@ STATIC int ProcessOneLoop(CtlSourceT *source, json_object *loopJ, AlsaSndLoopT *
AFB_ApiError(source->api, "ProcessOneLoop: loop=%s not found config=%s", loop->uid, json_object_get_string(loopJ));
goto OnErrorExit;
}
- loop->uid= sndLoop.uid;
- loop->devpath= sndLoop.devpath;
- loop->cardid=sndLoop.cardid;
- loop->cardidx=sndLoop.cardidx;
-
+ loop->uid = sndLoop.uid;
+ loop->devpath = sndLoop.devpath;
+ loop->cardid = sndLoop.cardid;
+ loop->cardidx = sndLoop.cardidx;
+ loop->registry= calloc (1,sizeof(RegistryHandleT));
+
+ // process volume ramps
+ if (rampsJ) {
+ int rcount;
+ switch (json_object_get_type(rampsJ)) {
+ case json_type_object:
+ rcount = 1;
+ loop->ramps = calloc(rcount+1, sizeof (AlsaVolRampT));
+ error = ProcessOneRamp(source, loop->uid, rampsJ, &loop->ramps[0]);
+ if (error) goto OnErrorExit;
+ break;
+ case json_type_array:
+ rcount = (int) json_object_array_length(rampsJ);
+ loop->ramps = calloc(rcount+1, sizeof (AlsaVolRampT));
+ for (int idx = 0; idx < rcount; idx++) {
+ json_object *rampJ = json_object_array_get_idx(rampsJ, idx);
+ error = ProcessOneRamp(source, loop->uid, rampJ, &loop->ramps[idx]);
+ if (error) goto OnErrorExit;
+ }
+ break;
+ default:
+ AFB_ApiError(source->api, "ProcessOneLoop:%s invalid ramps=%s", loop->uid, json_object_get_string(rampsJ));
+ goto OnErrorExit;
+ }
+ }
// Default devices is payback=0 capture=1
if (!devicesJ) {
@@ -149,37 +202,37 @@ OnErrorExit:
return -1;
}
-PUBLIC int SndFrontend (CtlSourceT *source, json_object *argsJ) {
+PUBLIC int SndFrontend(CtlSourceT *source, json_object *argsJ) {
SoftMixerHandleT *mixerHandle = (SoftMixerHandleT*) source->context;
int error;
-
- assert (mixerHandle);
-
- if (mixerHandle->loop) {
+
+ assert(mixerHandle);
+
+ if (mixerHandle->frontend) {
AFB_ApiError(source->api, "SndFrontend: mixer=%s SndFrontend already declared %s", mixerHandle->uid, json_object_get_string(argsJ));
- goto OnErrorExit;
+ goto OnErrorExit;
}
-
- mixerHandle->loop= calloc(1, sizeof (AlsaSndLoopT));
-
+
+ mixerHandle->frontend = calloc(1, sizeof (AlsaSndLoopT));
+
// or syntax purpose array is accepted but frontend should have a single driver entry
- json_type type= json_object_get_type(argsJ);
+ json_type type = json_object_get_type(argsJ);
if (type == json_type_array) {
- size_t count= json_object_array_length(argsJ);
+ size_t count = json_object_array_length(argsJ);
if (count != 1) {
AFB_ApiError(source->api, "SndFrontend: mixer=%s frontend only support on input driver args=%s", mixerHandle->uid, json_object_get_string(argsJ));
- goto OnErrorExit;
+ goto OnErrorExit;
}
- argsJ= json_object_array_get_idx(argsJ,0);
- }
-
- type= json_object_get_type(argsJ);
+ argsJ = json_object_array_get_idx(argsJ, 0);
+ }
+
+ type = json_object_get_type(argsJ);
if (type != json_type_object) {
AFB_ApiError(source->api, "SndFrontend: mixer=%s invalid object type= %s", mixerHandle->uid, json_object_get_string(argsJ));
goto OnErrorExit;
}
- error = ProcessOneLoop(source, argsJ, mixerHandle->loop);
+ error = ProcessOneLoop(source, argsJ, mixerHandle->frontend);
if (error) {
AFB_ApiError(source->api, "SndFrontend: mixer=%s invalid object= %s", mixerHandle->uid, json_object_get_string(argsJ));
goto OnErrorExit;