2 * Remix Stream Player: TIZEN device output
4 * Govindaraju SM <govi.sm@samsung.com>, August 2011
5 * Prince Kumar Dubey <prince.dubey@samsung.com>, August 2011
10 #include <remix/remix.h>
13 #ifdef HAVE_LIBSNDFILE
18 int _edje_multisense_default_log_dom = -1;
23 #define ERR(...) EINA_LOG_DOM_ERR(_edje_multisense_default_log_dom, __VA_ARGS__)
27 #define WRN(...) EINA_LOG_DOM_WARN(_edje_multisense_default_log_dom, __VA_ARGS__)
29 #define STREAM_PLAYER_BUFFERLEN 2048
30 #define DEFAULT_FORMAT MMSOUND_PCM_S16_LE
31 #define TIMEOUT_FOR_MM_HANDLER 10
33 typedef struct _RemixPlayerData RemixPlayerData;
34 typedef short PLAYER_PCM;
36 struct _RemixPlayerData {
37 RemixPCM databuffer[STREAM_PLAYER_BUFFERLEN];
38 PLAYER_PCM *playbuffer;
39 MMSoundPcmHandle_t handle;
40 MMSoundPcmChannel_t channel;
47 unsigned int buffer_size;
52 /* Optimisation dependencies: none */
53 static RemixBase *remix_player_optimise (RemixEnv *env, RemixBase *base);
56 remix_player_reset_device (RemixEnv *env, RemixBase *base)
59 RemixPlayerData *player_data = remix_base_get_instance_data(env, base);
61 if (player_data->handle)
63 mm_sound_pcm_play_stop(player_data->handle);
64 mm_sound_pcm_play_close(player_data->handle);
65 player_data->handle = NULL;
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,
73 if(mm_sound_pcm_play_start(player_data->handle) < 0)
75 remix_set_error (env, REMIX_ERROR_SYSTEM);
79 if( old_buffer_size < player_data->buffer_size)
81 if( player_data->playbuffer ) free(player_data->playbuffer);
82 player_data->playbuffer = calloc(sizeof(PLAYER_PCM), player_data->buffer_size);
83 if(!player_data->playbuffer)
85 remix_set_error (env, REMIX_ERROR_SYSTEM);
93 _vconf_noti_key_changed_cb(keynode_t *node, void *data)
95 RemixPlayerData *player = (RemixPlayerData *)data;
96 char *keyname = vconf_keynode_get_name(node);
98 if (strcmp(keyname, VCONFKEY_SETAPPL_SOUND_STATUS_BOOL) == 0)
99 player->snd_on = vconf_keynode_get_bool(node);
101 if (strcmp(keyname, VCONFKEY_SETAPPL_TOUCH_SOUNDS_BOOL) == 0)
102 player->tch_snd_on = vconf_keynode_get_bool(node);
104 if (strcmp(keyname, VCONFKEY_SYSMAN_EARJACK) == 0)
106 int ear_jack = vconf_keynode_get_int(node);
107 if (ear_jack == VCONFKEY_SYSMAN_EARJACK_REMOVED)
108 remix_player_reset_device (player->env, player->base);
113 remix_player_init (RemixEnv *env, RemixBase *base, CDSet *parameters)
115 RemixCount nr_channels;
117 RemixPlayerData *player_data = calloc(1, sizeof (RemixPlayerData));
121 remix_set_error(env, REMIX_ERROR_SYSTEM);
125 remix_base_set_instance_data(env, base, player_data);
126 channels = remix_get_channels (env);
128 nr_channels = cd_set_size (env, channels);
129 if (nr_channels == 1)
131 player_data->stereo = 0;
132 player_data->channel = MMSOUND_PCM_MONO;
134 else if (nr_channels == 2)
136 player_data->stereo = 1;
137 player_data->channel = MMSOUND_PCM_STEREO;
140 player_data->frequency = remix_get_samplerate(env);
141 player_data->buffer_size = 0;
142 player_data->max_value = (RemixPCM) SHRT_MAX / 2;
144 base = remix_player_optimise (env, base);
145 player_data->env = env;
146 player_data->base = base;
148 if (vconf_get_bool(VCONFKEY_SETAPPL_SOUND_STATUS_BOOL,
149 &player_data->snd_on) < 0)
150 WRN("\nFail to get VCONFKEY_SETAPPL_SOUND_STATUS_BOOL boolean value");
152 if (vconf_get_bool(VCONFKEY_SETAPPL_TOUCH_SOUNDS_BOOL,
153 &player_data->tch_snd_on) < 0)
154 WRN("\nFail to get VCONFKEY_SETAPPL_TOUCH_SOUNDS_BOOL boolean value");
156 if (vconf_notify_key_changed(VCONFKEY_SETAPPL_SOUND_STATUS_BOOL,
157 _vconf_noti_key_changed_cb, player_data) < 0)
158 WRN("\nFail to register VCONFKEY_SETAPPL_SOUND_STATUS_BOOL key callback");
160 if (vconf_notify_key_changed(VCONFKEY_SETAPPL_TOUCH_SOUNDS_BOOL,
161 _vconf_noti_key_changed_cb, player_data) < 0)
162 WRN("\nFail to register VCONFKEY_SETAPPL_SOUND_STATUS_BOOL key callback");
164 if (vconf_notify_key_changed(VCONFKEY_SYSMAN_EARJACK,
165 _vconf_noti_key_changed_cb, player_data) < 0)
166 WRN("\nFail to register VCONFKEY_SYSMAN_EARJACK key callback");
173 remix_player_clone (RemixEnv *env, RemixBase *base)
175 RemixBase *new_player = remix_base_new (env);
177 remix_player_init( env, new_player, NULL);
182 remix_player_destroy (RemixEnv *env, RemixBase *base)
184 RemixPlayerData *player_data = remix_base_get_instance_data(env, base);
186 if (vconf_ignore_key_changed(VCONFKEY_SETAPPL_SOUND_STATUS_BOOL,
187 _vconf_noti_key_changed_cb) < 0)
188 WRN("\nFail to unregister VCONFKEY_SETAPPL_SOUND_STATUS_BOOL key callback");
189 if (vconf_ignore_key_changed(VCONFKEY_SETAPPL_TOUCH_SOUNDS_BOOL,
190 _vconf_noti_key_changed_cb) < 0)
191 WRN("\nFail to unregister VCONFKEY_SETAPPL_TOUCH_SOUNDS_BOOL key callback");
192 if (vconf_ignore_key_changed(VCONFKEY_SYSMAN_EARJACK,
193 _vconf_noti_key_changed_cb) < 0)
194 WRN("\nFail to unregister VCONFKEY_SYSMAN_EARJACK key callback");
196 if(player_data->handle)
198 mm_sound_pcm_play_stop(player_data->handle);
199 mm_sound_pcm_play_close(player_data->handle);
201 if (player_data->timeout) ecore_timer_del(player_data->timeout);
202 if(player_data->playbuffer) free(player_data->playbuffer);
208 remix_player_ready (RemixEnv *env, RemixBase *base)
210 RemixPlayerData *player_data = remix_base_get_instance_data(env, base);
211 RemixCount nr_channels;
215 channels = remix_get_channels (env);
216 samplerate = (int) remix_get_samplerate (env);
218 nr_channels = cd_set_size (env, channels);
220 return (samplerate == player_data->frequency &&
221 ((nr_channels == 1 && player_data->stereo == 0) ||
222 (nr_channels > 1 && player_data->stereo == 1)));
226 remix_player_prepare (RemixEnv *env, RemixBase *base)
228 remix_player_reset_device (env, base);
233 remix_player_playbuffer (RemixEnv *env, RemixPlayerData *player, RemixPCM *data,
241 length = count * sizeof(RemixCount);
243 for (i = 0; i < count; i++)
245 value = *data++ * (player->max_value);
246 *(player->playbuffer + i) = (PLAYER_PCM) value;
249 ret = mm_sound_pcm_play_write(player->handle,
258 /* An RemixChunkFunc for making noise */
260 remix_player_chunk (RemixEnv *env, RemixChunk *chunk, RemixCount offset,
261 RemixCount count, int channelname, void *data)
263 RemixPlayerData *player = (RemixPlayerData *)data;
264 RemixCount remaining = count, written = 0, n, playcount;
267 while (remaining > 0)
269 playcount = MIN (remaining, player->buffer_size);
271 d = &chunk->data[offset];
272 n = remix_player_playbuffer (env, player, d, playcount);
277 n /= sizeof (PLAYER_PCM);
288 remix_player_process (RemixEnv *env, RemixBase *base, RemixCount count,
289 RemixStream *input, RemixStream *output)
291 RemixCount remaining = count, processed = 0, n, nn, nr_channels;
292 RemixPlayerData *player_data = remix_base_get_instance_data(env, base);
294 if ((!player_data->snd_on) || (!player_data->tch_snd_on)) return count;
295 nr_channels = remix_stream_nr_channels (env, input);
297 if (nr_channels == 1 && player_data->stereo == 0)
299 return remix_stream_chunkfuncify (env, input, count,
300 remix_player_chunk, player_data);
302 else if (nr_channels == 2 && player_data->stereo == 1)
304 while (remaining > 0)
306 n = MIN (remaining, (player_data->buffer_size / 2) );
307 n = remix_stream_interleave_2 (env, input,
308 REMIX_CHANNEL_LEFT, REMIX_CHANNEL_RIGHT,
309 player_data->databuffer, n);
311 nn = remix_player_playbuffer (env, player_data,
312 player_data->databuffer, nn);
321 ERR("[remix_player_process] unsupported stream/output channel\n");
322 ERR ("combination %ld / %d\n", nr_channels, player_data->stereo ? 2 : 1);
328 remix_player_length (RemixEnv *env, RemixBase *base)
330 return REMIX_COUNT_INFINITE;
334 remix_player_seek (RemixEnv *env, RemixBase *base, RemixCount count)
340 _remix_mm_handle_close(void *data)
342 RemixPlayerData *player_data = data;
344 if (!player_data) return ECORE_CALLBACK_CANCEL;
345 if (!player_data->handle) return ECORE_CALLBACK_CANCEL;
347 mm_sound_pcm_play_stop(player_data->handle);
348 mm_sound_pcm_play_close(player_data->handle);
349 player_data->handle = NULL;
350 player_data->timeout = NULL;
352 return ECORE_CALLBACK_CANCEL;
356 remix_player_flush (RemixEnv *env, RemixBase *base)
359 RemixPlayerData *player_data = remix_base_get_instance_data(env, base);
361 if (player_data->timeout) ecore_timer_del(player_data->timeout);
362 player_data->timeout = ecore_timer_add(TIMEOUT_FOR_MM_HANDLER,
363 _remix_mm_handle_close, player_data);
365 if (player_data->handle) return 0;
367 old_buffer_size = player_data->buffer_size;
368 player_data->buffer_size = mm_sound_pcm_play_open_no_session(&player_data->handle,
369 player_data->frequency,
370 player_data->channel,
373 if(mm_sound_pcm_play_start(player_data->handle) < 0)
375 remix_set_error (env, REMIX_ERROR_SYSTEM);
378 //player_data->buffer_size is unsigned int, so it cannot be value under 0
379 /* if(player_data->buffer_size < 0)
381 remix_set_error (env, REMIX_ERROR_SYSTEM);
386 if( old_buffer_size < player_data->buffer_size)
388 if( player_data->playbuffer ) free(player_data->playbuffer);
389 player_data->playbuffer = calloc(sizeof(PLAYER_PCM), player_data->buffer_size);
390 if(!player_data->playbuffer)
392 remix_set_error (env, REMIX_ERROR_SYSTEM);
400 static struct _RemixMethods _remix_player_methods = {
402 remix_player_destroy,
404 remix_player_prepare,
405 remix_player_process,
412 remix_player_optimise (RemixEnv *env, RemixBase *base)
414 remix_base_set_methods (env, base, &_remix_player_methods);
418 static struct _RemixMetaText tizen_player_metatext = {
420 "TIZEN Sound Player",
421 "Output the stream into TIZEN System",
422 "Copyright (C) 2011, Samsung Electronics Co., Ltd.",
423 "http://www.samsung.com",
424 REMIX_ONE_AUTHOR ("govi.sm@samsung.com", "prince.dubey@samsung.com"),
427 static struct _RemixPlugin tizen_player_plugin = {
428 &tizen_player_metatext,
430 CD_EMPTY_SET, /* init scheme */
432 CD_EMPTY_SET, /* process scheme */
434 NULL, /* plugin data */
439 remix_load (RemixEnv *env)
441 CDList *plugins = cd_list_new (env);
442 plugins = cd_list_prepend (env, plugins,
443 CD_POINTER(&tizen_player_plugin));