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
13 #include <remix/remix.h>
15 #ifdef HAVE_LIBSNDFILE
20 int _edje_multisense_default_log_dom = -1;
25 #define ERR(...) EINA_LOG_DOM_ERR(_edje_multisense_default_log_dom, __VA_ARGS__)
29 #define WRN(...) EINA_LOG_DOM_WARN(_edje_multisense_default_log_dom, __VA_ARGS__)
31 #define STREAM_PLAYER_BUFFERLEN 2048
32 #define DEFAULT_FORMAT MMSOUND_PCM_S16_LE
34 typedef struct _RemixPlayerData RemixPlayerData;
35 typedef short PLAYER_PCM;
37 struct _RemixPlayerData {
38 RemixPCM databuffer[STREAM_PLAYER_BUFFERLEN];
39 PLAYER_PCM *playbuffer;
40 MMSoundPcmHandle_t handle;
41 MMSoundPcmChannel_t channel;
46 unsigned int buffer_size;
51 /* Optimisation dependencies: none */
52 static RemixBase *remix_player_optimise (RemixEnv *env, RemixBase *base);
55 remix_player_reset_device (RemixEnv *env, RemixBase *base)
58 RemixPlayerData *player_data = remix_base_get_instance_data(env, base);
60 if (player_data->handle)
62 mm_sound_pcm_play_stop(player_data->handle);
63 mm_sound_pcm_play_close(player_data->handle);
64 player_data->handle = NULL;
66 old_buffer_size = player_data->buffer_size;
67 player_data->buffer_size = mm_sound_pcm_play_open_no_session(&player_data->handle,
68 player_data->frequency,
72 if(mm_sound_pcm_play_start(player_data->handle) < 0)
74 remix_set_error (env, REMIX_ERROR_SYSTEM);
78 if(player_data->buffer_size < 0)
80 remix_set_error (env, REMIX_ERROR_SYSTEM);
84 if( old_buffer_size < player_data->buffer_size)
86 if( player_data->playbuffer ) free(player_data->playbuffer);
87 player_data->playbuffer = calloc(sizeof(PLAYER_PCM), player_data->buffer_size);
88 if(!player_data->playbuffer)
90 remix_set_error (env, REMIX_ERROR_SYSTEM);
98 _vconf_noti_key_changed_cb(keynode_t *node, void *data)
100 RemixPlayerData *player = (RemixPlayerData *)data;
101 char *keyname = vconf_keynode_get_name(node);
103 if (strcmp(keyname, VCONFKEY_SETAPPL_SOUND_STATUS_BOOL) == 0)
104 player->snd_on = vconf_keynode_get_bool(node);
106 else if (strcmp(keyname, VCONFKEY_SYSMAN_EARJACK) == 0)
108 int ear_jack = vconf_keynode_get_int(node);
109 if (ear_jack == VCONFKEY_SYSMAN_EARJACK_REMOVED)
110 remix_player_reset_device (player->env, player->base);
115 remix_player_init (RemixEnv *env, RemixBase *base, CDSet *parameters)
117 RemixCount nr_channels;
119 RemixPlayerData *player_data = calloc(1, sizeof (RemixPlayerData));
123 remix_set_error(env, REMIX_ERROR_SYSTEM);
127 remix_base_set_instance_data(env, base, player_data);
128 channels = remix_get_channels (env);
130 nr_channels = cd_set_size (env, channels);
131 if (nr_channels == 1)
133 player_data->stereo = 0;
134 player_data->channel = MMSOUND_PCM_MONO;
136 else if (nr_channels == 2)
138 player_data->stereo = 1;
139 player_data->channel = MMSOUND_PCM_STEREO;
142 player_data->frequency = remix_get_samplerate(env);
143 player_data->buffer_size = 0;
144 player_data->max_value = (RemixPCM) SHRT_MAX / 2;
146 remix_player_reset_device (env, (RemixBase *)base);
148 base = remix_player_optimise (env, base);
149 player_data->env = env;
150 player_data->base = base;
151 if (vconf_get_bool(VCONFKEY_SETAPPL_SOUND_STATUS_BOOL, &player_data->snd_on) < 0)
152 WRN("\nFail to get VCONFKEY_SETAPPL_SOUND_STATUS_BOOL boolean value");
154 if (vconf_notify_key_changed(VCONFKEY_SETAPPL_SOUND_STATUS_BOOL,_vconf_noti_key_changed_cb, player_data) < 0)
155 WRN("\nFail to register VCONFKEY_SETAPPL_SOUND_STATUS_BOOL key callback");
156 if (vconf_notify_key_changed(VCONFKEY_SYSMAN_EARJACK, _vconf_noti_key_changed_cb, player_data) < 0)
157 WRN("\nFail to register VCONFKEY_SYSMAN_EARJACK key callback");
164 remix_player_clone (RemixEnv *env, RemixBase *base)
166 RemixBase *new_player = remix_base_new (env);
168 remix_player_init( env, new_player, NULL);
173 remix_player_destroy (RemixEnv *env, RemixBase *base)
175 RemixPlayerData *player_data = remix_base_get_instance_data(env, base);
177 if (vconf_ignore_key_changed(VCONFKEY_SETAPPL_SOUND_STATUS_BOOL,_vconf_noti_key_changed_cb) < 0)
178 WRN("\nFail to unregister VCONFKEY_SETAPPL_SOUND_STATUS_BOOL key callback");
179 if (vconf_ignore_key_changed(VCONFKEY_SYSMAN_EARJACK, _vconf_noti_key_changed_cb) < 0)
180 WRN("\nFail to unregister VCONFKEY_SYSMAN_EARJACK key callback");
182 if(player_data->handle)
184 mm_sound_pcm_play_stop(player_data->handle);
185 mm_sound_pcm_play_close(player_data->handle);
187 if(player_data->playbuffer) free(player_data->playbuffer);
193 remix_player_ready (RemixEnv *env, RemixBase *base)
195 RemixPlayerData *player_data = remix_base_get_instance_data(env, base);
196 RemixCount nr_channels;
200 channels = remix_get_channels (env);
201 samplerate = (int) remix_get_samplerate (env);
203 nr_channels = cd_set_size (env, channels);
205 return (samplerate == player_data->frequency &&
206 ((nr_channels == 1 && player_data->stereo == 0) ||
207 (nr_channels > 1 && player_data->stereo == 1)));
211 remix_player_prepare (RemixEnv *env, RemixBase *base)
213 remix_player_reset_device (env, base);
218 remix_player_playbuffer (RemixEnv *env, RemixPlayerData *player, RemixPCM *data,
226 length = count * sizeof(RemixCount);
228 for (i = 0; i < count; i++)
230 value = *data++ * (player->max_value);
231 *(player->playbuffer + i) = (PLAYER_PCM) value;
234 ret = mm_sound_pcm_play_write(player->handle,
243 /* An RemixChunkFunc for making noise */
245 remix_player_chunk (RemixEnv *env, RemixChunk *chunk, RemixCount offset,
246 RemixCount count, int channelname, void *data)
248 RemixPlayerData *player = (RemixPlayerData *)data;
249 RemixCount remaining = count, written = 0, n, playcount;
252 while (remaining > 0)
254 playcount = MIN (remaining, player->buffer_size);
256 d = &chunk->data[offset];
257 n = remix_player_playbuffer (env, player, d, playcount);
262 n /= sizeof (PLAYER_PCM);
273 remix_player_process (RemixEnv *env, RemixBase *base, RemixCount count,
274 RemixStream *input, RemixStream *output)
276 RemixCount remaining = count, processed = 0, n, nn, nr_channels;
277 RemixPlayerData *player_data = remix_base_get_instance_data(env, base);
279 if (!player_data->snd_on) return count;
280 nr_channels = remix_stream_nr_channels (env, input);
282 if (nr_channels == 1 && player_data->stereo == 0)
284 return remix_stream_chunkfuncify (env, input, count,
285 remix_player_chunk, player_data);
287 else if (nr_channels == 2 && player_data->stereo == 1)
289 while (remaining > 0)
291 n = MIN (remaining, (player_data->buffer_size / 2) );
292 n = remix_stream_interleave_2 (env, input,
293 REMIX_CHANNEL_LEFT, REMIX_CHANNEL_RIGHT,
294 player_data->databuffer, n);
296 nn = remix_player_playbuffer (env, player_data,
297 player_data->databuffer, nn);
306 ERR("[remix_player_process] unsupported stream/output channel\n");
307 ERR ("combination %ld / %d\n", nr_channels, player_data->stereo ? 2 : 1);
313 remix_player_length (RemixEnv *env, RemixBase *base)
315 return REMIX_COUNT_INFINITE;
319 remix_player_seek (RemixEnv *env, RemixBase *base, RemixCount count)
325 remix_player_flush (RemixEnv *env, RemixBase *base)
327 RemixPlayerData *player_data = remix_base_get_instance_data(env, base);
328 remix_player_reset_device (env, base);
332 static struct _RemixMethods _remix_player_methods = {
334 remix_player_destroy,
336 remix_player_prepare,
337 remix_player_process,
344 remix_player_optimise (RemixEnv *env, RemixBase *base)
346 remix_base_set_methods (env, base, &_remix_player_methods);
350 static struct _RemixMetaText tizen_player_metatext = {
352 "TIZEN Sound Player",
353 "Output the stream into TIZEN System",
354 "Copyright (C) 2011, Samsung Electronics Co., Ltd.",
355 "http://www.samsung.com",
356 REMIX_ONE_AUTHOR ("govi.sm@samsung.com", "prince.dubey@samsung.com"),
359 static struct _RemixPlugin tizen_player_plugin = {
360 &tizen_player_metatext,
362 CD_EMPTY_SET, /* init scheme */
364 CD_EMPTY_SET, /* process scheme */
366 NULL, /* plugin data */
371 remix_load (RemixEnv *env)
373 CDList *plugins = cd_list_new (env);
374 plugins = cd_list_prepend (env, plugins,
375 CD_POINTER(&tizen_player_plugin));