diff options
Diffstat (limited to 'audio/out')
-rw-r--r-- | audio/out/ao.c | 8 | ||||
-rw-r--r-- | audio/out/ao_alsa.c | 16 | ||||
-rw-r--r-- | audio/out/ao_openal.c | 95 | ||||
-rw-r--r-- | audio/out/ao_wasapi.c | 7 | ||||
-rwxr-xr-x | audio/out/ao_wasapi.h | 11 | ||||
-rwxr-xr-x | audio/out/ao_wasapi_utils.c | 60 | ||||
-rwxr-xr-x | audio/out/ao_wasapi_utils.h | 1 |
7 files changed, 113 insertions, 85 deletions
diff --git a/audio/out/ao.c b/audio/out/ao.c index 02dff063ff..daa9c306b5 100644 --- a/audio/out/ao.c +++ b/audio/out/ao.c @@ -493,8 +493,12 @@ static void get_devices(struct ao *ao, struct ao_device_list *list) if (ao->driver->list_devs) ao->driver->list_devs(ao, list); // Add at least a default entry - if (list->num_devices == num) - ao_device_list_add(list, ao, &(struct ao_device_desc){"", "Default"}); + if (list->num_devices == num) { + char name[80] = "Default"; + if (num > 1) + mp_snprintf_cat(name, sizeof(name), " (%s)", ao->driver->name); + ao_device_list_add(list, ao, &(struct ao_device_desc){"", name}); + } } bool ao_hotplug_check_update(struct ao_hotplug *hp) diff --git a/audio/out/ao_alsa.c b/audio/out/ao_alsa.c index 4112ab3c83..9ffd4792ee 100644 --- a/audio/out/ao_alsa.c +++ b/audio/out/ao_alsa.c @@ -977,6 +977,20 @@ alsa_error: return -1; } +static bool is_useless_device(char *name) +{ + char *crap[] = {"front", "rear", "center_lfe", "side", "surround21", + "surround40", "surround41", "surround50", "surround51", "surround71", + "sysdefault", "pulse", "null", "dsnoop", "dmix", "hw", "iec958"}; + for (int i = 0; i < MP_ARRAY_SIZE(crap); i++) { + int l = strlen(crap[i]); + if (name && strncmp(name, crap[i], l) == 0 && + (!name[l] || name[l] == ':')) + return true; + } + return false; +} + static void list_devs(struct ao *ao, struct ao_device_list *list) { void **hints; @@ -987,7 +1001,7 @@ static void list_devs(struct ao *ao, struct ao_device_list *list) char *name = snd_device_name_get_hint(hints[n], "NAME"); char *desc = snd_device_name_get_hint(hints[n], "DESC"); char *io = snd_device_name_get_hint(hints[n], "IOID"); - if (io && strcmp(io, "Output") == 0) { + if (!is_useless_device(name) && (!io || strcmp(io, "Output") == 0)) { char desc2[1024]; snprintf(desc2, sizeof(desc2), "%s", desc ? desc : ""); for (int i = 0; desc2[i]; i++) { diff --git a/audio/out/ao_openal.c b/audio/out/ao_openal.c index 9207a846b3..c6c924b244 100644 --- a/audio/out/ao_openal.c +++ b/audio/out/ao_openal.c @@ -44,8 +44,7 @@ #define MAX_CHANS MP_NUM_CHANNELS #define NUM_BUF 128 -#define CHUNK_SIZE 512 -#define CHUNK_SAMPLES (CHUNK_SIZE / 2) +#define CHUNK_SAMPLES 256 static ALuint buffers[MAX_CHANS][NUM_BUF]; static ALuint sources[MAX_CHANS]; @@ -56,6 +55,8 @@ static struct ao *ao_data; struct priv { char *cfg_device; + ALenum al_format; + int chunk_size; }; static void reset(struct ao *ao); @@ -117,22 +118,51 @@ struct speaker { }; static const struct speaker speaker_pos[] = { - {MP_SPEAKER_ID_FL, {-1, 0, 0.5}}, - {MP_SPEAKER_ID_FR, { 1, 0, 0.5}}, - {MP_SPEAKER_ID_FC, { 0, 0, 1}}, - {MP_SPEAKER_ID_LFE, { 0, 0, 0.1}}, - {MP_SPEAKER_ID_BL, {-1, 0, -1}}, - {MP_SPEAKER_ID_BR, { 1, 0, -1}}, - {MP_SPEAKER_ID_BC, { 0, 0, -1}}, - {MP_SPEAKER_ID_SL, {-1, 0, 0}}, - {MP_SPEAKER_ID_SR, { 1, 0, 0}}, + {MP_SPEAKER_ID_FL, {-0.500, 0, -0.866}}, // -30 deg + {MP_SPEAKER_ID_FR, { 0.500, 0, -0.866}}, // 30 deg + {MP_SPEAKER_ID_FC, { 0, 0, -1}}, // 0 deg + {MP_SPEAKER_ID_LFE, { 0, -1, 0}}, // below + {MP_SPEAKER_ID_BL, {-0.609, 0, 0.793}}, // -142.5 deg + {MP_SPEAKER_ID_BR, { 0.609, 0, 0.793}}, // 142.5 deg + {MP_SPEAKER_ID_BC, { 0, 0, 1}}, // 180 deg + {MP_SPEAKER_ID_SL, {-0.985, 0, 0.174}}, // -100 deg + {MP_SPEAKER_ID_SR, { 0.985, 0, 0.174}}, // 100 deg {-1}, }; +static ALenum get_al_format(int format) +{ + switch (format) { + case AF_FORMAT_U8P: return AL_FORMAT_MONO8; + case AF_FORMAT_S16P: return AL_FORMAT_MONO16; + case AF_FORMAT_FLOATP: + if (alIsExtensionPresent((ALchar*)"AL_EXT_float32") == AL_TRUE) + return AL_FORMAT_MONO_FLOAT32; + break; + case AF_FORMAT_DOUBLEP: + if (alIsExtensionPresent((ALchar*)"AL_EXT_double") == AL_TRUE) + return AL_FORMAT_MONO_DOUBLE_EXT; + break; + } + return AL_FALSE; +} + +// close audio device +static void uninit(struct ao *ao) +{ + ALCcontext *ctx = alcGetCurrentContext(); + ALCdevice *dev = alcGetContextsDevice(ctx); + reset(ao); + alcMakeContextCurrent(NULL); + alcDestroyContext(ctx); + alcCloseDevice(dev); + ao_data = NULL; +} + static int init(struct ao *ao) { float position[3] = {0, 0, 0}; - float direction[6] = {0, 0, 1, 0, -1, 0}; + float direction[6] = {0, 0, -1, 0, 1, 0}; ALCdevice *dev = NULL; ALCcontext *ctx = NULL; ALCint freq = 0; @@ -184,25 +214,31 @@ static int init(struct ao *ao) alcGetIntegerv(dev, ALC_FREQUENCY, 1, &freq); if (alcGetError(dev) == ALC_NO_ERROR && freq) ao->samplerate = freq; - ao->format = AF_FORMAT_S16P; + + p->al_format = AL_FALSE; + int try_formats[AF_FORMAT_COUNT]; + af_get_best_sample_formats(ao->format, try_formats); + for (int n = 0; try_formats[n]; n++) { + p->al_format = get_al_format(try_formats[n]); + if (p->al_format != AL_FALSE) { + ao->format = try_formats[n]; + break; + } + } + + if (p->al_format == AL_FALSE) { + MP_FATAL(ao, "Can't find appropriate sample format.\n"); + uninit(ao); + goto err_out; + } + + p->chunk_size = CHUNK_SAMPLES * af_fmt_to_bytes(ao->format); return 0; err_out: return -1; } -// close audio device -static void uninit(struct ao *ao) -{ - ALCcontext *ctx = alcGetCurrentContext(); - ALCdevice *dev = alcGetContextsDevice(ctx); - reset(ao); - alcMakeContextCurrent(NULL); - alcDestroyContext(ctx); - alcCloseDevice(dev); - ao_data = NULL; -} - static void drain(struct ao *ao) { ALint state; @@ -274,14 +310,15 @@ static int get_space(struct ao *ao) */ static int play(struct ao *ao, void **data, int samples, int flags) { + struct priv *p = ao->priv; ALint state; int num = samples / CHUNK_SAMPLES; for (int i = 0; i < num; i++) { for (int ch = 0; ch < ao->channels.num; ch++) { - int16_t *d = data[ch]; - d += i * CHUNK_SAMPLES; - alBufferData(buffers[ch][cur_buf[ch]], AL_FORMAT_MONO16, d, - CHUNK_SIZE, ao->samplerate); + char *d = data[ch]; + d += i * p->chunk_size; + alBufferData(buffers[ch][cur_buf[ch]], p->al_format, d, + p->chunk_size, ao->samplerate); alSourceQueueBuffers(sources[ch], 1, &buffers[ch][cur_buf[ch]]); cur_buf[ch] = (cur_buf[ch] + 1) % NUM_BUF; } diff --git a/audio/out/ao_wasapi.c b/audio/out/ao_wasapi.c index 81b7535c4b..2edbdf5ef0 100644 --- a/audio/out/ao_wasapi.c +++ b/audio/out/ao_wasapi.c @@ -237,8 +237,6 @@ static void uninit(struct ao *ao) MP_ERR(ao, "Audio loop thread refuses to abort\n"); return; } - if (state->VistaBlob.hAvrt) - FreeLibrary(state->VistaBlob.hAvrt); SAFE_RELEASE(state->hInitDone, CloseHandle(state->hInitDone)); SAFE_RELEASE(state->hWake, CloseHandle(state->hWake)); @@ -255,8 +253,6 @@ static int init(struct ao *ao) struct wasapi_state *state = ao->priv; state->log = ao->log; - if(!wasapi_fill_VistaBlob(state)) - MP_WARN(ao, "Error loading thread priority functions\n"); state->hInitDone = CreateEventW(NULL, FALSE, FALSE, NULL); state->hWake = CreateEventW(NULL, FALSE, FALSE, NULL); @@ -341,7 +337,8 @@ static int control(struct ao *ao, enum aocontrol cmd, void *arg) return CONTROL_OK; case AOCONTROL_HAS_PER_APP_VOLUME: - return CONTROL_TRUE; + return state->share_mode == AUDCLNT_SHAREMODE_SHARED ? + CONTROL_TRUE : CONTROL_FALSE; case AOCONTROL_UPDATE_STREAM_TITLE: { MP_VERBOSE(state, "Updating stream title to \"%s\"\n", (char*)arg); wchar_t *title = mp_from_utf8(NULL, (char*)arg); diff --git a/audio/out/ao_wasapi.h b/audio/out/ao_wasapi.h index 24b9b862ed..2fbd2d5a9c 100755 --- a/audio/out/ao_wasapi.h +++ b/audio/out/ao_wasapi.h @@ -79,7 +79,6 @@ typedef struct wasapi_state { /* for setting the audio thread priority */ HANDLE hTask; /* AV thread */ - DWORD taskIndex; /* AV task ID */ /* WASAPI proxy handles, for Single-Threaded Apartment communication. One is needed for each audio thread object that's accessed from the main thread. */ @@ -110,16 +109,6 @@ typedef struct wasapi_state { size_t buffer_block_size; /* Size of each block in bytes */ UINT32 bufferFrameCount; /* wasapi buffer block size, number of frames, frame size at format.nBlockAlign */ - /* Don't use these functions directly in case - they are unimplemented for some reason. - (XP shouldn't be an issue since it doesn't support wasapi, maybe wine?) - Blob is owned by the main thread */ - struct { - HMODULE hAvrt; - HANDLE (WINAPI *pAvSetMmThreadCharacteristicsW)(LPCWSTR, LPDWORD); - WINBOOL (WINAPI *pAvRevertMmThreadCharacteristics)(HANDLE); - } VistaBlob; - change_notify change; } wasapi_state; diff --git a/audio/out/ao_wasapi_utils.c b/audio/out/ao_wasapi_utils.c index 1f885004a9..be81f0e730 100755 --- a/audio/out/ao_wasapi_utils.c +++ b/audio/out/ao_wasapi_utils.c @@ -185,36 +185,6 @@ char *mp_HRESULT_to_str_buf(char *buf, size_t buf_size, HRESULT hr) wasapi_explain_err(hr), (uint32_t) hr); return buf; } - -bool wasapi_fill_VistaBlob(wasapi_state *state) -{ - if (!state) - goto exit_label; - state->VistaBlob.hAvrt = LoadLibraryW(L"avrt.dll"); - if (!state->VistaBlob.hAvrt) - goto exit_label; - - state->VistaBlob.pAvSetMmThreadCharacteristicsW = - (HANDLE (WINAPI *)(LPCWSTR, LPDWORD)) - GetProcAddress(state->VistaBlob.hAvrt, "AvSetMmThreadCharacteristicsW"); - if (!state->VistaBlob.pAvSetMmThreadCharacteristicsW) - goto exit_label; - - state->VistaBlob.pAvRevertMmThreadCharacteristics = - (WINBOOL (WINAPI *)(HANDLE)) - GetProcAddress(state->VistaBlob.hAvrt, "AvRevertMmThreadCharacteristics"); - if (!state->VistaBlob.pAvRevertMmThreadCharacteristics) - goto exit_label; - - return true; -exit_label: - if (state->VistaBlob.hAvrt) { - FreeLibrary(state->VistaBlob.hAvrt); - state->VistaBlob.hAvrt = NULL; - } - return false; -} - static void update_waveformat_datarate(WAVEFORMATEXTENSIBLE *wformat) { WAVEFORMATEX *wf = &wformat->Format; @@ -399,6 +369,23 @@ exit_label: return false; } +// This works like try_format_exclusive(), but will try to fallback to the AC3 +// format if the format is a non-AC3 passthrough format. *wformat will be +// adjusted accordingly. +static bool try_format_exclusive_with_spdif_fallback(struct ao *ao, + WAVEFORMATEXTENSIBLE *wformat) +{ + if (try_format_exclusive(ao, wformat)) + return true; + int special_format = special_subtype_to_format(&wformat->SubFormat); + if (special_format && special_format != AF_FORMAT_S_AC3) { + MP_VERBOSE(ao, "Retrying as AC3.\n"); + wformat->SubFormat = *format_to_subtype(AF_FORMAT_S_AC3); + return try_format_exclusive(ao, wformat); + } + return false; +} + static bool search_sample_formats(struct ao *ao, WAVEFORMATEXTENSIBLE *wformat, int samplerate, struct mp_chmap *channels) { @@ -508,7 +495,7 @@ static bool find_formats_exclusive(struct ao *ao, bool do_search) // Try the requested format as is. If that doesn't work, and the // do_search argument is set, do the pcm format search. - if (!try_format_exclusive(ao, &wformat) && + if (!try_format_exclusive_with_spdif_fallback(ao, &wformat) && (!do_search || !search_channels(ao, &wformat))) return false; @@ -721,9 +708,10 @@ reinit: hr = init_session_display(state); EXIT_ON_ERROR(hr); - if (state->VistaBlob.hAvrt) { - state->hTask = - state->VistaBlob.pAvSetMmThreadCharacteristicsW(L"Pro Audio", &state->taskIndex); + state->hTask = AvSetMmThreadCharacteristics(L"Pro Audio", &(DWORD){0}); + if (!state->hTask) { + MP_WARN(state, "Failed to set AV thread to Pro Audio: %s\n", + mp_LastError_to_str()); } MP_VERBOSE(state, "Format fixed. Using %lld byte buffer block size\n", @@ -1177,8 +1165,6 @@ void wasapi_thread_uninit(struct ao *ao) SAFE_RELEASE(state->pAudioClient, IAudioClient_Release(state->pAudioClient)); SAFE_RELEASE(state->pDevice, IMMDevice_Release(state->pDevice)); SAFE_RELEASE(state->pEnumerator, IMMDeviceEnumerator_Release(state->pEnumerator)); - - if (state->hTask) - state->VistaBlob.pAvRevertMmThreadCharacteristics(state->hTask); + SAFE_RELEASE(state->hTask, AvRevertMmThreadCharacteristics(state->hTask)); MP_DBG(ao, "Thread uninit done\n"); } diff --git a/audio/out/ao_wasapi_utils.h b/audio/out/ao_wasapi_utils.h index 5ac2d3efba..deaffd77e4 100755 --- a/audio/out/ao_wasapi_utils.h +++ b/audio/out/ao_wasapi_utils.h @@ -33,6 +33,7 @@ char *mp_HRESULT_to_str_buf(char *buf, size_t buf_size, HRESULT hr); #define mp_GUID_to_str(guid) mp_GUID_to_str_buf((char[40]){0}, 40, (guid)) #define mp_PKEY_to_str(pkey) mp_PKEY_to_str_buf((char[42]){0}, 42, (pkey)) #define mp_HRESULT_to_str(hr) mp_HRESULT_to_str_buf((char[60]){0}, 60, (hr)) +#define mp_LastError_to_str() mp_HRESULT_to_str(HRESULT_FROM_WIN32(GetLastError())) bool wasapi_fill_VistaBlob(wasapi_state *state); |