зеркало из https://github.com/mozilla/gecko-dev.git
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:
Родитель
387f4ae5fd
Коммит
b774a54cc4
|
@ -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",
|
||||
¶mSize,
|
||||
&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));
|
||||
|
|
Загрузка…
Ссылка в новой задаче