ao_wasapi: return bool instead of HRESULT from thread_init

Any bad HRESULTs should have been printed already and lots of failure modes
don't have an HRESULT leading to awkward hr = E_FAIL business.

This also checks the exit status of GetBufferSize in the align hack. A final
fatal message is added if either of the retry hacks fail.
This commit is contained in:
Kevin Mitchell 2017-07-12 23:37:45 -07:00
parent 61c8a147b5
commit bee602da82
3 changed files with 48 additions and 38 deletions

View File

@ -201,9 +201,9 @@ static DWORD __stdcall AudioThread(void *lpParameter)
mpthread_set_name("wasapi event");
CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
state->init_ret = wasapi_thread_init(ao);
state->init_ok = wasapi_thread_init(ao);
SetEvent(state->hInitDone);
if (FAILED(state->init_ret))
if (!state->init_ok)
goto exit_label;
MP_DBG(ao, "Entering dispatch loop\n");
@ -302,7 +302,7 @@ static int init(struct ao *ao)
state->dispatch = mp_dispatch_create(state);
mp_dispatch_set_wakeup_fn(state->dispatch, thread_wakeup, ao);
state->init_ret = E_FAIL;
state->init_ok = false;
state->hAudioThread = CreateThread(NULL, 0, &AudioThread, ao, 0, NULL);
if (!state->hAudioThread) {
MP_FATAL(ao, "Failed to create audio thread\n");
@ -312,7 +312,7 @@ static int init(struct ao *ao)
WaitForSingleObject(state->hInitDone, INFINITE); // wait on init complete
SAFE_DESTROY(state->hInitDone,CloseHandle(state->hInitDone));
if (FAILED(state->init_ret)) {
if (!state->init_ok) {
if (!ao->probing)
MP_FATAL(ao, "Received failure from audio thread\n");
uninit(ao);

View File

@ -64,8 +64,8 @@ enum wasapi_thread_state {
typedef struct wasapi_state {
struct mp_log *log;
bool init_ok; // status of init phase
// Thread handles
HRESULT init_ret; // status of init phase
HANDLE hInitDone; // set when init is complete in audio thread
HANDLE hAudioThread; // the audio thread itself
HANDLE hWake; // thread wakeup event
@ -114,7 +114,7 @@ bstr wasapi_get_specified_device_string(struct ao *ao);
LPWSTR wasapi_find_deviceID(struct ao *ao);
void wasapi_dispatch(struct ao *ao);
HRESULT wasapi_thread_init(struct ao *ao);
bool wasapi_thread_init(struct ao *ao);
void wasapi_thread_uninit(struct ao *ao);
void wasapi_receive_proxies(wasapi_state *state);

View File

@ -833,7 +833,7 @@ exit_label:
destroy_enumerator(enumerator);
}
static HRESULT load_device(struct mp_log *l,
static bool load_device(struct mp_log *l,
IMMDevice **ppDevice, LPWSTR deviceID)
{
IMMDeviceEnumerator *pEnumerator = NULL;
@ -849,7 +849,7 @@ exit_label:
if (FAILED(hr))
mp_err(l, "Error loading selected device: %s\n", mp_HRESULT_to_str(hr));
SAFE_RELEASE(pEnumerator);
return hr;
return SUCCEEDED(hr);
}
static LPWSTR select_device(struct mp_log *l, struct device_desc *d)
@ -934,7 +934,7 @@ exit_label:
return deviceID;
}
HRESULT wasapi_thread_init(struct ao *ao)
bool wasapi_thread_init(struct ao *ao)
{
struct wasapi_state *state = ao->priv;
MP_DBG(ao, "Init wasapi thread\n");
@ -946,14 +946,18 @@ HRESULT wasapi_thread_init(struct ao *ao)
retry:
if (state->deviceID) {
hr = load_device(ao->log, &state->pDevice, state->deviceID);
EXIT_ON_ERROR(hr);
if (!load_device(ao->log, &state->pDevice, state->deviceID))
return false;
MP_DBG(ao, "Activating pAudioClient interface\n");
hr = IMMDeviceActivator_Activate(state->pDevice, &IID_IAudioClient,
CLSCTX_ALL, NULL,
(void **)&state->pAudioClient);
EXIT_ON_ERROR(hr);
if (FAILED(hr)) {
MP_FATAL(ao, "Error activating device: %s\n",
mp_HRESULT_to_str(hr));
return false;
}
} else {
MP_VERBOSE(ao, "Trying UWP wrapper.\n");
@ -961,67 +965,73 @@ retry:
HANDLE lib = LoadLibraryW(L"wasapiuwp2.dll");
if (!lib) {
MP_ERR(ao, "Wrapper not found: %d\n", (int)GetLastError());
hr = E_FAIL;
EXIT_ON_ERROR(hr);
}
if (lib) {
wuCreateDefaultAudioRenderer =
(void*)GetProcAddress(lib, "wuCreateDefaultAudioRenderer");
return false;
}
wuCreateDefaultAudioRenderer =
(void*)GetProcAddress(lib, "wuCreateDefaultAudioRenderer");
if (!wuCreateDefaultAudioRenderer) {
MP_ERR(ao, "Function not found.\n");
hr = E_FAIL;
EXIT_ON_ERROR(hr);
return false;
}
IUnknown *res = NULL;
hr = wuCreateDefaultAudioRenderer(&res);
MP_VERBOSE(ao, "Device: %s %p\n", mp_HRESULT_to_str(hr), res);
EXIT_ON_ERROR(hr);
if (FAILED(hr)) {
MP_FATAL(ao, "Error activating device: %s\n",
mp_HRESULT_to_str(hr));
return false;
}
hr = IUnknown_QueryInterface(res, &IID_IAudioClient,
(void **)&state->pAudioClient);
IUnknown_Release(res);
EXIT_ON_ERROR(hr);
if (FAILED(hr)) {
MP_FATAL(ao, "Failed to get UWP audio client: %s\n",
mp_HRESULT_to_str(hr));
return false;
}
}
// In the event of an align hack, we've already done this.
if (!align_hack) {
MP_DBG(ao, "Probing formats\n");
if (!find_formats(ao)) {
hr = E_FAIL;
EXIT_ON_ERROR(hr);
}
if (!find_formats(ao))
return false;
}
MP_DBG(ao, "Fixing format\n");
hr = fix_format(ao, align_hack);
switch (hr) {
case AUDCLNT_E_BUFFER_SIZE_NOT_ALIGNED:
if (align_hack)
if (align_hack) {
MP_FATAL(ao, "Align hack failed\n");
break;
}
// According to MSDN, we must use this as base after the failure.
IAudioClient_GetBufferSize(state->pAudioClient,
&state->bufferFrameCount);
hr = IAudioClient_GetBufferSize(state->pAudioClient,
&state->bufferFrameCount);
if (FAILED(hr)) {
MP_FATAL(ao, "Error getting buffer size for align hack: %s\n",
mp_HRESULT_to_str(hr));
return false;
}
wasapi_thread_uninit(ao);
align_hack = true;
MP_WARN(ao, "This appears to require a weird Windows 7 hack. Retrying.\n");
goto retry;
case AUDCLNT_E_DEVICE_IN_USE:
case AUDCLNT_E_DEVICE_INVALIDATED:
if (retry_wait > 8)
break;
if (retry_wait > 8) {
MP_FATAL(ao, "Bad device retry failed\n");
return false;
}
wasapi_thread_uninit(ao);
MP_WARN(ao, "Retrying in %"PRId64" us\n", retry_wait);
mp_sleep_us(retry_wait);
retry_wait *= 2;
goto retry;
}
EXIT_ON_ERROR(hr);
MP_DBG(ao, "Init wasapi thread done\n");
return S_OK;
exit_label:
MP_FATAL(state, "Error setting up audio thread: %s\n", mp_HRESULT_to_str(hr));
return hr;
return SUCCEEDED(hr);
}
void wasapi_thread_uninit(struct ao *ao)