Bug 776137 - Apply latency correction to audio stream position on macOS. r=padenot

--HG--
extra : rebase_source : ea7d68e32bdc1d3712b64a42f6fdaa75f0933988
This commit is contained in:
Matthew Gregan 2018-03-28 11:44:15 +13:00
Родитель 4bfb789b0c
Коммит f3e9b08714
4 изменённых файлов: 23 добавлений и 94 удалений

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

@ -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 7401fc25a9d87ed57d49648883e3e5658305c1cb (2018-03-26 16:54:01 +0200)
The git commit ID used was f34f392de5158feb46202e8ae58528bfb42f2759 (2018-03-27 17:45:10 -0400)

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

@ -159,10 +159,12 @@ TEST(cubeb, duplex_collection_change)
input_params.rate = 48000;
input_params.channels = 1;
input_params.layout = CUBEB_LAYOUT_MONO;
input_params.prefs = CUBEB_STREAM_PREF_NONE;
output_params.format = STREAM_FORMAT;
output_params.rate = 48000;
output_params.channels = 2;
output_params.layout = CUBEB_LAYOUT_STEREO;
output_params.prefs = CUBEB_STREAM_PREF_NONE;
r = cubeb_get_min_latency(ctx, &output_params, &latency_frames);
ASSERT_EQ(r, CUBEB_OK) << "Could not get minimal latency";

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

@ -348,6 +348,7 @@ void run_loopback_separate_streams_test(bool is_float)
output_params.rate = SAMPLE_FREQUENCY;
output_params.channels = 1;
output_params.layout = CUBEB_LAYOUT_MONO;
output_params.prefs = CUBEB_STREAM_PREF_NONE;
std::unique_ptr<user_state_loopback> user_data(new user_state_loopback());
ASSERT_TRUE(!!user_data) << "Error allocating user data";
@ -515,6 +516,7 @@ void run_loopback_device_selection_test(bool is_float)
output_params.rate = SAMPLE_FREQUENCY;
output_params.channels = 1;
output_params.layout = CUBEB_LAYOUT_MONO;
output_params.prefs = CUBEB_STREAM_PREF_NONE;
std::unique_ptr<user_state_loopback> user_data(new user_state_loopback());
ASSERT_TRUE(!!user_data) << "Error allocating user data";

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

@ -70,6 +70,7 @@ static void audiounit_close_stream(cubeb_stream *stm);
static int audiounit_setup_stream(cubeb_stream *stm);
static vector<AudioObjectID>
audiounit_get_devices_of_type(cubeb_device_type devtype);
static UInt32 audiounit_get_device_presentation_latency(AudioObjectID devid, AudioObjectPropertyScope scope);
extern cubeb_ops const audiounit_ops;
@ -178,8 +179,7 @@ struct cubeb_stream {
atomic<bool> draining{ false };
/* Latency requested by the user. */
uint32_t latency_frames = 0;
atomic<uint64_t> current_latency_frames{ 0 };
uint64_t hw_latency_frames = UINT64_MAX;
atomic<uint32_t> current_latency_frames{ 0 };
atomic<float> panning{ 0 };
unique_ptr<cubeb_resampler, decltype(&cubeb_resampler_destroy)> resampler;
/* This is true if a device change callback is currently running. */
@ -320,19 +320,6 @@ AudioConvertHostTimeToNanos(uint64_t host_time)
}
#endif
static int64_t
audiotimestamp_to_latency(AudioTimeStamp const * tstamp, cubeb_stream * stream)
{
if (!(tstamp->mFlags & kAudioTimeStampHostTimeValid)) {
return 0;
}
uint64_t pres = AudioConvertHostTimeToNanos(tstamp->mHostTime);
uint64_t now = AudioConvertHostTimeToNanos(AudioGetCurrentHostTime());
return ((pres - now) * stream->output_desc.mSampleRate) / 1000000000LL;
}
static void
audiounit_set_global_latency(cubeb_stream * stm, uint32_t latency_frames)
{
@ -526,7 +513,6 @@ audiounit_output_callback(void * user_ptr,
return noErr;
}
stm->current_latency_frames = audiotimestamp_to_latency(tstamp, stm);
if (stm->draining) {
OSStatus r = AudioOutputUnitStop(stm->output_unit);
assert(r == 0);
@ -2541,6 +2527,14 @@ audiounit_setup_stream(cubeb_stream * stm)
LOG("AudioUnitInitialize/output rv=%d", r);
return CUBEB_ERROR;
}
stm->current_latency_frames = audiounit_get_device_presentation_latency(stm->output_device.id, kAudioDevicePropertyScopeOutput);
Float64 unit_s;
UInt32 size = sizeof(unit_s);
if (AudioUnitGetProperty(stm->output_unit, kAudioUnitProperty_Latency, kAudioUnitScope_Global, 0, &unit_s, &size) == noErr) {
stm->current_latency_frames += static_cast<uint32_t>(unit_s * stm->output_desc.mSampleRate);
}
}
if (stm->input_unit && stm->output_unit) {
@ -2764,7 +2758,11 @@ static int
audiounit_stream_get_position(cubeb_stream * stm, uint64_t * position)
{
assert(stm);
*position = stm->frames_played;
if (stm->current_latency_frames > stm->frames_played) {
*position = 0;
} else {
*position = stm->frames_played - stm->current_latency_frames;
}
return CUBEB_OK;
}
@ -2775,74 +2773,7 @@ audiounit_stream_get_latency(cubeb_stream * stm, uint32_t * latency)
//TODO
return CUBEB_ERROR_NOT_SUPPORTED;
#else
auto_lock lock(stm->mutex);
if (stm->hw_latency_frames == UINT64_MAX) {
UInt32 size;
uint32_t device_latency_frames, device_safety_offset;
double unit_latency_sec;
AudioDeviceID output_device_id;
OSStatus r;
AudioObjectPropertyAddress latency_address = {
kAudioDevicePropertyLatency,
kAudioDevicePropertyScopeOutput,
kAudioObjectPropertyElementMaster
};
AudioObjectPropertyAddress safety_offset_address = {
kAudioDevicePropertySafetyOffset,
kAudioDevicePropertyScopeOutput,
kAudioObjectPropertyElementMaster
};
output_device_id = audiounit_get_default_device_id(CUBEB_DEVICE_TYPE_OUTPUT);
if (output_device_id == kAudioObjectUnknown) {
return CUBEB_ERROR;
}
size = sizeof(unit_latency_sec);
r = AudioUnitGetProperty(stm->output_unit,
kAudioUnitProperty_Latency,
kAudioUnitScope_Global,
0,
&unit_latency_sec,
&size);
if (r != noErr) {
LOG("AudioUnitGetProperty/kAudioUnitProperty_Latency rv=%d", r);
return CUBEB_ERROR;
}
size = sizeof(device_latency_frames);
r = AudioObjectGetPropertyData(output_device_id,
&latency_address,
0,
NULL,
&size,
&device_latency_frames);
if (r != noErr) {
LOG("AudioUnitGetPropertyData/latency_frames rv=%d", r);
return CUBEB_ERROR;
}
size = sizeof(device_safety_offset);
r = AudioObjectGetPropertyData(output_device_id,
&safety_offset_address,
0,
NULL,
&size,
&device_safety_offset);
if (r != noErr) {
LOG("AudioUnitGetPropertyData/safety_offset rv=%d", r);
return CUBEB_ERROR;
}
/* This part is fixed and depend on the stream parameter and the hardware. */
stm->hw_latency_frames =
static_cast<uint32_t>(unit_latency_sec * stm->output_desc.mSampleRate)
+ device_latency_frames
+ device_safety_offset;
}
*latency = stm->hw_latency_frames + stm->current_latency_frames;
*latency = stm->current_latency_frames;
return CUBEB_OK;
#endif
}
@ -3089,7 +3020,7 @@ static UInt32
audiounit_get_device_presentation_latency(AudioObjectID devid, AudioObjectPropertyScope scope)
{
AudioObjectPropertyAddress adr = { 0, scope, kAudioObjectPropertyElementMaster };
UInt32 size, dev, stream = 0, offset;
UInt32 size, dev, stream = 0;
AudioStreamID sid[1];
adr.mSelector = kAudioDevicePropertyLatency;
@ -3106,13 +3037,7 @@ audiounit_get_device_presentation_latency(AudioObjectID devid, AudioObjectProper
AudioObjectGetPropertyData(sid[0], &adr, 0, NULL, &size, &stream);
}
adr.mSelector = kAudioDevicePropertySafetyOffset;
size = sizeof(UInt32);
if (AudioObjectGetPropertyData(devid, &adr, 0, NULL, &size, &offset) != noErr) {
offset = 0;
}
return dev + stream + offset;
return dev + stream;
}
static int