summaryrefslogtreecommitdiffstats
path: root/audio
diff options
context:
space:
mode:
Diffstat (limited to 'audio')
-rw-r--r--audio/filter/af_lavrresample.c37
-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
8 files changed, 137 insertions, 98 deletions
diff --git a/audio/filter/af_lavrresample.c b/audio/filter/af_lavrresample.c
index 721bb30165..f7f448cad0 100644
--- a/audio/filter/af_lavrresample.c
+++ b/audio/filter/af_lavrresample.c
@@ -91,8 +91,6 @@ struct af_resample {
int out_rate;
int out_format;
struct mp_chmap out_channels;
-
- double missing_samples; // fractional samples not yet output
};
#if HAVE_LIBAVRESAMPLE
@@ -226,8 +224,6 @@ static int configure_lavrr(struct af_instance *af, struct mp_audio *in,
s->out_channels= out->channels;
s->in_channels = in->channels;
- s->missing_samples = 0;
-
av_opt_set_int(s->avrctx, "filter_size", s->opts.filter_size, 0);
av_opt_set_int(s->avrctx, "phase_shift", s->opts.phase_shift, 0);
av_opt_set_int(s->avrctx, "linear_interp", s->opts.linear, 0);
@@ -427,6 +423,18 @@ static void extra_output_conversion(struct af_instance *af, struct mp_audio *mpa
}
mp_audio_set_format(mpa, AF_FORMAT_S24);
}
+
+ for (int p = 0; p < mpa->num_planes; p++) {
+ void *ptr = mpa->planes[p];
+ int total = mpa->samples * mpa->spf;
+ if (af_fmt_from_planar(mpa->format) == AF_FORMAT_FLOAT) {
+ for (int s = 0; s < total; s++)
+ ((float *)ptr)[s] = av_clipf(((float *)ptr)[s], -1.0f, 1.0f);
+ } else if (af_fmt_from_planar(mpa->format) == AF_FORMAT_DOUBLE) {
+ for (int s = 0; s < total; s++)
+ ((double *)ptr)[s] = MPCLAMP(((double *)ptr)[s], -1.0, 1.0);
+ }
+ }
}
// This relies on the tricky way mpa was allocated.
@@ -521,15 +529,18 @@ static int filter(struct af_instance *af, struct mp_audio *in)
int new_rate = rate_from_speed(s->in_rate_af, s->playback_speed);
bool need_reinit = fabs(new_rate / (double)s->in_rate - 1) > 0.01;
- if (!need_reinit && s->avrctx) {
- double speed_factor = s->playback_speed * s->in_rate_af / s->in_rate;
- int in_samples = in ? in->samples : 0;
- double wanted_samples = in_samples / speed_factor + s->missing_samples;
- int wanted_samples_i = lrint(wanted_samples);
- s->missing_samples = wanted_samples - wanted_samples_i;
- if (avresample_set_compensation(s->avrctx,
- (wanted_samples_i - in_samples) * s->out_rate / s->in_rate,
- wanted_samples_i * s->out_rate / s->in_rate) < 0)
+ if (s->avrctx) {
+ AVRational r = av_d2q(s->playback_speed * s->in_rate_af / s->in_rate,
+ INT_MAX / 2);
+ // Essentially, swr/avresample_set_compensation() does 2 things:
+ // - adjust output sample rate by sample_delta/compensation_distance
+ // - reset the adjustment after compensation_distance output samples
+ // Increase the compensation_distance to avoid undesired reset
+ // semantics - we want to keep the ratio for the whole frame we're
+ // feeding it, until the next filter() call.
+ int mult = INT_MAX / 2 / MPMAX(MPMAX(abs(r.num), abs(r.den)), 1);
+ r = (AVRational){ r.num * mult, r.den * mult };
+ if (avresample_set_compensation(s->avrctx, r.den - r.num, r.den) < 0)
need_reinit = true;
}
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);