author | Matthew Gregan <kinetik@flim.org> |
Mon, 16 Jul 2012 17:15:24 -0400 | |
changeset 100940 | e40d733dae5358a96c42c3d91d95ad83f3365c20 |
parent 100939 | 376aa1851c9afaf7c929c14b8d6d849a718e1a16 |
child 100941 | 5276035f74f397fab2bdc1e8a65b9b7b5efa53ab |
push id | 23202 |
push user | emorley@mozilla.com |
push date | Tue, 31 Jul 2012 12:59:27 +0000 |
treeherder | mozilla-central@1ab429a89429 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | doublec |
bugs | 761274 |
milestone | 17.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/content/media/nsAudioStream.cpp +++ b/content/media/nsAudioStream.cpp @@ -875,23 +875,23 @@ class nsBufferedAudioStream : public nsA PRInt32 GetMinWriteSize(); private: static long DataCallback_S(cubeb_stream*, void* aThis, void* aBuffer, long aFrames) { return static_cast<nsBufferedAudioStream*>(aThis)->DataCallback(aBuffer, aFrames); } - static int StateCallback_S(cubeb_stream*, void* aThis, cubeb_state aState) + static void StateCallback_S(cubeb_stream*, void* aThis, cubeb_state aState) { - return static_cast<nsBufferedAudioStream*>(aThis)->StateCallback(aState); + static_cast<nsBufferedAudioStream*>(aThis)->StateCallback(aState); } long DataCallback(void* aBuffer, long aFrames); - int StateCallback(cubeb_state aState); + void StateCallback(cubeb_state aState); // Shared implementation of underflow adjusted position calculation. // Caller must own the monitor. PRInt64 GetPositionInFramesUnlocked(); // The monitor is held to protect all access to member variables. Write() // waits while mBuffer is full; DataCallback() notifies as it consumes // data from mBuffer. Drain() waits while mState is DRAINING; @@ -1263,22 +1263,21 @@ nsBufferedAudioStream::DataCallback(void memset(static_cast<PRUint8*>(aBuffer) + available, 0, bytesWanted); mLostFrames += bytesWanted / mBytesPerFrame; bytesWanted = 0; } return aFrames - (bytesWanted / mBytesPerFrame); } -int +void nsBufferedAudioStream::StateCallback(cubeb_state aState) { MonitorAutoLock mon(mMonitor); if (aState == CUBEB_STATE_DRAINED) { mState = DRAINED; } else if (aState == CUBEB_STATE_ERROR) { mState = ERRORED; } mon.NotifyAll(); - return CUBEB_OK; } #endif
--- a/media/libcubeb/AUTHORS +++ b/media/libcubeb/AUTHORS @@ -1,1 +1,2 @@ Matthew Gregan <kinetik@flim.org> +Alexandre Ratchov <alex@caoua.org>
--- a/media/libcubeb/README_MOZILLA +++ b/media/libcubeb/README_MOZILLA @@ -1,8 +1,8 @@ The source from this directory was copied from the cubeb git repository using the update.sh script. The only changes made were those applied by update.sh and the addition of Makefile.in build files for the Mozilla build system. The cubeb git repository is: git://github.com/kinetiknz/cubeb.git -The git commit ID used was 21d9678eb9755761f7a9d26253189b926258de7c. +The git commit ID used was f3116936eba69aced240df7db77264269f3f95ae.
--- a/media/libcubeb/include/cubeb.h +++ b/media/libcubeb/include/cubeb.h @@ -35,18 +35,18 @@ extern "C" { unsigned int latency_ms = 250; cubeb_stream * stm; cubeb_stream_init(app_ctx, &stm, "Example Stream 1", params, latency_ms, data_cb, state_cb, NULL); cubeb_stream_start(stm); for (;;) { - cubeb_get_time(stm, &ts); - printf("time=%lu\n", ts); + cubeb_stream_get_position(stm, &ts); + printf("time=%llu\n", ts); sleep(1); } cubeb_stream_stop(stm); cubeb_stream_destroy(stm); cubeb_destroy(app_ctx); @endcode @@ -59,20 +59,19 @@ extern "C" { buf[i][c] = 0; } } return nframes; } @endcode @code - int state_cb(cubeb_stream * stm, void * user, cubeb_state state) + void state_cb(cubeb_stream * stm, void * user, cubeb_state state) { printf("state=%d\n", state); - return CUBEB_OK; } @endcode */ /** @file The <tt>libcubeb</tt> C API. */ @@ -136,31 +135,34 @@ enum { typedef long (* cubeb_data_callback)(cubeb_stream * stream, void * user_ptr, void * buffer, long nframes); /** User supplied state callback. @param stream @param user_ptr - @param state - @retval CUBEB_OK - @retval CUBEB_ERROR */ -typedef int (* cubeb_state_callback)(cubeb_stream * stream, - void * user_ptr, - cubeb_state state); + @param state */ +typedef void (* cubeb_state_callback)(cubeb_stream * stream, + void * user_ptr, + cubeb_state state); /** Initialize an application context. This will perform any library or application scoped initialization. @param context @param context_name @retval CUBEB_OK @retval CUBEB_ERROR */ int cubeb_init(cubeb ** context, char const * context_name); +/** Get a read-only string identifying this context's current backend. + @param context + @retval Read-only string identifying current backend. */ +char const * cubeb_get_backend_id(cubeb * context); + /** Destroy an application context. @param context */ void cubeb_destroy(cubeb * context); /** Initialize a stream associated with the supplied application context. @param context @param stream @param stream_name
--- a/media/libcubeb/src/cubeb_alsa.c +++ b/media/libcubeb/src/cubeb_alsa.c @@ -15,16 +15,18 @@ #include <unistd.h> #include <alsa/asoundlib.h> #include "cubeb/cubeb.h" #define CUBEB_STREAM_MAX 16 #define CUBEB_WATCHDOG_MS 10000 #define UNUSED __attribute__ ((__unused__)) +#define ALSA_PA_PLUGIN "ALSA <-> PulseAudio PCM I/O Plugin" + /* ALSA is not thread-safe. snd_pcm_t instances are individually protected by the owning cubeb_stream's mutex. snd_pcm_t creation and destruction is not thread-safe until ALSA 1.0.24 (see alsa-lib.git commit 91c9c8f1), so those calls must be wrapped in the following mutex. */ static pthread_mutex_t cubeb_alsa_mutex = PTHREAD_MUTEX_INITIALIZER; static int cubeb_alsa_error_handler_set = 0; struct cubeb { @@ -469,16 +471,34 @@ cubeb_unregister_stream(cubeb_stream * s } static void silent_error_handler(char const * file UNUSED, int line UNUSED, char const * function UNUSED, int err UNUSED, char const * fmt UNUSED, ...) { } +static int +pcm_uses_pulseaudio_plugin(snd_pcm_t * pcm) +{ + snd_output_t * out; + char * buf; + size_t bufsz; + int r; + + snd_output_buffer_open(&out); + snd_pcm_dump(pcm, out); + bufsz = snd_output_buffer_string(out, &buf); + r = bufsz >= strlen(ALSA_PA_PLUGIN) && + strncmp(buf, ALSA_PA_PLUGIN, strlen(ALSA_PA_PLUGIN)) == 0; + snd_output_close(out); + + return r; +} + int cubeb_init(cubeb ** context, char const * context_name UNUSED) { cubeb * ctx; int r; int i; int fd[2]; pthread_attr_t attr; @@ -526,16 +546,22 @@ cubeb_init(cubeb ** context, char const r = pthread_attr_destroy(&attr); assert(r == 0); *context = ctx; return CUBEB_OK; } +char const * +cubeb_get_backend_id(cubeb * ctx UNUSED) +{ + return "alsa"; +} + void cubeb_destroy(cubeb * ctx) { int r; assert(ctx); pthread_mutex_lock(&ctx->mutex); @@ -616,16 +642,22 @@ cubeb_stream_init(cubeb * ctx, cubeb_str if (r < 0) { cubeb_stream_destroy(stm); return CUBEB_ERROR; } r = snd_pcm_nonblock(stm->pcm, 1); assert(r == 0); + /* Ugly hack: the PA ALSA plugin allows buffer configurations that can't + possibly work. See https://bugzilla.mozilla.org/show_bug.cgi?id=761274 */ + if (pcm_uses_pulseaudio_plugin(stm->pcm)) { + latency = latency < 200 ? 200 : latency; + } + r = snd_pcm_set_params(stm->pcm, format, SND_PCM_ACCESS_RW_INTERLEAVED, stm->params.channels, stm->params.rate, 1, latency * 1000); if (r < 0) { cubeb_stream_destroy(stm); return CUBEB_ERROR_INVALID_FORMAT; }
--- a/media/libcubeb/src/cubeb_audiounit.c +++ b/media/libcubeb/src/cubeb_audiounit.c @@ -82,16 +82,22 @@ audio_unit_output_callback(void * user_p int cubeb_init(cubeb ** context, char const * context_name) { *context = (void *) 0xdeadbeef; return CUBEB_OK; } +char const * +cubeb_get_backend_id(cubeb * ctx) +{ + return "audiounit"; +} + void cubeb_destroy(cubeb * ctx) { assert(ctx == (void *) 0xdeadbeef); } int cubeb_stream_init(cubeb * context, cubeb_stream ** stream, char const * stream_name,
--- a/media/libcubeb/src/cubeb_pulse.c +++ b/media/libcubeb/src/cubeb_pulse.c @@ -111,19 +111,19 @@ stream_request_callback(pa_stream * s, s return; } r = pa_stream_write(s, buffer, got * frame_size, NULL, 0, PA_SEEK_RELATIVE); assert(r == 0); if ((size_t) got < size / frame_size) { size_t buffer_fill = pa_stream_get_buffer_attr(s)->maxlength - pa_stream_writable_size(s); - double buffer_time = (double) buffer_fill / stm->sample_spec.rate; + pa_usec_t buffer_time = pa_bytes_to_usec(buffer_fill, &stm->sample_spec); /* pa_stream_drain is useless, see PA bug# 866. this is a workaround. */ - stm->drain_timer = pa_context_rttime_new(stm->context->context, pa_rtclock_now() + buffer_time * 1e6, stream_drain_callback, stm); + stm->drain_timer = pa_context_rttime_new(stm->context->context, pa_rtclock_now() + buffer_time, stream_drain_callback, stm); stm->shutdown = 1; return; } towrite -= size; } assert(towrite == 0); @@ -206,16 +206,22 @@ cubeb_init(cubeb ** context, char const state_wait(ctx, PA_CONTEXT_READY); *context = ctx; return CUBEB_OK; } +char const * +cubeb_get_backend_id(cubeb * ctx) +{ + return "pulse"; +} + void cubeb_destroy(cubeb * ctx) { pa_operation * o; if (ctx->context) { pa_threaded_mainloop_lock(ctx->mainloop); o = pa_context_drain(ctx->context, context_notify_callback, ctx->mainloop); @@ -290,17 +296,17 @@ cubeb_stream_init(cubeb * context, cubeb stm->state_callback = state_callback; stm->user_ptr = user_ptr; stm->sample_spec = ss; battr.maxlength = -1; battr.tlength = pa_usec_to_bytes(latency * PA_USEC_PER_MSEC, &stm->sample_spec); battr.prebuf = -1; - battr.minreq = battr.tlength / 2; + battr.minreq = battr.tlength / 4; battr.fragsize = -1; pa_threaded_mainloop_lock(stm->context->mainloop); stm->stream = pa_stream_new(stm->context->context, stream_name, &ss, &map); pa_stream_set_state_callback(stm->stream, stream_state_callback, stm->context->mainloop); pa_stream_set_write_callback(stm->stream, stream_request_callback, stm); pa_stream_connect_playback(stm->stream, NULL, &battr, PA_STREAM_AUTO_TIMING_UPDATE | PA_STREAM_INTERPOLATE_TIMING |
--- a/media/libcubeb/src/cubeb_winmm.c +++ b/media/libcubeb/src/cubeb_winmm.c @@ -1,10 +1,10 @@ /* - * Copyright 2011 Mozilla Foundation + * Copyright © 2011 Mozilla Foundation * * This program is made available under an ISC-style license. See the * accompanying file LICENSE for details. */ #undef NDEBUG #include <assert.h> #include <windows.h> #include <mmreg.h> @@ -118,16 +118,17 @@ cubeb_refill_stream(cubeb_stream * stm) wanted = (DWORD) stm->buffer_size / bytes_per_frame(stm->params); /* It is assumed that the caller is holding this lock. It must be dropped during the callback to avoid deadlocks. */ LeaveCriticalSection(&stm->lock); got = stm->data_callback(stm, stm->user_ptr, hdr->lpData, wanted); EnterCriticalSection(&stm->lock); if (got < 0) { + LeaveCriticalSection(&stm->lock); /* XXX handle this case */ assert(0); return; } else if (got < wanted) { stm->draining = 1; } assert(hdr->dwFlags & WHDR_PREPARED); @@ -221,16 +222,22 @@ cubeb_init(cubeb ** context, char const InitializeCriticalSection(&ctx->lock); ctx->active_streams = 0; *context = ctx; return CUBEB_OK; } +char const * +cubeb_get_backend_id(cubeb * ctx) +{ + return "winmm"; +} + void cubeb_destroy(cubeb * ctx) { DWORD rv; assert(ctx->active_streams == 0); assert(!InterlockedPopEntrySList(ctx->work));