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
32 typedef struct _RemixPlayerData RemixPlayerData;
33 typedef short PLAYER_PCM;
35 struct _RemixPlayerData {
36 RemixPCM databuffer[STREAM_PLAYER_BUFFERLEN];
37 PLAYER_PCM *playbuffer;
38 MMSoundPcmHandle_t handle;
39 MMSoundPcmChannel_t channel;
52 /* Optimisation dependencies: none */
53 static RemixBase *remix_player_optimise (RemixEnv *env, RemixBase *base);
56 remix_player_open_device (RemixEnv *env, RemixBase *base)
58 RemixPlayerData *player_data = remix_base_get_instance_data(env, base);
60 if (!player_data) return -1;
62 if (player_data->handle) return 0;
64 player_data->old_buffer_size = player_data->buffer_size;
65 player_data->buffer_size = mm_sound_pcm_play_open_no_session(&player_data->handle,
66 player_data->frequency,
70 if (mm_sound_pcm_play_start(player_data->handle) < 0)
72 remix_set_error (env, REMIX_ERROR_SYSTEM);
76 if (player_data->buffer_size < 0)
78 remix_set_error (env, REMIX_ERROR_SYSTEM);
82 if (player_data->old_buffer_size < player_data->buffer_size)
84 if (player_data->playbuffer) free(player_data->playbuffer);
85 player_data->playbuffer = calloc(sizeof(PLAYER_PCM), player_data->buffer_size);
86 if (!player_data->playbuffer)
88 remix_set_error (env, REMIX_ERROR_SYSTEM);
97 _vconf_noti_key_changed_cb(keynode_t *node, void *data)
99 RemixPlayerData *player = (RemixPlayerData *)data;
100 char *keyname = vconf_keynode_get_name(node);
101 int sound_status = 0;
103 if (strcmp(keyname, VCONFKEY_SETAPPL_SOUND_STATUS_BOOL) == 0)
104 player->snd_on = vconf_keynode_get_bool(node);
106 if (strcmp(keyname, VCONFKEY_SETAPPL_TOUCH_SOUNDS_BOOL) == 0)
107 player->tch_snd_on = vconf_keynode_get_bool(node);
109 if (strcmp(keyname, VCONFKEY_SOUND_STATUS) == 0)
111 vconf_get_int(VCONFKEY_SOUND_STATUS, &sound_status);
112 player->vrecord_on = sound_status & VCONFKEY_SOUND_STATUS_AVRECORDING;
118 remix_player_init (RemixEnv *env, RemixBase *base, CDSet *parameters)
120 RemixCount nr_channels;
122 RemixPlayerData *player_data = calloc(1, sizeof (RemixPlayerData));
123 int sound_status = 0;
127 remix_set_error(env, REMIX_ERROR_SYSTEM);
131 remix_base_set_instance_data(env, base, player_data);
132 channels = remix_get_channels (env);
134 nr_channels = cd_set_size (env, channels);
135 if (nr_channels == 1)
137 player_data->stereo = 0;
138 player_data->channel = MMSOUND_PCM_MONO;
140 else if (nr_channels == 2)
142 player_data->stereo = 1;
143 player_data->channel = MMSOUND_PCM_STEREO;
146 player_data->frequency = remix_get_samplerate(env);
147 player_data->buffer_size = 0;
148 player_data->max_value = (RemixPCM) SHRT_MAX / 2;
150 base = remix_player_optimise (env, base);
151 player_data->env = env;
152 player_data->base = base;
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");
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");
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");
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");
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");
174 if (vconf_notify_key_changed(VCONFKEY_SOUND_STATUS,
175 _vconf_noti_key_changed_cb, player_data) < 0)
176 WRN("\nFail to get VCONFKEY_SOUND_STATUS int value");
178 if (vconf_get_int(VCONFKEY_SOUND_STATUS, &sound_status) < 0)
179 WRN("\nFail to get VCONFKEY_SOUND_STATUS int value");
180 player_data->vrecord_on = sound_status & VCONFKEY_SOUND_STATUS_AVRECORDING;
187 remix_player_clone (RemixEnv *env, RemixBase *base)
189 RemixBase *new_player = remix_base_new (env);
191 remix_player_init( env, new_player, NULL);
196 remix_player_destroy (RemixEnv *env, RemixBase *base)
198 RemixPlayerData *player_data = remix_base_get_instance_data(env, base);
200 if (vconf_ignore_key_changed(VCONFKEY_SETAPPL_SOUND_STATUS_BOOL,
201 _vconf_noti_key_changed_cb) < 0)
202 WRN("\nFail to unregister VCONFKEY_SETAPPL_SOUND_STATUS_BOOL key callback");
203 if (vconf_ignore_key_changed(VCONFKEY_SETAPPL_TOUCH_SOUNDS_BOOL,
204 _vconf_noti_key_changed_cb) < 0)
205 WRN("\nFail to unregister VCONFKEY_SETAPPL_TOUCH_SOUNDS_BOOL key callback");
206 if (vconf_ignore_key_changed(VCONFKEY_SYSMAN_EARJACK,
207 _vconf_noti_key_changed_cb) < 0)
208 WRN("\nFail to unregister VCONFKEY_SYSMAN_EARJACK key callback");
209 if (vconf_ignore_key_changed(VCONFKEY_SOUND_STATUS,
210 _vconf_noti_key_changed_cb) < 0)
211 WRN("\nFail to unregister VCONFKEY_SOUND_STATUS key callback");
213 if (player_data->handle)
215 if (mm_sound_pcm_play_stop(player_data->handle) < 0)
216 remix_set_error (env, REMIX_ERROR_SYSTEM);
218 mm_sound_pcm_play_close(player_data->handle);
219 player_data->handle = NULL;
222 if (player_data->playbuffer) free(player_data->playbuffer);
224 // TODO: base must be freed, otherwise memory leak.
225 // Need to check why this call create problem in player plugin load.
226 // if (base) remix_free(base);
231 remix_player_ready (RemixEnv *env, RemixBase *base)
233 RemixPlayerData *player_data = remix_base_get_instance_data(env, base);
234 RemixCount nr_channels;
238 channels = remix_get_channels (env);
239 samplerate = (int) remix_get_samplerate (env);
241 nr_channels = cd_set_size (env, channels);
243 return (samplerate == player_data->frequency &&
244 ((nr_channels == 1 && player_data->stereo == 0) ||
245 (nr_channels > 1 && player_data->stereo == 1)));
249 remix_player_prepare (RemixEnv *env, RemixBase *base)
255 remix_player_playbuffer (RemixEnv *env, RemixPlayerData *player, RemixPCM *data,
263 length = count * sizeof(RemixCount);
265 for (i = 0; i < count; i++)
267 value = *data++ * (player->max_value);
268 *(player->playbuffer + i) = (PLAYER_PCM) value;
272 ret = mm_sound_pcm_play_write(player->handle,
281 /* An RemixChunkFunc for making noise */
283 remix_player_chunk (RemixEnv *env, RemixChunk *chunk, RemixCount offset,
284 RemixCount count, int channelname, void *data)
286 RemixPlayerData *player = (RemixPlayerData *)data;
287 RemixCount remaining = count, written = 0, n, playcount;
290 while (remaining > 0)
292 playcount = MIN (remaining, player->buffer_size);
294 d = &chunk->data[offset];
295 n = remix_player_playbuffer (env, player, d, playcount);
300 n /= sizeof (PLAYER_PCM);
311 remix_player_process (RemixEnv *env, RemixBase *base, RemixCount count,
312 RemixStream *input, RemixStream *output)
314 RemixCount remaining = count, processed = 0, n, nn, nr_channels;
315 RemixPlayerData *player_data = remix_base_get_instance_data(env, base);
318 if (!player_data) return 0;
320 if (!player_data->handle) remix_player_open_device (env, base);
322 if ((!player_data->snd_on) || (!player_data->tch_snd_on)
323 || (player_data->vrecord_on) ) return count;
325 nr_channels = remix_stream_nr_channels (env, input);
327 if (nr_channels == 1 && player_data->stereo == 0)
329 return remix_stream_chunkfuncify (env, input, count,
330 remix_player_chunk, player_data);
332 else if (nr_channels == 2 && player_data->stereo == 1)
334 while (remaining > 0)
336 n = MIN (remaining, (player_data->buffer_size / 2) );
337 n = remix_stream_interleave_2 (env, input,
338 REMIX_CHANNEL_LEFT, REMIX_CHANNEL_RIGHT,
339 player_data->databuffer, n);
341 nn = remix_player_playbuffer (env, player_data,
342 player_data->databuffer, nn);
351 ERR("[remix_player_process] unsupported stream/output channel\n");
352 ERR ("combination %ld / %d\n", nr_channels, player_data->stereo ? 2 : 1);
358 remix_player_length (RemixEnv *env, RemixBase *base)
360 return REMIX_COUNT_INFINITE;
364 remix_player_seek (RemixEnv *env, RemixBase *base, RemixCount count)
370 _remix_mm_handle_close(void *data)
372 RemixPlayerData *player_data = data;
374 if (!player_data) return EINA_FALSE;
375 if (!player_data->handle) return EINA_FALSE;
377 if (mm_sound_pcm_play_stop(player_data->handle) < 0)
379 player_data->handle = NULL;
383 mm_sound_pcm_play_close(player_data->handle);
384 player_data->handle = NULL;
391 remix_player_flush (RemixEnv *env, RemixBase *base)
397 remix_player_reset (RemixEnv *env, RemixBase *base)
399 RemixPlayerData *player_data = remix_base_get_instance_data(env, base);
401 if (!player_data) return -1;
403 if (_remix_mm_handle_close(player_data)) return 0;
407 static struct _RemixMethods _remix_player_methods = {
409 remix_player_destroy,
411 remix_player_prepare,
412 remix_player_process,
420 remix_player_optimise (RemixEnv *env, RemixBase *base)
422 remix_base_set_methods (env, base, &_remix_player_methods);
426 static struct _RemixMetaText tizen_player_metatext = {
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"),
435 static struct _RemixPlugin tizen_player_plugin = {
436 &tizen_player_metatext,
438 CD_EMPTY_SET, /* init scheme */
440 CD_EMPTY_SET, /* process scheme */
442 NULL, /* plugin data */
447 remix_load (RemixEnv *env)
449 CDList *plugins = cd_list_new (env);
450 plugins = cd_list_prepend (env, plugins,
451 CD_POINTER(&tizen_player_plugin));