summaryrefslogtreecommitdiffstats
path: root/audio/out
diff options
context:
space:
mode:
Diffstat (limited to 'audio/out')
-rw-r--r--audio/out/ao.c8
-rw-r--r--audio/out/ao_alsa.c16
-rw-r--r--audio/out/ao_openal.c95
-rw-r--r--audio/out/ao_wasapi.c7
-rwxr-xr-xaudio/out/ao_wasapi.h11
-rwxr-xr-xaudio/out/ao_wasapi_utils.c60
-rwxr-xr-xaudio/out/ao_wasapi_utils.h1
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);