зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1337805 - Update cubeb from upstream 21e96ac. r=padenot
MozReview-Commit-ID: 62VM613n915 --HG-- extra : rebase_source : 5a58866e8e3a0458eacabcdbb894bffcebe3467f
This commit is contained in:
Родитель
448874c0f1
Коммит
c0634dbb84
|
@ -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 927877c3204d6b8467b6dc782ca2aa740d240d41.
|
||||
The git commit ID used was 21e96ac7fd456dc957cd9947a61da1366a1f862d.
|
||||
|
|
|
@ -27,7 +27,8 @@ TEST(cubeb, latency)
|
|||
}
|
||||
|
||||
r = cubeb_get_preferred_channel_layout(ctx, &layout);
|
||||
ASSERT_TRUE(r == CUBEB_OK || r == CUBEB_ERROR_NOT_SUPPORTED);
|
||||
ASSERT_TRUE(r == CUBEB_OK || r == CUBEB_ERROR_NOT_SUPPORTED ||
|
||||
(r == CUBEB_ERROR && layout == CUBEB_LAYOUT_UNDEFINED));
|
||||
|
||||
cubeb_stream_params params = {
|
||||
CUBEB_SAMPLE_FLOAT32NE,
|
||||
|
|
|
@ -316,12 +316,12 @@ alsa_process_stream(cubeb_stream * stm)
|
|||
/* Capture: Pass read frames to callback function */
|
||||
if (stm->stream_type == SND_PCM_STREAM_CAPTURE && stm->bufframes > 0 &&
|
||||
(!stm->other_stream || stm->other_stream->bufframes < stm->other_stream->buffer_size)) {
|
||||
long wrote = stm->bufframes;
|
||||
snd_pcm_sframes_t wrote = stm->bufframes;
|
||||
struct cubeb_stream * mainstm = stm->other_stream ? stm->other_stream : stm;
|
||||
void * other_buffer = stm->other_stream ? stm->other_stream->buffer + stm->other_stream->bufframes : NULL;
|
||||
|
||||
/* Correct write size to the other stream available space */
|
||||
if (stm->other_stream && wrote > stm->other_stream->buffer_size - stm->other_stream->bufframes) {
|
||||
if (stm->other_stream && wrote > (snd_pcm_sframes_t) (stm->other_stream->buffer_size - stm->other_stream->bufframes)) {
|
||||
wrote = stm->other_stream->buffer_size - stm->other_stream->bufframes;
|
||||
}
|
||||
|
||||
|
@ -341,14 +341,14 @@ alsa_process_stream(cubeb_stream * stm)
|
|||
}
|
||||
|
||||
/* Playback: Don't have enough data? Let's ask for more. */
|
||||
if (stm->stream_type == SND_PCM_STREAM_PLAYBACK && avail > stm->bufframes &&
|
||||
if (stm->stream_type == SND_PCM_STREAM_PLAYBACK && avail > (snd_pcm_sframes_t) stm->bufframes &&
|
||||
(!stm->other_stream || stm->other_stream->bufframes > 0)) {
|
||||
long got = avail - stm->bufframes;
|
||||
void * other_buffer = stm->other_stream ? stm->other_stream->buffer : NULL;
|
||||
char * buftail = stm->buffer + snd_pcm_frames_to_bytes(stm->pcm, stm->bufframes);
|
||||
|
||||
/* Correct read size to the other stream available frames */
|
||||
if (stm->other_stream && got > stm->other_stream->bufframes) {
|
||||
if (stm->other_stream && got > (snd_pcm_sframes_t) stm->other_stream->bufframes) {
|
||||
got = stm->other_stream->bufframes;
|
||||
}
|
||||
|
||||
|
@ -368,7 +368,7 @@ alsa_process_stream(cubeb_stream * stm)
|
|||
}
|
||||
|
||||
/* Playback: Still don't have enough data? Add some silence. */
|
||||
if (stm->stream_type == SND_PCM_STREAM_PLAYBACK && avail > stm->bufframes) {
|
||||
if (stm->stream_type == SND_PCM_STREAM_PLAYBACK && avail > (snd_pcm_sframes_t) stm->bufframes) {
|
||||
long drain_frames = avail - stm->bufframes;
|
||||
double drain_time = (double) drain_frames / stm->params.rate;
|
||||
|
||||
|
@ -933,6 +933,9 @@ alsa_stream_init_single(cubeb * ctx, cubeb_stream ** stream, char const * stream
|
|||
r = pthread_mutex_init(&stm->mutex, NULL);
|
||||
assert(r == 0);
|
||||
|
||||
r = pthread_cond_init(&stm->cond, NULL);
|
||||
assert(r == 0);
|
||||
|
||||
r = alsa_locked_pcm_open(&stm->pcm, pcm_name, stm->stream_type, ctx->local_config);
|
||||
if (r < 0) {
|
||||
alsa_stream_destroy(stm);
|
||||
|
@ -976,9 +979,6 @@ alsa_stream_init_single(cubeb * ctx, cubeb_stream ** stream, char const * stream
|
|||
r = snd_pcm_poll_descriptors(stm->pcm, stm->saved_fds, stm->nfds);
|
||||
assert((nfds_t) r == stm->nfds);
|
||||
|
||||
r = pthread_cond_init(&stm->cond, NULL);
|
||||
assert(r == 0);
|
||||
|
||||
if (alsa_register_stream(ctx, stm) != 0) {
|
||||
alsa_stream_destroy(stm);
|
||||
return CUBEB_ERROR;
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include <AudioToolbox/AudioToolbox.h>
|
||||
#include "cubeb/cubeb.h"
|
||||
#include "cubeb-internal.h"
|
||||
#include "cubeb_mixer.h"
|
||||
#include "cubeb_panner.h"
|
||||
#if !TARGET_OS_IPHONE
|
||||
#include "cubeb_osx_run_loop.h"
|
||||
|
@ -40,6 +41,8 @@ typedef UInt32 AudioFormatFlags;
|
|||
#define AU_OUT_BUS 0
|
||||
#define AU_IN_BUS 1
|
||||
|
||||
#define fieldOffset(type, field) ((size_t) &((type *) 0)->field)
|
||||
|
||||
#define PRINT_ERROR_CODE(str, r) do { \
|
||||
LOG("System call failed: %s (rv: %d)", str, (int) r); \
|
||||
} while(0)
|
||||
|
@ -56,6 +59,10 @@ void audiounit_stream_stop_internal(cubeb_stream * stm);
|
|||
void audiounit_stream_start_internal(cubeb_stream * stm);
|
||||
static void audiounit_close_stream(cubeb_stream *stm);
|
||||
static int audiounit_setup_stream(cubeb_stream *stm);
|
||||
static int audiounit_create_unit(AudioUnit * unit, bool is_input,
|
||||
const cubeb_stream_params * /* stream_params */,
|
||||
AudioDeviceID device);
|
||||
static cubeb_channel_layout audiounit_get_channel_layout(bool preferred);
|
||||
|
||||
extern cubeb_ops const audiounit_ops;
|
||||
|
||||
|
@ -83,6 +90,54 @@ struct auto_array_wrapper {
|
|||
virtual ~auto_array_wrapper() {}
|
||||
};
|
||||
|
||||
class auto_channel_layout
|
||||
{
|
||||
public:
|
||||
auto_channel_layout()
|
||||
: layout(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
auto_channel_layout(size_t size)
|
||||
: layout(reinterpret_cast<AudioChannelLayout*>(malloc(size)))
|
||||
{
|
||||
memset(layout, 0, size);
|
||||
}
|
||||
|
||||
~auto_channel_layout()
|
||||
{
|
||||
release();
|
||||
}
|
||||
|
||||
void reset(size_t size)
|
||||
{
|
||||
release();
|
||||
layout = reinterpret_cast<AudioChannelLayout*>(malloc(size));
|
||||
memset(layout, 0, size);
|
||||
}
|
||||
|
||||
AudioChannelLayout* get()
|
||||
{
|
||||
return layout;
|
||||
}
|
||||
|
||||
size_t size()
|
||||
{
|
||||
return sizeof(*layout);
|
||||
}
|
||||
|
||||
private:
|
||||
void release()
|
||||
{
|
||||
if (layout) {
|
||||
free(layout);
|
||||
layout = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
AudioChannelLayout * layout;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct auto_array_wrapper_impl : public auto_array_wrapper {
|
||||
explicit auto_array_wrapper_impl(uint32_t size)
|
||||
|
@ -130,6 +185,11 @@ private:
|
|||
auto_array<T> ar;
|
||||
};
|
||||
|
||||
enum io_side {
|
||||
INPUT,
|
||||
OUTPUT,
|
||||
};
|
||||
|
||||
struct cubeb_stream {
|
||||
explicit cubeb_stream(cubeb * context);
|
||||
|
||||
|
@ -195,6 +255,42 @@ bool has_output(cubeb_stream * stm)
|
|||
return stm->output_stream_params.rate != 0;
|
||||
}
|
||||
|
||||
cubeb_channel
|
||||
channel_label_to_cubeb_channel(UInt32 label)
|
||||
{
|
||||
switch (label) {
|
||||
case kAudioChannelLabel_Mono: return CHANNEL_MONO;
|
||||
case kAudioChannelLabel_Left: return CHANNEL_LEFT;
|
||||
case kAudioChannelLabel_Right: return CHANNEL_RIGHT;
|
||||
case kAudioChannelLabel_Center: return CHANNEL_CENTER;
|
||||
case kAudioChannelLabel_LFEScreen: return CHANNEL_LFE;
|
||||
case kAudioChannelLabel_LeftSurround: return CHANNEL_LS;
|
||||
case kAudioChannelLabel_RightSurround: return CHANNEL_RS;
|
||||
case kAudioChannelLabel_RearSurroundLeft: return CHANNEL_RLS;
|
||||
case kAudioChannelLabel_RearSurroundRight: return CHANNEL_RRS;
|
||||
case kAudioChannelLabel_CenterSurround: return CHANNEL_RCENTER;
|
||||
default: return CHANNEL_INVALID;
|
||||
}
|
||||
}
|
||||
|
||||
AudioChannelLabel
|
||||
cubeb_channel_to_channel_label(cubeb_channel channel)
|
||||
{
|
||||
switch (channel) {
|
||||
case CHANNEL_MONO: return kAudioChannelLabel_Mono;
|
||||
case CHANNEL_LEFT: return kAudioChannelLabel_Left;
|
||||
case CHANNEL_RIGHT: return kAudioChannelLabel_Right;
|
||||
case CHANNEL_CENTER: return kAudioChannelLabel_Center;
|
||||
case CHANNEL_LFE: return kAudioChannelLabel_LFEScreen;
|
||||
case CHANNEL_LS: return kAudioChannelLabel_LeftSurround;
|
||||
case CHANNEL_RS: return kAudioChannelLabel_RightSurround;
|
||||
case CHANNEL_RLS: return kAudioChannelLabel_RearSurroundLeft;
|
||||
case CHANNEL_RRS: return kAudioChannelLabel_RearSurroundRight;
|
||||
case CHANNEL_RCENTER: return kAudioChannelLabel_CenterSurround;
|
||||
default: return kAudioChannelLabel_Unknown;
|
||||
}
|
||||
}
|
||||
|
||||
#if TARGET_OS_IPHONE
|
||||
typedef UInt32 AudioDeviceID;
|
||||
typedef UInt32 AudioObjectID;
|
||||
|
@ -958,6 +1054,26 @@ audiounit_get_preferred_sample_rate(cubeb * /* ctx */, uint32_t * rate)
|
|||
return CUBEB_OK;
|
||||
}
|
||||
|
||||
static int
|
||||
audiounit_get_preferred_channel_layout(cubeb * /* ctx */, cubeb_channel_layout * layout)
|
||||
{
|
||||
// The preferred layout is only returned when the connected sound device
|
||||
// (e.g. ASUS Xonar U7), has preferred layout setting.
|
||||
// For default output on Mac, there is no preferred channel layout,
|
||||
// so it might return UNDEFINED.
|
||||
// In that case, we should get the channel configuration directly.
|
||||
*layout = audiounit_get_channel_layout(true);
|
||||
if (*layout == CUBEB_LAYOUT_UNDEFINED) {
|
||||
*layout = audiounit_get_channel_layout(false);
|
||||
}
|
||||
|
||||
if (*layout == CUBEB_LAYOUT_UNDEFINED) {
|
||||
return CUBEB_ERROR;
|
||||
}
|
||||
|
||||
return CUBEB_OK;
|
||||
}
|
||||
|
||||
static OSStatus audiounit_remove_device_listener(cubeb * context);
|
||||
|
||||
static void
|
||||
|
@ -1021,6 +1137,80 @@ audio_stream_desc_init(AudioStreamBasicDescription * ss,
|
|||
return CUBEB_OK;
|
||||
}
|
||||
|
||||
static int
|
||||
audiounit_layout_init(AudioUnit * unit,
|
||||
io_side side,
|
||||
const cubeb_stream_params * stream_params)
|
||||
{
|
||||
assert(stream_params->layout != CUBEB_LAYOUT_UNDEFINED);
|
||||
assert(stream_params->channels == CUBEB_CHANNEL_LAYOUT_MAPS[stream_params->layout].channels);
|
||||
|
||||
OSStatus r;
|
||||
auto_channel_layout layout(sizeof(AudioChannelLayout));
|
||||
|
||||
switch (stream_params->layout) {
|
||||
case CUBEB_LAYOUT_DUAL_MONO:
|
||||
case CUBEB_LAYOUT_STEREO:
|
||||
layout.get()->mChannelLayoutTag = kAudioChannelLayoutTag_Stereo;
|
||||
break;
|
||||
case CUBEB_LAYOUT_MONO:
|
||||
layout.get()->mChannelLayoutTag = kAudioChannelLayoutTag_Mono;
|
||||
break;
|
||||
case CUBEB_LAYOUT_3F:
|
||||
layout.get()->mChannelLayoutTag = kAudioChannelLayoutTag_ITU_3_0;
|
||||
break;
|
||||
case CUBEB_LAYOUT_2F1:
|
||||
layout.get()->mChannelLayoutTag = kAudioChannelLayoutTag_ITU_2_1;
|
||||
break;
|
||||
case CUBEB_LAYOUT_3F1:
|
||||
layout.get()->mChannelLayoutTag = kAudioChannelLayoutTag_ITU_3_1;
|
||||
break;
|
||||
case CUBEB_LAYOUT_2F2:
|
||||
layout.get()->mChannelLayoutTag = kAudioChannelLayoutTag_ITU_2_2;
|
||||
break;
|
||||
case CUBEB_LAYOUT_3F2:
|
||||
layout.get()->mChannelLayoutTag = kAudioChannelLayoutTag_ITU_3_2;
|
||||
break;
|
||||
case CUBEB_LAYOUT_3F2_LFE:
|
||||
layout.get()->mChannelLayoutTag = kAudioChannelLayoutTag_AudioUnit_5_1;
|
||||
break;
|
||||
default:
|
||||
layout.get()->mChannelLayoutTag = kAudioChannelLayoutTag_Unknown;
|
||||
break;
|
||||
}
|
||||
|
||||
// For those layouts that can't be matched to coreaudio's predefined layout,
|
||||
// we use customized layout.
|
||||
if (layout.get()->mChannelLayoutTag == kAudioChannelLayoutTag_Unknown) {
|
||||
size_t size = fieldOffset(AudioChannelLayout, mChannelDescriptions[stream_params->channels]);
|
||||
layout.reset(size);
|
||||
layout.get()->mChannelLayoutTag = kAudioChannelLayoutTag_UseChannelDescriptions;
|
||||
layout.get()->mNumberChannelDescriptions = stream_params->channels;
|
||||
for (UInt32 i = 0 ; i < stream_params->channels ; ++i) {
|
||||
layout.get()->mChannelDescriptions[i].mChannelLabel =
|
||||
cubeb_channel_to_channel_label(CHANNEL_INDEX_TO_ORDER[stream_params->layout][i]);
|
||||
layout.get()->mChannelDescriptions[i].mChannelFlags = kAudioChannelFlags_AllOff;
|
||||
}
|
||||
}
|
||||
|
||||
r = AudioUnitSetProperty(*unit,
|
||||
kAudioUnitProperty_AudioChannelLayout,
|
||||
side == INPUT ? kAudioUnitScope_Output : kAudioUnitScope_Input,
|
||||
side == INPUT ? AU_IN_BUS : AU_OUT_BUS,
|
||||
layout.get(),
|
||||
layout.size());
|
||||
if (r != noErr) {
|
||||
if (side == INPUT) {
|
||||
PRINT_ERROR_CODE("AudioUnitSetProperty/input/kAudioUnitProperty_AudioChannelLayout", r);
|
||||
} else {
|
||||
PRINT_ERROR_CODE("AudioUnitSetProperty/output/kAudioUnitProperty_AudioChannelLayout", r);
|
||||
}
|
||||
return CUBEB_ERROR;
|
||||
}
|
||||
|
||||
return CUBEB_OK;
|
||||
}
|
||||
|
||||
static int
|
||||
audiounit_create_unit(AudioUnit * unit,
|
||||
bool is_input,
|
||||
|
@ -1243,20 +1433,15 @@ buffer_size_changed_callback(void * inClientData,
|
|||
}
|
||||
}
|
||||
|
||||
enum set_buffer_size_side {
|
||||
INPUT,
|
||||
OUTPUT,
|
||||
};
|
||||
|
||||
static int
|
||||
audiounit_set_buffer_size(cubeb_stream * stm, uint32_t new_size_frames, set_buffer_size_side set_side)
|
||||
audiounit_set_buffer_size(cubeb_stream * stm, uint32_t new_size_frames, io_side side)
|
||||
{
|
||||
AudioUnit au = stm->output_unit;
|
||||
AudioUnitScope au_scope = kAudioUnitScope_Input;
|
||||
AudioUnitElement au_element = AU_OUT_BUS;
|
||||
const char * au_type = "output";
|
||||
|
||||
if (set_side == INPUT) {
|
||||
if (side == INPUT) {
|
||||
au = stm->input_unit;
|
||||
au_scope = kAudioUnitScope_Output;
|
||||
au_element = AU_IN_BUS;
|
||||
|
@ -1272,7 +1457,7 @@ audiounit_set_buffer_size(cubeb_stream * stm, uint32_t new_size_frames, set_buff
|
|||
&buffer_frames,
|
||||
&size);
|
||||
if (r != noErr) {
|
||||
if (set_side == INPUT) {
|
||||
if (side == INPUT) {
|
||||
PRINT_ERROR_CODE("AudioUnitGetProperty/input/kAudioDevicePropertyBufferFrameSize", r);
|
||||
} else {
|
||||
PRINT_ERROR_CODE("AudioUnitGetProperty/output/kAudioDevicePropertyBufferFrameSize", r);
|
||||
|
@ -1290,7 +1475,7 @@ audiounit_set_buffer_size(cubeb_stream * stm, uint32_t new_size_frames, set_buff
|
|||
buffer_size_changed_callback,
|
||||
stm);
|
||||
if (r != noErr) {
|
||||
if (set_side == INPUT) {
|
||||
if (side == INPUT) {
|
||||
PRINT_ERROR_CODE("AudioUnitAddPropertyListener/input/kAudioDevicePropertyBufferFrameSize", r);
|
||||
} else {
|
||||
PRINT_ERROR_CODE("AudioUnitAddPropertyListener/output/kAudioDevicePropertyBufferFrameSize", r);
|
||||
|
@ -1307,7 +1492,7 @@ audiounit_set_buffer_size(cubeb_stream * stm, uint32_t new_size_frames, set_buff
|
|||
&new_size_frames,
|
||||
sizeof(new_size_frames));
|
||||
if (r != noErr) {
|
||||
if (set_side == INPUT) {
|
||||
if (side == INPUT) {
|
||||
PRINT_ERROR_CODE("AudioUnitSetProperty/input/kAudioDevicePropertyBufferFrameSize", r);
|
||||
} else {
|
||||
PRINT_ERROR_CODE("AudioUnitSetProperty/output/kAudioDevicePropertyBufferFrameSize", r);
|
||||
|
@ -1318,7 +1503,7 @@ audiounit_set_buffer_size(cubeb_stream * stm, uint32_t new_size_frames, set_buff
|
|||
buffer_size_changed_callback,
|
||||
stm);
|
||||
if (r != noErr) {
|
||||
if (set_side == INPUT) {
|
||||
if (side == INPUT) {
|
||||
PRINT_ERROR_CODE("AudioUnitAddPropertyListener/input/kAudioDevicePropertyBufferFrameSize", r);
|
||||
} else {
|
||||
PRINT_ERROR_CODE("AudioUnitAddPropertyListener/output/kAudioDevicePropertyBufferFrameSize", r);
|
||||
|
@ -1344,7 +1529,7 @@ audiounit_set_buffer_size(cubeb_stream * stm, uint32_t new_size_frames, set_buff
|
|||
buffer_size_changed_callback,
|
||||
stm);
|
||||
if (r != noErr) {
|
||||
if (set_side == INPUT) {
|
||||
if (side == INPUT) {
|
||||
PRINT_ERROR_CODE("AudioUnitAddPropertyListener/input/kAudioDevicePropertyBufferFrameSize", r);
|
||||
} else {
|
||||
PRINT_ERROR_CODE("AudioUnitAddPropertyListener/output/kAudioDevicePropertyBufferFrameSize", r);
|
||||
|
@ -1489,7 +1674,7 @@ audiounit_configure_output(cubeb_stream * stm)
|
|||
&output_hw_desc,
|
||||
&size);
|
||||
if (r != noErr) {
|
||||
PRINT_ERROR_CODE("AudioUnitGetProperty/output/tkAudioUnitProperty_StreamFormat", r);
|
||||
PRINT_ERROR_CODE("AudioUnitGetProperty/output/kAudioUnitProperty_StreamFormat", r);
|
||||
return CUBEB_ERROR;
|
||||
}
|
||||
stm->output_hw_rate = output_hw_desc.mSampleRate;
|
||||
|
@ -1538,6 +1723,8 @@ audiounit_configure_output(cubeb_stream * stm)
|
|||
return CUBEB_ERROR;
|
||||
}
|
||||
|
||||
audiounit_layout_init(&stm->output_unit, OUTPUT, &stm->output_stream_params);
|
||||
|
||||
LOG("(%p) Output audiounit init successfully.", stm);
|
||||
return CUBEB_OK;
|
||||
}
|
||||
|
@ -2528,13 +2715,76 @@ int audiounit_register_device_collection_changed(cubeb * context,
|
|||
return (ret == noErr) ? CUBEB_OK : CUBEB_ERROR;
|
||||
}
|
||||
|
||||
static cubeb_channel_layout
|
||||
audiounit_get_channel_layout(bool preferred)
|
||||
{
|
||||
OSStatus rv = noErr;
|
||||
|
||||
// Get the default ouput unit
|
||||
AudioUnit output_unit;
|
||||
audiounit_create_unit(&output_unit, false, nullptr, 0);
|
||||
|
||||
// Get the channel layout
|
||||
UInt32 size = 0;
|
||||
rv = AudioUnitGetPropertyInfo(output_unit,
|
||||
preferred ? kAudioDevicePropertyPreferredChannelLayout :
|
||||
kAudioUnitProperty_AudioChannelLayout,
|
||||
kAudioUnitScope_Output,
|
||||
AU_OUT_BUS,
|
||||
&size,
|
||||
nullptr);
|
||||
if (rv != noErr) {
|
||||
if (preferred) {
|
||||
PRINT_ERROR_CODE("AudioUnitGetPropertyInfo/kAudioDevicePropertyPreferredChannelLayout", rv);
|
||||
} else {
|
||||
PRINT_ERROR_CODE("AudioUnitGetPropertyInfo/kAudioUnitProperty_AudioChannelLayout", rv);
|
||||
}
|
||||
return CUBEB_LAYOUT_UNDEFINED;
|
||||
}
|
||||
assert(size > 0);
|
||||
|
||||
auto_channel_layout layout(size);
|
||||
rv = AudioUnitGetProperty(output_unit,
|
||||
preferred ? kAudioDevicePropertyPreferredChannelLayout :
|
||||
kAudioUnitProperty_AudioChannelLayout,
|
||||
kAudioUnitScope_Output,
|
||||
AU_OUT_BUS,
|
||||
layout.get(),
|
||||
&size);
|
||||
if (rv != noErr) {
|
||||
if (preferred) {
|
||||
PRINT_ERROR_CODE("AudioUnitGetProperty/kAudioDevicePropertyPreferredChannelLayout", rv);
|
||||
} else {
|
||||
PRINT_ERROR_CODE("AudioUnitGetProperty/kAudioUnitProperty_AudioChannelLayout", rv);
|
||||
}
|
||||
return CUBEB_LAYOUT_UNDEFINED;
|
||||
}
|
||||
|
||||
if (layout.get()->mChannelLayoutTag != kAudioChannelLayoutTag_UseChannelDescriptions) {
|
||||
// kAudioChannelLayoutTag_UseChannelBitmap
|
||||
// kAudioChannelLayoutTag_Mono
|
||||
// kAudioChannelLayoutTag_Stereo
|
||||
// ....
|
||||
LOG("Only handle UseChannelDescriptions for now.\n");
|
||||
return CUBEB_LAYOUT_UNDEFINED;
|
||||
}
|
||||
|
||||
cubeb_channel_map cm;
|
||||
cm.channels = layout.get()->mNumberChannelDescriptions;
|
||||
for (UInt32 i = 0; i < layout.get()->mNumberChannelDescriptions; ++i) {
|
||||
cm.map[i] = channel_label_to_cubeb_channel(layout.get()->mChannelDescriptions[i].mChannelLabel);
|
||||
}
|
||||
|
||||
return cubeb_channel_map_to_layout(&cm);
|
||||
}
|
||||
|
||||
cubeb_ops const audiounit_ops = {
|
||||
/*.init =*/ audiounit_init,
|
||||
/*.get_backend_id =*/ audiounit_get_backend_id,
|
||||
/*.get_max_channel_count =*/ audiounit_get_max_channel_count,
|
||||
/*.get_min_latency =*/ audiounit_get_min_latency,
|
||||
/*.get_preferred_sample_rate =*/ audiounit_get_preferred_sample_rate,
|
||||
/*.get_preferred_channel_layout =*/ nullptr,
|
||||
/*.get_preferred_channel_layout =*/ audiounit_get_preferred_channel_layout,
|
||||
/*.enumerate_devices =*/ audiounit_enumerate_devices,
|
||||
/*.destroy =*/ audiounit_destroy,
|
||||
/*.stream_init =*/ audiounit_stream_init,
|
||||
|
|
|
@ -9,6 +9,55 @@
|
|||
#include "cubeb-internal.h"
|
||||
#include "cubeb_mixer.h"
|
||||
|
||||
// DUAL_MONO(_LFE) is same as STEREO(_LFE).
|
||||
#define MASK_MONO (1 << CHANNEL_MONO)
|
||||
#define MASK_MONO_LFE (MASK_MONO | (1 << CHANNEL_LFE))
|
||||
#define MASK_STEREO ((1 << CHANNEL_LEFT) | (1 << CHANNEL_RIGHT))
|
||||
#define MASK_STEREO_LFE (MASK_STEREO | (1 << CHANNEL_LFE))
|
||||
#define MASK_3F (MASK_STEREO | (1 << CHANNEL_CENTER))
|
||||
#define MASK_3F_LFE (MASK_3F | (1 << CHANNEL_LFE))
|
||||
#define MASK_2F1 (MASK_STEREO | (1 << CHANNEL_RCENTER))
|
||||
#define MASK_2F1_LFE (MASK_2F1 | (1 << CHANNEL_LFE))
|
||||
#define MASK_3F1 (MASK_3F | (1 << CHANNEL_RCENTER))
|
||||
#define MASK_3F1_LFE (MASK_3F1 | (1 << CHANNEL_LFE))
|
||||
#define MASK_2F2 (MASK_STEREO | (1 << CHANNEL_LS) | (1 << CHANNEL_RS))
|
||||
#define MASK_2F2_LFE (MASK_2F2 | (1 << CHANNEL_LFE))
|
||||
#define MASK_3F2 (MASK_2F2 | (1 << CHANNEL_CENTER))
|
||||
#define MASK_3F2_LFE (MASK_3F2 | (1 << CHANNEL_LFE))
|
||||
#define MASK_3F3R_LFE (MASK_3F2_LFE | (1 << CHANNEL_RCENTER))
|
||||
#define MASK_3F4_LFE (MASK_3F2_LFE | (1 << CHANNEL_RLS) | (1 << CHANNEL_RRS))
|
||||
|
||||
cubeb_channel_layout cubeb_channel_map_to_layout(cubeb_channel_map const * channel_map)
|
||||
{
|
||||
uint32_t channel_mask = 0;
|
||||
for (uint8_t i = 0 ; i < channel_map->channels ; ++i) {
|
||||
if (channel_map->map[i] == CHANNEL_INVALID) {
|
||||
return CUBEB_LAYOUT_UNDEFINED;
|
||||
}
|
||||
channel_mask |= 1 << channel_map->map[i];
|
||||
}
|
||||
|
||||
switch(channel_mask) {
|
||||
case MASK_MONO: return CUBEB_LAYOUT_MONO;
|
||||
case MASK_MONO_LFE: return CUBEB_LAYOUT_MONO_LFE;
|
||||
case MASK_STEREO: return CUBEB_LAYOUT_STEREO;
|
||||
case MASK_STEREO_LFE: return CUBEB_LAYOUT_STEREO_LFE;
|
||||
case MASK_3F: return CUBEB_LAYOUT_3F;
|
||||
case MASK_3F_LFE: return CUBEB_LAYOUT_3F_LFE;
|
||||
case MASK_2F1: return CUBEB_LAYOUT_2F1;
|
||||
case MASK_2F1_LFE: return CUBEB_LAYOUT_2F1_LFE;
|
||||
case MASK_3F1: return CUBEB_LAYOUT_3F1;
|
||||
case MASK_3F1_LFE: return CUBEB_LAYOUT_3F1_LFE;
|
||||
case MASK_2F2: return CUBEB_LAYOUT_2F2;
|
||||
case MASK_2F2_LFE: return CUBEB_LAYOUT_2F2_LFE;
|
||||
case MASK_3F2: return CUBEB_LAYOUT_3F2;
|
||||
case MASK_3F2_LFE: return CUBEB_LAYOUT_3F2_LFE;
|
||||
case MASK_3F3R_LFE: return CUBEB_LAYOUT_3F3R_LFE;
|
||||
case MASK_3F4_LFE: return CUBEB_LAYOUT_3F4_LFE;
|
||||
default: return CUBEB_LAYOUT_UNDEFINED;
|
||||
}
|
||||
}
|
||||
|
||||
cubeb_layout_map const CUBEB_CHANNEL_LAYOUT_MAPS[CUBEB_LAYOUT_MAX] = {
|
||||
{ "undefined", 0, CUBEB_LAYOUT_UNDEFINED },
|
||||
{ "dual mono", 2, CUBEB_LAYOUT_DUAL_MONO },
|
||||
|
|
|
@ -52,6 +52,13 @@ static cubeb_channel const CHANNEL_INDEX_TO_ORDER[CUBEB_LAYOUT_MAX][CHANNEL_MAX]
|
|||
{ CHANNEL_LEFT, CHANNEL_RIGHT, CHANNEL_CENTER, CHANNEL_LFE, CHANNEL_RLS, CHANNEL_RRS, CHANNEL_LS, CHANNEL_RS } // 3F4_LFE
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
unsigned int channels;
|
||||
cubeb_channel map[CHANNEL_MAX];
|
||||
} cubeb_channel_map;
|
||||
|
||||
cubeb_channel_layout cubeb_channel_map_to_layout(cubeb_channel_map const * channel_map);
|
||||
|
||||
bool cubeb_should_upmix(cubeb_stream_params const * stream, cubeb_stream_params const * mixer);
|
||||
|
||||
bool cubeb_should_downmix(cubeb_stream_params const * stream, cubeb_stream_params const * mixer);
|
||||
|
|
|
@ -525,55 +525,15 @@ layout_to_channel_map(cubeb_channel_layout layout, pa_channel_map * cm)
|
|||
}
|
||||
}
|
||||
|
||||
// DUAL_MONO(_LFE) is same as STEREO(_LFE).
|
||||
#define MASK_MONO (1 << CHANNEL_MONO)
|
||||
#define MASK_MONO_LFE (MASK_MONO | (1 << CHANNEL_LFE))
|
||||
#define MASK_STEREO ((1 << CHANNEL_LEFT) | (1 << CHANNEL_RIGHT))
|
||||
#define MASK_STEREO_LFE (MASK_STEREO | (1 << CHANNEL_LFE))
|
||||
#define MASK_3F (MASK_STEREO | (1 << CHANNEL_CENTER))
|
||||
#define MASK_3F_LFE (MASK_3F | (1 << CHANNEL_LFE))
|
||||
#define MASK_2F1 (MASK_STEREO | (1 << CHANNEL_RCENTER))
|
||||
#define MASK_2F1_LFE (MASK_2F1 | (1 << CHANNEL_LFE))
|
||||
#define MASK_3F1 (MASK_3F | (1 << CHANNEL_RCENTER))
|
||||
#define MASK_3F1_LFE (MASK_3F1 | (1 << CHANNEL_LFE))
|
||||
#define MASK_2F2 (MASK_STEREO | (1 << CHANNEL_LS) | (1 << CHANNEL_RS))
|
||||
#define MASK_2F2_LFE (MASK_2F2 | (1 << CHANNEL_LFE))
|
||||
#define MASK_3F2 (MASK_2F2 | (1 << CHANNEL_CENTER))
|
||||
#define MASK_3F2_LFE (MASK_3F2 | (1 << CHANNEL_LFE))
|
||||
#define MASK_3F3R_LFE (MASK_3F2_LFE | (1 << CHANNEL_RCENTER))
|
||||
#define MASK_3F4_LFE (MASK_3F2_LFE | (1 << CHANNEL_RLS) | (1 << CHANNEL_RRS))
|
||||
|
||||
static cubeb_channel_layout
|
||||
channel_map_to_layout(pa_channel_map * cm)
|
||||
{
|
||||
uint32_t channel_mask = 0;
|
||||
for (uint8_t i = 0 ; i < cm->channels ; ++i) {
|
||||
cubeb_channel channel = pa_channel_to_cubeb_channel(cm->map[i]);
|
||||
if (channel == CHANNEL_INVALID) {
|
||||
return CUBEB_LAYOUT_UNDEFINED;
|
||||
}
|
||||
channel_mask |= 1 << channel;
|
||||
}
|
||||
|
||||
switch(channel_mask) {
|
||||
case MASK_MONO: return CUBEB_LAYOUT_MONO;
|
||||
case MASK_MONO_LFE: return CUBEB_LAYOUT_MONO_LFE;
|
||||
case MASK_STEREO: return CUBEB_LAYOUT_STEREO;
|
||||
case MASK_STEREO_LFE: return CUBEB_LAYOUT_STEREO_LFE;
|
||||
case MASK_3F: return CUBEB_LAYOUT_3F;
|
||||
case MASK_3F_LFE: return CUBEB_LAYOUT_3F_LFE;
|
||||
case MASK_2F1: return CUBEB_LAYOUT_2F1;
|
||||
case MASK_2F1_LFE: return CUBEB_LAYOUT_2F1_LFE;
|
||||
case MASK_3F1: return CUBEB_LAYOUT_3F1;
|
||||
case MASK_3F1_LFE: return CUBEB_LAYOUT_3F1_LFE;
|
||||
case MASK_2F2: return CUBEB_LAYOUT_2F2;
|
||||
case MASK_2F2_LFE: return CUBEB_LAYOUT_2F2_LFE;
|
||||
case MASK_3F2: return CUBEB_LAYOUT_3F2;
|
||||
case MASK_3F2_LFE: return CUBEB_LAYOUT_3F2_LFE;
|
||||
case MASK_3F3R_LFE: return CUBEB_LAYOUT_3F3R_LFE;
|
||||
case MASK_3F4_LFE: return CUBEB_LAYOUT_3F4_LFE;
|
||||
default: return CUBEB_LAYOUT_UNDEFINED;
|
||||
cubeb_channel_map cubeb_map;
|
||||
cubeb_map.channels = cm->channels;
|
||||
for (uint32_t i = 0 ; i < cm->channels ; ++i) {
|
||||
cubeb_map.map[i] = pa_channel_to_cubeb_channel(cm->map[i]);
|
||||
}
|
||||
return cubeb_channel_map_to_layout(&cubeb_map);
|
||||
}
|
||||
|
||||
static void pulse_context_destroy(cubeb * ctx);
|
||||
|
|
|
@ -4,11 +4,7 @@
|
|||
* This program is made available under an ISC-style license. See the
|
||||
* accompanying file LICENSE for details.
|
||||
*/
|
||||
// Explicitly define NTDDI_VERSION rather than letting the value be derived
|
||||
// from _WIN32_WINNT because we depend on values defined for XP SP2 and WS03
|
||||
// SP1.
|
||||
#define _WIN32_WINNT 0x0502
|
||||
#define NTDDI_VERSION 0x05020100
|
||||
#define _WIN32_WINNT 0x0600
|
||||
#define NOMINMAX
|
||||
|
||||
#include <initguid.h>
|
||||
|
@ -164,10 +160,6 @@ private:
|
|||
HRESULT result;
|
||||
};
|
||||
|
||||
typedef HANDLE (WINAPI *set_mm_thread_characteristics_function)(
|
||||
const char * TaskName, LPDWORD TaskIndex);
|
||||
typedef BOOL (WINAPI *revert_mm_thread_characteristics_function)(HANDLE handle);
|
||||
|
||||
extern cubeb_ops const wasapi_ops;
|
||||
|
||||
int wasapi_stream_stop(cubeb_stream * stm);
|
||||
|
@ -181,11 +173,6 @@ static std::unique_ptr<wchar_t const []> utf8_to_wstr(char const * str);
|
|||
|
||||
struct cubeb {
|
||||
cubeb_ops const * ops = &wasapi_ops;
|
||||
/* Library dynamically opened to increase the render thread priority, and
|
||||
the two function pointers we need. */
|
||||
HMODULE mmcss_module = nullptr;
|
||||
set_mm_thread_characteristics_function set_mm_thread_characteristics = nullptr;
|
||||
revert_mm_thread_characteristics_function revert_mm_thread_characteristics = nullptr;
|
||||
};
|
||||
|
||||
class wasapi_endpoint_notification_client;
|
||||
|
@ -864,8 +851,7 @@ wasapi_stream_render_loop(LPVOID stream)
|
|||
|
||||
/* We could consider using "Pro Audio" here for WebAudio and
|
||||
maybe WebRTC. */
|
||||
mmcss_handle =
|
||||
stm->context->set_mm_thread_characteristics("Audio", &mmcss_task_index);
|
||||
mmcss_handle = AvSetMmThreadCharacteristicsA("Audio", &mmcss_task_index);
|
||||
if (!mmcss_handle) {
|
||||
/* This is not fatal, but we might glitch under heavy load. */
|
||||
LOG("Unable to use mmcss to bump the render thread priority: %lx", GetLastError());
|
||||
|
@ -967,7 +953,7 @@ wasapi_stream_render_loop(LPVOID stream)
|
|||
}
|
||||
|
||||
if (mmcss_handle) {
|
||||
stm->context->revert_mm_thread_characteristics(mmcss_handle);
|
||||
AvRevertMmThreadCharacteristics(mmcss_handle);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -975,16 +961,6 @@ wasapi_stream_render_loop(LPVOID stream)
|
|||
|
||||
void wasapi_destroy(cubeb * context);
|
||||
|
||||
HANDLE WINAPI set_mm_thread_characteristics_noop(const char *, LPDWORD mmcss_task_index)
|
||||
{
|
||||
return (HANDLE)1;
|
||||
}
|
||||
|
||||
BOOL WINAPI revert_mm_thread_characteristics_noop(HANDLE mmcss_handle)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
HRESULT register_notification_client(cubeb_stream * stm)
|
||||
{
|
||||
HRESULT hr = CoCreateInstance(__uuidof(MMDeviceEnumerator),
|
||||
|
@ -1162,27 +1138,6 @@ int wasapi_init(cubeb ** context, char const * context_name)
|
|||
|
||||
ctx->ops = &wasapi_ops;
|
||||
|
||||
ctx->mmcss_module = LoadLibraryA("Avrt.dll");
|
||||
|
||||
if (ctx->mmcss_module) {
|
||||
ctx->set_mm_thread_characteristics =
|
||||
(set_mm_thread_characteristics_function) GetProcAddress(
|
||||
ctx->mmcss_module, "AvSetMmThreadCharacteristicsA");
|
||||
ctx->revert_mm_thread_characteristics =
|
||||
(revert_mm_thread_characteristics_function) GetProcAddress(
|
||||
ctx->mmcss_module, "AvRevertMmThreadCharacteristics");
|
||||
if (!(ctx->set_mm_thread_characteristics && ctx->revert_mm_thread_characteristics)) {
|
||||
LOG("Could not load AvSetMmThreadCharacteristics or AvRevertMmThreadCharacteristics: %lx", GetLastError());
|
||||
FreeLibrary(ctx->mmcss_module);
|
||||
}
|
||||
} else {
|
||||
// This is not a fatal error, but we might end up glitching when
|
||||
// the system is under high load.
|
||||
LOG("Could not load Avrt.dll");
|
||||
ctx->set_mm_thread_characteristics = &set_mm_thread_characteristics_noop;
|
||||
ctx->revert_mm_thread_characteristics = &revert_mm_thread_characteristics_noop;
|
||||
}
|
||||
|
||||
*context = ctx;
|
||||
|
||||
return CUBEB_OK;
|
||||
|
@ -1239,9 +1194,6 @@ bool stop_and_join_render_thread(cubeb_stream * stm)
|
|||
|
||||
void wasapi_destroy(cubeb * context)
|
||||
{
|
||||
if (context->mmcss_module) {
|
||||
FreeLibrary(context->mmcss_module);
|
||||
}
|
||||
delete context;
|
||||
}
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче