From 576ad01988874c9615520f0e003a03ae5ef0eeb4 Mon Sep 17 00:00:00 2001 From: Matthew Gregan Date: Fri, 13 Jan 2012 14:38:39 +1300 Subject: [PATCH] Bug 623444 - Import Windows libcubeb implementation. r=doublec, r=khuey --- config/autoconf.mk.in | 1 + config/system-headers | 1 + configure.in | 18 +- js/src/config/system-headers | 1 + layout/build/Makefile.in | 4 - layout/media/Makefile.in | 10 + layout/media/symbols.def.in | 9 + media/libcubeb/AUTHORS | 1 + media/libcubeb/LICENSE | 13 + media/libcubeb/Makefile.in | 52 ++++ media/libcubeb/README | 3 + media/libcubeb/README_MOZILLA | 8 + media/libcubeb/include/Makefile.in | 48 +++ media/libcubeb/include/cubeb-stdint.h | 1 + media/libcubeb/include/cubeb.h | 208 +++++++++++++ media/libcubeb/src/Makefile.in | 58 ++++ media/libcubeb/src/cubeb_winmm.c | 433 ++++++++++++++++++++++++++ media/libcubeb/update.sh | 27 ++ toolkit/content/license.html | 25 ++ toolkit/toolkit-makefiles.sh | 8 + toolkit/toolkit-tiers.mk | 6 + 21 files changed, 930 insertions(+), 5 deletions(-) create mode 100644 media/libcubeb/AUTHORS create mode 100644 media/libcubeb/LICENSE create mode 100644 media/libcubeb/Makefile.in create mode 100644 media/libcubeb/README create mode 100644 media/libcubeb/README_MOZILLA create mode 100644 media/libcubeb/include/Makefile.in create mode 100644 media/libcubeb/include/cubeb-stdint.h create mode 100644 media/libcubeb/include/cubeb.h create mode 100644 media/libcubeb/src/Makefile.in create mode 100644 media/libcubeb/src/cubeb_winmm.c create mode 100644 media/libcubeb/update.sh diff --git a/config/autoconf.mk.in b/config/autoconf.mk.in index d7bb9421a58f..57cca0db44bf 100644 --- a/config/autoconf.mk.in +++ b/config/autoconf.mk.in @@ -160,6 +160,7 @@ MOZ_ZIPWRITER = @MOZ_ZIPWRITER@ MOZ_OGG = @MOZ_OGG@ MOZ_RAW = @MOZ_RAW@ MOZ_SYDNEYAUDIO = @MOZ_SYDNEYAUDIO@ +MOZ_CUBEB = @MOZ_CUBEB@ MOZ_WAVE = @MOZ_WAVE@ MOZ_MEDIA = @MOZ_MEDIA@ MOZ_VORBIS = @MOZ_VORBIS@ diff --git a/config/system-headers b/config/system-headers index 160816a0ddf8..5bddb3649656 100644 --- a/config/system-headers +++ b/config/system-headers @@ -1050,4 +1050,5 @@ tremor/ivorbiscodec.h ogg/ogg.h ogg/os_types.h nestegg/nestegg.h +cubeb/cubeb.h #endif diff --git a/configure.in b/configure.in index 8d6e1c31ca16..1847f11232a3 100644 --- a/configure.in +++ b/configure.in @@ -4586,6 +4586,7 @@ MOZ_AUTH_EXTENSION=1 MOZ_OGG=1 MOZ_RAW= MOZ_SYDNEYAUDIO= +MOZ_CUBEB= MOZ_VORBIS= MOZ_TREMOR= MOZ_WAVE=1 @@ -5596,6 +5597,7 @@ MOZ_ARG_DISABLE_BOOL(ogg, if test -n "$MOZ_OGG"; then AC_DEFINE(MOZ_OGG) MOZ_SYDNEYAUDIO=1 + MOZ_CUBEB=1 MOZ_MEDIA=1 case "$target_cpu" in arm*) @@ -5713,6 +5715,7 @@ AC_SUBST(MOZ_LIBVPX_LIBS) if test -n "$MOZ_WEBM" -a -z "$MOZ_NATIVE_LIBVPX"; then MOZ_SYDNEYAUDIO=1 + MOZ_CUBEB=1 MOZ_MEDIA=1 case "$target_cpu" in arm*) @@ -5824,17 +5827,29 @@ MOZ_ARG_DISABLE_BOOL(wave, if test -n "$MOZ_WAVE"; then AC_DEFINE(MOZ_WAVE) MOZ_SYDNEYAUDIO=1 + MOZ_CUBEB=1 MOZ_MEDIA=1 fi dnl ======================================================== -dnl = Handle dependent SYDNEYAUDIO and MEDIA defines +dnl = Handle dependent SYDNEYAUDIO, CUBEB, and MEDIA defines dnl ======================================================== if test -n "$MOZ_SYDNEYAUDIO"; then AC_DEFINE(MOZ_SYDNEYAUDIO) fi +if test -n "$MOZ_CUBEB"; then + case "$target" in + *-mingw*) + AC_DEFINE(MOZ_CUBEB) + ;; + *) + dnl Other targets will be enabled soon. + ;; + esac +fi + if test -n "$MOZ_MEDIA"; then AC_DEFINE(MOZ_MEDIA) fi @@ -8696,6 +8711,7 @@ AC_SUBST(MOZ_APP_EXTRA_LIBS) AC_SUBST(MOZ_MEDIA) AC_SUBST(MOZ_SYDNEYAUDIO) +AC_SUBST(MOZ_CUBEB) AC_SUBST(MOZ_WAVE) AC_SUBST(MOZ_VORBIS) AC_SUBST(MOZ_TREMOR) diff --git a/js/src/config/system-headers b/js/src/config/system-headers index 160816a0ddf8..5bddb3649656 100644 --- a/js/src/config/system-headers +++ b/js/src/config/system-headers @@ -1050,4 +1050,5 @@ tremor/ivorbiscodec.h ogg/ogg.h ogg/os_types.h nestegg/nestegg.h +cubeb/cubeb.h #endif diff --git a/layout/build/Makefile.in b/layout/build/Makefile.in index b2609b888ff8..4c42e8bd4d40 100644 --- a/layout/build/Makefile.in +++ b/layout/build/Makefile.in @@ -182,10 +182,6 @@ SHARED_LIBRARY_LIBS += \ $(NULL) endif -ifdef MOZ_SYDNEYAUDIO -LOCAL_INCLUDES += -I$(DEPTH)/content/html/content/src -endif - ifdef NS_PRINTING SHARED_LIBRARY_LIBS += \ ../printing/$(LIB_PREFIX)gkprinting_s.$(LIB_SUFFIX) \ diff --git a/layout/media/Makefile.in b/layout/media/Makefile.in index 7943211ea5ec..6988a80d389f 100644 --- a/layout/media/Makefile.in +++ b/layout/media/Makefile.in @@ -86,6 +86,12 @@ SHARED_LIBRARY_LIBS += \ $(NULL) endif +ifdef MOZ_CUBEB +SHARED_LIBRARY_LIBS += \ + $(DEPTH)/media/libcubeb/src/$(LIB_PREFIX)cubeb.$(LIB_SUFFIX) \ + $(NULL) +endif + SHARED_LIBRARY_LIBS += \ $(DEPTH)/gfx/angle/$(LIB_PREFIX)angle.$(LIB_SUFFIX) \ $(NULL) @@ -100,6 +106,10 @@ else EXTRA_DSO_LDOPTS += $(MOZ_ZLIB_LIBS) endif +ifdef MOZ_CUBEB +EXTRA_DSO_LDOPTS += $(call EXPAND_LIBNAME, winmm ksguid) +endif + DEFFILE = symbols.def endif diff --git a/layout/media/symbols.def.in b/layout/media/symbols.def.in index b09e08a19e88..f76c639a972f 100644 --- a/layout/media/symbols.def.in +++ b/layout/media/symbols.def.in @@ -73,6 +73,15 @@ sa_stream_pause sa_stream_resume sa_stream_write #endif +#ifdef MOZ_CUBEB +cubeb_destroy +cubeb_init +cubeb_stream_destroy +cubeb_stream_get_position +cubeb_stream_init +cubeb_stream_start +cubeb_stream_stop +#endif #ifdef MOZ_OGG th_comment_clear th_comment_init diff --git a/media/libcubeb/AUTHORS b/media/libcubeb/AUTHORS new file mode 100644 index 000000000000..8204f40f474d --- /dev/null +++ b/media/libcubeb/AUTHORS @@ -0,0 +1 @@ +Matthew Gregan diff --git a/media/libcubeb/LICENSE b/media/libcubeb/LICENSE new file mode 100644 index 000000000000..fffc9dc40536 --- /dev/null +++ b/media/libcubeb/LICENSE @@ -0,0 +1,13 @@ +Copyright © 2011 Mozilla Foundation + +Permission to use, copy, modify, and distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. diff --git a/media/libcubeb/Makefile.in b/media/libcubeb/Makefile.in new file mode 100644 index 000000000000..9f5ac0e369d5 --- /dev/null +++ b/media/libcubeb/Makefile.in @@ -0,0 +1,52 @@ +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is mozilla.org code. +# +# The Initial Developer of the Original Code is +# Mozilla Foundation +# Portions created by the Initial Developer are Copyright (C) 2011 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Matthew Gregan +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +DEPTH = ../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +MODULE = cubeb + +DIRS = \ + include \ + src \ + $(NULL) + +include $(topsrcdir)/config/rules.mk diff --git a/media/libcubeb/README b/media/libcubeb/README new file mode 100644 index 000000000000..feb141ecde2c --- /dev/null +++ b/media/libcubeb/README @@ -0,0 +1,3 @@ +See INSTALL for build instructions. + +Licensed under an ISC-style license. See LICENSE for details. diff --git a/media/libcubeb/README_MOZILLA b/media/libcubeb/README_MOZILLA new file mode 100644 index 000000000000..f236dc0d1bc6 --- /dev/null +++ b/media/libcubeb/README_MOZILLA @@ -0,0 +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 ddfaaf39c1a15cfb1a04ce62d6bd253737fc764a-dirty. diff --git a/media/libcubeb/include/Makefile.in b/media/libcubeb/include/Makefile.in new file mode 100644 index 000000000000..cd837d38e0a7 --- /dev/null +++ b/media/libcubeb/include/Makefile.in @@ -0,0 +1,48 @@ +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is mozilla.org code. +# +# The Initial Developer of the Original Code is +# Mozilla Foundation +# Portions created by the Initial Developer are Copyright (C) 2011 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Matthew Gregan +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +DEPTH = ../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +EXPORTS_NAMESPACES = cubeb +EXPORTS_cubeb = cubeb.h cubeb-stdint.h + +include $(topsrcdir)/config/rules.mk diff --git a/media/libcubeb/include/cubeb-stdint.h b/media/libcubeb/include/cubeb-stdint.h new file mode 100644 index 000000000000..13c8060f7351 --- /dev/null +++ b/media/libcubeb/include/cubeb-stdint.h @@ -0,0 +1 @@ +#include "mozilla/StdInt.h" diff --git a/media/libcubeb/include/cubeb.h b/media/libcubeb/include/cubeb.h new file mode 100644 index 000000000000..25dde0e0b04e --- /dev/null +++ b/media/libcubeb/include/cubeb.h @@ -0,0 +1,208 @@ +/* + * Copyright © 2011 Mozilla Foundation + * + * This program is made available under an ISC-style license. See the + * accompanying file LICENSE for details. + */ +#ifndef CUBEB_c2f983e9_c96f_e71c_72c3_bbf62992a382 +#define CUBEB_c2f983e9_c96f_e71c_72c3_bbf62992a382 + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** @mainpage + + @section intro Introduction + + This is the documentation for the libcubeb C API. + libcubeb is a callback-based audio API library allowing the + authoring of portable multiplatform audio playback. + + @section example Example code + + @code + cubeb * app_ctx; + cubeb_init(&app_ctx, "Example Application"); + + cubeb_stream_params params; + params.format = CUBEB_SAMPLE_S16NE; + params.rate = 48000; + params.channels = 2; + + 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); + sleep(1); + } + cubeb_stream_stop(stm); + + cubeb_stream_destroy(stm); + cubeb_destroy(app_ctx); + @endcode + + @code + long data_cb(cubeb_stream * stm, void * user, void * buffer, long nframes) + { + short * buf = buffer; + for (i = 0; i < nframes; ++i) { + for (c = 0; c < params.channels; ++c) { + buf[i][c] = 0; + } + } + return nframes; + } + @endcode + + @code + int state_cb(cubeb_stream * stm, void * user, cubeb_state state) + { + printf("state=%d\n", state); + return CUBEB_OK; + } + @endcode +*/ + + +/** @file + The libcubeb C API. */ + +typedef struct cubeb cubeb; /**< Opaque handle referencing the application state. */ +typedef struct cubeb_stream cubeb_stream; /**< Opaque handle referencing the stream state. */ + +/** Sample format enumeration. */ +typedef enum { + /**< Little endian 16-bit signed PCM. */ + CUBEB_SAMPLE_S16LE, + /**< Big endian 16-bit signed PCM. */ + CUBEB_SAMPLE_S16BE, + /**< Little endian 32-bit IEEE floating point PCM. */ + CUBEB_SAMPLE_FLOAT32LE, + /**< Big endian 32-bit IEEE floating point PCM. */ + CUBEB_SAMPLE_FLOAT32BE, +#ifdef WORDS_BIGENDIAN + /**< Native endian 16-bit signed PCM. */ + CUBEB_SAMPLE_S16NE = CUBEB_SAMPLE_S16BE, + /**< Native endian 32-bit IEEE floating point PCM. */ + CUBEB_SAMPLE_FLOAT32NE = CUBEB_SAMPLE_FLOAT32BE +#else + /**< Native endian 16-bit signed PCM. */ + CUBEB_SAMPLE_S16NE = CUBEB_SAMPLE_S16LE, + /**< Native endian 32-bit IEEE floating point PCM. */ + CUBEB_SAMPLE_FLOAT32NE = CUBEB_SAMPLE_FLOAT32LE +#endif +} cubeb_sample_format; + +/** Stream format initialization parameters. */ +typedef struct { + cubeb_sample_format format; /**< Requested sample format. One of + #cubeb_sample_format. */ + unsigned int rate; /**< Requested sample rate. Valid range is [1, 192000]. */ + unsigned int channels; /**< Requested channel count. Valid range is [1, 32]. */ +} cubeb_stream_params; + +/** Stream states signaled via state_callback. */ +typedef enum { + CUBEB_STATE_STARTED, /**< Stream started. */ + CUBEB_STATE_STOPPED, /**< Stream stopped. */ + CUBEB_STATE_DRAINED /**< Stream drained. */ +} cubeb_state; + +/** Result code enumeration. */ +enum { + CUBEB_OK = 0, /**< Success. */ + CUBEB_ERROR = -1, /**< Unclassified error. */ + CUBEB_ERROR_INVALID_FORMAT /**< Unsupported #cubeb_stream_params requested. */ +}; + +/** User supplied data callback. + @param stream + @param user_ptr + @param buffer + @param nframes + @retval Number of frames written to buffer, which must equal nframes except at end of stream. + @retval CUBEB_ERROR on error, in which case the data callback will stop + and the stream will enter a shutdown state. */ +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); + +/** 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); + +/** 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 + @param stream_params + @param latency Approximate stream latency in milliseconds. Valid range is [1, 2000]. + @param data_callback Will be called to preroll data before playback is + started by cubeb_stream_start. + @param state_callback + @param user_ptr + @retval CUBEB_OK + @retval CUBEB_ERROR + @retval CUBEB_ERROR_INVALID_FORMAT */ +int cubeb_stream_init(cubeb * context, cubeb_stream ** stream, char const * stream_name, + cubeb_stream_params stream_params, unsigned int latency, + cubeb_data_callback data_callback, + cubeb_state_callback state_callback, + void * user_ptr); + +/** Destroy a stream. + @param stream */ +void cubeb_stream_destroy(cubeb_stream * stream); + +/** Start playback. + @param stream + @retval CUBEB_OK + @retval CUBEB_ERROR */ +int cubeb_stream_start(cubeb_stream * stream); + +/** Stop playback. + @param stream + @retval CUBEB_OK + @retval CUBEB_ERROR */ +int cubeb_stream_stop(cubeb_stream * stream); + +/** Get the current stream playback position. + @param stream + @param position Playback position in frames. + @retval CUBEB_OK + @retval CUBEB_ERROR */ +int cubeb_stream_get_position(cubeb_stream * stream, uint64_t * position); + +#ifdef __cplusplus +} +#endif + +#endif /* CUBEB_c2f983e9_c96f_e71c_72c3_bbf62992a382 */ diff --git a/media/libcubeb/src/Makefile.in b/media/libcubeb/src/Makefile.in new file mode 100644 index 000000000000..781df2d82fca --- /dev/null +++ b/media/libcubeb/src/Makefile.in @@ -0,0 +1,58 @@ +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is mozilla.org code. +# +# The Initial Developer of the Original Code is +# Mozilla Foundation +# Portions created by the Initial Developer are Copyright (C) 2011 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Matthew Gregan +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +DEPTH = ../../.. +topsrcdir = @top_srcdir@ +srcdir = @srcdir@ +VPATH = @srcdir@ + +include $(DEPTH)/config/autoconf.mk + +MODULE = cubeb +LIBRARY_NAME = cubeb +FORCE_STATIC_LIB= 1 +ifeq (WINNT,$(OS_TARGET)) +VISIBILITY_FLAGS = +endif + +ifeq (WINNT,$(OS_TARGET)) +CSRCS = \ + cubeb_winmm.c \ + $(NULL) +endif + +include $(topsrcdir)/config/rules.mk diff --git a/media/libcubeb/src/cubeb_winmm.c b/media/libcubeb/src/cubeb_winmm.c new file mode 100644 index 000000000000..1a0b98317f6a --- /dev/null +++ b/media/libcubeb/src/cubeb_winmm.c @@ -0,0 +1,433 @@ +/* + * Copyright  2011 Mozilla Foundation + * + * This program is made available under an ISC-style license. See the + * accompanying file LICENSE for details. + */ +#undef NDEBUG +#include +#include +#include +#include +#include +#include +#include "cubeb/cubeb.h" + +#include + +#define NBUFS 4 + +struct cubeb_stream_item { + SLIST_ENTRY head; + cubeb_stream * stream; +}; + +struct cubeb { + HANDLE event; + HANDLE thread; + int shutdown; + PSLIST_HEADER work; +}; + +struct cubeb_stream { + cubeb * context; + cubeb_stream_params params; + cubeb_data_callback data_callback; + cubeb_state_callback state_callback; + void * user_ptr; + WAVEHDR buffers[NBUFS]; + int next_buffer; + int free_buffers; + int shutdown; + int draining; + HANDLE event; + HWAVEOUT waveout; + CRITICAL_SECTION lock; +}; + +static size_t +bytes_per_frame(cubeb_stream_params params) +{ + size_t bytes; + + switch (params.format) { + case CUBEB_SAMPLE_S16LE: + bytes = sizeof(signed int); + break; + case CUBEB_SAMPLE_FLOAT32LE: + bytes = sizeof(float); + break; + default: + assert(0); + } + + return bytes * params.channels; +} + +static WAVEHDR * +cubeb_get_next_buffer(cubeb_stream * stm) +{ + WAVEHDR * hdr = NULL; + + assert(stm->free_buffers > 0 && stm->free_buffers <= NBUFS); + hdr = &stm->buffers[stm->next_buffer]; + assert(hdr->dwFlags == 0 || + (hdr->dwFlags & WHDR_DONE && !(hdr->dwFlags & WHDR_INQUEUE))); + stm->next_buffer = (stm->next_buffer + 1) % NBUFS; + stm->free_buffers -= 1; + + return hdr; +} + +static void +cubeb_submit_buffer(cubeb_stream * stm, WAVEHDR * hdr) +{ + long got; + MMRESULT r; + + got = stm->data_callback(stm, stm->user_ptr, hdr->lpData, + hdr->dwBufferLength / bytes_per_frame(stm->params)); + if (got < 0) { + /* XXX handle this case */ + assert(0); + return; + } else if ((DWORD) got < hdr->dwBufferLength / bytes_per_frame(stm->params)) { + r = waveOutUnprepareHeader(stm->waveout, hdr, sizeof(*hdr)); + assert(r == MMSYSERR_NOERROR); + + hdr->dwBufferLength = got * bytes_per_frame(stm->params); + + r = waveOutPrepareHeader(stm->waveout, hdr, sizeof(*hdr)); + assert(r == MMSYSERR_NOERROR); + + stm->draining = 1; + } + + assert(hdr->dwFlags & WHDR_PREPARED); + + r = waveOutWrite(stm->waveout, hdr, sizeof(*hdr)); + assert(r == MMSYSERR_NOERROR); +} + +static unsigned __stdcall +cubeb_buffer_thread(void * user_ptr) +{ + cubeb * ctx = (cubeb *) user_ptr; + assert(ctx); + + for (;;) { + DWORD rv; + struct cubeb_stream_item * item; + + rv = WaitForSingleObject(ctx->event, INFINITE); + assert(rv == WAIT_OBJECT_0); + + item = (struct cubeb_stream_item *) InterlockedPopEntrySList(ctx->work); + while (item) { + cubeb_stream * stm = item->stream; + + EnterCriticalSection(&stm->lock); + stm->free_buffers += 1; + assert(stm->free_buffers > 0 && stm->free_buffers <= NBUFS); + + if (stm->draining || stm->shutdown) { + if (stm->free_buffers == NBUFS) { + if (stm->draining) { + stm->state_callback(stm, stm->user_ptr, CUBEB_STATE_DRAINED); + } + SetEvent(stm->event); + } + } else { + cubeb_submit_buffer(stm, cubeb_get_next_buffer(stm)); + } + LeaveCriticalSection(&stm->lock); + + _aligned_free(item); + + item = (struct cubeb_stream_item *) InterlockedPopEntrySList(ctx->work); + } + + if (ctx->shutdown) { + break; + } + } + + return 0; +} + +static void CALLBACK +cubeb_buffer_callback(HWAVEOUT waveout, UINT msg, DWORD_PTR user_ptr, DWORD_PTR p1, DWORD_PTR p2) +{ + cubeb_stream * stm = (cubeb_stream *) user_ptr; + struct cubeb_stream_item * item; + + if (msg != WOM_DONE) { + return; + } + + item = _aligned_malloc(sizeof(struct cubeb_stream_item), MEMORY_ALLOCATION_ALIGNMENT); + assert(item); + item->stream = stm; + InterlockedPushEntrySList(stm->context->work, &item->head); + + SetEvent(stm->context->event); +} + +int +cubeb_init(cubeb ** context, char const * context_name) +{ + cubeb * ctx; + + ctx = calloc(1, sizeof(*ctx)); + assert(ctx); + + ctx->work = _aligned_malloc(sizeof(*ctx->work), MEMORY_ALLOCATION_ALIGNMENT); + assert(ctx->work); + InitializeSListHead(ctx->work); + + ctx->event = CreateEvent(NULL, FALSE, FALSE, NULL); + if (!ctx->event) { + cubeb_destroy(ctx); + return CUBEB_ERROR; + } + + ctx->thread = (HANDLE) _beginthreadex(NULL, 64 * 1024, cubeb_buffer_thread, ctx, 0, NULL); + if (!ctx->thread) { + cubeb_destroy(ctx); + return CUBEB_ERROR; + } + + *context = ctx; + + return CUBEB_OK; +} + +void +cubeb_destroy(cubeb * ctx) +{ + DWORD rv; + + assert(!InterlockedPopEntrySList(ctx->work)); + + if (ctx->thread) { + ctx->shutdown = 1; + SetEvent(ctx->event); + rv = WaitForSingleObject(ctx->thread, INFINITE); + assert(rv == WAIT_OBJECT_0); + CloseHandle(ctx->thread); + } + + if (ctx->event) { + CloseHandle(ctx->event); + } + + _aligned_free(ctx->work); + + free(ctx); +} + +int +cubeb_stream_init(cubeb * context, cubeb_stream ** stream, char const * stream_name, + cubeb_stream_params stream_params, unsigned int latency, + cubeb_data_callback data_callback, + cubeb_state_callback state_callback, + void * user_ptr) +{ + MMRESULT r; + WAVEFORMATEXTENSIBLE wfx; + cubeb_stream * stm; + int i; + size_t bufsz; + + if (stream_params.rate < 1 || stream_params.rate > 192000 || + stream_params.channels < 1 || stream_params.channels > 32 || + latency < 1 || latency > 2000) { + return CUBEB_ERROR_INVALID_FORMAT; + } + + memset(&wfx, 0, sizeof(wfx)); + if (stream_params.channels > 2) { + wfx.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE; + wfx.Format.cbSize = sizeof(wfx) - sizeof(wfx.Format); + } else { + wfx.Format.wFormatTag = WAVE_FORMAT_PCM; + if (stream_params.format == CUBEB_SAMPLE_FLOAT32LE) { + wfx.Format.wFormatTag = WAVE_FORMAT_IEEE_FLOAT; + } + wfx.Format.cbSize = 0; + } + wfx.Format.nChannels = stream_params.channels; + wfx.Format.nSamplesPerSec = stream_params.rate; + + /* XXX fix channel mappings */ + wfx.dwChannelMask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT; + + switch (stream_params.format) { + case CUBEB_SAMPLE_S16LE: + wfx.Format.wBitsPerSample = 16; + wfx.SubFormat = KSDATAFORMAT_SUBTYPE_PCM; + break; + case CUBEB_SAMPLE_FLOAT32LE: + wfx.Format.wBitsPerSample = 32; + wfx.SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT; + break; + default: + return CUBEB_ERROR_INVALID_FORMAT; + } + + wfx.Format.nBlockAlign = (wfx.Format.wBitsPerSample * wfx.Format.nChannels) / 8; + wfx.Format.nAvgBytesPerSec = wfx.Format.nSamplesPerSec * wfx.Format.nBlockAlign; + wfx.Samples.wValidBitsPerSample = 0; + wfx.Samples.wSamplesPerBlock = 0; + wfx.Samples.wReserved = 0; + + stm = calloc(1, sizeof(*stm)); + assert(stm); + + stm->context = context; + + stm->params = stream_params; + + stm->data_callback = data_callback; + stm->state_callback = state_callback; + stm->user_ptr = user_ptr; + + bufsz = (size_t) (stm->params.rate / 1000.0 * latency * bytes_per_frame(stm->params) / NBUFS); + if (bufsz % bytes_per_frame(stm->params) != 0) { + bufsz += bytes_per_frame(stm->params) - (bufsz % bytes_per_frame(stm->params)); + } + assert(bufsz % bytes_per_frame(stm->params) == 0); + + for (i = 0; i < NBUFS; ++i) { + stm->buffers[i].lpData = calloc(1, bufsz); + assert(stm->buffers[i].lpData); + stm->buffers[i].dwBufferLength = bufsz; + stm->buffers[i].dwFlags = 0; + } + + InitializeCriticalSection(&stm->lock); + + stm->event = CreateEvent(NULL, FALSE, FALSE, NULL); + if (!stm->event) { + cubeb_stream_destroy(stm); + return CUBEB_ERROR; + } + + stm->free_buffers = NBUFS; + + /* cubeb_buffer_callback will be called during waveOutOpen, so all + other initialization must be complete before calling it. */ + r = waveOutOpen(&stm->waveout, WAVE_MAPPER, &wfx.Format, + (DWORD_PTR) cubeb_buffer_callback, (DWORD_PTR) stm, + CALLBACK_FUNCTION); + if (r != MMSYSERR_NOERROR) { + cubeb_stream_destroy(stm); + return CUBEB_ERROR; + } + assert(r == MMSYSERR_NOERROR); + + r = waveOutPause(stm->waveout); + assert(r == MMSYSERR_NOERROR); + + for (i = 0; i < NBUFS; ++i) { + WAVEHDR * hdr = cubeb_get_next_buffer(stm); + + r = waveOutPrepareHeader(stm->waveout, hdr, sizeof(*hdr)); + assert(r == MMSYSERR_NOERROR); + + cubeb_submit_buffer(stm, hdr); + } + + *stream = stm; + + return CUBEB_OK; +} + +void +cubeb_stream_destroy(cubeb_stream * stm) +{ + MMRESULT r; + DWORD rv; + int i; + int enqueued; + + if (stm->waveout) { + EnterCriticalSection(&stm->lock); + stm->shutdown = 1; + + r = waveOutReset(stm->waveout); + assert(r == MMSYSERR_NOERROR); + + enqueued = NBUFS - stm->free_buffers; + LeaveCriticalSection(&stm->lock); + + /* wait for all blocks to complete */ + if (enqueued > 0) { + rv = WaitForSingleObject(stm->event, INFINITE); + assert(rv == WAIT_OBJECT_0); + } + + for (i = 0; i < NBUFS; ++i) { + r = waveOutUnprepareHeader(stm->waveout, &stm->buffers[i], sizeof(stm->buffers[i])); + assert(r == MMSYSERR_NOERROR); + } + + r = waveOutClose(stm->waveout); + assert(r == MMSYSERR_NOERROR); + } + + if (stm->event) { + CloseHandle(stm->event); + } + + DeleteCriticalSection(&stm->lock); + + for (i = 0; i < NBUFS; ++i) { + free(stm->buffers[i].lpData); + } + + free(stm); +} + +int +cubeb_stream_start(cubeb_stream * stm) +{ + MMRESULT r; + + r = waveOutRestart(stm->waveout); + assert(r == MMSYSERR_NOERROR); + + stm->state_callback(stm, stm->user_ptr, CUBEB_STATE_STARTED); + + return CUBEB_OK; +} + +int +cubeb_stream_stop(cubeb_stream * stm) +{ + MMRESULT r; + + r = waveOutPause(stm->waveout); + assert(r == MMSYSERR_NOERROR); + + stm->state_callback(stm, stm->user_ptr, CUBEB_STATE_STOPPED); + + return CUBEB_OK; +} + +int +cubeb_stream_get_position(cubeb_stream * stm, uint64_t * position) +{ + MMRESULT r; + MMTIME time; + + time.wType = TIME_SAMPLES; + r = waveOutGetPosition(stm->waveout, &time, sizeof(time)); + assert(r == MMSYSERR_NOERROR); + assert(time.wType == TIME_SAMPLES); + + *position = time.u.sample; + + return CUBEB_OK; +} + diff --git a/media/libcubeb/update.sh b/media/libcubeb/update.sh new file mode 100644 index 000000000000..a5d9addcdca4 --- /dev/null +++ b/media/libcubeb/update.sh @@ -0,0 +1,27 @@ +# Usage: sh update.sh +set -e + +cp $1/include/cubeb/cubeb.h include +cp $1/src/cubeb_alsa.c src +cp $1/src/cubeb_winmm.c src +cp $1/src/cubeb_audiounit.c src +cp $1/LICENSE . +cp $1/README . +cp $1/AUTHORS . +if [ -d $1/.git ]; then + rev=$(cd $1 && git rev-parse --verify HEAD) + dirty=$(cd $1 && git diff-index --name-only HEAD) +fi + +if [ -n "$rev" ]; then + version=$rev + if [ -n "$dirty" ]; then + version=$version-dirty + echo "WARNING: updating from a dirty git repository." + fi + sed -i.bak -e "/The git commit ID used was/ s/[0-9a-f]\+\(-dirty\)\?\./$version./" README_MOZILLA + rm README_MOZILLA.bak +else + echo "Remember to update README_MOZILLA with the version details." +fi + diff --git a/toolkit/content/license.html b/toolkit/content/license.html index 342921aec3ab..9e75f74251d7 100644 --- a/toolkit/content/license.html +++ b/toolkit/content/license.html @@ -132,6 +132,7 @@
  • Japan Network Information Center License
  • jemalloc License
  • jQuery License
  • +
  • libcubeb License
  • libevent License
  • libffi License
  • libnestegg License
  • @@ -2936,6 +2937,30 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
    +

    libcubeb License

    + +

    This license applies to files in the directory + media/libcubeb. +

    + +
    +Copyright © 2011 Mozilla Foundation
    +
    +Permission to use, copy, modify, and distribute this software for any
    +purpose with or without fee is hereby granted, provided that the above
    +copyright notice and this permission notice appear in all copies.
    +
    +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
    +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
    +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
    +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
    +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
    +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
    +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
    +
    + +
    +

    libevent License

    This license applies to files in the directory diff --git a/toolkit/toolkit-makefiles.sh b/toolkit/toolkit-makefiles.sh index 1c9ba46e2d91..1817f48ad5e8 100644 --- a/toolkit/toolkit-makefiles.sh +++ b/toolkit/toolkit-makefiles.sh @@ -1584,6 +1584,14 @@ if [ "$MOZ_WAVE" ]; then " fi +if [ "$MOZ_CUBEB" ]; then + add_makefiles " + media/libcubeb/Makefile + media/libcubeb/include/Makefile + media/libcubeb/src/Makefile + " +fi + if [ "$MOZ_SYDNEYAUDIO" ]; then add_makefiles " media/libsydneyaudio/Makefile diff --git a/toolkit/toolkit-tiers.mk b/toolkit/toolkit-tiers.mk index 72fe7dcba3c4..89163d1d3152 100644 --- a/toolkit/toolkit-tiers.mk +++ b/toolkit/toolkit-tiers.mk @@ -154,6 +154,12 @@ tier_platform_dirs += \ $(NULL) endif +ifdef MOZ_CUBEB +tier_platform_dirs += \ + media/libcubeb \ + $(NULL) +endif + ifndef MOZ_NATIVE_PNG tier_platform_dirs += media/libpng endif