2 * Copyright (C) 2015 "IoT.bzh"
3 * Author "Manuel Bachmann"
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
21 #include "audio-api.h"
22 #include "audio-alsa.h"
24 #include "audio-pulse.h"
27 #include "afb-plugin.h"
28 #include "afb-req-itf.h"
30 /* ------ BACKEND FUNCTIONS ------- */
32 void _backend_init (const char *name, audioCtxHandleT *ctx) {
34 char *backend_env = getenv ("AFB_AUDIO_OUTPUT");
35 unsigned char res = 0;
38 if (!backend_env || (strcasecmp (backend_env, "Pulse") == 0))
39 res = _pulse_init (name, ctx);
42 res = _alsa_init (name, ctx);
45 fprintf (stderr, "Could not initialize Audio backend\n");
48 void _backend_free (audioCtxHandleT *ctx) {
51 if (ctx->audio_dev) _pulse_free (ctx); else
53 _alsa_free (ctx->name);
56 void _backend_play (audioCtxHandleT *ctx) {
59 if (ctx->audio_dev) _pulse_play (ctx); else
61 _alsa_play (ctx->idx);
64 void _backend_stop (audioCtxHandleT *ctx) {
67 if (ctx->audio_dev) _pulse_stop (ctx); else
69 _alsa_stop (ctx->idx);
72 unsigned int _backend_get_volume (audioCtxHandleT *ctx, unsigned int channel) {
75 if (ctx->audio_dev) return _pulse_get_volume (ctx, channel); else
77 return _alsa_get_volume (ctx->idx, channel);
80 void _backend_set_volume (audioCtxHandleT *ctx, unsigned int channel, unsigned int vol) {
83 if (ctx->audio_dev) _pulse_set_volume (ctx, channel, vol); else
85 _alsa_set_volume (ctx->idx, channel, vol);
88 void _backend_set_volume_all (audioCtxHandleT *ctx, unsigned int vol) {
91 if (ctx->audio_dev) _pulse_set_volume_all (ctx, vol); else
93 _alsa_set_volume_all (ctx->idx, vol);
96 unsigned char _backend_get_mute (audioCtxHandleT *ctx) {
99 if (ctx->audio_dev) return _pulse_get_mute (ctx); else
101 return _alsa_get_mute (ctx->idx);
104 void _backend_set_mute (audioCtxHandleT *ctx, unsigned char mute) {
107 if (ctx->audio_dev) _pulse_set_mute (ctx, mute); else
109 _alsa_set_mute (ctx->idx, mute);
112 void _backend_set_channels (audioCtxHandleT *ctx, unsigned int channels) {
115 if (ctx->audio_dev) return; else
117 _alsa_set_channels (ctx->idx, channels);
120 /* ------ LOCAL HELPER FUNCTIONS --------- */
122 /* private client context creation ; default values */
123 STATIC audioCtxHandleT* initAudioCtx () {
125 audioCtxHandleT *ctx;
128 ctx = malloc (sizeof(audioCtxHandleT));
129 ctx->audio_dev = NULL;
131 for (i = 0; i < 8; i++)
140 STATIC AFB_error releaseAudio (audioCtxHandleT *ctx) {
145 /* clean client context */
151 /* called when client session dies [e.g. client quits for more than 15mns] */
152 STATIC void freeAudio (void *context) {
157 /* ------ PUBLIC PLUGIN FUNCTIONS --------- */
159 STATIC void init (struct afb_req request) { /* AFB_SESSION_CHECK */
163 /* create a private client context */
164 if (!request.context)
165 request.context = initAudioCtx();
167 _backend_init("default", request.context);
169 jresp = json_object_new_object();
170 json_object_object_add (jresp, "info", json_object_new_string ("Audio initialized"));
172 afb_req_success (request, jresp, "Audio initiliazed");
175 STATIC void volume (struct afb_req request) { /* AFB_SESSION_CHECK */
177 audioCtxHandleT *ctx = (audioCtxHandleT*)request.context;
178 const char *value = afb_req_argument (request, "value");
180 unsigned int volume[8], i;
182 char volume_str[256];
185 /* no "?value=" parameter : return current state */
187 for (i = 0; i < 8; i++) {
188 ctx->volume[i] = _backend_get_volume (ctx, i);
189 snprintf (volume_str+len_str, sizeof(volume_str)-len_str, "%d,", ctx->volume[i]);
190 len_str = strlen(volume_str);
192 jresp = json_object_new_object();
193 json_object_object_add (jresp, "volume", json_object_new_string(volume_str));
196 /* "?value=" parameter, set volume */
198 volume_i = strdup (value);
199 volume_i = strtok (volume_i, ",");
200 volume[0] = (unsigned int) atoi (volume_i);
202 if (100 < volume[0]) {
204 //request.errcode = MHD_HTTP_SERVICE_UNAVAILABLE;
205 afb_req_fail (request, "Failed", "Volume must be between 0 and 100");
208 ctx->volume[0] = volume[0];
209 _backend_set_volume (ctx, 0, ctx->volume[0]);
210 snprintf (volume_str, sizeof(volume_str), "%d,", ctx->volume[0]);
212 for (i = 1; i < 8; i++) {
213 volume_i = strtok (NULL, ",");
214 /* if there is only one value, set all channels to this one */
215 if (!volume_i && i == 1)
216 _backend_set_volume_all (ctx, ctx->volume[0]);
217 if (!volume_i || 100 < atoi(volume_i) || atoi(volume_i) < 0) {
218 ctx->volume[i] = _backend_get_volume (ctx, i);
220 ctx->volume[i] = (unsigned int) atoi(volume_i);
221 _backend_set_volume (ctx, i, ctx->volume[i]);
223 len_str = strlen(volume_str);
224 snprintf (volume_str+len_str, sizeof(volume_str)-len_str, "%d,", ctx->volume[i]);
226 jresp = json_object_new_object();
227 json_object_object_add (jresp, "volume", json_object_new_string(volume_str));
230 afb_req_success (request, jresp, "Audio - Volume changed");
233 STATIC void channels (struct afb_req request) { /* AFB_SESSION_CHECK */
235 audioCtxHandleT *ctx = (audioCtxHandleT*)request.context;
236 const char *value = afb_req_argument (request, "value");
237 json_object *jresp = json_object_new_object();
238 char channels_str[256];
240 /* no "?value=" parameter : return current state */
242 snprintf (channels_str, sizeof(channels_str), "%d", ctx->channels);
243 json_object_object_add (jresp, "channels", json_object_new_string (channels_str));
246 /* "?value=" parameter, set channels */
248 ctx->channels = (unsigned int) atoi (value);
249 _backend_set_channels (ctx, ctx->channels);
251 snprintf (channels_str, sizeof(channels_str), "%d", ctx->channels);
252 json_object_object_add (jresp, "channels", json_object_new_string (channels_str));
255 afb_req_success (request, jresp, "Audio - Channels set");
258 STATIC void mute (struct afb_req request) { /* AFB_SESSION_CHECK */
260 audioCtxHandleT *ctx = (audioCtxHandleT*)request.context;
261 const char *value = afb_req_argument (request, "value");
262 json_object *jresp = json_object_new_object();
264 /* no "?value=" parameter : return current state */
266 ctx->mute = _backend_get_mute (ctx);
268 json_object_object_add (jresp, "mute", json_object_new_string ("on"))
269 : json_object_object_add (jresp, "mute", json_object_new_string ("off"));
272 /* "?value=" parameter is "1" or "true" */
273 else if ( atoi(value) == 1 || !strcasecmp(value, "true") ) {
275 _backend_set_mute (ctx, ctx->mute);
277 json_object_object_add (jresp, "mute", json_object_new_string ("on"));
280 /* "?value=" parameter is "0" or "false" */
281 else if ( atoi(value) == 0 || !strcasecmp(value, "false") ) {
283 _backend_set_mute (ctx, ctx->mute);
285 json_object_object_add (jresp, "mute", json_object_new_string ("off"));
288 afb_req_success (request, jresp, "Audio - Mute set");
291 STATIC void play (struct afb_req request) { /* AFB_SESSION_CHECK */
293 audioCtxHandleT *ctx = (audioCtxHandleT*)request.context;
294 const char *value = afb_req_argument (request, "value");
295 json_object *jresp = json_object_new_object();
297 /* no "?value=" parameter : return current state */
300 json_object_object_add (jresp, "play", json_object_new_string ("on"))
301 : json_object_object_add (jresp, "play", json_object_new_string ("off"));
304 /* "?value=" parameter is "1" or "true" */
305 else if ( atoi(value) == 1 || !strcasecmp(value, "true") ) {
309 json_object_object_add (jresp, "play", json_object_new_string ("on"));
312 /* "?value=" parameter is "0" or "false" */
313 else if ( atoi(value) == 0 || !strcasecmp(value, "false") ) {
317 json_object_object_add (jresp, "play", json_object_new_string ("off"));
320 afb_req_success (request, jresp, "Audio - Play");
323 STATIC void ping (struct afb_req request) { /* AFB_SESSION_NONE */
324 afb_req_success (request, NULL, "Audio - Ping success");
327 STATIC const struct AFB_restapi pluginApis[]= {
328 {"init" , AFB_SESSION_CHECK, init , "Audio API - init"},
329 {"volume" , AFB_SESSION_CHECK, volume , "Audio API - volume"},
330 {"channels", AFB_SESSION_CHECK, channels , "Audio API - channels"},
331 {"mute" , AFB_SESSION_CHECK, mute , "Audio API - mute"},
332 {"play" , AFB_SESSION_CHECK, play , "Audio API - play"},
333 {"ping" , AFB_SESSION_NONE, ping , "Audio API - ping"},
337 STATIC const struct AFB_plugin plug_desc = {
338 .type = AFB_PLUGIN_JSON,
339 .info = "Application Framework Binder - Audio plugin",