Bug 1531833 - Update libcubeb to c0a717 (and rebase an in-tree patch). r=kinetik

This has been reviewed by snorp, kinetik, achronop, in bug 1531833, and the
rollup has been rubberstamped by achronop in
https://github.com/kinetiknz/cubeb/pull/501.

Differential Revision: https://phabricator.services.mozilla.com/D26937

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Paul Adenot 2019-04-11 09:19:39 +00:00
Родитель 387f4ae5fd
Коммит b774a54cc4
7 изменённых файлов: 250 добавлений и 88 удалений

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

@ -1,34 +1,3 @@
diff --git a/media/libcubeb/include/cubeb.h b/media/libcubeb/include/cubeb.h
--- a/media/libcubeb/include/cubeb.h
+++ b/media/libcubeb/include/cubeb.h
@@ -216,20 +216,23 @@ enum {
CHANNEL_FRONT_CENTER | CHANNEL_LOW_FREQUENCY |
CHANNEL_BACK_LEFT | CHANNEL_BACK_RIGHT |
CHANNEL_SIDE_LEFT | CHANNEL_SIDE_RIGHT,
};
/** Miscellaneous stream preferences. */
typedef enum {
CUBEB_STREAM_PREF_NONE = 0x00, /**< No stream preferences are requested. */
- CUBEB_STREAM_PREF_LOOPBACK = 0x01 /**< Request a loopback stream. Should be
- specified on the input params and an
- output device to loopback from should
- be passed in place of an input device. */
+ CUBEB_STREAM_PREF_LOOPBACK = 0x01, /**< Request a loopback stream. Should be
+ specified on the input params and an
+ output device to loopback from should
+ be passed in place of an input device. */
+ CUBEB_STREAM_PREF_DISABLE_DEVICE_SWITCHING = 0x02, /**< Disable switching
+ default device on OS
+ changes. */
} cubeb_stream_prefs;
/** Stream format initialization parameters. */
typedef struct {
cubeb_sample_format format; /**< Requested sample format. One of
#cubeb_sample_format. */
uint32_t rate; /**< Requested sample rate. Valid range is [1000, 192000]. */
uint32_t channels; /**< Requested channel count. Valid range is [1, 8]. */
diff --git a/media/libcubeb/src/cubeb_wasapi.cpp b/media/libcubeb/src/cubeb_wasapi.cpp
--- a/media/libcubeb/src/cubeb_wasapi.cpp
+++ b/media/libcubeb/src/cubeb_wasapi.cpp
@ -85,3 +54,26 @@ diff --git a/media/libcubeb/src/cubeb_wasapi.cpp b/media/libcubeb/src/cubeb_wasa
// The variables intialized in wasapi_stream_init,
// must be destroyed in wasapi_stream_destroy.
stm->linear_input_buffer.reset();
diff --git a/media/libcubeb/include/cubeb.h b/media/libcubeb/include/cubeb.h
--- a/media/libcubeb/include/cubeb.h
+++ a/media/libcubeb/include/cubeb.h
@@ -222,16 +222,19 @@
/** Miscellaneous stream preferences. */
typedef enum {
CUBEB_STREAM_PREF_NONE = 0x00, /**< No stream preferences are requested. */
CUBEB_STREAM_PREF_LOOPBACK = 0x01, /**< Request a loopback stream. Should be
specified on the input params and an
output device to loopback from should
be passed in place of an input device. */
+ CUBEB_STREAM_PREF_DISABLE_DEVICE_SWITCHING = 0x02, /**< Disable switching
+ default device on OS
+ changes. */
CUBEB_STREAM_PREF_VOICE = 0x04 /**< This stream is going to transport voice data.
Depending on the backend and platform, this can
change the audio input or output devices
selected, as well as the quality of the stream,
for example to accomodate bluetooth SCO modes on
bluetooth devices. */
} cubeb_stream_prefs;

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

@ -224,12 +224,18 @@ enum {
typedef enum {
CUBEB_STREAM_PREF_NONE = 0x00, /**< No stream preferences are requested. */
CUBEB_STREAM_PREF_LOOPBACK = 0x01, /**< Request a loopback stream. Should be
specified on the input params and an
output device to loopback from should
be passed in place of an input device. */
specified on the input params and an
output device to loopback from should
be passed in place of an input device. */
CUBEB_STREAM_PREF_DISABLE_DEVICE_SWITCHING = 0x02, /**< Disable switching
default device on OS
changes. */
CUBEB_STREAM_PREF_VOICE = 0x04 /**< This stream is going to transport voice data.
Depending on the backend and platform, this can
change the audio input or output devices
selected, as well as the quality of the stream,
for example to accomodate bluetooth SCO modes on
bluetooth devices. */
} cubeb_stream_prefs;
/** Stream format initialization parameters. */

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

@ -19,5 +19,5 @@ origin:
license: "ISC"
# update.sh will update this value
release: "66d9c48d916f00c396482f9c5075feacc2bc0db8 (2019-04-03 12:41:20 +0300)"
release: "c0a71704ae935666ecbd0e8a61345de583139607 (2019-04-10 18:19:29 +0200)"

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

@ -43,10 +43,9 @@
#define SL_ANDROID_RECORDING_PRESET_VOICE_RECOGNITION ((SLuint32) 0x00000003)
/** uses the main microphone tuned for audio communications */
#define SL_ANDROID_RECORDING_PRESET_VOICE_COMMUNICATION ((SLuint32) 0x00000004)
/** uses the main microphone unprocessed */
#define SL_ANDROID_RECORDING_PRESET_UNPROCESSED ((SLuint32) 0x00000005)
/** Audio recording get session ID (read only) */
/** Audio recording get session ID key */
#define SL_ANDROID_KEY_RECORDING_SESSION_ID ((const SLchar*) "androidRecordingSessionId")
/*---------------------------------------------------------------------------*/
/* Android AudioPlayer configuration */
@ -69,9 +68,35 @@
#define SL_ANDROID_STREAM_ALARM ((SLint32) 0x00000004)
/* same as android.media.AudioManager.STREAM_NOTIFICATION */
#define SL_ANDROID_STREAM_NOTIFICATION ((SLint32) 0x00000005)
/* same as android.media.AudioManager.STREAM_BLUETOOTH_SCO */
#define SL_ANDROID_STREAM_BLUETOOTH_SCO ((SLint32) 0x00000006)
/* same as android.media.AudioManager.STREAM_SYSTEM_ENFORCED */
#define SL_ANDROID_STREAM_SYSTEM_ENFORCED ((SLint32) 0x00000007)
/*---------------------------------------------------------------------------*/
/* Android AudioPlayer and AudioRecorder configuration */
/*---------------------------------------------------------------------------*/
/** Audio Performance mode.
* Performance mode tells the framework how to configure the audio path
* for a player or recorder according to application performance and
* functional requirements.
* It affects the output or input latency based on acceptable tradeoffs on
* battery drain and use of pre or post processing effects.
* Performance mode should be set before realizing the object and should be
* read after realizing the object to check if the requested mode could be
* granted or not.
*/
/** Audio Performance mode key */
#define SL_ANDROID_KEY_PERFORMANCE_MODE ((const SLchar*) "androidPerformanceMode")
/** Audio performance values */
/* No specific performance requirement. Allows HW and SW pre/post processing. */
#define SL_ANDROID_PERFORMANCE_NONE ((SLuint32) 0x00000000)
/* Priority given to latency. No HW or software pre/post processing.
* This is the default if no performance mode is specified. */
#define SL_ANDROID_PERFORMANCE_LATENCY ((SLuint32) 0x00000001)
/* Priority given to latency while still allowing HW pre and post processing. */
#define SL_ANDROID_PERFORMANCE_LATENCY_EFFECTS ((SLuint32) 0x00000002)
/* Priority given to power saving if latency is not a concern.
* Allows HW and SW pre/post processing. */
#define SL_ANDROID_PERFORMANCE_POWER_SAVING ((SLuint32) 0x00000003)
#endif /* OPENSL_ES_ANDROIDCONFIGURATION_H_ */

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

@ -868,7 +868,7 @@ audiounit_reinit_stream_async(cubeb_stream * stm, device_flags_value flags)
{
if (std::atomic_exchange(&stm->reinit_pending, true)) {
// A reinit task is already pending, nothing more to do.
ALOG("(%p) re-init stream task already pending, cancelling request ", stm);
ALOG("(%p) re-init stream task already pending, cancelling request", stm);
return;
}
@ -944,7 +944,7 @@ audiounit_property_listener_callback(AudioObjectID id, UInt32 address_count,
}
break;
case kAudioDevicePropertyDataSource: {
LOG("Event[%u] - mSelector == kAudioHardwarePropertyDataSource for id=%d", (unsigned int) i, id);
LOG("Event[%u] - mSelector == kAudioDevicePropertyDataSource for id=%d", (unsigned int) i, id);
}
break;
default:
@ -1314,9 +1314,9 @@ audiounit_get_preferred_sample_rate(cubeb * /* ctx */, uint32_t * rate)
static cubeb_channel_layout
audiounit_convert_channel_layout(AudioChannelLayout * layout)
{
// When having on or two channel, force mono or stereo. Some devices (namely,
// Bose QC35, mark 1 and 2), expose a single channel mapped to the right for
// some reason.
// When having one or two channel, force mono or stereo. Some devices (namely,
// Bose QC35, mark 1 and 2), expose a single channel mapped to the right for
// some reason.
if (layout->mNumberChannelDescriptions == 1) {
return CUBEB_LAYOUT_MONO;
} else if (layout->mNumberChannelDescriptions == 2) {
@ -1611,7 +1611,7 @@ audiounit_create_blank_aggregate_device(AudioObjectID * plugin_id, AudioDeviceID
0, NULL,
&size);
if (r != noErr) {
LOG("AudioHardwareGetPropertyInfo/kAudioHardwarePropertyPlugInForBundleID, rv=%d", r);
LOG("AudioObjectGetPropertyDataSize/kAudioHardwarePropertyPlugInForBundleID, rv=%d", r);
return CUBEB_ERROR;
}
@ -1629,7 +1629,7 @@ audiounit_create_blank_aggregate_device(AudioObjectID * plugin_id, AudioDeviceID
&size,
&translation_value);
if (r != noErr) {
LOG("AudioHardwareGetProperty/kAudioHardwarePropertyPlugInForBundleID, rv=%d", r);
LOG("AudioObjectGetPropertyData/kAudioHardwarePropertyPlugInForBundleID, rv=%d", r);
return CUBEB_ERROR;
}
@ -2072,23 +2072,23 @@ audiounit_create_unit(AudioUnit * unit, device_info * device)
if (device->flags & DEV_INPUT) {
r = audiounit_enable_unit_scope(unit, io_side::INPUT, ENABLE);
if (r != CUBEB_OK) {
LOG("Failed to enable audiounit input scope ");
LOG("Failed to enable audiounit input scope");
return r;
}
r = audiounit_enable_unit_scope(unit, io_side::OUTPUT, DISABLE);
if (r != CUBEB_OK) {
LOG("Failed to disable audiounit output scope ");
LOG("Failed to disable audiounit output scope");
return r;
}
} else if (device->flags & DEV_OUTPUT) {
r = audiounit_enable_unit_scope(unit, io_side::OUTPUT, ENABLE);
if (r != CUBEB_OK) {
LOG("Failed to enable audiounit output scope ");
LOG("Failed to enable audiounit output scope");
return r;
}
r = audiounit_enable_unit_scope(unit, io_side::INPUT, DISABLE);
if (r != CUBEB_OK) {
LOG("Failed to disable audiounit input scope ");
LOG("Failed to disable audiounit input scope");
return r;
}
} else {
@ -2588,16 +2588,16 @@ audiounit_setup_stream(cubeb_stream * stm)
}
/* Latency cannot change if another stream is operating in parallel. In this case
* latecy is set to the other stream value. */
* latency is set to the other stream value. */
if (audiounit_active_streams(stm->context) > 1) {
LOG("(%p) More than one active stream, use global latency.", stm);
stm->latency_frames = stm->context->global_latency_frames;
} else {
/* Silently clamp the latency down to the platform default, because we
* synthetize the clock from the callbacks, and we want the clock to update
* often. */
* synthetize the clock from the callbacks, and we want the clock to update
* often. */
stm->latency_frames = audiounit_clamp_latency(stm, stm->latency_frames);
assert(stm->latency_frames); // Ungly error check
assert(stm->latency_frames); // Ugly error check
audiounit_set_global_latency(stm->context, stm->latency_frames);
}

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

@ -63,6 +63,11 @@
#define DEFAULT_SAMPLE_RATE 48000
#define DEFAULT_NUM_OF_FRAMES 480
// If the latency requested is above this threshold, this stream is considered
// intended for playback (vs. real-time). Tell Android it should favor saving
// power over performance or latency.
// This is around 100ms at 44100 or 48000
#define POWERSAVE_LATENCY_FRAMES_THRESHOLD 4000
static struct cubeb_ops const opensl_ops;
@ -84,7 +89,7 @@ struct cubeb {
};
#define NELEMS(A) (sizeof(A) / sizeof A[0])
#define NBUFS 4
#define NBUFS 2
struct cubeb_stream {
/* Note: Must match cubeb_stream layout in cubeb.c. */
@ -155,10 +160,13 @@ struct cubeb_stream {
cubeb_resampler * resampler;
unsigned int user_output_rate;
unsigned int output_configured_rate;
unsigned int latency_frames;
unsigned int buffer_size_frames;
// Audio output latency used in cubeb_stream_get_position().
unsigned int output_latency_ms;
int64_t lastPosition;
int64_t lastPositionTimeStamp;
int64_t lastCompensativePosition;
int voice;
};
/* Forward declaration. */
@ -846,16 +854,17 @@ opensl_configure_capture(cubeb_stream * stm, cubeb_stream_params * params)
lDataSource.pLocator = &lDataLocatorIn;
lDataSource.pFormat = NULL;
const SLuint32 lSoundRecorderIIDCount = 2;
const SLInterfaceID lSoundRecorderIIDs[] = { stm->context->SL_IID_RECORD,
stm->context->SL_IID_ANDROIDSIMPLEBUFFERQUEUE };
const SLboolean lSoundRecorderReqs[] = { SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE };
stm->context->SL_IID_ANDROIDSIMPLEBUFFERQUEUE,
stm->context->SL_IID_ANDROIDCONFIGURATION };
const SLboolean lSoundRecorderReqs[] = { SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE};
// create the audio recorder abstract object
SLresult res = (*stm->context->eng)->CreateAudioRecorder(stm->context->eng,
&stm->recorderObj,
&lDataSource,
&lDataSink,
lSoundRecorderIIDCount,
NELEMS(lSoundRecorderIIDs),
lSoundRecorderIIDs,
lSoundRecorderReqs);
// Sample rate not supported. Try again with default sample rate!
@ -874,7 +883,7 @@ opensl_configure_capture(cubeb_stream * stm, cubeb_stream_params * params)
&stm->recorderObj,
&lDataSource,
&lDataSink,
lSoundRecorderIIDCount,
NELEMS(lSoundRecorderIIDs),
lSoundRecorderIIDs,
lSoundRecorderReqs);
@ -884,6 +893,35 @@ opensl_configure_capture(cubeb_stream * stm, cubeb_stream_params * params)
}
}
SLAndroidConfigurationItf recorderConfig;
res = (*stm->recorderObj)
->GetInterface(stm->recorderObj,
stm->context->SL_IID_ANDROIDCONFIGURATION,
&recorderConfig);
if (res != SL_RESULT_SUCCESS) {
LOG("Failed to get the android configuration interface for recorder. Error "
"code: %lu",
res);
return CUBEB_ERROR;
}
// Voice recognition is the lowest latency, according to the docs. Camcorder
// uses a microphone that is in the same direction as the camera.
SLint32 streamType = stm->voice ? SL_ANDROID_RECORDING_PRESET_VOICE_RECOGNITION
: SL_ANDROID_RECORDING_PRESET_CAMCORDER;
res = (*recorderConfig)
->SetConfiguration(recorderConfig, SL_ANDROID_KEY_RECORDING_PRESET,
&streamType, sizeof(SLint32));
if (res != SL_RESULT_SUCCESS) {
LOG("Failed to set the android configuration to VOICE for the recorder. "
"Error code: %lu",
res);
return CUBEB_ERROR;
}
// realize the audio recorder
res = (*stm->recorderObj)->Realize(stm->recorderObj, SL_BOOLEAN_FALSE);
if (res != SL_RESULT_SUCCESS) {
@ -937,7 +975,7 @@ opensl_configure_capture(cubeb_stream * stm, cubeb_stream_params * params)
// Calculate length of input buffer according to requested latency
stm->input_frame_size = params->channels * sizeof(int16_t);
stm->input_buffer_length = (stm->input_frame_size * stm->latency_frames);
stm->input_buffer_length = (stm->input_frame_size * stm->buffer_size_frames);
// Calculate the capacity of input array
stm->input_array_capacity = NBUFS;
@ -1048,7 +1086,7 @@ opensl_configure_playback(cubeb_stream * stm, cubeb_stream_params * params) {
stm->output_configured_rate = preferred_sampling_rate;
stm->bytespersec = stm->output_configured_rate * stm->framesize;
stm->queuebuf_len = stm->framesize * stm->latency_frames;
stm->queuebuf_len = stm->framesize * stm->buffer_size_frames;
// Calculate the capacity of input array
stm->queuebuf_capacity = NBUFS;
@ -1063,12 +1101,80 @@ opensl_configure_playback(cubeb_stream * stm, cubeb_stream_params * params) {
assert(stm->queuebuf[i]);
}
SLAndroidConfigurationItf playerConfig;
res = (*stm->playerObj)
->GetInterface(stm->playerObj,
stm->context->SL_IID_ANDROIDCONFIGURATION,
&playerConfig);
if (res != SL_RESULT_SUCCESS) {
LOG("Failed to get Android configuration interface. Error code: %lu", res);
return CUBEB_ERROR;
}
SLint32 streamType = SL_ANDROID_STREAM_MEDIA;
if (stm->voice) {
streamType = SL_ANDROID_STREAM_VOICE;
}
res = (*playerConfig)->SetConfiguration(playerConfig,
SL_ANDROID_KEY_STREAM_TYPE,
&streamType,
sizeof(streamType));
if (res != SL_RESULT_SUCCESS) {
LOG("Failed to set Android configuration to %d Error code: %lu",
streamType, res);
return CUBEB_ERROR;
}
SLuint32 performanceMode = SL_ANDROID_PERFORMANCE_LATENCY;
if (stm->buffer_size_frames > POWERSAVE_LATENCY_FRAMES_THRESHOLD) {
performanceMode = SL_ANDROID_PERFORMANCE_POWER_SAVING;
}
res = (*playerConfig)->SetConfiguration(playerConfig,
SL_ANDROID_KEY_PERFORMANCE_MODE,
&performanceMode,
sizeof(performanceMode));
if (res != SL_RESULT_SUCCESS) {
LOG("Failed to set Android performance mode to %d Error code: %lu. This is"
" not fatal", performanceMode, res);
}
res = (*stm->playerObj)->Realize(stm->playerObj, SL_BOOLEAN_FALSE);
if (res != SL_RESULT_SUCCESS) {
LOG("Failed to realize player object. Error code: %lu", res);
return CUBEB_ERROR;
}
// There are two ways of getting the audio output latency:
// - a configuration value, only available on some devices (notably devices
// running FireOS)
// - A Java method, that we call using JNI.
//
// The first method is prefered, if available, because it can account for more
// latency causes, and is more precise.
// Latency has to be queried after the realization of the interface, when
// using SL_IID_ANDROIDCONFIGURATION.
SLuint32 audioLatency = 0;
SLuint32 paramSize = sizeof(SLuint32);
// The reported latency is in milliseconds.
res = (*playerConfig)->GetConfiguration(playerConfig,
(const SLchar *)"androidGetAudioLatency",
&paramSize,
&audioLatency);
if (res == SL_RESULT_SUCCESS) {
LOG("Got playback latency using android configuration extension");
stm->output_latency_ms = audioLatency;
} else if (cubeb_output_latency_method_is_loaded(stm->context->p_output_latency_function)) {
LOG("Got playback latency using JNI");
stm->output_latency_ms = cubeb_get_output_latency(stm->context->p_output_latency_function);
} else {
LOG("No alternate latency querying method loaded, A/V sync will be off.");
stm->output_latency_ms = 0;
}
LOG("Audio output latency: %dms", stm->output_latency_ms);
res = (*stm->playerObj)->GetInterface(stm->playerObj,
stm->context->SL_IID_PLAY,
&stm->play);
@ -1148,6 +1254,14 @@ opensl_validate_stream_param(cubeb_stream_params * stream_params)
return CUBEB_OK;
}
int has_pref_set(cubeb_stream_params* input_params,
cubeb_stream_params* output_params,
cubeb_stream_prefs pref)
{
return (input_params && input_params->prefs & pref) ||
(output_params && output_params->prefs & pref);
}
static int
opensl_stream_init(cubeb * ctx, cubeb_stream ** stream, char const * stream_name,
cubeb_devid input_device,
@ -1185,10 +1299,14 @@ opensl_stream_init(cubeb * ctx, cubeb_stream ** stream, char const * stream_name
stm->data_callback = data_callback;
stm->state_callback = state_callback;
stm->user_ptr = user_ptr;
stm->latency_frames = latency_frames ? latency_frames : DEFAULT_NUM_OF_FRAMES;
stm->buffer_size_frames = latency_frames ? latency_frames : DEFAULT_NUM_OF_FRAMES;
stm->input_enabled = (input_stream_params) ? 1 : 0;
stm->output_enabled = (output_stream_params) ? 1 : 0;
stm->shutdown = 1;
stm->voice = has_pref_set(input_stream_params, output_stream_params, CUBEB_STREAM_PREF_VOICE);
LOG("cubeb stream prefs: voice: %s", stm->voice ? "true" : "false");
#ifdef DEBUG
pthread_mutexattr_t attr;
@ -1203,7 +1321,7 @@ opensl_stream_init(cubeb * ctx, cubeb_stream ** stream, char const * stream_name
if (output_stream_params) {
LOG("Playback params: Rate %d, channels %d, format %d, latency in frames %d.",
output_stream_params->rate, output_stream_params->channels,
output_stream_params->format, stm->latency_frames);
output_stream_params->format, stm->buffer_size_frames);
r = opensl_configure_playback(stm, output_stream_params);
if (r != CUBEB_OK) {
opensl_stream_destroy(stm);
@ -1214,7 +1332,7 @@ opensl_stream_init(cubeb * ctx, cubeb_stream ** stream, char const * stream_name
if (input_stream_params) {
LOG("Capture params: Rate %d, channels %d, format %d, latency in frames %d.",
input_stream_params->rate, input_stream_params->channels,
input_stream_params->format, stm->latency_frames);
input_stream_params->format, stm->buffer_size_frames);
r = opensl_configure_capture(stm, input_stream_params);
if (r != CUBEB_OK) {
opensl_stream_destroy(stm);
@ -1452,10 +1570,6 @@ opensl_stream_get_position(cubeb_stream * stm, uint64_t * position)
uint32_t compensation_msec = 0;
SLresult res;
if (!cubeb_output_latency_method_is_loaded(stm->context->p_output_latency_function)) {
return CUBEB_ERROR_NOT_SUPPORTED;
}
res = (*stm->play)->GetPosition(stm->play, &msec);
if (res != SL_RESULT_SUCCESS)
return CUBEB_ERROR;
@ -1471,22 +1585,22 @@ opensl_stream_get_position(cubeb_stream * stm, uint64_t * position)
}
uint64_t samplerate = stm->user_output_rate;
uint32_t mixer_latency = cubeb_get_output_latency(stm->context->p_output_latency_function);
uint32_t output_latency = stm->output_latency_ms;
pthread_mutex_lock(&stm->mutex);
int64_t maximum_position = stm->written * (int64_t)stm->user_output_rate / stm->output_configured_rate;
pthread_mutex_unlock(&stm->mutex);
assert(maximum_position >= 0);
if (msec > mixer_latency) {
if (msec > output_latency) {
int64_t unadjusted_position;
if (stm->lastCompensativePosition > msec + compensation_msec) {
// Over compensation, use lastCompensativePosition.
unadjusted_position =
samplerate * (stm->lastCompensativePosition - mixer_latency) / 1000;
samplerate * (stm->lastCompensativePosition - output_latency) / 1000;
} else {
unadjusted_position =
samplerate * (msec - mixer_latency + compensation_msec) / 1000;
samplerate * (msec - output_latency + compensation_msec) / 1000;
stm->lastCompensativePosition = msec + compensation_msec;
}
*position = unadjusted_position < maximum_position ?

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

@ -141,6 +141,7 @@ int wasapi_stream_stop(cubeb_stream * stm);
int wasapi_stream_start(cubeb_stream * stm);
void close_wasapi_stream(cubeb_stream * stm);
int setup_wasapi_stream(cubeb_stream * stm);
ERole pref_to_role(cubeb_stream_prefs param);
static char const * wstr_to_utf8(wchar_t const * str);
static std::unique_ptr<wchar_t const []> utf8_to_wstr(char const * str);
@ -191,6 +192,8 @@ struct cubeb_stream {
* and what will be presented in the callback. */
cubeb_stream_params input_stream_params = { CUBEB_SAMPLE_FLOAT32NE, 0, 0, CUBEB_LAYOUT_UNDEFINED, CUBEB_STREAM_PREF_NONE };
cubeb_stream_params output_stream_params = { CUBEB_SAMPLE_FLOAT32NE, 0, 0, CUBEB_LAYOUT_UNDEFINED, CUBEB_STREAM_PREF_NONE };
/* A MMDevice role for this stream: either communication or console here. */
ERole role;
/* The input and output device, or NULL for default. */
std::unique_ptr<const wchar_t[]> input_device;
std::unique_ptr<const wchar_t[]> output_device;
@ -565,9 +568,10 @@ public:
return S_OK;
}
wasapi_endpoint_notification_client(HANDLE event)
wasapi_endpoint_notification_client(HANDLE event, ERole role)
: ref_count(1)
, reconfigure_event(event)
, role(role)
{ }
virtual ~wasapi_endpoint_notification_client()
@ -579,7 +583,7 @@ public:
LOG("endpoint: Audio device default changed.");
/* we only support a single stream type for now. */
if (flow != eRender && role != eConsole) {
if (flow != eRender && role != this->role) {
return S_OK;
}
@ -622,6 +626,7 @@ private:
/* refcount for this instance, necessary to implement MSCOM semantics. */
LONG ref_count;
HANDLE reconfigure_event;
ERole role;
};
namespace {
@ -1256,7 +1261,7 @@ HRESULT register_notification_client(cubeb_stream * stm)
return hr;
}
stm->notification_client.reset(new wasapi_endpoint_notification_client(stm->reconfigure_event));
stm->notification_client.reset(new wasapi_endpoint_notification_client(stm->reconfigure_event, stm->role));
hr = stm->device_enumerator->RegisterEndpointNotificationCallback(stm->notification_client.get());
if (FAILED(hr)) {
@ -1351,7 +1356,7 @@ HRESULT unregister_collection_notification_client(cubeb * context)
return hr;
}
HRESULT get_default_endpoint(com_ptr<IMMDevice> & device, EDataFlow direction)
HRESULT get_default_endpoint(com_ptr<IMMDevice> & device, EDataFlow direction, ERole role)
{
com_ptr<IMMDeviceEnumerator> enumerator;
HRESULT hr = CoCreateInstance(__uuidof(MMDeviceEnumerator),
@ -1361,7 +1366,7 @@ HRESULT get_default_endpoint(com_ptr<IMMDevice> & device, EDataFlow direction)
LOG("Could not get device enumerator: %lx", hr);
return hr;
}
hr = enumerator->GetDefaultAudioEndpoint(direction, eConsole, device.receive());
hr = enumerator->GetDefaultAudioEndpoint(direction, role, device.receive());
if (FAILED(hr)) {
LOG("Could not get default audio endpoint: %lx", hr);
return hr;
@ -1447,11 +1452,11 @@ int wasapi_init(cubeb ** context, char const * context_name)
so that this backend is not incorrectly enabled on platforms that don't
support WASAPI. */
com_ptr<IMMDevice> device;
HRESULT hr = get_default_endpoint(device, eRender);
HRESULT hr = get_default_endpoint(device, eRender, eConsole);
if (FAILED(hr)) {
XASSERT(hr != CO_E_NOTINITIALIZED);
LOG("It wasn't able to find a default rendering device: %lx", hr);
hr = get_default_endpoint(device, eCapture);
hr = get_default_endpoint(device, eCapture, eConsole);
if (FAILED(hr)) {
LOG("It wasn't able to find a default capture device: %lx", hr);
return CUBEB_ERROR;
@ -1550,7 +1555,7 @@ wasapi_get_max_channel_count(cubeb * ctx, uint32_t * max_channels)
XASSERT(ctx && max_channels);
com_ptr<IMMDevice> device;
HRESULT hr = get_default_endpoint(device, eRender);
HRESULT hr = get_default_endpoint(device, eRender, eConsole);
if (FAILED(hr)) {
return CUBEB_ERROR;
}
@ -1582,8 +1587,10 @@ wasapi_get_min_latency(cubeb * ctx, cubeb_stream_params params, uint32_t * laten
return CUBEB_ERROR_INVALID_FORMAT;
}
ERole role = pref_to_role(params.prefs);
com_ptr<IMMDevice> device;
HRESULT hr = get_default_endpoint(device, eRender);
HRESULT hr = get_default_endpoint(device, eRender, role);
if (FAILED(hr)) {
LOG("Could not get default endpoint: %lx", hr);
return CUBEB_ERROR;
@ -1623,7 +1630,7 @@ int
wasapi_get_preferred_sample_rate(cubeb * ctx, uint32_t * rate)
{
com_ptr<IMMDevice> device;
HRESULT hr = get_default_endpoint(device, eRender);
HRESULT hr = get_default_endpoint(device, eRender, eConsole);
if (FAILED(hr)) {
return CUBEB_ERROR;
}
@ -1755,7 +1762,7 @@ int setup_wasapi_stream_one_side(cubeb_stream * stm,
// If caller has requested loopback but not specified a device, look for
// the default render device. Otherwise look for the default device
// appropriate to the direction.
hr = get_default_endpoint(device, is_loopback ? eRender : direction);
hr = get_default_endpoint(device, is_loopback ? eRender : direction, pref_to_role(stream_params->prefs));
if (FAILED(hr)) {
if (is_loopback) {
LOG("Could not get default render endpoint for loopback, error: %lx\n", hr);
@ -2057,6 +2064,16 @@ int setup_wasapi_stream(cubeb_stream * stm)
return CUBEB_OK;
}
ERole
pref_to_role(cubeb_stream_prefs prefs)
{
if (prefs & CUBEB_STREAM_PREF_VOICE) {
return eCommunications;
}
return eConsole;
}
int
wasapi_stream_init(cubeb * context, cubeb_stream ** stream,
char const * stream_name,
@ -2082,6 +2099,14 @@ wasapi_stream_init(cubeb * context, cubeb_stream ** stream,
stm->data_callback = data_callback;
stm->state_callback = state_callback;
stm->user_ptr = user_ptr;
if (stm->output_stream_params.prefs & CUBEB_STREAM_PREF_VOICE ||
stm->input_stream_params.prefs & CUBEB_STREAM_PREF_VOICE) {
stm->role = eCommunications;
} else {
stm->role = eConsole;
}
if (input_stream_params) {
stm->input_stream_params = *input_stream_params;
stm->input_device = utf8_to_wstr(reinterpret_cast<char const *>(input_device));