зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1132257 - Update cubeb from upstream. r=padenot
This commit is contained in:
Родитель
a533827683
Коммит
8b8ae2538d
|
@ -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 14d97931da6435d10aa4dcb444896af0314372f4.
|
||||
The git commit ID used was 66aa55bb3b883381a73ad12d20688b932858be28.
|
||||
|
|
|
@ -477,7 +477,6 @@ audiounit_stream_init(cubeb * context, cubeb_stream ** stream, char const * stre
|
|||
unsigned int buffer_size, default_buffer_size;
|
||||
OSStatus r;
|
||||
UInt32 size;
|
||||
AudioDeviceID output_device_id;
|
||||
AudioValueRange latency_range;
|
||||
|
||||
assert(context);
|
||||
|
@ -783,7 +782,6 @@ audiounit_stream_get_latency(cubeb_stream * stm, uint32_t * latency)
|
|||
|
||||
int audiounit_stream_set_volume(cubeb_stream * stm, float volume)
|
||||
{
|
||||
AudioDeviceID id;
|
||||
OSStatus r;
|
||||
|
||||
r = AudioUnitSetParameter(stm->unit,
|
||||
|
|
|
@ -34,15 +34,14 @@
|
|||
// #define LOGGING_ENABLED
|
||||
|
||||
#ifdef LOGGING_ENABLED
|
||||
# define LOG(...) do { \
|
||||
fprintf(stdout, __VA_ARGS__); \
|
||||
fprintf(stdout, "\n"); \
|
||||
} while(0);
|
||||
#define LOG(...) do { \
|
||||
fprintf(stderr, __VA_ARGS__); \
|
||||
} while(0)
|
||||
#else
|
||||
# define LOG(...)
|
||||
#define LOG(...)
|
||||
#endif
|
||||
|
||||
#define ARRAY_LENGTH(array_) \
|
||||
#define ARRAY_LENGTH(array_) \
|
||||
(sizeof(array_) / sizeof(array_[0]))
|
||||
|
||||
namespace {
|
||||
|
@ -85,7 +84,6 @@ void SafeRelease(T * ptr)
|
|||
class owned_critical_section
|
||||
{
|
||||
public:
|
||||
|
||||
owned_critical_section()
|
||||
#ifdef DEBUG
|
||||
: owner(0)
|
||||
|
@ -136,7 +134,7 @@ private:
|
|||
|
||||
struct auto_lock {
|
||||
auto_lock(owned_critical_section * lock)
|
||||
:lock(lock)
|
||||
: lock(lock)
|
||||
{
|
||||
lock->enter();
|
||||
}
|
||||
|
@ -150,7 +148,7 @@ private:
|
|||
|
||||
struct auto_unlock {
|
||||
auto_unlock(owned_critical_section * lock)
|
||||
:lock(lock)
|
||||
: lock(lock)
|
||||
{
|
||||
lock->leave();
|
||||
}
|
||||
|
@ -163,33 +161,29 @@ private:
|
|||
};
|
||||
|
||||
struct auto_com {
|
||||
auto_com()
|
||||
: need_uninit(false) {
|
||||
HRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
|
||||
// This is for information purposes only, in anycase, COM is initialized
|
||||
// at the end of the constructor.
|
||||
if (hr == RPC_E_CHANGED_MODE) {
|
||||
// This is an error, COM was not initialized by this function, so it is
|
||||
auto_com() {
|
||||
result = CoInitializeEx(NULL, COINIT_MULTITHREADED);
|
||||
}
|
||||
~auto_com() {
|
||||
if (result == RPC_E_CHANGED_MODE) {
|
||||
// This is not an error, COM was not initialized by this function, so it is
|
||||
// not necessary to uninit it.
|
||||
LOG("COM already initialized in STA.");
|
||||
} else if (hr == S_FALSE) {
|
||||
LOG("COM already initialized in STA.\n");
|
||||
} else if (result == S_FALSE) {
|
||||
// This is not an error. We are allowed to call CoInitializeEx more than
|
||||
// once, as long as it is matches by an CoUninitialize call.
|
||||
// We do that in the dtor which is guaranteed to be called.
|
||||
LOG("COM already initialized in MTA");
|
||||
need_uninit = true;
|
||||
} else if (hr == S_OK) {
|
||||
LOG("COM initialized.");
|
||||
need_uninit = true;
|
||||
LOG("COM already initialized in MTA\n");
|
||||
}
|
||||
}
|
||||
~auto_com() {
|
||||
if (need_uninit) {
|
||||
if (SUCCEEDED(result)) {
|
||||
CoUninitialize();
|
||||
}
|
||||
}
|
||||
bool ok() {
|
||||
return result == RPC_E_CHANGED_MODE || SUCCEEDED(result);
|
||||
}
|
||||
private:
|
||||
bool need_uninit;
|
||||
HRESULT result;
|
||||
};
|
||||
|
||||
typedef HANDLE (WINAPI *set_mm_thread_characteristics_function)(
|
||||
|
@ -205,7 +199,6 @@ int setup_wasapi_stream(cubeb_stream * stm);
|
|||
|
||||
}
|
||||
|
||||
|
||||
struct cubeb
|
||||
{
|
||||
cubeb_ops const * ops;
|
||||
|
@ -258,7 +251,7 @@ struct cubeb_stream
|
|||
HANDLE refill_event;
|
||||
/* Each cubeb_stream has its own thread. */
|
||||
HANDLE thread;
|
||||
/* We synthetize our clock from the callbacks. */
|
||||
/* We synthesize our clock from the callbacks. */
|
||||
LONG64 clock;
|
||||
owned_critical_section * stream_reset_lock;
|
||||
/* Maximum number of frames we can be requested in a callback. */
|
||||
|
@ -296,7 +289,7 @@ public:
|
|||
HRESULT STDMETHODCALLTYPE
|
||||
QueryInterface(REFIID riid, VOID **ppvInterface)
|
||||
{
|
||||
if (IID_IUnknown == riid) {
|
||||
if (__uuidof(IUnknown) == riid) {
|
||||
AddRef();
|
||||
*ppvInterface = (IUnknown*)this;
|
||||
} else if (__uuidof(IMMNotificationClient) == riid) {
|
||||
|
@ -326,7 +319,10 @@ public:
|
|||
return S_OK;
|
||||
}
|
||||
|
||||
auto_com autocom;
|
||||
auto_com com;
|
||||
if (!com.ok()) {
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
/* Close the stream */
|
||||
wasapi_stream_stop(stm);
|
||||
|
@ -346,27 +342,27 @@ public:
|
|||
* log is enabled), for debugging. */
|
||||
HRESULT STDMETHODCALLTYPE OnDeviceAdded(LPCWSTR device_id)
|
||||
{
|
||||
LOG("Audio device added.");
|
||||
LOG("Audio device added.\n");
|
||||
return S_OK;
|
||||
};
|
||||
|
||||
HRESULT STDMETHODCALLTYPE OnDeviceRemoved(LPCWSTR device_id)
|
||||
{
|
||||
LOG("Audio device removed.");
|
||||
LOG("Audio device removed.\n");
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE
|
||||
OnDeviceStateChanged(LPCWSTR device_id, DWORD new_state)
|
||||
{
|
||||
LOG("Audio device state changed.");
|
||||
LOG("Audio device state changed.\n");
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE
|
||||
OnPropertyValueChanged(LPCWSTR device_id, const PROPERTYKEY key)
|
||||
{
|
||||
LOG("Audio device property value changed.");
|
||||
LOG("Audio device property value changed.\n");
|
||||
return S_OK;
|
||||
}
|
||||
private:
|
||||
|
@ -488,7 +484,7 @@ refill(cubeb_stream * stm, float * data, long frames_needed)
|
|||
|
||||
/* Go in draining mode if we got fewer frames than requested. */
|
||||
if (out_frames < frames_needed) {
|
||||
LOG("draining.");
|
||||
LOG("draining.\n");
|
||||
stm->draining = true;
|
||||
}
|
||||
|
||||
|
@ -513,10 +509,14 @@ wasapi_stream_render_loop(LPVOID stream)
|
|||
bool is_playing = true;
|
||||
HANDLE wait_array[2] = {stm->shutdown_event, stm->refill_event};
|
||||
HANDLE mmcss_handle = NULL;
|
||||
HRESULT hr;
|
||||
HRESULT hr = 0;
|
||||
bool first = true;
|
||||
DWORD mmcss_task_index = 0;
|
||||
auto_com com;
|
||||
if (!com.ok()) {
|
||||
LOG("COM initialization failed on render_loop thread.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* We could consider using "Pro Audio" here for WebAudio and
|
||||
* maybe WebRTC. */
|
||||
|
@ -524,7 +524,7 @@ wasapi_stream_render_loop(LPVOID stream)
|
|||
stm->context->set_mm_thread_characteristics("Audio", &mmcss_task_index);
|
||||
if (!mmcss_handle) {
|
||||
/* This is not fatal, but we might glitch under heavy load. */
|
||||
LOG("Unable to use mmcss to bump the render thread priority: %x", GetLastError());
|
||||
LOG("Unable to use mmcss to bump the render thread priority: %x\n", GetLastError());
|
||||
}
|
||||
|
||||
|
||||
|
@ -549,7 +549,7 @@ wasapi_stream_render_loop(LPVOID stream)
|
|||
|
||||
hr = stm->client->GetCurrentPadding(&padding);
|
||||
if (FAILED(hr)) {
|
||||
LOG("Failed to get padding");
|
||||
LOG("Failed to get padding\n");
|
||||
is_playing = false;
|
||||
continue;
|
||||
}
|
||||
|
@ -576,11 +576,11 @@ wasapi_stream_render_loop(LPVOID stream)
|
|||
|
||||
hr = stm->render_client->ReleaseBuffer(available, 0);
|
||||
if (FAILED(hr)) {
|
||||
LOG("failed to release buffer.");
|
||||
LOG("failed to release buffer.\n");
|
||||
is_playing = false;
|
||||
}
|
||||
} else {
|
||||
LOG("failed to get buffer.");
|
||||
LOG("failed to get buffer.\n");
|
||||
is_playing = false;
|
||||
}
|
||||
}
|
||||
|
@ -619,7 +619,7 @@ HRESULT register_notification_client(cubeb_stream * stm)
|
|||
IID_PPV_ARGS(&stm->device_enumerator));
|
||||
|
||||
if (FAILED(hr)) {
|
||||
LOG("Could not get device enumerator: %x", hr);
|
||||
LOG("Could not get device enumerator: %x\n", hr);
|
||||
return hr;
|
||||
}
|
||||
|
||||
|
@ -628,7 +628,7 @@ HRESULT register_notification_client(cubeb_stream * stm)
|
|||
hr = stm->device_enumerator->RegisterEndpointNotificationCallback(stm->notification_client);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
LOG("Could not register endpoint notification callback: %x", hr);
|
||||
LOG("Could not register endpoint notification callback: %x\n", hr);
|
||||
return hr;
|
||||
}
|
||||
|
||||
|
@ -657,9 +657,8 @@ HRESULT get_default_endpoint(IMMDevice ** device)
|
|||
HRESULT hr = CoCreateInstance(__uuidof(MMDeviceEnumerator),
|
||||
NULL, CLSCTX_INPROC_SERVER,
|
||||
IID_PPV_ARGS(&enumerator));
|
||||
|
||||
if (FAILED(hr)) {
|
||||
LOG("Could not get device enumerator.");
|
||||
LOG("Could not get device enumerator.\n");
|
||||
return hr;
|
||||
}
|
||||
/* eMultimedia is okay for now ("Music, movies, narration, [...]").
|
||||
|
@ -668,7 +667,7 @@ HRESULT get_default_endpoint(IMMDevice ** device)
|
|||
* and eCommunication ("Voice communication"). */
|
||||
hr = enumerator->GetDefaultAudioEndpoint(eRender, eMultimedia, device);
|
||||
if (FAILED(hr)) {
|
||||
LOG("Could not get default audio endpoint. %d", __LINE__);
|
||||
LOG("Could not get default audio endpoint. %d\n", __LINE__);
|
||||
SafeRelease(enumerator);
|
||||
return hr;
|
||||
}
|
||||
|
@ -684,6 +683,9 @@ int wasapi_init(cubeb ** context, char const * context_name)
|
|||
{
|
||||
HRESULT hr;
|
||||
auto_com com;
|
||||
if (!com.ok()) {
|
||||
return CUBEB_ERROR;
|
||||
}
|
||||
|
||||
/* We don't use the device yet, but need to make sure we can initialize one
|
||||
so that this backend is not incorrectly enabled on platforms that don't
|
||||
|
@ -691,7 +693,7 @@ int wasapi_init(cubeb ** context, char const * context_name)
|
|||
IMMDevice * device;
|
||||
hr = get_default_endpoint(&device);
|
||||
if (FAILED(hr)) {
|
||||
LOG("Could not get device.");
|
||||
LOG("Could not get device.\n");
|
||||
return CUBEB_ERROR;
|
||||
}
|
||||
SafeRelease(device);
|
||||
|
@ -710,13 +712,13 @@ int wasapi_init(cubeb ** context, char const * context_name)
|
|||
(revert_mm_thread_characteristics_function) GetProcAddress(
|
||||
ctx->mmcss_module, "AvRevertMmThreadCharacteristics");
|
||||
if (!(ctx->set_mm_thread_characteristics && ctx->revert_mm_thread_characteristics)) {
|
||||
LOG("Could not load AvSetMmThreadCharacteristics or AvRevertMmThreadCharacteristics: %x", GetLastError());
|
||||
LOG("Could not load AvSetMmThreadCharacteristics or AvRevertMmThreadCharacteristics: %x\n", GetLastError());
|
||||
FreeLibrary(ctx->mmcss_module);
|
||||
}
|
||||
} else {
|
||||
// This is not a fatal error, but we might end up glitching when
|
||||
// the system is under high load.
|
||||
LOG("Could not load Avrt.dll");
|
||||
LOG("Could not load Avrt.dll\n");
|
||||
ctx->set_mm_thread_characteristics = &set_mm_thread_characteristics_noop;
|
||||
ctx->revert_mm_thread_characteristics = &revert_mm_thread_characteristics_noop;
|
||||
}
|
||||
|
@ -749,6 +751,9 @@ wasapi_get_max_channel_count(cubeb * ctx, uint32_t * max_channels)
|
|||
IAudioClient * client;
|
||||
WAVEFORMATEX * mix_format;
|
||||
auto_com com;
|
||||
if (!com.ok()) {
|
||||
return CUBEB_ERROR;
|
||||
}
|
||||
|
||||
assert(ctx && max_channels);
|
||||
|
||||
|
@ -787,11 +792,14 @@ wasapi_get_min_latency(cubeb * ctx, cubeb_stream_params params, uint32_t * laten
|
|||
IAudioClient * client;
|
||||
REFERENCE_TIME default_period;
|
||||
auto_com com;
|
||||
if (!com.ok()) {
|
||||
return CUBEB_ERROR;
|
||||
}
|
||||
|
||||
IMMDevice * device;
|
||||
hr = get_default_endpoint(&device);
|
||||
if (FAILED(hr)) {
|
||||
LOG("Could not get default endpoint:%x.", hr)
|
||||
LOG("Could not get default endpoint:%x.\n", hr);
|
||||
return CUBEB_ERROR;
|
||||
}
|
||||
|
||||
|
@ -800,7 +808,7 @@ wasapi_get_min_latency(cubeb * ctx, cubeb_stream_params params, uint32_t * laten
|
|||
NULL, (void **)&client);
|
||||
SafeRelease(device);
|
||||
if (FAILED(hr)) {
|
||||
LOG("Could not activate device for latency: %x.", hr)
|
||||
LOG("Could not activate device for latency: %x.\n", hr);
|
||||
return CUBEB_ERROR;
|
||||
}
|
||||
|
||||
|
@ -808,11 +816,11 @@ wasapi_get_min_latency(cubeb * ctx, cubeb_stream_params params, uint32_t * laten
|
|||
hr = client->GetDevicePeriod(&default_period, NULL);
|
||||
if (FAILED(hr)) {
|
||||
SafeRelease(client);
|
||||
LOG("Could not get device period: %x.", hr)
|
||||
LOG("Could not get device period: %x.\n", hr);
|
||||
return CUBEB_ERROR;
|
||||
}
|
||||
|
||||
LOG("default device period: %ld", default_period)
|
||||
LOG("default device period: %ld\n", default_period);
|
||||
|
||||
/* According to the docs, the best latency we can achieve is by synchronizing
|
||||
* the stream and the engine.
|
||||
|
@ -831,6 +839,9 @@ wasapi_get_preferred_sample_rate(cubeb * ctx, uint32_t * rate)
|
|||
IAudioClient * client;
|
||||
WAVEFORMATEX * mix_format;
|
||||
auto_com com;
|
||||
if (!com.ok()) {
|
||||
return CUBEB_ERROR;
|
||||
}
|
||||
|
||||
IMMDevice * device;
|
||||
hr = get_default_endpoint(&device);
|
||||
|
@ -915,7 +926,7 @@ handle_channel_layout(cubeb_stream * stm, WAVEFORMATEX ** mix_format, const cub
|
|||
if (hr == S_FALSE) {
|
||||
/* Not supported, but WASAPI gives us a suggestion. Use it, and handle the
|
||||
* eventual upmix/downmix ourselves */
|
||||
LOG("Using WASAPI suggested format: channels: %d", closest->nChannels);
|
||||
LOG("Using WASAPI suggested format: channels: %d\n", closest->nChannels);
|
||||
WAVEFORMATEXTENSIBLE * closest_pcm = reinterpret_cast<WAVEFORMATEXTENSIBLE *>(closest);
|
||||
assert(closest_pcm->SubFormat == format_pcm->SubFormat);
|
||||
CoTaskMemFree(*mix_format);
|
||||
|
@ -926,7 +937,7 @@ handle_channel_layout(cubeb_stream * stm, WAVEFORMATEX ** mix_format, const cub
|
|||
* of the code figure out the right conversion path. */
|
||||
**mix_format = hw_mixformat;
|
||||
} else if (hr == S_OK) {
|
||||
LOG("Requested format accepted by WASAPI.");
|
||||
LOG("Requested format accepted by WASAPI.\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -936,15 +947,20 @@ int setup_wasapi_stream(cubeb_stream * stm)
|
|||
IMMDevice * device;
|
||||
WAVEFORMATEX * mix_format;
|
||||
|
||||
#ifdef DEBUG
|
||||
stm->stream_reset_lock->assert_current_thread_owns();
|
||||
#endif
|
||||
|
||||
auto_com com;
|
||||
if (!com.ok()) {
|
||||
return CUBEB_ERROR;
|
||||
}
|
||||
|
||||
assert(!stm->client && "WASAPI stream already setup, close it first.");
|
||||
|
||||
hr = get_default_endpoint(&device);
|
||||
if (FAILED(hr)) {
|
||||
LOG("Could not get default endpoint, error: %x", hr);
|
||||
LOG("Could not get default endpoint, error: %x\n", hr);
|
||||
auto_unlock unlock(stm->stream_reset_lock);
|
||||
wasapi_stream_destroy(stm);
|
||||
return CUBEB_ERROR;
|
||||
|
@ -953,11 +969,11 @@ int setup_wasapi_stream(cubeb_stream * stm)
|
|||
/* Get a client. We will get all other interfaces we need from
|
||||
* this pointer. */
|
||||
hr = device->Activate(__uuidof(IAudioClient),
|
||||
CLSCTX_INPROC_SERVER,
|
||||
NULL, (void **)&stm->client);
|
||||
CLSCTX_INPROC_SERVER,
|
||||
NULL, (void **)&stm->client);
|
||||
SafeRelease(device);
|
||||
if (FAILED(hr)) {
|
||||
LOG("Could not activate the device to get an audio client: error: %x", hr);
|
||||
LOG("Could not activate the device to get an audio client: error: %x\n", hr);
|
||||
auto_unlock unlock(stm->stream_reset_lock);
|
||||
wasapi_stream_destroy(stm);
|
||||
return CUBEB_ERROR;
|
||||
|
@ -967,7 +983,7 @@ int setup_wasapi_stream(cubeb_stream * stm)
|
|||
* and the format the stream we want to play uses. */
|
||||
hr = stm->client->GetMixFormat(&mix_format);
|
||||
if (FAILED(hr)) {
|
||||
LOG("Could not fetch current mix format from the audio client: error: %x", hr);
|
||||
LOG("Could not fetch current mix format from the audio client: error: %x\n", hr);
|
||||
auto_unlock unlock(stm->stream_reset_lock);
|
||||
wasapi_stream_destroy(stm);
|
||||
return CUBEB_ERROR;
|
||||
|
@ -982,17 +998,17 @@ int setup_wasapi_stream(cubeb_stream * stm)
|
|||
stm->mix_params.channels = mix_format->nChannels;
|
||||
|
||||
hr = stm->client->Initialize(AUDCLNT_SHAREMODE_SHARED,
|
||||
AUDCLNT_STREAMFLAGS_EVENTCALLBACK |
|
||||
AUDCLNT_STREAMFLAGS_NOPERSIST,
|
||||
ms_to_hns(stm->latency),
|
||||
0,
|
||||
mix_format,
|
||||
NULL);
|
||||
AUDCLNT_STREAMFLAGS_EVENTCALLBACK |
|
||||
AUDCLNT_STREAMFLAGS_NOPERSIST,
|
||||
ms_to_hns(stm->latency),
|
||||
0,
|
||||
mix_format,
|
||||
NULL);
|
||||
|
||||
CoTaskMemFree(mix_format);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
LOG("Unable to initialize audio client: %x.", hr);
|
||||
LOG("Unable to initialize audio client: %x.\n", hr);
|
||||
auto_unlock unlock(stm->stream_reset_lock);
|
||||
wasapi_stream_destroy(stm);
|
||||
return CUBEB_ERROR;
|
||||
|
@ -1000,37 +1016,37 @@ int setup_wasapi_stream(cubeb_stream * stm)
|
|||
|
||||
hr = stm->client->GetBufferSize(&stm->buffer_frame_count);
|
||||
if (FAILED(hr)) {
|
||||
LOG("Could not get the buffer size from the client %x.", hr);
|
||||
LOG("Could not get the buffer size from the client %x.\n", hr);
|
||||
auto_unlock unlock(stm->stream_reset_lock);
|
||||
wasapi_stream_destroy(stm);
|
||||
return CUBEB_ERROR;
|
||||
}
|
||||
|
||||
if (should_upmix(stm) || should_downmix(stm)) {
|
||||
stm->mix_buffer = (float *)malloc(frames_to_bytes_before_mix(stm, stm->buffer_frame_count));
|
||||
stm->mix_buffer = (float *) malloc(frames_to_bytes_before_mix(stm, stm->buffer_frame_count));
|
||||
}
|
||||
|
||||
hr = stm->client->SetEventHandle(stm->refill_event);
|
||||
if (FAILED(hr)) {
|
||||
LOG("Could set the event handle for the client %x.", hr);
|
||||
LOG("Could set the event handle for the client %x.\n", hr);
|
||||
auto_unlock unlock(stm->stream_reset_lock);
|
||||
wasapi_stream_destroy(stm);
|
||||
return CUBEB_ERROR;
|
||||
}
|
||||
|
||||
hr = stm->client->GetService(__uuidof(IAudioRenderClient),
|
||||
(void **)&stm->render_client);
|
||||
(void **)&stm->render_client);
|
||||
if (FAILED(hr)) {
|
||||
LOG("Could not get the render client %x.", hr);
|
||||
LOG("Could not get the render client %x.\n", hr);
|
||||
auto_unlock unlock(stm->stream_reset_lock);
|
||||
wasapi_stream_destroy(stm);
|
||||
return CUBEB_ERROR;
|
||||
}
|
||||
|
||||
hr = stm->client->GetService(__uuidof(IAudioStreamVolume),
|
||||
(void **)&stm->audio_stream_volume);
|
||||
(void **)&stm->audio_stream_volume);
|
||||
if (FAILED(hr)) {
|
||||
LOG("Could not get the IAudioStreamVolume %x.", hr);
|
||||
LOG("Could not get the IAudioStreamVolume %x.\n", hr);
|
||||
auto_unlock unlock(stm->stream_reset_lock);
|
||||
wasapi_stream_destroy(stm);
|
||||
return CUBEB_ERROR;
|
||||
|
@ -1041,14 +1057,14 @@ int setup_wasapi_stream(cubeb_stream * stm)
|
|||
* of channels of the stream, not the number of channels
|
||||
* that WASAPI wants. */
|
||||
stm->resampler = cubeb_resampler_create(stm, stm->stream_params,
|
||||
stm->mix_params.rate,
|
||||
stm->data_callback,
|
||||
stm->buffer_frame_count,
|
||||
stm->user_ptr,
|
||||
CUBEB_RESAMPLER_QUALITY_DESKTOP);
|
||||
stm->mix_params.rate,
|
||||
stm->data_callback,
|
||||
stm->buffer_frame_count,
|
||||
stm->user_ptr,
|
||||
CUBEB_RESAMPLER_QUALITY_DESKTOP);
|
||||
if (!stm->resampler) {
|
||||
LOG("Could not get a resampler\n");
|
||||
auto_unlock unlock(stm->stream_reset_lock);
|
||||
LOG("Could not get a resampler");
|
||||
wasapi_stream_destroy(stm);
|
||||
return CUBEB_ERROR;
|
||||
}
|
||||
|
@ -1065,6 +1081,9 @@ wasapi_stream_init(cubeb * context, cubeb_stream ** stream,
|
|||
HRESULT hr;
|
||||
int rv;
|
||||
auto_com com;
|
||||
if (!com.ok()) {
|
||||
return CUBEB_ERROR;
|
||||
}
|
||||
|
||||
assert(context && stream);
|
||||
|
||||
|
@ -1082,12 +1101,12 @@ wasapi_stream_init(cubeb * context, cubeb_stream ** stream,
|
|||
stm->clock = 0;
|
||||
|
||||
/* Null out WASAPI-specific state */
|
||||
stm->resampler = nullptr;
|
||||
stm->client = nullptr;
|
||||
stm->render_client = nullptr;
|
||||
stm->audio_stream_volume = nullptr;
|
||||
stm->device_enumerator = nullptr;
|
||||
stm->notification_client = nullptr;
|
||||
stm->resampler = NULL;
|
||||
stm->client = NULL;
|
||||
stm->render_client = NULL;
|
||||
stm->audio_stream_volume = NULL;
|
||||
stm->device_enumerator = NULL;
|
||||
stm->notification_client = NULL;
|
||||
|
||||
stm->stream_reset_lock = new owned_critical_section();
|
||||
|
||||
|
@ -1095,14 +1114,14 @@ wasapi_stream_init(cubeb * context, cubeb_stream ** stream,
|
|||
stm->refill_event = CreateEvent(NULL, 0, 0, NULL);
|
||||
|
||||
if (!stm->shutdown_event) {
|
||||
LOG("Can't create the shutdown event, error: %x.", GetLastError());
|
||||
LOG("Can't create the shutdown event, error: %x\n", GetLastError());
|
||||
wasapi_stream_destroy(stm);
|
||||
return CUBEB_ERROR;
|
||||
}
|
||||
|
||||
if (!stm->refill_event) {
|
||||
SafeRelease(stm->shutdown_event);
|
||||
LOG("Can't create the refill event, error: %x.", GetLastError());
|
||||
LOG("Can't create the refill event, error: %x\n", GetLastError());
|
||||
wasapi_stream_destroy(stm);
|
||||
return CUBEB_ERROR;
|
||||
}
|
||||
|
@ -1122,7 +1141,7 @@ wasapi_stream_init(cubeb * context, cubeb_stream ** stream,
|
|||
if (FAILED(hr)) {
|
||||
/* this is not fatal, we can still play audio, but we won't be able
|
||||
* to keep using the default audio endpoint if it changes. */
|
||||
LOG("failed to register notification client, %x", hr);
|
||||
LOG("failed to register notification client, %x\n", hr);
|
||||
}
|
||||
|
||||
*stream = stm;
|
||||
|
@ -1134,21 +1153,23 @@ void close_wasapi_stream(cubeb_stream * stm)
|
|||
{
|
||||
assert(stm);
|
||||
|
||||
#ifdef DEBUG
|
||||
stm->stream_reset_lock->assert_current_thread_owns();
|
||||
#endif
|
||||
|
||||
SafeRelease(stm->client);
|
||||
stm->client = nullptr;
|
||||
stm->client = NULL;
|
||||
|
||||
SafeRelease(stm->render_client);
|
||||
stm->client = nullptr;
|
||||
stm->render_client = NULL;
|
||||
|
||||
if (stm->resampler) {
|
||||
cubeb_resampler_destroy(stm->resampler);
|
||||
stm->resampler = nullptr;
|
||||
stm->resampler = NULL;
|
||||
}
|
||||
|
||||
free(stm->mix_buffer);
|
||||
stm->mix_buffer = nullptr;
|
||||
stm->mix_buffer = NULL;
|
||||
}
|
||||
|
||||
void wasapi_stream_destroy(cubeb_stream * stm)
|
||||
|
@ -1158,8 +1179,14 @@ void wasapi_stream_destroy(cubeb_stream * stm)
|
|||
unregister_notification_client(stm);
|
||||
|
||||
if (stm->thread) {
|
||||
SetEvent(stm->shutdown_event);
|
||||
WaitForSingleObject(stm->thread, INFINITE);
|
||||
BOOL ok = SetEvent(stm->shutdown_event);
|
||||
if (!ok) {
|
||||
LOG("Destroy SetEvent failed: %d\n", GetLastError());
|
||||
}
|
||||
DWORD r = WaitForSingleObject(stm->thread, INFINITE);
|
||||
if (r == WAIT_FAILED) {
|
||||
LOG("Destroy WaitForSingleObject on thread failed: %d\n", GetLastError());
|
||||
}
|
||||
CloseHandle(stm->thread);
|
||||
stm->thread = 0;
|
||||
}
|
||||
|
@ -1179,27 +1206,25 @@ void wasapi_stream_destroy(cubeb_stream * stm)
|
|||
|
||||
int wasapi_stream_start(cubeb_stream * stm)
|
||||
{
|
||||
HRESULT hr;
|
||||
|
||||
auto_lock lock(stm->stream_reset_lock);
|
||||
|
||||
assert(stm);
|
||||
assert(stm && !stm->thread);
|
||||
|
||||
stm->thread = (HANDLE) _beginthreadex(NULL, 256 * 1024, wasapi_stream_render_loop, stm, STACK_SIZE_PARAM_IS_A_RESERVATION, NULL);
|
||||
if (stm->thread == NULL) {
|
||||
LOG("could not create WASAPI render thread.");
|
||||
LOG("could not create WASAPI render thread.\n");
|
||||
return CUBEB_ERROR;
|
||||
}
|
||||
|
||||
hr = stm->client->Start();
|
||||
HRESULT hr = stm->client->Start();
|
||||
if (FAILED(hr)) {
|
||||
LOG("could not start the stream.");
|
||||
LOG("could not start the stream.\n");
|
||||
return CUBEB_ERROR;
|
||||
} else {
|
||||
stm->state_callback(stm, stm->user_ptr, CUBEB_STATE_STARTED);
|
||||
}
|
||||
|
||||
stm->state_callback(stm, stm->user_ptr, CUBEB_STATE_STARTED);
|
||||
|
||||
return CUBEB_OK;
|
||||
return FAILED(hr) ? CUBEB_ERROR : CUBEB_OK;
|
||||
}
|
||||
|
||||
int wasapi_stream_stop(cubeb_stream * stm)
|
||||
|
@ -1208,23 +1233,31 @@ int wasapi_stream_stop(cubeb_stream * stm)
|
|||
|
||||
auto_lock lock(stm->stream_reset_lock);
|
||||
|
||||
SetEvent(stm->shutdown_event);
|
||||
BOOL ok = SetEvent(stm->shutdown_event);
|
||||
if (!ok) {
|
||||
LOG("Stop SetEvent failed: %d\n", GetLastError());
|
||||
}
|
||||
|
||||
HRESULT hr = stm->client->Stop();
|
||||
if (FAILED(hr)) {
|
||||
LOG("could not stop AudioClient");
|
||||
LOG("could not stop AudioClient\n");
|
||||
}
|
||||
|
||||
if (stm->thread) {
|
||||
auto_unlock lock(stm->stream_reset_lock);
|
||||
WaitForSingleObject(stm->thread, INFINITE);
|
||||
DWORD r = WaitForSingleObject(stm->thread, INFINITE);
|
||||
if (r == WAIT_FAILED) {
|
||||
LOG("Stop WaitForSingleObject on thread failed: %d\n", GetLastError());
|
||||
}
|
||||
CloseHandle(stm->thread);
|
||||
stm->thread = NULL;
|
||||
}
|
||||
|
||||
stm->state_callback(stm, stm->user_ptr, CUBEB_STATE_STOPPED);
|
||||
if (SUCCEEDED(hr)) {
|
||||
stm->state_callback(stm, stm->user_ptr, CUBEB_STATE_STOPPED);
|
||||
}
|
||||
|
||||
return CUBEB_OK;
|
||||
return FAILED(hr) ? CUBEB_ERROR : CUBEB_OK;
|
||||
}
|
||||
|
||||
int wasapi_stream_get_position(cubeb_stream * stm, uint64_t * position)
|
||||
|
@ -1267,7 +1300,7 @@ int wasapi_stream_set_volume(cubeb_stream * stm, float volume)
|
|||
|
||||
hr = stm->audio_stream_volume->GetChannelCount(&channels);
|
||||
if (hr != S_OK) {
|
||||
LOG("could not get the channel count: %x", hr);
|
||||
LOG("could not get the channel count: %x\n", hr);
|
||||
return CUBEB_ERROR;
|
||||
}
|
||||
|
||||
|
@ -1279,7 +1312,7 @@ int wasapi_stream_set_volume(cubeb_stream * stm, float volume)
|
|||
|
||||
hr = stm->audio_stream_volume->SetAllVolumes(channels, volumes);
|
||||
if (hr != S_OK) {
|
||||
LOG("coult not set the channels volume: %x", hr);
|
||||
LOG("could not set the channels volume: %x\n", hr);
|
||||
return CUBEB_ERROR;
|
||||
}
|
||||
return CUBEB_OK;
|
||||
|
@ -1303,6 +1336,5 @@ cubeb_ops const wasapi_ops = {
|
|||
/*.stream_get_current_device =*/ NULL,
|
||||
/*.stream_device_destroy =*/ NULL,
|
||||
/*.stream_register_device_changed_callback =*/ NULL
|
||||
};
|
||||
};
|
||||
} // namespace anonymous
|
||||
|
||||
|
|
|
@ -654,6 +654,10 @@ winmm_stream_get_latency(cubeb_stream * stm, uint32_t * latency)
|
|||
written = stm->written;
|
||||
LeaveCriticalSection(&stm->lock);
|
||||
|
||||
if (r != MMSYSERR_NOERROR || time.wType != TIME_SAMPLES) {
|
||||
return CUBEB_ERROR;
|
||||
}
|
||||
|
||||
*latency = written - time.u.sample;
|
||||
|
||||
return CUBEB_OK;
|
||||
|
|
Загрузка…
Ссылка в новой задаче