зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1339816 - Update cubeb from upstream to 8977c13b. r=padenot a=needmacnightlyrespin
MozReview-Commit-ID: 942LCa6dOzJ --HG-- extra : source : 9416a107fa60f31c745acf7821b52cd5a8ef8e98
This commit is contained in:
Родитель
59cd73fbfa
Коммит
3d4c312be6
|
@ -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 21e96ac7fd456dc957cd9947a61da1366a1f862d.
|
||||
The git commit ID used was 8977c13bf0dab9a7716501ae92ca5945fe4e1dae.
|
||||
|
|
|
@ -717,7 +717,8 @@ TEST(cubeb, resampler_passthrough_duplex_callback_reordering)
|
|||
|
||||
output_seq_idx += BUF_BASE_SIZE;
|
||||
|
||||
ASSERT_EQ(prebuffer_frames, static_cast<long>(ARRAY_LENGTH(input_buffer_prebuffer) / input_params.channels));
|
||||
// prebuffer_frames will hold the frames used by the resampler.
|
||||
ASSERT_EQ(prebuffer_frames, BUF_BASE_SIZE);
|
||||
ASSERT_EQ(got, BUF_BASE_SIZE);
|
||||
|
||||
for (uint32_t i = 0; i < 300; i++) {
|
||||
|
|
|
@ -49,6 +49,16 @@ typedef UInt32 AudioFormatFlags;
|
|||
|
||||
const char * DISPATCH_QUEUE_LABEL = "org.mozilla.cubeb";
|
||||
|
||||
#ifdef ALOGV
|
||||
#undef ALOGV
|
||||
#endif
|
||||
#define ALOGV(msg, ...) dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{LOGV(msg, ##__VA_ARGS__);})
|
||||
|
||||
#ifdef ALOG
|
||||
#undef ALOG
|
||||
#endif
|
||||
#define ALOG(msg, ...) dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{LOG(msg, ##__VA_ARGS__);})
|
||||
|
||||
/* Testing empirically, some headsets report a minimal latency that is very
|
||||
* low, but this does not work in practice. Lie and say the minimum is 256
|
||||
* frames. */
|
||||
|
@ -221,13 +231,17 @@ struct cubeb_stream {
|
|||
/* Hold the input samples in every
|
||||
* input callback iteration */
|
||||
std::unique_ptr<auto_array_wrapper> input_linear_buffer;
|
||||
// After the resampling some input data remains stored inside
|
||||
// the resampler. This number is used in order to calculate
|
||||
// the number of extra silence frames in input.
|
||||
std::atomic<uint32_t> available_input_frames{ 0 };
|
||||
/* Frames on input buffer */
|
||||
std::atomic<uint32_t> input_buffer_frames{ 0 };
|
||||
/* Frame counters */
|
||||
std::atomic<uint64_t> frames_played{ 0 };
|
||||
uint64_t frames_queued = 0;
|
||||
std::atomic<int64_t> frames_read{ 0 };
|
||||
std::atomic<bool> shutdown{ false };
|
||||
std::atomic<bool> shutdown{ true };
|
||||
std::atomic<bool> draining{ false };
|
||||
/* Latency requested by the user. */
|
||||
uint32_t latency_frames = 0;
|
||||
|
@ -235,11 +249,6 @@ struct cubeb_stream {
|
|||
uint64_t hw_latency_frames = UINT64_MAX;
|
||||
std::atomic<float> panning{ 0 };
|
||||
std::unique_ptr<cubeb_resampler, decltype(&cubeb_resampler_destroy)> resampler;
|
||||
/* This is the number of output callback we got in a row. This is usually one,
|
||||
* but can be two when the input and output rate are different, and more when
|
||||
* a device has been plugged or unplugged, as there can be some time before
|
||||
* the device is ready. */
|
||||
std::atomic<int> output_callback_in_a_row{ 0 };
|
||||
/* This is true if a device change callback is currently running. */
|
||||
std::atomic<bool> switching_device{ false };
|
||||
std::atomic<bool> buffer_size_change_state{ false };
|
||||
|
@ -377,16 +386,18 @@ audiounit_render_input(cubeb_stream * stm,
|
|||
stm->input_linear_buffer->push(input_buffer_list.mBuffers[0].mData,
|
||||
input_frames * stm->input_desc.mChannelsPerFrame);
|
||||
|
||||
LOGV("(%p) input: buffers %u, size %u, channels %u, frames %d.",
|
||||
/* Advance input frame counter. */
|
||||
assert(input_frames > 0);
|
||||
stm->frames_read += input_frames;
|
||||
stm->available_input_frames += input_frames;
|
||||
|
||||
ALOGV("(%p) input: buffers %u, size %u, channels %u, rendered frames %d, total frames %d.",
|
||||
stm,
|
||||
(unsigned int) input_buffer_list.mNumberBuffers,
|
||||
(unsigned int) input_buffer_list.mBuffers[0].mDataByteSize,
|
||||
(unsigned int) input_buffer_list.mBuffers[0].mNumberChannels,
|
||||
(unsigned int) input_frames);
|
||||
|
||||
/* Advance input frame counter. */
|
||||
assert(input_frames > 0);
|
||||
stm->frames_read += input_frames;
|
||||
(unsigned int) input_frames,
|
||||
stm->available_input_frames.load());
|
||||
|
||||
return noErr;
|
||||
}
|
||||
|
@ -405,19 +416,10 @@ audiounit_input_callback(void * user_ptr,
|
|||
assert(AU_IN_BUS == bus);
|
||||
|
||||
if (stm->shutdown) {
|
||||
LOG("(%p) input shutdown", stm);
|
||||
ALOG("(%p) input shutdown", stm);
|
||||
return noErr;
|
||||
}
|
||||
|
||||
// This happens when we're finally getting a new input callback after having
|
||||
// switched device, we can clear the input buffer now, only keeping the data
|
||||
// we just got.
|
||||
if (stm->output_callback_in_a_row > stm->expected_output_callbacks_in_a_row) {
|
||||
stm->input_linear_buffer->pop(
|
||||
stm->input_linear_buffer->length() -
|
||||
input_frames * stm->input_stream_params.channels);
|
||||
}
|
||||
|
||||
OSStatus r = audiounit_render_input(stm, flags, tstamp, bus, input_frames);
|
||||
if (r != noErr) {
|
||||
return r;
|
||||
|
@ -425,7 +427,6 @@ audiounit_input_callback(void * user_ptr,
|
|||
|
||||
// Full Duplex. We'll call data_callback in the AudioUnit output callback.
|
||||
if (stm->output_unit != NULL) {
|
||||
stm->output_callback_in_a_row = 0;
|
||||
return noErr;
|
||||
}
|
||||
|
||||
|
@ -449,6 +450,12 @@ audiounit_input_callback(void * user_ptr,
|
|||
return noErr;
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
minimum_resampling_input_frames(cubeb_stream *stm)
|
||||
{
|
||||
return ceilf(stm->input_hw_rate / stm->output_hw_rate * stm->input_buffer_frames);
|
||||
}
|
||||
|
||||
static bool
|
||||
is_extra_input_needed(cubeb_stream * stm)
|
||||
{
|
||||
|
@ -457,17 +464,8 @@ is_extra_input_needed(cubeb_stream * stm)
|
|||
* Otherwise, if we had more than expected callbacks in a row, or we're currently
|
||||
* switching, we add some silence as well to compensate for the fact that
|
||||
* we're lacking some input data. */
|
||||
|
||||
/* If resampling is taking place after every output callback
|
||||
* the input buffer expected to be empty. Any frame left over
|
||||
* from resampling is stored inside the resampler available to
|
||||
* be used in next iteration as needed.
|
||||
* BUT when noop_resampler is operating we have left over
|
||||
* frames since it does not store anything internally. */
|
||||
return stm->frames_read == 0 ||
|
||||
(stm->input_linear_buffer->length() == 0 &&
|
||||
(stm->output_callback_in_a_row > stm->expected_output_callbacks_in_a_row ||
|
||||
stm->switching_device));
|
||||
stm->available_input_frames.load() < minimum_resampling_input_frames(stm);
|
||||
}
|
||||
|
||||
static OSStatus
|
||||
|
@ -483,20 +481,19 @@ audiounit_output_callback(void * user_ptr,
|
|||
|
||||
cubeb_stream * stm = static_cast<cubeb_stream *>(user_ptr);
|
||||
|
||||
stm->output_callback_in_a_row++;
|
||||
ALOGV("(%p) output: buffers %u, size %u, channels %u, frames %u, total input frames %d.",
|
||||
stm,
|
||||
(unsigned int) outBufferList->mNumberBuffers,
|
||||
(unsigned int) outBufferList->mBuffers[0].mDataByteSize,
|
||||
(unsigned int) outBufferList->mBuffers[0].mNumberChannels,
|
||||
(unsigned int) output_frames,
|
||||
stm->available_input_frames.load());
|
||||
|
||||
LOGV("(%p) output: buffers %u, size %u, channels %u, frames %u.",
|
||||
stm,
|
||||
(unsigned int) outBufferList->mNumberBuffers,
|
||||
(unsigned int) outBufferList->mBuffers[0].mDataByteSize,
|
||||
(unsigned int) outBufferList->mBuffers[0].mNumberChannels,
|
||||
(unsigned int) output_frames);
|
||||
|
||||
long input_frames = 0;
|
||||
long input_frames = 0, input_frames_before_fill = 0;
|
||||
void * output_buffer = NULL, * input_buffer = NULL;
|
||||
|
||||
if (stm->shutdown) {
|
||||
LOG("(%p) output shutdown.", stm);
|
||||
ALOG("(%p) output shutdown.", stm);
|
||||
audiounit_make_silent(&outBufferList->mBuffers[0]);
|
||||
return noErr;
|
||||
}
|
||||
|
@ -518,16 +515,19 @@ audiounit_output_callback(void * user_ptr,
|
|||
/* If Full duplex get also input buffer */
|
||||
if (stm->input_unit != NULL) {
|
||||
if (is_extra_input_needed(stm)) {
|
||||
uint32_t min_input_frames_required = ceilf(stm->input_hw_rate / stm->output_hw_rate *
|
||||
stm->input_buffer_frames);
|
||||
stm->input_linear_buffer->push_silence(min_input_frames_required * stm->input_desc.mChannelsPerFrame);
|
||||
LOG("(%p) %s pushed %u frames of input silence.", stm, stm->frames_read == 0 ? "Input hasn't started," :
|
||||
stm->switching_device ? "Device switching," : "Drop out,", min_input_frames_required);
|
||||
uint32_t min_input_frames = minimum_resampling_input_frames(stm);
|
||||
stm->input_linear_buffer->push_silence(min_input_frames * stm->input_desc.mChannelsPerFrame);
|
||||
stm->available_input_frames += min_input_frames;
|
||||
|
||||
ALOG("(%p) %s pushed %u frames of input silence.", stm, stm->frames_read == 0 ? "Input hasn't started," :
|
||||
stm->switching_device ? "Device switching," : "Drop out,", min_input_frames);
|
||||
}
|
||||
// The input buffer
|
||||
input_buffer = stm->input_linear_buffer->data();
|
||||
// Number of input frames in the buffer
|
||||
// Number of input frames in the buffer. It will change to actually used frames
|
||||
// inside fill
|
||||
input_frames = stm->input_linear_buffer->length() / stm->input_desc.mChannelsPerFrame;
|
||||
// Number of input frames pushed inside resampler.
|
||||
input_frames_before_fill = input_frames;
|
||||
}
|
||||
|
||||
/* Call user callback through resampler. */
|
||||
|
@ -538,7 +538,11 @@ audiounit_output_callback(void * user_ptr,
|
|||
output_frames);
|
||||
|
||||
if (input_buffer) {
|
||||
stm->input_linear_buffer->pop(input_frames * stm->input_desc.mChannelsPerFrame);
|
||||
// Decrease counter by the number of frames used by resampler
|
||||
stm->available_input_frames -= input_frames;
|
||||
assert(stm->available_input_frames.load() >= 0);
|
||||
// Pop from the buffer the frames pushed to the resampler.
|
||||
stm->input_linear_buffer->pop(input_frames_before_fill * stm->input_desc.mChannelsPerFrame);
|
||||
}
|
||||
|
||||
if (outframes < 0) {
|
||||
|
@ -714,6 +718,9 @@ audiounit_property_listener_callback(AudioObjectID /* id */, UInt32 address_coun
|
|||
case kAudioDevicePropertyDataSource:
|
||||
LOG("Event[%u] - mSelector == kAudioHardwarePropertyDataSource", (unsigned int) i);
|
||||
break;
|
||||
default:
|
||||
LOG("Event[%u] - mSelector == Unexpected Event id %d, return", (unsigned int) i, addresses[i].mSelector);
|
||||
return noErr;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -890,6 +897,16 @@ audiounit_uninstall_device_changed_callback(cubeb_stream * stm)
|
|||
if (r != noErr) {
|
||||
return CUBEB_ERROR;
|
||||
}
|
||||
|
||||
/* Event to notify when the input is going away. */
|
||||
AudioDeviceID dev = stm->input_device ? stm->input_device :
|
||||
audiounit_get_default_device_id(CUBEB_DEVICE_TYPE_INPUT);
|
||||
r = audiounit_remove_listener(stm, dev, kAudioDevicePropertyDeviceIsAlive,
|
||||
kAudioObjectPropertyScopeGlobal, &audiounit_property_listener_callback);
|
||||
if (r != noErr) {
|
||||
PRINT_ERROR_CODE("AudioObjectRemovePropertyListener/input/kAudioDevicePropertyDeviceIsAlive", r);
|
||||
return CUBEB_ERROR;
|
||||
}
|
||||
}
|
||||
return CUBEB_OK;
|
||||
}
|
||||
|
@ -1301,18 +1318,8 @@ audiounit_init_input_linear_buffer(cubeb_stream * stream, uint32_t capacity)
|
|||
} else {
|
||||
stream->input_linear_buffer.reset(new auto_array_wrapper_impl<float>(size));
|
||||
}
|
||||
|
||||
assert(stream->input_linear_buffer->length() == 0);
|
||||
|
||||
// Pre-buffer silence if needed
|
||||
if (capacity != 1) {
|
||||
size_t silence_size = stream->input_buffer_frames *
|
||||
stream->input_desc.mChannelsPerFrame;
|
||||
stream->input_linear_buffer->push_silence(silence_size);
|
||||
|
||||
assert(stream->input_linear_buffer->length() == silence_size);
|
||||
}
|
||||
|
||||
return CUBEB_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -72,6 +72,7 @@ long passthrough_resampler<T>::fill(void * input_buffer, long * input_frames_cou
|
|||
|
||||
if (input_buffer) {
|
||||
internal_input_buffer.pop(nullptr, frames_to_samples(output_frames));
|
||||
*input_frames_count = output_frames;
|
||||
}
|
||||
|
||||
return rv;
|
||||
|
@ -179,7 +180,7 @@ cubeb_resampler_speex<T, InputProcessor, OutputProcessor>
|
|||
/* process the input, and present exactly `output_frames_needed` in the
|
||||
* callback. */
|
||||
input_processor->input(input_buffer, *input_frames_count);
|
||||
resampled_input = input_processor->output(resampled_frame_count);
|
||||
resampled_input = input_processor->output(resampled_frame_count, (size_t*)input_frames_count);
|
||||
|
||||
long got = data_callback(stream, user_ptr,
|
||||
resampled_input, nullptr, resampled_frame_count);
|
||||
|
@ -226,7 +227,7 @@ cubeb_resampler_speex<T, InputProcessor, OutputProcessor>
|
|||
* callback. */
|
||||
input_processor->input(in_buffer, *input_frames_count);
|
||||
resampled_input =
|
||||
input_processor->output(output_frames_before_processing);
|
||||
input_processor->output(output_frames_before_processing, (size_t*)input_frames_count);
|
||||
} else {
|
||||
resampled_input = nullptr;
|
||||
}
|
||||
|
|
|
@ -222,7 +222,7 @@ public:
|
|||
|
||||
/** Returns a buffer containing exactly `output_frame_count` resampled frames.
|
||||
* The consumer should not hold onto the pointer. */
|
||||
T * output(size_t output_frame_count)
|
||||
T * output(size_t output_frame_count, size_t * input_frames_used)
|
||||
{
|
||||
if (resampling_out_buffer.capacity() < frames_to_samples(output_frame_count)) {
|
||||
resampling_out_buffer.reserve(frames_to_samples(output_frame_count));
|
||||
|
@ -239,6 +239,7 @@ public:
|
|||
/* This shifts back any unresampled samples to the beginning of the input
|
||||
buffer. */
|
||||
resampling_in_buffer.pop(nullptr, frames_to_samples(in_len));
|
||||
*input_frames_used = in_len;
|
||||
|
||||
return resampling_out_buffer.data();
|
||||
}
|
||||
|
@ -376,7 +377,7 @@ public:
|
|||
* @parameter frames_needed the number of frames to be returned.
|
||||
* @return a buffer containing the delayed frames. The consumer should not
|
||||
* hold onto the pointer. */
|
||||
T * output(uint32_t frames_needed)
|
||||
T * output(uint32_t frames_needed, size_t * input_frames_used)
|
||||
{
|
||||
if (delay_output_buffer.capacity() < frames_to_samples(frames_needed)) {
|
||||
delay_output_buffer.reserve(frames_to_samples(frames_needed));
|
||||
|
@ -386,6 +387,7 @@ public:
|
|||
delay_output_buffer.push(delay_input_buffer.data(),
|
||||
frames_to_samples(frames_needed));
|
||||
delay_input_buffer.pop(nullptr, frames_to_samples(frames_needed));
|
||||
*input_frames_used = frames_needed;
|
||||
|
||||
return delay_output_buffer.data();
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче