зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1362334 - Update cubeb from upstream to 26a50b0. r=kinetik
MozReview-Commit-ID: KQXwt0DJHvP
This commit is contained in:
Родитель
5e15c14056
Коммит
517b0f8cbf
|
@ -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;
|
||||
|
|
Загрузка…
Ссылка в новой задаче