mirror of https://github.com/mpv-player/mpv
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:
parent
61c8a147b5
commit
bee602da82
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue