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