Enabling and Disabling of Multisense Sound based on Touch Sound check status in setti...
[platform/core/uifw/edje-multisense-plugin.git] / src / tizen_sound_player / tizen_sound_player.c
1 /*
2  * Remix Stream Player: TIZEN device output
3  *
4  * Govindaraju SM <govi.sm@samsung.com>, August 2011
5  * Prince Kumar Dubey <prince.dubey@samsung.com>, August 2011
6  */
7
8 #include "config.h"
9 #include <mm_sound.h>
10 #include <remix/remix.h>
11 #include <Eina.h>
12 #include <Ecore.h>
13 #ifdef HAVE_LIBSNDFILE
14 #include <sndfile.h>
15 #endif
16 #include <vconf.h>
17
18 int _edje_multisense_default_log_dom = -1;
19
20 #ifdef ERR
21 # undef ERR
22 #endif
23 #define ERR(...) EINA_LOG_DOM_ERR(_edje_multisense_default_log_dom, __VA_ARGS__)
24 #ifdef WRN
25 # undef WRN
26 #endif
27 #define WRN(...) EINA_LOG_DOM_WARN(_edje_multisense_default_log_dom, __VA_ARGS__)
28
29 #define STREAM_PLAYER_BUFFERLEN 2048
30 #define DEFAULT_FORMAT MMSOUND_PCM_S16_LE
31 #define TIMEOUT_FOR_MM_HANDLER 10
32
33 typedef struct _RemixPlayerData RemixPlayerData;
34 typedef short PLAYER_PCM;
35
36 struct _RemixPlayerData {
37    RemixPCM databuffer[STREAM_PLAYER_BUFFERLEN];
38    PLAYER_PCM *playbuffer;
39    MMSoundPcmHandle_t handle;
40    MMSoundPcmChannel_t channel;
41    RemixPCM max_value;
42    RemixEnv *env;
43    RemixBase *base;
44    Ecore_Timer *timeout;
45    int snd_on;
46    int tch_snd_on;
47    unsigned int buffer_size;
48    int stereo;
49    int frequency;
50 };
51
52 /* Optimisation dependencies: none */
53 static RemixBase *remix_player_optimise (RemixEnv *env, RemixBase *base);
54
55 static RemixBase *
56 remix_player_reset_device (RemixEnv *env, RemixBase *base)
57 {
58    int old_buffer_size;
59    RemixPlayerData *player_data = remix_base_get_instance_data(env, base);
60
61    if (player_data->handle)
62      {
63         mm_sound_pcm_play_stop(player_data->handle);
64         mm_sound_pcm_play_close(player_data->handle);
65         player_data->handle = NULL;
66      }
67    old_buffer_size = player_data->buffer_size;
68    player_data->buffer_size = mm_sound_pcm_play_open_no_session(&player_data->handle,
69                                                      player_data->frequency,
70                                                      player_data->channel,
71                                                      DEFAULT_FORMAT,
72                                                      VOLUME_TYPE_SYSTEM);
73    if(mm_sound_pcm_play_start(player_data->handle) < 0)
74      {
75         remix_set_error (env, REMIX_ERROR_SYSTEM);
76         return RemixNone;
77      }
78
79    if(player_data->buffer_size < 0)
80      {
81         remix_set_error (env, REMIX_ERROR_SYSTEM);
82         return RemixNone;
83      }
84
85    if( old_buffer_size < player_data->buffer_size)
86      {
87         if( player_data->playbuffer ) free(player_data->playbuffer);
88         player_data->playbuffer = calloc(sizeof(PLAYER_PCM), player_data->buffer_size);
89         if(!player_data->playbuffer)
90           {
91              remix_set_error (env, REMIX_ERROR_SYSTEM);
92              return RemixNone;
93           }
94    }
95    return base;
96 }
97
98 static void
99 _vconf_noti_key_changed_cb(keynode_t *node, void *data)
100 {
101    RemixPlayerData *player = (RemixPlayerData *)data;
102    char *keyname = vconf_keynode_get_name(node);
103
104    if (strcmp(keyname, VCONFKEY_SETAPPL_SOUND_STATUS_BOOL) == 0)
105      player->snd_on = vconf_keynode_get_bool(node);
106
107    if (strcmp(keyname, VCONFKEY_SETAPPL_TOUCH_SOUNDS_BOOL) == 0)
108      player->tch_snd_on = vconf_keynode_get_bool(node);
109
110    if (strcmp(keyname, VCONFKEY_SYSMAN_EARJACK) == 0)
111      {
112         int ear_jack = vconf_keynode_get_int(node);
113         if (ear_jack == VCONFKEY_SYSMAN_EARJACK_REMOVED)
114           remix_player_reset_device (player->env, player->base);
115      }
116 }
117
118 static RemixBase *
119 remix_player_init (RemixEnv *env, RemixBase *base, CDSet *parameters)
120    {
121    RemixCount nr_channels;
122    CDSet *channels;
123    RemixPlayerData *player_data = calloc(1, sizeof (RemixPlayerData));
124
125    if (!player_data)
126      {
127         remix_set_error(env, REMIX_ERROR_SYSTEM);
128         return RemixNone;
129      }
130
131    remix_base_set_instance_data(env, base, player_data);
132    channels = remix_get_channels (env);
133
134     nr_channels = cd_set_size (env, channels);
135     if (nr_channels == 1)
136       {
137          player_data->stereo = 0;
138          player_data->channel = MMSOUND_PCM_MONO;
139       }
140     else if (nr_channels == 2)
141       {
142          player_data->stereo = 1;
143          player_data->channel = MMSOUND_PCM_STEREO;
144       }
145
146    player_data->frequency = remix_get_samplerate(env);
147    player_data->buffer_size = 0;
148    player_data->max_value = (RemixPCM) SHRT_MAX / 2;
149
150    base = remix_player_optimise (env, base);
151    player_data->env = env;
152    player_data->base = base;
153
154    if (vconf_get_bool(VCONFKEY_SETAPPL_SOUND_STATUS_BOOL,
155                       &player_data->snd_on) < 0)
156      WRN("\nFail to get VCONFKEY_SETAPPL_SOUND_STATUS_BOOL boolean value");
157
158    if (vconf_get_bool(VCONFKEY_SETAPPL_TOUCH_SOUNDS_BOOL,
159                       &player_data->tch_snd_on) < 0)
160      WRN("\nFail to get VCONFKEY_SETAPPL_TOUCH_SOUNDS_BOOL boolean value");
161
162    if (vconf_notify_key_changed(VCONFKEY_SETAPPL_SOUND_STATUS_BOOL,
163                                 _vconf_noti_key_changed_cb, player_data) < 0)
164      WRN("\nFail to register VCONFKEY_SETAPPL_SOUND_STATUS_BOOL key callback");
165
166    if (vconf_notify_key_changed(VCONFKEY_SETAPPL_TOUCH_SOUNDS_BOOL,
167                                 _vconf_noti_key_changed_cb, player_data) < 0)
168      WRN("\nFail to register VCONFKEY_SETAPPL_SOUND_STATUS_BOOL key callback");
169
170    if (vconf_notify_key_changed(VCONFKEY_SYSMAN_EARJACK,
171                                 _vconf_noti_key_changed_cb, player_data) < 0)
172      WRN("\nFail to register VCONFKEY_SYSMAN_EARJACK key callback");
173
174    return base;
175 }
176
177
178 static RemixBase *
179 remix_player_clone (RemixEnv *env, RemixBase *base)
180 {
181    RemixBase *new_player = remix_base_new (env);
182
183    remix_player_init( env, new_player,  NULL);
184    return new_player;
185 }
186
187 static int
188 remix_player_destroy (RemixEnv *env, RemixBase *base)
189 {
190    RemixPlayerData *player_data = remix_base_get_instance_data(env, base);
191
192    if (vconf_ignore_key_changed(VCONFKEY_SETAPPL_SOUND_STATUS_BOOL,
193                                 _vconf_noti_key_changed_cb) < 0)
194      WRN("\nFail to unregister VCONFKEY_SETAPPL_SOUND_STATUS_BOOL key callback");
195    if (vconf_ignore_key_changed(VCONFKEY_SETAPPL_TOUCH_SOUNDS_BOOL,
196                                 _vconf_noti_key_changed_cb) < 0)
197      WRN("\nFail to unregister VCONFKEY_SETAPPL_TOUCH_SOUNDS_BOOL key callback");
198    if (vconf_ignore_key_changed(VCONFKEY_SYSMAN_EARJACK,
199                                 _vconf_noti_key_changed_cb) < 0)
200      WRN("\nFail to unregister VCONFKEY_SYSMAN_EARJACK key callback");
201
202    if(player_data->handle)
203      {
204         mm_sound_pcm_play_stop(player_data->handle);
205         mm_sound_pcm_play_close(player_data->handle);
206      }
207    if (player_data->timeout) ecore_timer_del(player_data->timeout);
208    if(player_data->playbuffer) free(player_data->playbuffer);
209    free (player_data);
210    return 0;
211 }
212
213 static int
214 remix_player_ready (RemixEnv *env, RemixBase *base)
215 {
216    RemixPlayerData *player_data = remix_base_get_instance_data(env, base);
217    RemixCount nr_channels;
218    CDSet *channels;
219    int samplerate;
220
221    channels = remix_get_channels (env);
222    samplerate = (int) remix_get_samplerate (env);
223
224    nr_channels = cd_set_size (env, channels);
225
226    return (samplerate == player_data->frequency &&
227           ((nr_channels == 1 && player_data->stereo == 0) ||
228            (nr_channels > 1 && player_data->stereo == 1)));
229 }
230
231 static RemixBase *
232 remix_player_prepare (RemixEnv *env, RemixBase *base)
233 {
234    remix_player_reset_device (env, base);
235    return base;
236 }
237
238 static RemixCount
239 remix_player_playbuffer (RemixEnv *env, RemixPlayerData *player, RemixPCM *data,
240           RemixCount count)
241 {
242    RemixCount i;
243    RemixPCM value;
244    int ret = count;
245    size_t length;
246
247    length = count * sizeof(RemixCount);
248
249    for (i = 0; i < count; i++)
250      {
251         value = *data++ * (player->max_value);
252         *(player->playbuffer + i) = (PLAYER_PCM) value;
253      }
254
255    ret = mm_sound_pcm_play_write(player->handle,
256                                      player->playbuffer,
257                                      length);
258    if(ret < 0)
259      ERR("Write Fail\n");
260
261    return length;
262 }
263
264 /* An RemixChunkFunc for making noise */
265 static RemixCount
266 remix_player_chunk (RemixEnv *env, RemixChunk *chunk, RemixCount offset,
267           RemixCount count, int channelname, void *data)
268 {
269    RemixPlayerData *player = (RemixPlayerData *)data;
270    RemixCount remaining = count, written = 0, n, playcount;
271    RemixPCM *d;
272
273    while (remaining > 0)
274      {
275         playcount = MIN (remaining, player->buffer_size);
276
277         d = &chunk->data[offset];
278         n = remix_player_playbuffer (env, player, d, playcount);
279
280         if (n == -1)
281           return -1;
282         else
283           n /= sizeof (PLAYER_PCM);
284
285         offset += n;
286         written += n;
287         remaining -= n;
288      }
289
290    return written;
291 }
292
293 static RemixCount
294 remix_player_process (RemixEnv *env, RemixBase *base, RemixCount count,
295             RemixStream *input, RemixStream *output)
296 {
297    RemixCount remaining = count, processed = 0, n, nn, nr_channels;
298    RemixPlayerData *player_data = remix_base_get_instance_data(env, base);
299
300    if ((!player_data->snd_on) || (!player_data->tch_snd_on)) return count;
301    nr_channels = remix_stream_nr_channels (env, input);
302
303    if (nr_channels == 1 && player_data->stereo == 0)
304      { /* MONO */
305         return remix_stream_chunkfuncify (env, input, count,
306                   remix_player_chunk, player_data);
307      }
308    else if (nr_channels == 2 && player_data->stereo == 1)
309      { /* STEREO */
310         while (remaining > 0)
311           {
312              n = MIN (remaining, (player_data->buffer_size / 2) );
313              n = remix_stream_interleave_2 (env, input,
314                  REMIX_CHANNEL_LEFT, REMIX_CHANNEL_RIGHT,
315                  player_data->databuffer, n);
316              nn = 2 * n;
317              nn = remix_player_playbuffer (env, player_data,
318                                            player_data->databuffer, nn);
319
320              processed += n;
321              remaining -= n;
322           }
323         return processed;
324      }
325    else
326      {
327         ERR("[remix_player_process] unsupported stream/output channel\n");
328         ERR ("combination %ld / %d\n", nr_channels, player_data->stereo ? 2 : 1);
329         return -1;
330      }
331 }
332
333 static RemixCount
334 remix_player_length (RemixEnv *env, RemixBase *base)
335 {
336    return REMIX_COUNT_INFINITE;
337 }
338
339 static RemixCount
340 remix_player_seek (RemixEnv *env, RemixBase *base, RemixCount count)
341 {
342    return count;
343 }
344
345 static Eina_Bool
346 _remix_mm_handle_close(void *data)
347 {
348    RemixPlayerData *player_data = data;
349
350    if ((!player_data) && (!player_data->handle)) return ECORE_CALLBACK_CANCEL;
351
352    mm_sound_pcm_play_stop(player_data->handle);
353    mm_sound_pcm_play_close(player_data->handle);
354    player_data->handle = NULL;
355    player_data->timeout = NULL;
356
357    return ECORE_CALLBACK_CANCEL;
358 }
359
360 static int
361 remix_player_flush (RemixEnv *env, RemixBase *base)
362 {
363    int old_buffer_size;
364    RemixPlayerData *player_data = remix_base_get_instance_data(env, base);
365
366    if (player_data->timeout) ecore_timer_del(player_data->timeout);
367    player_data->timeout = ecore_timer_add(TIMEOUT_FOR_MM_HANDLER,
368                                           _remix_mm_handle_close, player_data);
369
370    if (player_data->handle) return 0;
371
372    old_buffer_size = player_data->buffer_size;
373    player_data->buffer_size = mm_sound_pcm_play_open_no_session(&player_data->handle,
374                                                      player_data->frequency,
375                                                      player_data->channel,
376                                                      DEFAULT_FORMAT,
377                                                      VOLUME_TYPE_SYSTEM);
378    if(mm_sound_pcm_play_start(player_data->handle) < 0)
379      {
380         remix_set_error (env, REMIX_ERROR_SYSTEM);
381         return -1;
382      }
383
384    if(player_data->buffer_size < 0)
385      {
386         remix_set_error (env, REMIX_ERROR_SYSTEM);
387         return -1;
388      }
389
390    if( old_buffer_size < player_data->buffer_size)
391      {
392         if( player_data->playbuffer ) free(player_data->playbuffer);
393         player_data->playbuffer = calloc(sizeof(PLAYER_PCM), player_data->buffer_size);
394         if(!player_data->playbuffer)
395           {
396              remix_set_error (env, REMIX_ERROR_SYSTEM);
397              return -1;
398           }
399    }
400
401    return 0;
402 }
403
404 static struct _RemixMethods _remix_player_methods = {
405    remix_player_clone,
406    remix_player_destroy,
407    remix_player_ready,
408    remix_player_prepare,
409    remix_player_process,
410    remix_player_length,
411    remix_player_seek,
412    remix_player_flush,
413 };
414
415 static RemixBase *
416 remix_player_optimise (RemixEnv *env, RemixBase *base)
417 {
418    remix_base_set_methods (env, base, &_remix_player_methods);
419    return base;
420 }
421
422 static struct _RemixMetaText tizen_player_metatext = {
423    "tizen_snd_player",
424    "TIZEN Sound Player",
425    "Output the stream into TIZEN System",
426    "Copyright (C) 2011, Samsung Electronics Co., Ltd.",
427    "http://www.samsung.com",
428    REMIX_ONE_AUTHOR ("govi.sm@samsung.com", "prince.dubey@samsung.com"),
429 };
430
431 static struct _RemixPlugin tizen_player_plugin = {
432    &tizen_player_metatext,
433    REMIX_FLAGS_NONE,
434    CD_EMPTY_SET, /* init scheme */
435    remix_player_init,
436    CD_EMPTY_SET, /* process scheme */
437    NULL, /* suggests */
438    NULL, /* plugin data */
439    NULL  /* destroy */
440 };
441
442 EAPI CDList *
443 remix_load (RemixEnv *env)
444 {
445    CDList *plugins = cd_list_new (env);
446    plugins = cd_list_prepend (env, plugins,
447                              CD_POINTER(&tizen_player_plugin));
448    return plugins;
449 }