diff options
author | David Walter Seikel | 2012-01-04 18:41:13 +1000 |
---|---|---|
committer | David Walter Seikel | 2012-01-04 18:41:13 +1000 |
commit | dd7595a3475407a7fa96a97393bae8c5220e8762 (patch) | |
tree | e341e911d7eb911a51684a7412ef7f7c7605d28e /libraries/edje/src/modules/alsa_snd_player/alsa_snd_player.c | |
parent | Add the skeleton. (diff) | |
download | SledjHamr-dd7595a3475407a7fa96a97393bae8c5220e8762.zip SledjHamr-dd7595a3475407a7fa96a97393bae8c5220e8762.tar.gz SledjHamr-dd7595a3475407a7fa96a97393bae8c5220e8762.tar.bz2 SledjHamr-dd7595a3475407a7fa96a97393bae8c5220e8762.tar.xz |
Add the base Enlightenment Foundation Libraries - eina, eet, evas, ecore, embryo, and edje.
Note that embryo wont be used, but I'm not sure yet if you can build edje without it.
Diffstat (limited to '')
-rw-r--r-- | libraries/edje/src/modules/alsa_snd_player/alsa_snd_player.c | 405 |
1 files changed, 405 insertions, 0 deletions
diff --git a/libraries/edje/src/modules/alsa_snd_player/alsa_snd_player.c b/libraries/edje/src/modules/alsa_snd_player/alsa_snd_player.c new file mode 100644 index 0000000..f397255 --- /dev/null +++ b/libraries/edje/src/modules/alsa_snd_player/alsa_snd_player.c | |||
@@ -0,0 +1,405 @@ | |||
1 | /* | ||
2 | * Remix ALSA Player: ALSA audio output | ||
3 | * | ||
4 | * Govindaraju SM <govi.sm@samsung.com>, October 2011 | ||
5 | * Prince Kumar Dubey <prince.dubey@samsung.com>, October 2011 | ||
6 | */ | ||
7 | |||
8 | #include "config.h" | ||
9 | #include <stdio.h> | ||
10 | #include <remix/remix.h> | ||
11 | #include <alsa/asoundlib.h> | ||
12 | #include <Eina.h> | ||
13 | #ifdef HAVE_LIBSNDFILE | ||
14 | #include <sndfile.h> | ||
15 | #endif | ||
16 | |||
17 | #define ALSA_PLAYER_BUFFERLEN 2048 | ||
18 | |||
19 | typedef struct _Alsa_Player_Data Alsa_Player_Data; | ||
20 | typedef short PLAYER_PCM; | ||
21 | |||
22 | struct _Alsa_Player_Data | ||
23 | { | ||
24 | RemixPCM databuffer[ALSA_PLAYER_BUFFERLEN]; | ||
25 | snd_pcm_t *alsa_dev; | ||
26 | unsigned int stereo; | ||
27 | unsigned channels; | ||
28 | unsigned int frequency; | ||
29 | }; | ||
30 | |||
31 | static int _log_dom = -1; | ||
32 | static int init_count = 0; | ||
33 | |||
34 | #ifdef WRN | ||
35 | # undef WRN | ||
36 | #endif | ||
37 | #define WRN(...) EINA_LOG_DOM_WARN(_log_dom, __VA_ARGS__) | ||
38 | |||
39 | //#define MIXDBG 1 | ||
40 | |||
41 | /* Optimisation dependencies: none */ | ||
42 | static RemixBase *alsa_player_optimise(RemixEnv *env, RemixBase *base); | ||
43 | |||
44 | static snd_pcm_t * | ||
45 | alsa_open(int channels, unsigned int samplerate, unsigned int *real_samplerate) | ||
46 | { | ||
47 | const char *device = "default"; | ||
48 | snd_pcm_t *alsa_dev = NULL; | ||
49 | snd_pcm_hw_params_t *hw_params; | ||
50 | snd_pcm_uframes_t alsa_buffer_frames; | ||
51 | snd_pcm_uframes_t alsa_period_size; | ||
52 | unsigned int samplerate_ret = 0; | ||
53 | int err; | ||
54 | |||
55 | alsa_buffer_frames = ALSA_PLAYER_BUFFERLEN; | ||
56 | alsa_period_size = ALSA_PLAYER_BUFFERLEN / 4; | ||
57 | |||
58 | if ((err = snd_pcm_open(&alsa_dev, device, SND_PCM_STREAM_PLAYBACK, 0)) < 0) | ||
59 | { | ||
60 | WRN("cannot open alsa playback stream (%s)", snd_strerror(err)); | ||
61 | goto catch_error; | ||
62 | } | ||
63 | snd_pcm_hw_params_alloca(&hw_params); | ||
64 | if ((err = snd_pcm_hw_params_any(alsa_dev, hw_params)) < 0) | ||
65 | { | ||
66 | WRN("cannot initialize snd hw params (%s)", snd_strerror(err)); | ||
67 | goto catch_error; | ||
68 | } | ||
69 | if ((err = snd_pcm_hw_params_set_access(alsa_dev, hw_params, | ||
70 | SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) | ||
71 | { | ||
72 | WRN("cannot set interleaved access (%s)", snd_strerror(err)); | ||
73 | goto catch_error; | ||
74 | } | ||
75 | if ((err = snd_pcm_hw_params_set_format(alsa_dev, hw_params, | ||
76 | SND_PCM_FORMAT_FLOAT)) < 0) | ||
77 | { | ||
78 | WRN("cannot set float sample format (%s)", snd_strerror(err)); | ||
79 | goto catch_error; | ||
80 | } | ||
81 | #ifdef MIXDBG // testing/debugging by making output samplerate be 48khz | ||
82 | samplerate_ret = 48000; | ||
83 | if ((err = snd_pcm_hw_params_set_rate_near(alsa_dev, hw_params, | ||
84 | &samplerate_ret, 0)) < 0) | ||
85 | { | ||
86 | WRN("cannot set sample rate (%s)", snd_strerror(err)); | ||
87 | goto catch_error; | ||
88 | } | ||
89 | #else | ||
90 | if ((err = snd_pcm_hw_params_set_rate_near(alsa_dev, hw_params, | ||
91 | &samplerate, 0)) < 0) | ||
92 | { | ||
93 | WRN("cannot set sample rate (%s)", snd_strerror(err)); | ||
94 | goto catch_error; | ||
95 | } | ||
96 | #endif | ||
97 | if ((err = snd_pcm_hw_params_set_channels(alsa_dev, hw_params, channels)) < 0) | ||
98 | { | ||
99 | WRN("cannot set channel count (%s)", snd_strerror(err)); | ||
100 | goto catch_error; | ||
101 | } | ||
102 | if ((err = snd_pcm_hw_params_set_buffer_size_near(alsa_dev, hw_params, | ||
103 | &alsa_buffer_frames)) < 0) | ||
104 | { | ||
105 | WRN("cannot set buffer size (%s)", snd_strerror(err)); | ||
106 | goto catch_error; | ||
107 | } | ||
108 | if ((err = snd_pcm_hw_params_set_period_size_near(alsa_dev, hw_params, | ||
109 | &alsa_period_size, 0)) < 0) | ||
110 | { | ||
111 | WRN("cannot set period size (%s)", snd_strerror(err)); | ||
112 | goto catch_error; | ||
113 | } | ||
114 | if ((err = snd_pcm_hw_params(alsa_dev, hw_params)) < 0) | ||
115 | { | ||
116 | WRN("cannot set parameters (%s)", snd_strerror(err)); | ||
117 | goto catch_error; | ||
118 | } | ||
119 | if ((err = snd_pcm_hw_params_get_rate(hw_params, &samplerate_ret, 0)) < 0) | ||
120 | { | ||
121 | WRN("cannot get samplerate (%s)", snd_strerror(err)); | ||
122 | goto catch_error; | ||
123 | } | ||
124 | if ((err = snd_pcm_prepare(alsa_dev)) < 0) | ||
125 | { | ||
126 | WRN("cannot prepare audio for use (%s)", snd_strerror(err)); | ||
127 | goto catch_error; | ||
128 | } | ||
129 | if (real_samplerate) *real_samplerate = samplerate_ret; | ||
130 | |||
131 | catch_error: | ||
132 | if ((err < 0) && (alsa_dev != NULL)) | ||
133 | { | ||
134 | snd_pcm_close(alsa_dev); | ||
135 | return NULL; | ||
136 | } | ||
137 | return alsa_dev; | ||
138 | } | ||
139 | |||
140 | static RemixBase * | ||
141 | alsa_player_reset_device(RemixEnv *env, RemixBase *base) | ||
142 | { | ||
143 | Alsa_Player_Data *player_data = remix_base_get_instance_data(env, base); | ||
144 | unsigned int real_samplerate = 0; | ||
145 | |||
146 | if (player_data->alsa_dev) | ||
147 | { | ||
148 | snd_pcm_drain(player_data->alsa_dev); | ||
149 | snd_pcm_close(player_data->alsa_dev); | ||
150 | } | ||
151 | player_data->alsa_dev = alsa_open(player_data->channels, | ||
152 | player_data->frequency, | ||
153 | &real_samplerate); | ||
154 | if (!player_data->alsa_dev) | ||
155 | { | ||
156 | remix_set_error(env, REMIX_ERROR_SYSTEM); | ||
157 | return RemixNone; | ||
158 | } | ||
159 | // printf("%i != %i\n", real_samplerate, player_data->frequency); | ||
160 | if (real_samplerate != player_data->frequency) | ||
161 | { | ||
162 | player_data->frequency = real_samplerate; | ||
163 | remix_set_samplerate(env, player_data->frequency); | ||
164 | } | ||
165 | return base; | ||
166 | } | ||
167 | |||
168 | static RemixBase * | ||
169 | alsa_player_init(RemixEnv *env, RemixBase *base, CDSet *parameters __UNUSED__) | ||
170 | { | ||
171 | CDSet *channels; | ||
172 | Alsa_Player_Data *player_data = calloc(1, sizeof(Alsa_Player_Data)); | ||
173 | |||
174 | if (!player_data) | ||
175 | { | ||
176 | remix_set_error(env, REMIX_ERROR_SYSTEM); | ||
177 | return RemixNone; | ||
178 | } | ||
179 | |||
180 | init_count++; | ||
181 | if (init_count == 1) | ||
182 | { | ||
183 | eina_init(); | ||
184 | _log_dom = eina_log_domain_register("remix-alsa", EINA_COLOR_CYAN); | ||
185 | } | ||
186 | |||
187 | remix_base_set_instance_data(env, base, player_data); | ||
188 | channels = remix_get_channels(env); | ||
189 | |||
190 | player_data->channels = cd_set_size(env, channels); | ||
191 | if (player_data->channels == 1) player_data->stereo = 0; | ||
192 | else if (player_data->channels == 2) player_data->stereo = 1; | ||
193 | |||
194 | player_data->frequency = remix_get_samplerate(env); | ||
195 | alsa_player_reset_device(env, base); | ||
196 | base = alsa_player_optimise(env, base); | ||
197 | return base; | ||
198 | } | ||
199 | |||
200 | static RemixBase * | ||
201 | alsa_player_clone(RemixEnv *env, RemixBase *base __UNUSED__) | ||
202 | { | ||
203 | RemixBase *new_player = remix_base_new(env); | ||
204 | alsa_player_init(env, new_player, NULL); | ||
205 | return new_player; | ||
206 | } | ||
207 | |||
208 | static int | ||
209 | alsa_player_destroy(RemixEnv *env, RemixBase *base) | ||
210 | { | ||
211 | Alsa_Player_Data *player_data = remix_base_get_instance_data(env, base); | ||
212 | |||
213 | if (player_data->alsa_dev) | ||
214 | { | ||
215 | snd_pcm_drain(player_data->alsa_dev); | ||
216 | snd_pcm_close(player_data->alsa_dev); | ||
217 | } | ||
218 | free(player_data); | ||
219 | init_count--; | ||
220 | if (init_count == 0) | ||
221 | { | ||
222 | eina_log_domain_unregister(_log_dom); | ||
223 | _log_dom = -1; | ||
224 | eina_shutdown(); | ||
225 | } | ||
226 | return 0; | ||
227 | } | ||
228 | |||
229 | static int | ||
230 | alsa_player_ready(RemixEnv *env, RemixBase *base) | ||
231 | { | ||
232 | Alsa_Player_Data *player_data = remix_base_get_instance_data(env, base); | ||
233 | RemixCount nr_channels; | ||
234 | CDSet *channels; | ||
235 | int samplerate; | ||
236 | |||
237 | channels = remix_get_channels(env); | ||
238 | samplerate = (int)remix_get_samplerate(env); | ||
239 | nr_channels = cd_set_size(env, channels); | ||
240 | return ((samplerate == (int)player_data->frequency) && | ||
241 | (((nr_channels == 1) && (player_data->stereo == 0)) || | ||
242 | ((nr_channels > 1) && (player_data->stereo == 1)))); | ||
243 | } | ||
244 | |||
245 | static RemixBase * | ||
246 | alsa_player_prepare(RemixEnv *env, RemixBase *base) | ||
247 | { | ||
248 | alsa_player_reset_device(env, base); | ||
249 | return base; | ||
250 | } | ||
251 | |||
252 | static RemixCount | ||
253 | alsa_player_playbuffer(RemixEnv *env __UNUSED__, Alsa_Player_Data *player, RemixPCM *data, RemixCount count) | ||
254 | { | ||
255 | #ifdef MIXDBG | ||
256 | { | ||
257 | static int total = 0; | ||
258 | static SNDFILE *sfile = NULL; | ||
259 | static SF_INFO sfinfo; | ||
260 | |||
261 | if (total == 0) | ||
262 | { | ||
263 | sfinfo.frames = 0; | ||
264 | sfinfo.samplerate = player->frequency; | ||
265 | sfinfo.channels = 2; | ||
266 | sfinfo.format = SF_FORMAT_WAV | SF_FORMAT_PCM_16 | SF_ENDIAN_LITTLE; | ||
267 | sfinfo.sections = 0; | ||
268 | sfinfo.seekable = 0; | ||
269 | sfile = sf_open("out.wav", SFM_WRITE, &sfinfo); | ||
270 | } | ||
271 | |||
272 | if (sfile) | ||
273 | { | ||
274 | sf_writef_float(sfile, data, count); | ||
275 | total += count; | ||
276 | } | ||
277 | } | ||
278 | #endif | ||
279 | return snd_pcm_writei(player->alsa_dev, data, count); | ||
280 | } | ||
281 | |||
282 | static RemixCount | ||
283 | alsa_player_chunk(RemixEnv *env, RemixChunk *chunk, RemixCount offset, RemixCount count, int channelname __UNUSED__, void *data) | ||
284 | { | ||
285 | Alsa_Player_Data *player = data; | ||
286 | RemixCount remaining = count, written = 0, n, playcount; | ||
287 | RemixPCM *d; | ||
288 | |||
289 | while (remaining > 0) | ||
290 | { | ||
291 | playcount = MIN(remaining, ALSA_PLAYER_BUFFERLEN); | ||
292 | |||
293 | d = &chunk->data[offset]; | ||
294 | n = alsa_player_playbuffer(env, player, d, playcount); | ||
295 | |||
296 | if (n == -1) return -1; | ||
297 | else n /= sizeof(PLAYER_PCM); | ||
298 | |||
299 | offset += n; | ||
300 | written += n; | ||
301 | remaining -= n; | ||
302 | } | ||
303 | return written; | ||
304 | } | ||
305 | |||
306 | static RemixCount | ||
307 | alsa_player_process(RemixEnv *env, RemixBase *base, RemixCount count, RemixStream *input, RemixStream *output __UNUSED__) | ||
308 | { | ||
309 | Alsa_Player_Data *player_data = remix_base_get_instance_data(env, base); | ||
310 | RemixCount nr_channels = remix_stream_nr_channels(env, input); | ||
311 | RemixCount remaining = count, processed = 0, n, nn; | ||
312 | |||
313 | if ((nr_channels == 1) && (player_data->stereo == 0)) | ||
314 | { /*MONO*/ | ||
315 | return remix_stream_chunkfuncify(env, input, count, | ||
316 | alsa_player_chunk, player_data); | ||
317 | } | ||
318 | else if ((nr_channels == 2) && (player_data->stereo == 1)) | ||
319 | { /*STEREO*/ | ||
320 | while (remaining > 0) | ||
321 | { | ||
322 | n = MIN(remaining, ALSA_PLAYER_BUFFERLEN / 2); | ||
323 | n = remix_stream_interleave_2(env, input, | ||
324 | REMIX_CHANNEL_LEFT, | ||
325 | REMIX_CHANNEL_RIGHT, | ||
326 | player_data->databuffer, n); | ||
327 | nn = alsa_player_playbuffer(env, player_data, | ||
328 | player_data->databuffer, n); | ||
329 | processed += n; | ||
330 | remaining -= n; | ||
331 | } | ||
332 | return processed; | ||
333 | } | ||
334 | WRN("[alsa_player_process] unsupported stream/output channel " | ||
335 | "combination %ld / %d", nr_channels, player_data->stereo ? 2 : 1); | ||
336 | return -1; | ||
337 | } | ||
338 | |||
339 | static RemixCount | ||
340 | alsa_player_length(RemixEnv *env __UNUSED__, RemixBase *base __UNUSED__) | ||
341 | { | ||
342 | return REMIX_COUNT_INFINITE; | ||
343 | } | ||
344 | |||
345 | static RemixCount | ||
346 | alsa_player_seek(RemixEnv *env __UNUSED__, RemixBase *base __UNUSED__, RemixCount count __UNUSED__) | ||
347 | { | ||
348 | return count; | ||
349 | } | ||
350 | |||
351 | static int | ||
352 | alsa_player_flush(RemixEnv *env, RemixBase *base) | ||
353 | { | ||
354 | alsa_player_reset_device(env, base); | ||
355 | return 0; | ||
356 | } | ||
357 | |||
358 | static struct _RemixMethods _alsa_player_methods = | ||
359 | { | ||
360 | alsa_player_clone, | ||
361 | alsa_player_destroy, | ||
362 | alsa_player_ready, | ||
363 | alsa_player_prepare, | ||
364 | alsa_player_process, | ||
365 | alsa_player_length, | ||
366 | alsa_player_seek, | ||
367 | alsa_player_flush, | ||
368 | }; | ||
369 | |||
370 | static RemixBase * | ||
371 | alsa_player_optimise(RemixEnv *env, RemixBase *base) | ||
372 | { | ||
373 | remix_base_set_methods(env, base, &_alsa_player_methods); | ||
374 | return base; | ||
375 | } | ||
376 | |||
377 | static struct _RemixMetaText alsa_player_metatext = | ||
378 | { | ||
379 | "alsa_snd_player", | ||
380 | "ALSA sound player for Remix", | ||
381 | "Output the audio stream into ALSA Driver", | ||
382 | "Copyright (C) 2011, Samsung Electronics Co., Ltd.", | ||
383 | "http://www.samsung.com", | ||
384 | REMIX_ONE_AUTHOR("Govindaraju SM", "prince.dubey@samsung.com"), | ||
385 | }; | ||
386 | |||
387 | static struct _RemixPlugin alsa_player_plugin = | ||
388 | { | ||
389 | &alsa_player_metatext, | ||
390 | REMIX_FLAGS_NONE, | ||
391 | CD_EMPTY_SET, /* init scheme */ | ||
392 | alsa_player_init, | ||
393 | CD_EMPTY_SET, /* process scheme */ | ||
394 | NULL, /* suggests */ | ||
395 | NULL, /* plugin data */ | ||
396 | NULL /* destroy */ | ||
397 | }; | ||
398 | |||
399 | EAPI CDList * | ||
400 | remix_load(RemixEnv *env) | ||
401 | { | ||
402 | CDList *plugins = cd_list_new(env); | ||
403 | plugins = cd_list_prepend(env, plugins, CD_POINTER(&alsa_player_plugin)); | ||
404 | return plugins; | ||
405 | } | ||