CLOSED TREE: TraceMonkey merge head. (a=blockers)
[mozilla-central.git] / media / libsydneyaudio / sydney_android.patch
blobbf4e1ba6123d950d700c526b02bc5bf25d0d67af
1 diff --git a/media/libsydneyaudio/src/Makefile.in b/media/libsydneyaudio/src/Makefile.in
2 --- a/media/libsydneyaudio/src/Makefile.in
3 +++ b/media/libsydneyaudio/src/Makefile.in
4 @@ -51,7 +51,11 @@ CSRCS = \
5 $(NULL)
6 endif
8 -ifeq ($(OS_ARCH),Linux)
9 +ifeq ($(OS_TARGET),Android)
10 +CSRCS = \
11 + sydney_audio_android.c \
12 + $(NULL)
13 +else ifeq ($(OS_ARCH),Linux)
14 CSRCS = \
15 sydney_audio_alsa.c \
16 $(NULL)
17 diff --git a/media/libsydneyaudio/src/sydney_audio_android.c b/media/libsydneyaudio/src/sydney_audio_android.c
18 new file mode 100644
19 --- /dev/null
20 +++ b/media/libsydneyaudio/src/sydney_audio_android.c
21 @@ -0,0 +1,530 @@
22 +/* ***** BEGIN LICENSE BLOCK *****
23 + * Version: MPL 1.1/GPL 2.0/LGPL 2.1
24 + *
25 + * The contents of this file are subject to the Mozilla Public License Version
26 + * 1.1 (the "License"); you may not use this file except in compliance with
27 + * the License. You may obtain a copy of the License at
28 + * http://www.mozilla.org/MPL/
29 + *
30 + * Software distributed under the License is distributed on an "AS IS" basis,
31 + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
32 + * for the specific language governing rights and limitations under the
33 + * License.
34 + *
35 + * The Initial Developer of the Original Code is
36 + * CSIRO
37 + * Portions created by the Initial Developer are Copyright (C) 2007
38 + * the Initial Developer. All Rights Reserved.
39 + *
40 + * Contributor(s): Michael Martin
41 + * Michael Wu <mwu@mozilla.com>
42 + *
43 + * Alternatively, the contents of this file may be used under the terms of
44 + * either the GNU General Public License Version 2 or later (the "GPL"), or
45 + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
46 + * in which case the provisions of the GPL or the LGPL are applicable instead
47 + * of those above. If you wish to allow use of your version of this file only
48 + * under the terms of either the GPL or the LGPL, and not to allow others to
49 + * use your version of this file under the terms of the MPL, indicate your
50 + * decision by deleting the provisions above and replace them with the notice
51 + * and other provisions required by the GPL or the LGPL. If you do not delete
52 + * the provisions above, a recipient may use your version of this file under
53 + * the terms of any one of the MPL, the GPL or the LGPL.
54 + *
55 + * ***** END LICENSE BLOCK ***** *
56 + */
58 +#include <stdlib.h>
59 +#include <time.h>
60 +#include <jni.h>
61 +#include "sydney_audio.h"
63 +#include "android/log.h"
65 +#ifndef ALOG
66 +#if defined(DEBUG) || defined(FORCE_ALOG)
67 +#define ALOG(args...) __android_log_print(ANDROID_LOG_INFO, "Gecko - SYDNEY_AUDIO" , ## args)
68 +#else
69 +#define ALOG(args...)
70 +#endif
71 +#endif
73 +/* Android implementation based on sydney_audio_mac.c */
75 +#define NANOSECONDS_IN_MILLISECOND 1000000
76 +#define MILLISECONDS_PER_SECOND 1000
78 +/* android.media.AudioTrack */
79 +struct AudioTrack {
80 + jclass class;
81 + jmethodID constructor;
82 + jmethodID flush;
83 + jmethodID pause;
84 + jmethodID play;
85 + jmethodID setvol;
86 + jmethodID stop;
87 + jmethodID write;
88 + jmethodID getpos;
89 +};
91 +enum AudioTrackMode {
92 + MODE_STATIC = 0,
93 + MODE_STREAM = 1
94 +};
96 +/* android.media.AudioManager */
97 +enum AudioManagerStream {
98 + STREAM_VOICE_CALL = 0,
99 + STREAM_SYSTEM = 1,
100 + STREAM_RING = 2,
101 + STREAM_MUSIC = 3,
102 + STREAM_ALARM = 4,
103 + STREAM_NOTIFICATION = 5,
104 + STREAM_DTMF = 8
107 +/* android.media.AudioFormat */
108 +enum AudioFormatChannel {
109 + CHANNEL_OUT_MONO = 4,
110 + CHANNEL_OUT_STEREO = 12
113 +enum AudioFormatEncoding {
114 + ENCODING_PCM_16BIT = 2,
115 + ENCODING_PCM_8BIT = 3
118 +struct sa_stream {
119 + jobject output_unit;
121 + unsigned int rate;
122 + unsigned int channels;
123 + unsigned int isPaused;
125 + int64_t lastStartTime;
126 + int64_t timePlaying;
127 + int64_t amountWritten;
128 + unsigned int bufferSize;
130 + jclass at_class;
133 +static struct AudioTrack at;
134 +extern JNIEnv * GetJNIForThread();
136 +static jclass
137 +init_jni_bindings(JNIEnv *jenv) {
138 + jclass class =
139 + (*jenv)->NewGlobalRef(jenv,
140 + (*jenv)->FindClass(jenv,
141 + "android/media/AudioTrack"));
142 + at.constructor = (*jenv)->GetMethodID(jenv, class, "<init>", "(IIIIII)V");
143 + at.flush = (*jenv)->GetMethodID(jenv, class, "flush", "()V");
144 + at.pause = (*jenv)->GetMethodID(jenv, class, "pause", "()V");
145 + at.play = (*jenv)->GetMethodID(jenv, class, "play", "()V");
146 + at.setvol = (*jenv)->GetMethodID(jenv, class, "setStereoVolume", "(FF)I");
147 + at.stop = (*jenv)->GetMethodID(jenv, class, "stop", "()V");
148 + at.write = (*jenv)->GetMethodID(jenv, class, "write", "([BII)I");
149 + at.getpos = (*jenv)->GetMethodID(jenv, class, "getPlaybackHeadPosition", "()I");
151 + return class;
155 + * -----------------------------------------------------------------------------
156 + * Startup and shutdown functions
157 + * -----------------------------------------------------------------------------
158 + */
160 +int
161 +sa_stream_create_pcm(
162 + sa_stream_t ** _s,
163 + const char * client_name,
164 + sa_mode_t mode,
165 + sa_pcm_format_t format,
166 + unsigned int rate,
167 + unsigned int channels
168 +) {
170 + /*
171 + * Make sure we return a NULL stream pointer on failure.
172 + */
173 + if (_s == NULL) {
174 + return SA_ERROR_INVALID;
176 + *_s = NULL;
178 + if (mode != SA_MODE_WRONLY) {
179 + return SA_ERROR_NOT_SUPPORTED;
181 + if (format != SA_PCM_FORMAT_S16_NE) {
182 + return SA_ERROR_NOT_SUPPORTED;
184 + if (channels != 1 && channels != 2) {
185 + return SA_ERROR_NOT_SUPPORTED;
188 + /*
189 + * Allocate the instance and required resources.
190 + */
191 + sa_stream_t *s;
192 + if ((s = malloc(sizeof(sa_stream_t))) == NULL) {
193 + return SA_ERROR_OOM;
196 + s->output_unit = NULL;
197 + s->rate = rate;
198 + s->channels = channels;
199 + s->isPaused = 0;
201 + s->lastStartTime = 0;
202 + s->timePlaying = 0;
203 + s->amountWritten = 0;
205 + s->bufferSize = rate * channels;
207 + *_s = s;
208 + return SA_SUCCESS;
212 +int
213 +sa_stream_open(sa_stream_t *s) {
215 + if (s == NULL) {
216 + return SA_ERROR_NO_INIT;
218 + if (s->output_unit != NULL) {
219 + return SA_ERROR_INVALID;
222 + JNIEnv *jenv = GetJNIForThread();
223 + if (!jenv)
224 + return SA_ERROR_NO_DEVICE;
226 + if ((*jenv)->PushLocalFrame(jenv, 4)) {
227 + return SA_ERROR_OOM;
230 + s->at_class = init_jni_bindings(jenv);
232 + int32_t chanConfig = s->channels == 1 ?
233 + CHANNEL_OUT_MONO : CHANNEL_OUT_STEREO;
235 + jobject obj =
236 + (*jenv)->NewObject(jenv, s->at_class, at.constructor,
237 + STREAM_MUSIC,
238 + s->rate,
239 + chanConfig,
240 + ENCODING_PCM_16BIT,
241 + s->bufferSize,
242 + MODE_STREAM);
244 + if (!obj) {
245 + (*jenv)->DeleteGlobalRef(jenv, s->at_class);
246 + (*jenv)->PopLocalFrame(jenv, NULL);
247 + return SA_ERROR_OOM;
250 + s->output_unit = (*jenv)->NewGlobalRef(jenv, obj);
251 + (*jenv)->PopLocalFrame(jenv, NULL);
253 + ALOG("%x - New stream %d %d", s, s->rate, s->channels);
254 + return SA_SUCCESS;
258 +int
259 +sa_stream_destroy(sa_stream_t *s) {
261 + if (s == NULL) {
262 + return SA_ERROR_NO_INIT;
265 + JNIEnv *jenv = GetJNIForThread();
266 + if (!jenv)
267 + return SA_SUCCESS;
269 + (*jenv)->DeleteGlobalRef(jenv, s->output_unit);
270 + (*jenv)->DeleteGlobalRef(jenv, s->at_class);
271 + free(s);
273 + ALOG("%x - Stream destroyed", s);
274 + return SA_SUCCESS;
279 + * -----------------------------------------------------------------------------
280 + * Data read and write functions
281 + * -----------------------------------------------------------------------------
282 + */
284 +int
285 +sa_stream_write(sa_stream_t *s, const void *data, size_t nbytes) {
287 + if (s == NULL || s->output_unit == NULL) {
288 + return SA_ERROR_NO_INIT;
290 + if (nbytes == 0) {
291 + return SA_SUCCESS;
293 + JNIEnv *jenv = GetJNIForThread();
294 + if ((*jenv)->PushLocalFrame(jenv, 2)) {
295 + return SA_ERROR_OOM;
298 + jbyteArray bytearray = (*jenv)->NewByteArray(jenv, nbytes);
299 + if (!bytearray) {
300 + (*jenv)->ExceptionClear(jenv);
301 + (*jenv)->PopLocalFrame(jenv, NULL);
302 + return SA_ERROR_OOM;
305 + jbyte *byte = (*jenv)->GetByteArrayElements(jenv, bytearray, NULL);
306 + if (!byte) {
307 + (*jenv)->PopLocalFrame(jenv, NULL);
308 + return SA_ERROR_OOM;
311 + memcpy(byte, data, nbytes);
313 + size_t wroteSoFar = 0;
314 + jint retval;
316 + do {
317 + retval = (*jenv)->CallIntMethod(jenv,
318 + s->output_unit,
319 + at.write,
320 + bytearray,
321 + wroteSoFar,
322 + nbytes - wroteSoFar);
323 + if (retval < 0) {
324 + ALOG("%x - Write failed %d", s, retval);
325 + break;
328 + wroteSoFar += retval;
330 + if (wroteSoFar != nbytes) {
332 + /* android doesn't start playing until we explictly call play. */
333 + if (!s->isPaused)
334 + sa_stream_resume(s);
336 + struct timespec ts = {0, 100000000}; /* .10s */
337 + nanosleep(&ts, NULL);
339 + } while(wroteSoFar < nbytes);
341 + s->amountWritten += nbytes;
343 + (*jenv)->ReleaseByteArrayElements(jenv, bytearray, byte, 0);
345 + (*jenv)->PopLocalFrame(jenv, NULL);
347 + return retval < 0 ? SA_ERROR_INVALID : SA_SUCCESS;
352 + * -----------------------------------------------------------------------------
353 + * General query and support functions
354 + * -----------------------------------------------------------------------------
355 + */
357 +int
358 +sa_stream_get_write_size(sa_stream_t *s, size_t *size) {
360 + if (s == NULL || s->output_unit == NULL) {
361 + return SA_ERROR_NO_INIT;
364 + /* No android API for this, so estimate based on how much we have played and
365 + * how much we have written.
366 + */
367 + *size = s->bufferSize - ((s->timePlaying * s->channels * s->rate /
368 + MILLISECONDS_PER_SECOND) - s->amountWritten);
369 + ALOG("%x - Write Size %d", s, *size);
371 + return SA_SUCCESS;
375 +int
376 +sa_stream_get_position(sa_stream_t *s, sa_position_t position, int64_t *pos) {
378 + if (s == NULL || s->output_unit == NULL) {
379 + return SA_ERROR_NO_INIT;
382 + ALOG("%x - get position", s);
384 + JNIEnv *jenv = GetJNIForThread();
385 + *pos = (*jenv)->CallIntMethod(jenv, s->output_unit, at.getpos);
387 + /* android returns number of frames, so:
388 + position = frames * (PCM_16_BIT == 2 bytes) * channels
389 + */
390 + *pos *= s->channels * sizeof(int16_t);
391 + return SA_SUCCESS;
395 +int
396 +sa_stream_pause(sa_stream_t *s) {
398 + if (s == NULL || s->output_unit == NULL) {
399 + return SA_ERROR_NO_INIT;
402 + JNIEnv *jenv = GetJNIForThread();
403 + s->isPaused = 1;
405 + /* Update stats */
406 + if (s->lastStartTime != 0) {
407 + /* if lastStartTime is not zero, so playback has started */
408 + struct timespec current_time;
409 + clock_gettime(CLOCK_REALTIME, &current_time);
410 + int64_t ticker = current_time.tv_sec * 1000 + current_time.tv_nsec / 1000000;
411 + s->timePlaying += ticker - s->lastStartTime;
413 + ALOG("%x - Pause total time playing: %lld total written: %lld", s, s->timePlaying, s->amountWritten);
415 + (*jenv)->CallVoidMethod(jenv, s->output_unit, at.pause);
416 + return SA_SUCCESS;
420 +int
421 +sa_stream_resume(sa_stream_t *s) {
423 + if (s == NULL || s->output_unit == NULL) {
424 + return SA_ERROR_NO_INIT;
427 + ALOG("%x - resume", s);
429 + JNIEnv *jenv = GetJNIForThread();
430 + s->isPaused = 0;
432 + /* Update stats */
433 + struct timespec current_time;
434 + clock_gettime(CLOCK_REALTIME, &current_time);
435 + int64_t ticker = current_time.tv_sec * 1000 + current_time.tv_nsec / 1000000;
436 + s->lastStartTime = ticker;
438 + (*jenv)->CallVoidMethod(jenv, s->output_unit, at.play);
439 + return SA_SUCCESS;
443 +int
444 +sa_stream_drain(sa_stream_t *s)
446 + if (s == NULL || s->output_unit == NULL) {
447 + return SA_ERROR_NO_INIT;
450 + /* There is no way with the Android SDK to determine exactly how
451 + long to playback. So estimate and sleep for the long.
452 + */
454 + size_t available;
455 + sa_stream_get_write_size(s, &available);
457 + long x = (s->bufferSize - available) * 1000 / s->channels / s->rate / sizeof(int16_t) * NANOSECONDS_IN_MILLISECOND;
458 + ALOG("%x - Drain - sleep for %f ns", s, x);
460 + struct timespec ts = {0, x};
461 + nanosleep(&ts, NULL);
463 + return SA_SUCCESS;
468 + * -----------------------------------------------------------------------------
469 + * Extension functions
470 + * -----------------------------------------------------------------------------
471 + */
473 +int
474 +sa_stream_set_volume_abs(sa_stream_t *s, float vol) {
476 + if (s == NULL || s->output_unit == NULL) {
477 + return SA_ERROR_NO_INIT;
480 + JNIEnv *jenv = GetJNIForThread();
481 + (*jenv)->CallIntMethod(jenv, s->output_unit, at.setvol,
482 + (jfloat)vol, (jfloat)vol);
484 + return SA_SUCCESS;
488 + * -----------------------------------------------------------------------------
489 + * Unsupported functions
490 + * -----------------------------------------------------------------------------
491 + */
492 +#define UNSUPPORTED(func) func { return SA_ERROR_NOT_SUPPORTED; }
494 +UNSUPPORTED(int sa_stream_create_opaque(sa_stream_t **s, const char *client_name, sa_mode_t mode, const char *codec))
495 +UNSUPPORTED(int sa_stream_set_write_lower_watermark(sa_stream_t *s, size_t size))
496 +UNSUPPORTED(int sa_stream_set_read_lower_watermark(sa_stream_t *s, size_t size))
497 +UNSUPPORTED(int sa_stream_set_write_upper_watermark(sa_stream_t *s, size_t size))
498 +UNSUPPORTED(int sa_stream_set_read_upper_watermark(sa_stream_t *s, size_t size))
499 +UNSUPPORTED(int sa_stream_set_channel_map(sa_stream_t *s, const sa_channel_t map[], unsigned int n))
500 +UNSUPPORTED(int sa_stream_set_xrun_mode(sa_stream_t *s, sa_xrun_mode_t mode))
501 +UNSUPPORTED(int sa_stream_set_non_interleaved(sa_stream_t *s, int enable))
502 +UNSUPPORTED(int sa_stream_set_dynamic_rate(sa_stream_t *s, int enable))
503 +UNSUPPORTED(int sa_stream_set_driver(sa_stream_t *s, const char *driver))
504 +UNSUPPORTED(int sa_stream_start_thread(sa_stream_t *s, sa_event_callback_t callback))
505 +UNSUPPORTED(int sa_stream_stop_thread(sa_stream_t *s))
506 +UNSUPPORTED(int sa_stream_change_device(sa_stream_t *s, const char *device_name))
507 +UNSUPPORTED(int sa_stream_change_read_volume(sa_stream_t *s, const int32_t vol[], unsigned int n))
508 +UNSUPPORTED(int sa_stream_change_write_volume(sa_stream_t *s, const int32_t vol[], unsigned int n))
509 +UNSUPPORTED(int sa_stream_change_rate(sa_stream_t *s, unsigned int rate))
510 +UNSUPPORTED(int sa_stream_change_meta_data(sa_stream_t *s, const char *name, const void *data, size_t size))
511 +UNSUPPORTED(int sa_stream_change_user_data(sa_stream_t *s, const void *value))
512 +UNSUPPORTED(int sa_stream_set_adjust_rate(sa_stream_t *s, sa_adjust_t direction))
513 +UNSUPPORTED(int sa_stream_set_adjust_nchannels(sa_stream_t *s, sa_adjust_t direction))
514 +UNSUPPORTED(int sa_stream_set_adjust_pcm_format(sa_stream_t *s, sa_adjust_t direction))
515 +UNSUPPORTED(int sa_stream_set_adjust_watermarks(sa_stream_t *s, sa_adjust_t direction))
516 +UNSUPPORTED(int sa_stream_get_mode(sa_stream_t *s, sa_mode_t *access_mode))
517 +UNSUPPORTED(int sa_stream_get_codec(sa_stream_t *s, char *codec, size_t *size))
518 +UNSUPPORTED(int sa_stream_get_pcm_format(sa_stream_t *s, sa_pcm_format_t *format))
519 +UNSUPPORTED(int sa_stream_get_rate(sa_stream_t *s, unsigned int *rate))
520 +UNSUPPORTED(int sa_stream_get_nchannels(sa_stream_t *s, int *nchannels))
521 +UNSUPPORTED(int sa_stream_get_user_data(sa_stream_t *s, void **value))
522 +UNSUPPORTED(int sa_stream_get_write_lower_watermark(sa_stream_t *s, size_t *size))
523 +UNSUPPORTED(int sa_stream_get_read_lower_watermark(sa_stream_t *s, size_t *size))
524 +UNSUPPORTED(int sa_stream_get_write_upper_watermark(sa_stream_t *s, size_t *size))
525 +UNSUPPORTED(int sa_stream_get_read_upper_watermark(sa_stream_t *s, size_t *size))
526 +UNSUPPORTED(int sa_stream_get_channel_map(sa_stream_t *s, sa_channel_t map[], unsigned int *n))
527 +UNSUPPORTED(int sa_stream_get_xrun_mode(sa_stream_t *s, sa_xrun_mode_t *mode))
528 +UNSUPPORTED(int sa_stream_get_non_interleaved(sa_stream_t *s, int *enabled))
529 +UNSUPPORTED(int sa_stream_get_dynamic_rate(sa_stream_t *s, int *enabled))
530 +UNSUPPORTED(int sa_stream_get_driver(sa_stream_t *s, char *driver_name, size_t *size))
531 +UNSUPPORTED(int sa_stream_get_device(sa_stream_t *s, char *device_name, size_t *size))
532 +UNSUPPORTED(int sa_stream_get_read_volume(sa_stream_t *s, int32_t vol[], unsigned int *n))
533 +UNSUPPORTED(int sa_stream_get_write_volume(sa_stream_t *s, int32_t vol[], unsigned int *n))
534 +UNSUPPORTED(int sa_stream_get_meta_data(sa_stream_t *s, const char *name, void*data, size_t *size))
535 +UNSUPPORTED(int sa_stream_get_adjust_rate(sa_stream_t *s, sa_adjust_t *direction))
536 +UNSUPPORTED(int sa_stream_get_adjust_nchannels(sa_stream_t *s, sa_adjust_t *direction))
537 +UNSUPPORTED(int sa_stream_get_adjust_pcm_format(sa_stream_t *s, sa_adjust_t *direction))
538 +UNSUPPORTED(int sa_stream_get_adjust_watermarks(sa_stream_t *s, sa_adjust_t *direction))
539 +UNSUPPORTED(int sa_stream_get_state(sa_stream_t *s, sa_state_t *state))
540 +UNSUPPORTED(int sa_stream_get_event_error(sa_stream_t *s, sa_error_t *error))
541 +UNSUPPORTED(int sa_stream_get_event_notify(sa_stream_t *s, sa_notify_t *notify))
542 +UNSUPPORTED(int sa_stream_read(sa_stream_t *s, void *data, size_t nbytes))
543 +UNSUPPORTED(int sa_stream_read_ni(sa_stream_t *s, unsigned int channel, void *data, size_t nbytes))
544 +UNSUPPORTED(int sa_stream_write_ni(sa_stream_t *s, unsigned int channel, const void *data, size_t nbytes))
545 +UNSUPPORTED(int sa_stream_pwrite(sa_stream_t *s, const void *data, size_t nbytes, int64_t offset, sa_seek_t whence))
546 +UNSUPPORTED(int sa_stream_pwrite_ni(sa_stream_t *s, unsigned int channel, const void *data, size_t nbytes, int64_t offset, sa_seek_t whence))
547 +UNSUPPORTED(int sa_stream_get_read_size(sa_stream_t *s, size_t *size))
548 +UNSUPPORTED(int sa_stream_get_volume_abs(sa_stream_t *s, float *vol))
550 +const char *sa_strerror(int code) { return NULL; }