Bug 1362334 - Update cubeb from upstream to 26a50b0. r=kinetik

MozReview-Commit-ID: KQXwt0DJHvP
This commit is contained in:
Alex Chronopoulos 2017-05-09 09:49:30 +03:00
Родитель 5e15c14056
Коммит 517b0f8cbf
6 изменённых файлов: 200 добавлений и 175 удалений

Просмотреть файл

@ -5,4 +5,4 @@ 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 17503c41318ec7a18ba3d728fb803a66ec60cf84 (2017-04-25 15:26:11 +0200)
The git commit ID used was 26a50b08889a16d3f1e7fe05845cc107c7553f70 (2017-05-05 19:29:05 +1200)

Просмотреть файл

@ -8,6 +8,7 @@
#include "cubeb/cubeb.h"
#include "cubeb_mixer.h"
#include "common.h"
#include <memory>
#include <vector>
using std::vector;
@ -133,7 +134,11 @@ downmix_test(float const * data, cubeb_channel_layout in_layout, cubeb_channel_l
}
}
cubeb_downmix_float(in.data(), inframes, out.data(), in_params.channels, out_params.channels, in_params.layout, out_params.layout);
// Create a mixer for downmix only.
std::unique_ptr<cubeb_mixer, decltype(&cubeb_mixer_destroy)>
mixer(cubeb_mixer_create(in_params.format, CUBEB_MIXER_DIRECTION_DOWNMIX), cubeb_mixer_destroy);
cubeb_mixer_mix(mixer.get(), in.data(), inframes, out.data(), &in_params, &out_params);
uint32_t in_layout_mask = 0;
for (unsigned int i = 0 ; i < in_params.channels; ++i) {

Просмотреть файл

@ -92,41 +92,6 @@ make_sized_audio_channel_layout(size_t sz)
return std::unique_ptr<AudioChannelLayout, decltype(&free)>(acl, free);
}
struct mixer_proxy {
virtual void downmix(void * buffer, long frames,
cubeb_channel_layout input_layout,
cubeb_channel_layout output_layout) = 0;
virtual ~mixer_proxy() {};
};
template <typename T>
struct mixer_impl : public mixer_proxy {
typedef void (*downmix_func)(T * const, long, T *,
unsigned int, unsigned int,
cubeb_channel_layout, cubeb_channel_layout);
mixer_impl(downmix_func dmfunc) {
downmix_wrapper = dmfunc;
}
~mixer_impl() {}
void downmix(void * buffer, long frames,
cubeb_channel_layout input_layout,
cubeb_channel_layout output_layout) override {
uint32_t input_channels = CUBEB_CHANNEL_LAYOUT_MAPS[input_layout].channels;
uint32_t output_channels = CUBEB_CHANNEL_LAYOUT_MAPS[output_layout].channels;
T * out = static_cast<T*>(buffer);
// By using same buffer for downmixing input and output, we allow downmixing
// from 5.0/1 to 1.0/1, 2.0/1/2, 3.0/1, 4.0/1. Do nothing on other cases.
downmix_wrapper(out, frames, out, input_channels, output_channels,
input_layout, output_layout);
}
downmix_func downmix_wrapper;
};
enum io_side {
INPUT,
OUTPUT,
@ -199,7 +164,7 @@ struct cubeb_stream {
AudioDeviceID aggregate_device_id = 0; // the aggregate device id
AudioObjectID plugin_id = 0; // used to create aggregate device
/* Mixer interface */
std::unique_ptr<mixer_proxy> mixer;
std::unique_ptr<cubeb_mixer, decltype(&cubeb_mixer_destroy)> mixer;
};
bool has_input(cubeb_stream * stm)
@ -426,22 +391,17 @@ audiounit_mix_output_buffer(cubeb_stream * stm,
void * output_buffer,
long output_frames)
{
// The audio rendering mechanism on OS X will drop the extra channels beyond
// the channels that audio device can provide, so we need to downmix the
// audio data by ourselves to keep all the information.
cubeb_stream_params dest_params = {
cubeb_stream_params output_mixer_params = {
stm->output_stream_params.format,
stm->output_stream_params.rate,
CUBEB_CHANNEL_LAYOUT_MAPS[stm->context->layout].channels,
stm->context->layout
};
// We only handle downmixing for now.
if (cubeb_should_downmix(&stm->output_stream_params, &dest_params)) {
stm->mixer->downmix(output_buffer, output_frames,
stm->output_stream_params.layout, dest_params.layout);
}
// The downmixing(from 5.1) supports in-place conversion, so we can use
// the same buffer for both input and output of the mixer.
cubeb_mixer_mix(stm->mixer.get(), output_buffer, output_frames, output_buffer,
&stm->output_stream_params, &output_mixer_params);
}
static OSStatus
@ -817,17 +777,6 @@ audiounit_install_device_changed_callback(cubeb_stream * stm)
LOG("AudioObjectAddPropertyListener/output/kAudioDevicePropertyDataSource rv=%d", r);
return CUBEB_ERROR;
}
/* This event will notify us when the default audio device changes,
* for example when the user plugs in a USB headset and the system chooses it
* automatically as the default, or when another device is chosen in the
* dropdown list. */
r = audiounit_add_listener(stm, kAudioObjectSystemObject, kAudioHardwarePropertyDefaultOutputDevice,
kAudioObjectPropertyScopeGlobal, &audiounit_property_listener_callback);
if (r != noErr) {
LOG("AudioObjectAddPropertyListener/output/kAudioHardwarePropertyDefaultOutputDevice rv=%d", r);
return CUBEB_ERROR;
}
}
if (stm->input_unit) {
@ -845,14 +794,6 @@ audiounit_install_device_changed_callback(cubeb_stream * stm)
return CUBEB_ERROR;
}
/* This event will notify us when the default input device changes. */
r = audiounit_add_listener(stm, kAudioObjectSystemObject, kAudioHardwarePropertyDefaultInputDevice,
kAudioObjectPropertyScopeGlobal, &audiounit_property_listener_callback);
if (r != noErr) {
LOG("AudioObjectAddPropertyListener/input/kAudioHardwarePropertyDefaultInputDevice rv=%d", r);
return CUBEB_ERROR;
}
/* Event to notify when the input is going away. */
AudioDeviceID dev = audiounit_get_input_device_id(stm);
r = audiounit_add_listener(stm, dev, kAudioDevicePropertyDeviceIsAlive,
@ -866,6 +807,37 @@ audiounit_install_device_changed_callback(cubeb_stream * stm)
return CUBEB_OK;
}
static int
audiounit_install_system_changed_callback(cubeb_stream * stm)
{
OSStatus r;
if (stm->output_unit) {
/* This event will notify us when the default audio device changes,
* for example when the user plugs in a USB headset and the system chooses it
* automatically as the default, or when another device is chosen in the
* dropdown list. */
r = audiounit_add_listener(stm, kAudioObjectSystemObject, kAudioHardwarePropertyDefaultOutputDevice,
kAudioObjectPropertyScopeGlobal, &audiounit_property_listener_callback);
if (r != noErr) {
LOG("AudioObjectAddPropertyListener/output/kAudioHardwarePropertyDefaultOutputDevice rv=%d", r);
return CUBEB_ERROR;
}
}
if (stm->input_unit) {
/* This event will notify us when the default input device changes. */
r = audiounit_add_listener(stm, kAudioObjectSystemObject, kAudioHardwarePropertyDefaultInputDevice,
kAudioObjectPropertyScopeGlobal, &audiounit_property_listener_callback);
if (r != noErr) {
LOG("AudioObjectAddPropertyListener/input/kAudioHardwarePropertyDefaultInputDevice rv=%d", r);
return CUBEB_ERROR;
}
}
return CUBEB_OK;
}
static int
audiounit_uninstall_device_changed_callback(cubeb_stream * stm)
{
@ -883,12 +855,6 @@ audiounit_uninstall_device_changed_callback(cubeb_stream * stm)
if (r != noErr) {
return CUBEB_ERROR;
}
r = audiounit_remove_listener(stm, kAudioObjectSystemObject, kAudioHardwarePropertyDefaultOutputDevice,
kAudioObjectPropertyScopeGlobal, &audiounit_property_listener_callback);
if (r != noErr) {
return CUBEB_ERROR;
}
}
if (stm->input_unit) {
@ -904,12 +870,6 @@ audiounit_uninstall_device_changed_callback(cubeb_stream * stm)
return CUBEB_ERROR;
}
r = audiounit_remove_listener(stm, kAudioObjectSystemObject, kAudioHardwarePropertyDefaultInputDevice,
kAudioObjectPropertyScopeGlobal, &audiounit_property_listener_callback);
if (r != noErr) {
return CUBEB_ERROR;
}
AudioDeviceID dev = audiounit_get_input_device_id(stm);
r = audiounit_remove_listener(stm, dev, kAudioDevicePropertyDeviceIsAlive,
kAudioObjectPropertyScopeGlobal, &audiounit_property_listener_callback);
@ -921,6 +881,29 @@ audiounit_uninstall_device_changed_callback(cubeb_stream * stm)
return CUBEB_OK;
}
static int
audiounit_uninstall_system_changed_callback(cubeb_stream * stm)
{
OSStatus r;
if (stm->output_unit) {
r = audiounit_remove_listener(stm, kAudioObjectSystemObject, kAudioHardwarePropertyDefaultOutputDevice,
kAudioObjectPropertyScopeGlobal, &audiounit_property_listener_callback);
if (r != noErr) {
return CUBEB_ERROR;
}
}
if (stm->input_unit) {
r = audiounit_remove_listener(stm, kAudioObjectSystemObject, kAudioHardwarePropertyDefaultInputDevice,
kAudioObjectPropertyScopeGlobal, &audiounit_property_listener_callback);
if (r != noErr) {
return CUBEB_ERROR;
}
}
return CUBEB_OK;
}
/* Get the acceptable buffer size (in frames) that this device can work with. */
static int
audiounit_get_acceptable_latency_range(AudioValueRange * latency_range)
@ -1272,11 +1255,12 @@ audio_stream_desc_init(AudioStreamBasicDescription * ss,
void
audiounit_init_mixer(cubeb_stream * stm)
{
if (stm->output_desc.mFormatFlags & kAudioFormatFlagIsFloat) {
stm->mixer.reset(new mixer_impl<float>(&cubeb_downmix_float));
} else { // stm->output_desc.mFormatFlags & kAudioFormatFlagIsSignedInteger
stm->mixer.reset(new mixer_impl<short>(&cubeb_downmix_short));
}
// We only handle downmixing for now.
// The audio rendering mechanism on OS X will drop the extra channels beyond
// the channels that audio device can provide, so we need to downmix the
// audio data by ourselves to keep all the information.
stm->mixer.reset(cubeb_mixer_create(stm->output_stream_params.format,
CUBEB_MIXER_DIRECTION_DOWNMIX));
}
static int
@ -2452,6 +2436,7 @@ audiounit_setup_stream(cubeb_stream * stm)
cubeb_stream::cubeb_stream(cubeb * context)
: context(context)
, resampler(nullptr, cubeb_resampler_destroy)
, mixer(nullptr, cubeb_mixer_destroy)
{
PodZero(&input_desc, 1);
PodZero(&output_desc, 1);
@ -2515,6 +2500,12 @@ audiounit_stream_init(cubeb * context,
return r;
}
r = audiounit_install_system_changed_callback(stm.get());
if (r != CUBEB_OK) {
LOG("(%p) Could not install the device change callback.", stm.get());
return r;
}
*stream = stm.release();
LOG("(%p) Cubeb stream init successful.", *stream);
return CUBEB_OK;
@ -2545,6 +2536,7 @@ audiounit_close_stream(cubeb_stream *stm)
}
stm->resampler.reset();
stm->mixer.reset();
if (stm->aggregate_device_id) {
audiounit_destroy_aggregate_device(stm->plugin_id, stm->aggregate_device_id);
@ -2557,6 +2549,11 @@ audiounit_stream_destroy(cubeb_stream * stm)
{
stm->shutdown = true;
int r = audiounit_uninstall_system_changed_callback(stm);
if (r != CUBEB_OK) {
LOG("(%p) Could not uninstall the device changed callback", stm);
}
auto_lock context_lock(stm->context->mutex);
audiounit_stream_stop_internal(stm);

Просмотреть файл

@ -356,10 +356,20 @@ downmix_fallback(T const * const in, unsigned long inframes, T * out, unsigned i
template<typename T>
void
cubeb_downmix(T const * const in, long inframes, T * out,
unsigned int in_channels, unsigned int out_channels,
cubeb_channel_layout in_layout, cubeb_channel_layout out_layout)
cubeb_stream_params const * stream_params,
cubeb_stream_params const * mixer_params)
{
assert(in_channels >= out_channels && in_layout != CUBEB_LAYOUT_UNDEFINED);
assert(in && out);
assert(inframes);
assert(stream_params->channels >= mixer_params->channels &&
mixer_params->channels > 0);
assert(stream_params->layout != CUBEB_LAYOUT_UNDEFINED);
unsigned int in_channels = stream_params->channels;
cubeb_channel_layout in_layout = stream_params->layout;
unsigned int out_channels = mixer_params->channels;
cubeb_channel_layout out_layout = mixer_params->layout;
// If the channel number is different from the layout's setting,
// then we use fallback downmix mechanism.
@ -395,9 +405,16 @@ mono_to_stereo(T const * in, long insamples, T * out, unsigned int out_channels)
template<typename T>
void
cubeb_upmix(T const * in, long inframes, T * out,
unsigned int in_channels, unsigned int out_channels)
cubeb_stream_params const * stream_params,
cubeb_stream_params const * mixer_params)
{
assert(out_channels >= in_channels && in_channels > 0);
assert(in && out);
assert(inframes);
assert(mixer_params->channels >= stream_params->channels &&
stream_params->channels > 0);
unsigned int in_channels = stream_params->channels;
unsigned int out_channels = mixer_params->channels;
/* Either way, if we have 2 or more channels, the first two are L and R. */
/* If we are playing a mono stream over stereo speakers, copy the data over. */
@ -453,33 +470,71 @@ cubeb_should_mix(cubeb_stream_params const * stream, cubeb_stream_params const *
return cubeb_should_upmix(stream, mixer) || cubeb_should_downmix(stream, mixer);
}
void
cubeb_downmix_float(float * const in, long inframes, float * out,
unsigned int in_channels, unsigned int out_channels,
cubeb_channel_layout in_layout, cubeb_channel_layout out_layout)
struct cubeb_mixer {
virtual void mix(void * input_buffer, long frames, void * output_buffer,
cubeb_stream_params const * stream_params,
cubeb_stream_params const * mixer_params) = 0;
virtual ~cubeb_mixer() {};
};
template<typename T>
struct cubeb_mixer_impl : public cubeb_mixer {
explicit cubeb_mixer_impl(unsigned int d)
: direction(d)
{
cubeb_downmix(in, inframes, out, in_channels, out_channels, in_layout, out_layout);
}
void
cubeb_downmix_short(short * const in, long inframes, short * out,
unsigned int in_channels, unsigned int out_channels,
cubeb_channel_layout in_layout, cubeb_channel_layout out_layout)
void mix(void * input_buffer, long frames, void * output_buffer,
cubeb_stream_params const * stream_params,
cubeb_stream_params const * mixer_params)
{
cubeb_downmix(in, inframes, out, in_channels, out_channels, in_layout, out_layout);
if (frames <= 0) {
return;
}
T * in = static_cast<T*>(input_buffer);
T * out = static_cast<T*>(output_buffer);
void
cubeb_upmix_short(short * const in, long inframes, short * out,
unsigned int in_channels, unsigned int out_channels)
{
cubeb_upmix(in, inframes, out, in_channels, out_channels);
if ((direction & CUBEB_MIXER_DIRECTION_DOWNMIX) &&
cubeb_should_downmix(stream_params, mixer_params)) {
cubeb_downmix(in, frames, out, stream_params, mixer_params);
} else if ((direction & CUBEB_MIXER_DIRECTION_UPMIX) &&
cubeb_should_upmix(stream_params, mixer_params)) {
cubeb_upmix(in, frames, out, stream_params, mixer_params);
}
}
void
cubeb_upmix_float(float * const in, long inframes, float * out,
unsigned int in_channels, unsigned int out_channels)
~cubeb_mixer_impl() {};
unsigned char const direction;
};
cubeb_mixer * cubeb_mixer_create(cubeb_sample_format format,
unsigned char direction)
{
cubeb_upmix(in, inframes, out, in_channels, out_channels);
assert(direction & CUBEB_MIXER_DIRECTION_DOWNMIX ||
direction & CUBEB_MIXER_DIRECTION_UPMIX);
switch(format) {
case CUBEB_SAMPLE_S16NE:
return new cubeb_mixer_impl<short>(direction);
case CUBEB_SAMPLE_FLOAT32NE:
return new cubeb_mixer_impl<float>(direction);
default:
assert(false);
return nullptr;
}
}
void cubeb_mixer_destroy(cubeb_mixer * mixer)
{
delete mixer;
}
void cubeb_mixer_mix(cubeb_mixer * mixer,
void * const input_buffer, long frames, void * output_buffer,
cubeb_stream_params const * stream_params,
cubeb_stream_params const * mixer_params)
{
assert(mixer);
mixer->mix(input_buffer, frames, output_buffer, stream_params, mixer_params);
}

Просмотреть файл

@ -68,21 +68,19 @@ bool cubeb_should_downmix(cubeb_stream_params const * stream, cubeb_stream_param
bool cubeb_should_mix(cubeb_stream_params const * stream, cubeb_stream_params const * mixer);
void cubeb_downmix_float(float * const in, long inframes, float * out,
unsigned int in_channels, unsigned int out_channels,
cubeb_channel_layout in_layout, cubeb_channel_layout out_layout);
void cubeb_downmix_short(short * const in, long inframes, short * out,
unsigned int in_channels, unsigned int out_channels,
cubeb_channel_layout in_layout, cubeb_channel_layout out_layout);
void cubeb_upmix_float(float * const in, long inframes, float * out,
unsigned int in_channels, unsigned int out_channels);
void cubeb_upmix_short(short * const in, long inframes, short * out,
unsigned int in_channels, unsigned int out_channels);
typedef enum {
CUBEB_MIXER_DIRECTION_DOWNMIX = 0x01,
CUBEB_MIXER_DIRECTION_UPMIX = 0x02,
} cubeb_mixer_direction;
typedef struct cubeb_mixer cubeb_mixer;
cubeb_mixer * cubeb_mixer_create(cubeb_sample_format format,
unsigned char direction);
void cubeb_mixer_destroy(cubeb_mixer * mixer);
void cubeb_mixer_mix(cubeb_mixer * mixer,
void * input_buffer, long frames, void * output_buffer,
cubeb_stream_params const * stream_params,
cubeb_stream_params const * mixer_params);
#if defined(__cplusplus)
}

Просмотреть файл

@ -160,45 +160,6 @@ private:
HRESULT result;
};
struct mixing_wrapper {
virtual void mix(void * const input_buffer, long input_frames, void * output_buffer,
cubeb_stream_params const * stream_params,
cubeb_stream_params const * mixer_params) = 0;
virtual ~mixing_wrapper() {};
};
template <typename T>
struct mixing_impl : public mixing_wrapper {
typedef void (*downmix_func)(T * const, long, T *,
unsigned int, unsigned int,
cubeb_channel_layout, cubeb_channel_layout);
typedef void (*upmix_func)(T * const, long, T *,
unsigned int, unsigned int);
mixing_impl(downmix_func dmfunc, upmix_func umfunc) {
downmix_wrapper = dmfunc;
upmix_wrapper = umfunc;
}
~mixing_impl() {}
void mix(void * const input_buffer, long input_frames, void * output_buffer,
cubeb_stream_params const * stream_params,
cubeb_stream_params const * mixer_params) override {
T * const in = static_cast<T *>(input_buffer);
T * out = static_cast<T *>(output_buffer);
if (cubeb_should_upmix(stream_params, mixer_params)) {
upmix_wrapper(in, input_frames, out, stream_params->channels, mixer_params->channels);
} else if (cubeb_should_downmix(stream_params, mixer_params)) {
downmix_wrapper(in, input_frames, out, stream_params->channels, mixer_params->channels, stream_params->layout, mixer_params->layout);
}
}
downmix_func downmix_wrapper;
upmix_func upmix_wrapper;
};
extern cubeb_ops const wasapi_ops;
int wasapi_stream_stop(cubeb_stream * stm);
@ -303,8 +264,8 @@ struct cubeb_stream {
uint32_t output_buffer_frame_count = 0;
/* Resampler instance. Resampling will only happen if necessary. */
std::unique_ptr<cubeb_resampler, decltype(&cubeb_resampler_destroy)> resampler = { nullptr, cubeb_resampler_destroy };
/* Mixing interface */
std::unique_ptr<mixing_wrapper> mixing;
/* Mixer interface */
std::unique_ptr<cubeb_mixer, decltype(&cubeb_mixer_destroy)> mixer = { nullptr, cubeb_mixer_destroy };
/* A buffer for up/down mixing multi-channel audio. */
std::vector<BYTE> mix_buffer;
/* WASAPI input works in "packets". We re-linearize the audio packets
@ -598,7 +559,8 @@ refill(cubeb_stream * stm, void * input_buffer, long input_frames_count,
XASSERT(out_frames == output_frames_needed || stm->draining || !has_output(stm));
if (has_output(stm) && cubeb_should_mix(&stm->output_stream_params, &stm->output_mix_params)) {
stm->mixing->mix(dest, out_frames, output_buffer, &stm->output_stream_params, &stm->output_mix_params);
cubeb_mixer_mix(stm->mixer.get(), dest, out_frames, output_buffer,
&stm->output_stream_params, &stm->output_mix_params);
}
return out_frames;
@ -660,7 +622,7 @@ bool get_input_buffer(cubeb_stream * stm)
bool ok = stm->linear_input_buffer->reserve(stm->linear_input_buffer->length() +
packet_size * stm->input_stream_params.channels);
XASSERT(ok);
stm->mixing->mix(input_packet, packet_size,
cubeb_mixer_mix(stm->mixer.get(), input_packet, packet_size,
stm->linear_input_buffer->end(),
&stm->input_mix_params,
&stm->input_stream_params);
@ -1803,18 +1765,19 @@ wasapi_stream_init(cubeb * context, cubeb_stream ** stream,
case CUBEB_SAMPLE_S16NE:
stm->bytes_per_sample = sizeof(short);
stm->waveformatextensible_sub_format = KSDATAFORMAT_SUBTYPE_PCM;
stm->mixing.reset(new mixing_impl<short>(cubeb_downmix_short, cubeb_upmix_short));
stm->linear_input_buffer.reset(new auto_array_wrapper_impl<short>);
break;
case CUBEB_SAMPLE_FLOAT32NE:
stm->bytes_per_sample = sizeof(float);
stm->waveformatextensible_sub_format = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
stm->mixing.reset(new mixing_impl<float>(cubeb_downmix_float, cubeb_upmix_float));
stm->linear_input_buffer.reset(new auto_array_wrapper_impl<float>);
break;
default:
return CUBEB_ERROR_INVALID_FORMAT;
}
stm->mixer.reset(cubeb_mixer_create(output_stream_params ? output_stream_params->format :
input_stream_params->format,
CUBEB_MIXER_DIRECTION_DOWNMIX | CUBEB_MIXER_DIRECTION_UPMIX));
stm->latency = latency_frames;
@ -1881,8 +1844,6 @@ void close_wasapi_stream(cubeb_stream * stm)
stm->resampler.reset();
stm->mix_buffer.clear();
stm->mixing.reset();
stm->linear_input_buffer.reset();
}
void wasapi_stream_destroy(cubeb_stream * stm)
@ -1903,6 +1864,11 @@ void wasapi_stream_destroy(cubeb_stream * stm)
CloseHandle(stm->refill_event);
CloseHandle(stm->input_available_event);
// The variables intialized in wasapi_stream_init,
// must be destroyed in wasapi_stream_destroy.
stm->mixer.reset();
stm->linear_input_buffer.reset();
{
auto_lock lock(stm->stream_reset_lock);
close_wasapi_stream(stm);
@ -2027,6 +1993,10 @@ int wasapi_stream_stop(cubeb_stream * stm)
delete stm->emergency_bailout.load();
stm->emergency_bailout = nullptr;
}
} else {
// If we could not join the thread, put the stream in error.
stm->state_callback(stm, stm->user_ptr, CUBEB_STATE_ERROR);
return CUBEB_ERROR;
}
return CUBEB_OK;