From 6f2913ab5e366e8f3df12a7df11a85b7b6574e2c Mon Sep 17 00:00:00 2001 From: Manuel Bachmann Date: Tue, 22 Dec 2015 15:17:37 +0100 Subject: [PATCH] Audio API: manage multiple-channel volume You can now set the volume for multiple channels independantly by using the "value=<1>,<2>..." syntax. Signed-off-by: Manuel Bachmann --- plugins/audio/audio-alsa.c | 38 ++++++++++++++++++++++++++++++-------- plugins/audio/audio-alsa.h | 2 +- plugins/audio/audio-api.c | 45 +++++++++++++++++++++++++++++++++++---------- plugins/audio/audio-api.h | 4 ++-- 4 files changed, 68 insertions(+), 21 deletions(-) diff --git a/plugins/audio/audio-alsa.c b/plugins/audio/audio-alsa.c index 8e56e52d..1f54f244 100644 --- a/plugins/audio/audio-alsa.c +++ b/plugins/audio/audio-alsa.c @@ -19,6 +19,17 @@ #include "audio-api.h" #include "audio-alsa.h" +snd_mixer_selem_channel_id_t SCHANNELS[8] = { + SND_MIXER_SCHN_FRONT_LEFT, + SND_MIXER_SCHN_FRONT_RIGHT, + SND_MIXER_SCHN_FRONT_CENTER, + SND_MIXER_SCHN_REAR_LEFT, + SND_MIXER_SCHN_REAR_RIGHT, + SND_MIXER_SCHN_REAR_CENTER, + SND_MIXER_SCHN_SIDE_LEFT, + SND_MIXER_SCHN_SIDE_RIGHT +}; + PUBLIC unsigned char _alsa_init (const char *name, audioCtxHandleT *ctx) { snd_pcm_t *dev; @@ -28,7 +39,7 @@ PUBLIC unsigned char _alsa_init (const char *name, audioCtxHandleT *ctx) { snd_mixer_elem_t *mixer_elm; unsigned int rate = 22050; long vol, vol_min, vol_max; - int num; + int num, i; if (snd_pcm_open (&dev, name, SND_PCM_STREAM_PLAYBACK, 0) < 0) return 0; @@ -105,7 +116,8 @@ PUBLIC unsigned char _alsa_init (const char *name, audioCtxHandleT *ctx) { dev_ctx[num]->thr_finished = 0; /* make the client context aware of current card state */ - ctx->volume = _alsa_get_volume (num); + for (i = 0; i < 8; i++) + ctx->volume[i] = _alsa_get_volume (num, i); ctx->mute = _alsa_get_mute (num); ctx->idx = num; @@ -155,22 +167,32 @@ PUBLIC void _alsa_stop (unsigned int num) { pthread_join(dev_ctx[num]->thr, NULL); } -PUBLIC unsigned int _alsa_get_volume (unsigned int num) { +PUBLIC int _alsa_get_volume (unsigned int num, unsigned int channel) { if (!dev_ctx || !dev_ctx[num] || !dev_ctx[num]->mixer_elm) return; - snd_mixer_selem_get_playback_volume (dev_ctx[num]->mixer_elm, SND_MIXER_SCHN_FRONT_LEFT, &dev_ctx[num]->vol); + snd_mixer_selem_get_playback_volume (dev_ctx[num]->mixer_elm, SCHANNELS[channel], &dev_ctx[num]->vol); - return (unsigned int)(dev_ctx[num]->vol*100)/dev_ctx[num]->vol_max; + return (int)(dev_ctx[num]->vol*100)/dev_ctx[num]->vol_max; } -PUBLIC unsigned int _alsa_set_volume (unsigned int num, unsigned int vol) { +PUBLIC void _alsa_set_volume (unsigned int num, unsigned int channel, int vol) { - if (!dev_ctx || !dev_ctx[num] || !dev_ctx[num]->mixer_elm || vol > 100) + if (!dev_ctx || !dev_ctx[num] || !dev_ctx[num]->mixer_elm || + 0 > vol > 100) return; - snd_mixer_selem_set_playback_volume_all (dev_ctx[num]->mixer_elm, (vol*dev_ctx[num]->vol_max)/100); + snd_mixer_selem_set_playback_volume (dev_ctx[num]->mixer_elm, SCHANNELS[channel], (vol*dev_ctx[num]->vol_max)/100); + +} + +PUBLIC void _alsa_set_volume_all (unsigned int num, int vol) { + + if (!dev_ctx || !dev_ctx[num] || !dev_ctx[num]->mixer_elm || + 0 > vol > 100) + + snd_mixer_selem_set_playback_volume_all (dev_ctx[num]->mixer_elm, (vol*dev_ctx[num]->vol_max)/100); } PUBLIC unsigned char _alsa_get_mute (unsigned int num) { diff --git a/plugins/audio/audio-alsa.h b/plugins/audio/audio-alsa.h index 56b4f55f..85545d57 100644 --- a/plugins/audio/audio-alsa.h +++ b/plugins/audio/audio-alsa.h @@ -39,7 +39,7 @@ struct dev_ctx { }; STATIC void* _play_thread_fn (void *); -PUBLIC unsigned int _alsa_get_volume (unsigned int); +PUBLIC int _alsa_get_volume (unsigned int, unsigned int); PUBLIC unsigned char _alsa_get_mute (unsigned int); static struct dev_ctx **dev_ctx = NULL; diff --git a/plugins/audio/audio-api.c b/plugins/audio/audio-api.c index 60a5a962..915f8c6e 100644 --- a/plugins/audio/audio-api.c +++ b/plugins/audio/audio-api.c @@ -26,10 +26,12 @@ STATIC audioCtxHandleT* initAudioCtx () { audioCtxHandleT *ctx; + int i; ctx = malloc (sizeof(audioCtxHandleT)); ctx->idx = -1; - ctx->volume = 25; + for (i = 0; i < 8; i++) + ctx->volume[i] = 25; ctx->channels = 2; ctx->mute = 0; ctx->is_playing = 0; @@ -82,28 +84,51 @@ STATIC json_object* volume (AFB_request *request) { /* AFB_SESSION_CHECK */ audioCtxHandleT *ctx = (audioCtxHandleT*)request->client->ctx; const char *value = getQueryValue (request, "value"); json_object *jresp; - int volume; + int volume[8], i; + char *volume_i; char volume_str[256]; + int len_str = 0; /* no "?value=" parameter : return current state */ if (!value) { - ctx->volume = _alsa_get_volume (ctx->idx); - snprintf (volume_str, sizeof(volume_str), "%d", ctx->volume); + for (i = 0; i < 8; i++) { + ctx->volume[i] = _alsa_get_volume (ctx->idx, i); + snprintf (volume_str+len_str, sizeof(volume_str)-len_str, "%d,", ctx->volume[i]); + len_str = strlen(volume_str); + } jresp = json_object_new_object(); json_object_object_add (jresp, "volume", json_object_new_string(volume_str)); } /* "?value=" parameter, set volume */ else { - volume = atoi (value); - if (100 < volume < 0) { + volume_i = strdup (value); + volume_i = strtok (volume_i, ","); + volume[0] = atoi (volume_i); + + if (100 < volume[0] < 0) { + free (volume_i); request->errcode = MHD_HTTP_SERVICE_UNAVAILABLE; return (jsonNewMessage (AFB_FAIL, "Volume must be between 0 and 100")); } - ctx->volume = volume; - _alsa_set_volume (ctx->idx, ctx->volume); - - snprintf (volume_str, sizeof(volume_str), "%d", ctx->volume); + ctx->volume[0] = volume[0]; + _alsa_set_volume (ctx->idx, 0, ctx->volume[0]); + snprintf (volume_str, sizeof(volume_str), "%d,", ctx->volume[0]); + + for (i = 1; i < 8; i++) { + volume_i = strtok (NULL, ","); + /* if there is only one value, set all channels to this one */ + if (!volume_i && i == 1) + _alsa_set_volume_all (ctx->idx, ctx->volume[0]); + if (!volume_i || 100 < atoi(volume_i) < 0) { + ctx->volume[i] = _alsa_get_volume (ctx->idx, i); + } else { + ctx->volume[i] = atoi(volume_i); + _alsa_set_volume (ctx->idx, i, ctx->volume[i]); + } + len_str = strlen(volume_str); + snprintf (volume_str+len_str, sizeof(volume_str)-len_str, "%d,", ctx->volume[i]); + } jresp = json_object_new_object(); json_object_object_add (jresp, "volume", json_object_new_string(volume_str)); } diff --git a/plugins/audio/audio-api.h b/plugins/audio/audio-api.h index 12f70a8e..b6669ec9 100644 --- a/plugins/audio/audio-api.h +++ b/plugins/audio/audio-api.h @@ -36,10 +36,10 @@ typedef struct { typedef struct { audioDevT *radio; /* pointer to client audio card */ int idx; /* audio card index within global array */ - unsigned int volume; /* audio volume : 0-100 */ + int volume[8]; /* audio volume (8 channels) : 0-100 */ unsigned int channels; /* audio channels : 1(mono)/2(stereo)... */ unsigned char mute; /* audio muted : 0(false)/1(true) */ - unsigned char is_playing; /* audio is playing: 0(false)/1(true) */ + unsigned char is_playing; /* audio is playing: 0(false)/1(true) */ } audioCtxHandleT; -- 2.16.6