зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1266623 - Up/down mix WASAPI capture streams when stream formats don't match. r=padenot
This commit is contained in:
Родитель
db9357edba
Коммит
ff1d7be7b4
|
@ -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 dbdfb3904deb7a0381588209cdd7388217d96e61.
|
||||
The git commit ID used was 05abb60b99a46d1d21abe58d9e5f3bdb4f0df4a8.
|
||||
|
|
|
@ -133,6 +133,20 @@ public:
|
|||
length_ += length;
|
||||
}
|
||||
|
||||
/** Prepend `length` zero-ed elements to the end of the array, resizing the
|
||||
* array if needed.
|
||||
* @parameter length the number of elements to prepend to the array.
|
||||
*/
|
||||
void push_front_silence(size_t length)
|
||||
{
|
||||
if (length_ + length > capacity_) {
|
||||
reserve(length + length_);
|
||||
}
|
||||
PodMove(data_ + length, data_, length_);
|
||||
PodZero(data_, length);
|
||||
length_ += length;
|
||||
}
|
||||
|
||||
/** Return the number of free elements in the array. */
|
||||
size_t available() const
|
||||
{
|
||||
|
|
|
@ -366,7 +366,7 @@ public:
|
|||
LOG("Audio device default changed.\n");
|
||||
|
||||
/* we only support a single stream type for now. */
|
||||
if (flow != eRender && role != eMultimedia) {
|
||||
if (flow != eRender && role != eConsole) {
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
@ -586,7 +586,7 @@ bool get_input_buffer(cubeb_stream * stm)
|
|||
/* Get input packets until we have captured enough frames, and put them in a
|
||||
* contiguous buffer. */
|
||||
uint32_t offset = 0;
|
||||
uint32_t input_channel_count = stm->input_stream_params.channels;
|
||||
uint32_t input_channel_count = stm->input_mix_params.channels;
|
||||
while (offset != total_available_input * input_channel_count &&
|
||||
total_available_input) {
|
||||
hr = stm->capture_client->GetNextPacketSize(&next);
|
||||
|
@ -602,20 +602,41 @@ bool get_input_buffer(cubeb_stream * stm)
|
|||
|
||||
UINT32 packet_size;
|
||||
hr = stm->capture_client->GetBuffer(&input_packet,
|
||||
&packet_size,
|
||||
&flags,
|
||||
&dev_pos,
|
||||
NULL);
|
||||
&packet_size,
|
||||
&flags,
|
||||
&dev_pos,
|
||||
NULL);
|
||||
if (FAILED(hr)) {
|
||||
LOG("GetBuffer failed for capture: %x\n", hr);
|
||||
return false;
|
||||
}
|
||||
XASSERT(packet_size == next);
|
||||
if (flags & AUDCLNT_BUFFERFLAGS_SILENT) {
|
||||
stm->linear_input_buffer.push_silence(packet_size * input_channel_count);
|
||||
LOG("insert silence: ps=%u\n", packet_size);
|
||||
stm->linear_input_buffer.push_silence(packet_size * stm->input_stream_params.channels);
|
||||
} else {
|
||||
stm->linear_input_buffer.push(reinterpret_cast<float*>(input_packet),
|
||||
packet_size * input_channel_count);
|
||||
if (should_upmix(stm->input_mix_params, stm->input_stream_params)) {
|
||||
bool ok = stm->linear_input_buffer.reserve(stm->linear_input_buffer.length() +
|
||||
packet_size * stm->input_stream_params.channels);
|
||||
assert(ok);
|
||||
upmix(reinterpret_cast<float*>(input_packet), packet_size,
|
||||
stm->linear_input_buffer.data() + stm->linear_input_buffer.length(),
|
||||
input_channel_count,
|
||||
stm->input_stream_params.channels);
|
||||
stm->linear_input_buffer.set_length(stm->linear_input_buffer.length() + packet_size * stm->input_stream_params.channels);
|
||||
} else if (should_downmix(stm->input_mix_params, stm->input_stream_params)) {
|
||||
bool ok = stm->linear_input_buffer.reserve(stm->linear_input_buffer.length() +
|
||||
packet_size * stm->input_stream_params.channels);
|
||||
assert(ok);
|
||||
downmix(reinterpret_cast<float*>(input_packet), packet_size,
|
||||
stm->linear_input_buffer.data() + stm->linear_input_buffer.length(),
|
||||
input_channel_count,
|
||||
stm->input_stream_params.channels);
|
||||
stm->linear_input_buffer.set_length(stm->linear_input_buffer.length() + packet_size * stm->input_stream_params.channels);
|
||||
} else {
|
||||
stm->linear_input_buffer.push(reinterpret_cast<float*>(input_packet),
|
||||
packet_size * stm->input_stream_params.channels);
|
||||
}
|
||||
}
|
||||
hr = stm->capture_client->ReleaseBuffer(packet_size);
|
||||
if (FAILED(hr)) {
|
||||
|
@ -698,8 +719,13 @@ refill_callback_duplex(cubeb_stream * stm)
|
|||
}
|
||||
|
||||
// When WASAPI has not filled the input buffer yet, send silence.
|
||||
if (stm->linear_input_buffer.length() == 0) {
|
||||
stm->linear_input_buffer.push_silence(output_frames* stm->output_mix_params.channels);
|
||||
size_t input_frames = stm->linear_input_buffer.length() / stm->input_stream_params.channels;
|
||||
double output_duration = double(output_frames) / stm->output_mix_params.rate;
|
||||
double input_duration = double(input_frames) / stm->input_mix_params.rate;
|
||||
if (input_duration < output_duration) {
|
||||
size_t padding = round((output_duration - input_duration) * stm->input_mix_params.rate);
|
||||
LOG("padding silence: out=%f in=%f pad=%u\n", output_duration, input_duration, padding);
|
||||
stm->linear_input_buffer.push_front_silence(padding * stm->input_stream_params.channels);
|
||||
}
|
||||
|
||||
refill(stm,
|
||||
|
@ -986,11 +1012,7 @@ HRESULT get_default_endpoint(IMMDevice ** device, EDataFlow direction)
|
|||
LOG("Could not get device enumerator: %x\n", hr);
|
||||
return hr;
|
||||
}
|
||||
/* eMultimedia is okay for now ("Music, movies, narration, [...]").
|
||||
We will need to change this when we distinguish streams by use-case, other
|
||||
possible values being eConsole ("Games, system notification sounds [...]")
|
||||
and eCommunication ("Voice communication"). */
|
||||
hr = enumerator->GetDefaultAudioEndpoint(direction, eMultimedia, device);
|
||||
hr = enumerator->GetDefaultAudioEndpoint(direction, eConsole, device);
|
||||
if (FAILED(hr)) {
|
||||
LOG("Could not get default audio endpoint: %x\n", hr);
|
||||
SafeRelease(enumerator);
|
||||
|
@ -1243,7 +1265,7 @@ wasapi_get_min_latency(cubeb * ctx, cubeb_stream_params params, uint32_t * laten
|
|||
return CUBEB_ERROR;
|
||||
}
|
||||
|
||||
LOG("default device period: %ld\n", default_period);
|
||||
LOG("default device period: %lld\n", default_period);
|
||||
|
||||
/* According to the docs, the best latency we can achieve is by synchronizing
|
||||
the stream and the engine.
|
||||
|
@ -1430,6 +1452,9 @@ int setup_wasapi_stream_one_side(cubeb_stream * stm,
|
|||
mix_params->format = CUBEB_SAMPLE_FLOAT32NE;
|
||||
mix_params->rate = mix_format->nSamplesPerSec;
|
||||
mix_params->channels = mix_format->nChannels;
|
||||
LOG("Setup requested=[f=%d r=%u c=%u] mix=[f=%d r=%u c=%u]\n",
|
||||
stream_params->format, stream_params->rate, stream_params->channels,
|
||||
mix_params->format, mix_params->rate, mix_params->channels);
|
||||
|
||||
hr = (*audio_client)->Initialize(AUDCLNT_SHAREMODE_SHARED,
|
||||
AUDCLNT_STREAMFLAGS_EVENTCALLBACK |
|
||||
|
@ -1452,8 +1477,10 @@ int setup_wasapi_stream_one_side(cubeb_stream * stm,
|
|||
return CUBEB_ERROR;
|
||||
}
|
||||
|
||||
if (should_upmix(*stream_params, *mix_params) ||
|
||||
should_downmix(*stream_params, *mix_params)) {
|
||||
// Input is up/down mixed when depacketized in get_input_buffer.
|
||||
if (has_output(stm) &&
|
||||
(should_upmix(*stream_params, *mix_params) ||
|
||||
should_downmix(*stream_params, *mix_params))) {
|
||||
stm->mix_buffer = (float *)malloc(frames_to_bytes_before_mix(stm, *buffer_frame_count));
|
||||
}
|
||||
|
||||
|
@ -1490,6 +1517,7 @@ int setup_wasapi_stream(cubeb_stream * stm)
|
|||
XASSERT(!stm->output_client && "WASAPI stream already setup, close it first.");
|
||||
|
||||
if (has_input(stm)) {
|
||||
LOG("Setup capture: device=%x\n", (int)stm->input_device);
|
||||
rv = setup_wasapi_stream_one_side(stm,
|
||||
&stm->input_stream_params,
|
||||
stm->input_device,
|
||||
|
@ -1506,6 +1534,7 @@ int setup_wasapi_stream(cubeb_stream * stm)
|
|||
}
|
||||
|
||||
if (has_output(stm)) {
|
||||
LOG("Setup render: device=%x\n", (int)stm->output_device);
|
||||
rv = setup_wasapi_stream_one_side(stm,
|
||||
&stm->output_stream_params,
|
||||
stm->output_device,
|
||||
|
@ -1547,7 +1576,7 @@ int setup_wasapi_stream(cubeb_stream * stm)
|
|||
if (has_input(stm) && has_output(stm)) {
|
||||
assert(stm->input_stream_params.rate == stm->output_stream_params.rate);
|
||||
target_sample_rate = stm->input_stream_params.rate;
|
||||
} else if (has_input(stm)) {
|
||||
} else if (has_input(stm)) {
|
||||
target_sample_rate = stm->input_stream_params.rate;
|
||||
} else {
|
||||
XASSERT(has_output(stm));
|
||||
|
@ -1748,7 +1777,7 @@ int stream_start_one_side(cubeb_stream * stm, StreamDirection dir)
|
|||
HRESULT hr = dir == OUTPUT ? stm->output_client->Start() : stm->input_client->Start();
|
||||
if (hr == AUDCLNT_E_DEVICE_INVALIDATED) {
|
||||
LOG("audioclient invalidated for %s device, reconfiguring\n",
|
||||
dir == OUTPUT ? "output" : "input", hr);
|
||||
dir == OUTPUT ? "output" : "input");
|
||||
|
||||
BOOL ok = ResetEvent(stm->reconfigure_event);
|
||||
if (!ok) {
|
||||
|
@ -1765,7 +1794,7 @@ int stream_start_one_side(cubeb_stream * stm, StreamDirection dir)
|
|||
|
||||
HRESULT hr = dir == OUTPUT ? stm->output_client->Start() : stm->input_client->Start();
|
||||
if (FAILED(hr)) {
|
||||
LOG("could not start the %s stream after reconfig: %x (%s)\n",
|
||||
LOG("could not start the %s stream after reconfig: %x\n",
|
||||
dir == OUTPUT ? "output" : "input", hr);
|
||||
return CUBEB_ERROR;
|
||||
}
|
||||
|
@ -2049,7 +2078,7 @@ wasapi_create_device(IMMDeviceEnumerator * enumerator, IMMDevice * dev)
|
|||
}
|
||||
|
||||
ret->preferred = CUBEB_DEVICE_PREF_NONE;
|
||||
if (wasapi_is_default_device(flow, eMultimedia, device_id, enumerator))
|
||||
if (wasapi_is_default_device(flow, eConsole, device_id, enumerator))
|
||||
ret->preferred = (cubeb_device_pref)(ret->preferred | CUBEB_DEVICE_PREF_MULTIMEDIA);
|
||||
if (wasapi_is_default_device(flow, eCommunications, device_id, enumerator))
|
||||
ret->preferred = (cubeb_device_pref)(ret->preferred | CUBEB_DEVICE_PREF_VOICE);
|
||||
|
@ -2137,7 +2166,7 @@ wasapi_enumerate_devices(cubeb * context, cubeb_device_type type,
|
|||
}
|
||||
|
||||
if (type == CUBEB_DEVICE_TYPE_OUTPUT) flow = eRender;
|
||||
else if (type == CUBEB_DEVICE_TYPE_INPUT) flow = eCapture;
|
||||
else if (type == CUBEB_DEVICE_TYPE_INPUT) flow = eCapture;
|
||||
else if (type & (CUBEB_DEVICE_TYPE_INPUT | CUBEB_DEVICE_TYPE_INPUT)) flow = eAll;
|
||||
else return CUBEB_ERROR;
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче