summaryrefslogtreecommitdiffstats
path: root/audio
diff options
context:
space:
mode:
Diffstat (limited to 'audio')
-rw-r--r--audio/audio.c2
-rw-r--r--audio/chmap_sel.c22
-rw-r--r--audio/decode/ad_lavc.c33
-rw-r--r--audio/decode/dec_audio.c17
-rw-r--r--audio/decode/dec_audio.h2
-rw-r--r--audio/mixer.c15
-rw-r--r--audio/out/ao.c6
-rw-r--r--audio/out/ao_coreaudio.c8
-rw-r--r--audio/out/ao_coreaudio_properties.c2
-rw-r--r--audio/out/ao_coreaudio_utils.c31
-rw-r--r--audio/out/ao_coreaudio_utils.h3
-rw-r--r--audio/out/ao_dsound.c707
-rw-r--r--audio/out/ao_lavc.c2
-rw-r--r--audio/out/ao_null.c2
-rw-r--r--audio/out/ao_pcm.c2
-rw-r--r--audio/out/ao_pulse.c55
-rw-r--r--audio/out/ao_rsound.c2
-rw-r--r--audio/out/ao_sdl.c2
-rw-r--r--audio/out/ao_wasapi.c292
-rw-r--r--[-rwxr-xr-x]audio/out/ao_wasapi.h112
-rw-r--r--[-rwxr-xr-x]audio/out/ao_wasapi_changenotify.c62
-rw-r--r--[-rwxr-xr-x]audio/out/ao_wasapi_utils.c807
-rwxr-xr-xaudio/out/ao_wasapi_utils.h49
-rw-r--r--audio/out/pull.c2
24 files changed, 742 insertions, 1495 deletions
diff --git a/audio/audio.c b/audio/audio.c
index c4ad4021b5..157649c3f8 100644
--- a/audio/audio.c
+++ b/audio/audio.c
@@ -24,7 +24,7 @@
#include <libavutil/frame.h>
#include <libavutil/version.h>
-#include "talloc.h"
+#include "mpv_talloc.h"
#include "common/common.h"
#include "fmt-conversion.h"
#include "audio.h"
diff --git a/audio/chmap_sel.c b/audio/chmap_sel.c
index 8ddb7131e7..fa1941e6f6 100644
--- a/audio/chmap_sel.c
+++ b/audio/chmap_sel.c
@@ -274,19 +274,25 @@ static bool mp_chmap_is_better(struct mp_chmap *req, struct mp_chmap *old,
if (new_lost_r != old_lost_r)
return new_lost_r < old_lost_r;
+ struct mp_chmap old_p = *old, new_p = *new;
+ mp_chmap_remove_na(&old_p);
+ mp_chmap_remove_na(&new_p);
+
+ // If the situation is equal with replaced speakers, but the replacement is
+ // perfect for only one of them, let the better one win. This prefers
+ // inexact equivalents over exact supersets.
+ bool perfect_r_new = !new_lost_r && new_p.num <= old_p.num;
+ bool perfect_r_old = !old_lost_r && old_p.num <= new_p.num;
+ if (perfect_r_new != perfect_r_old)
+ return perfect_r_new;
+
int old_lost = mp_chmap_diffn(req, old);
int new_lost = mp_chmap_diffn(req, new);
-
- // If the situation is equal with replaced speakers, but one of them loses
- // less if no replacements are performed, pick the better one, even if it
- // means an upmix. This prefers exact supersets over inexact equivalents.
+ // If the situation is equal with replaced speakers, pick the better one,
+ // even if it means an upmix.
if (new_lost != old_lost)
return new_lost < old_lost;
- struct mp_chmap old_p = *old, new_p = *new;
- mp_chmap_remove_na(&old_p);
- mp_chmap_remove_na(&new_p);
-
// Some kind of upmix. If it's perfect, prefer the smaller one. Even if not,
// both have equal loss, so also prefer the smaller one.
// Drop padding channels (NA) for the sake of this check, as the number of
diff --git a/audio/decode/ad_lavc.c b/audio/decode/ad_lavc.c
index 3188834830..7e5c8d5aa5 100644
--- a/audio/decode/ad_lavc.c
+++ b/audio/decode/ad_lavc.c
@@ -26,7 +26,7 @@
#include <libavutil/common.h>
#include <libavutil/intreadwrite.h>
-#include "talloc.h"
+#include "mpv_talloc.h"
#include "config.h"
#include "common/av_common.h"
@@ -79,12 +79,12 @@ static int init(struct dec_audio *da, const char *decoder)
AVCodecContext *lavc_context;
AVCodec *lavc_codec;
struct sh_stream *sh = da->header;
- struct sh_audio *sh_audio = sh->audio;
+ struct mp_codec_params *c = sh->codec;
struct priv *ctx = talloc_zero(NULL, struct priv);
da->priv = ctx;
- ctx->force_channel_map = sh_audio->force_channels;
+ ctx->force_channel_map = c->force_channels;
lavc_codec = avcodec_find_decoder_by_name(decoder);
if (!lavc_codec) {
@@ -116,20 +116,20 @@ static int init(struct dec_audio *da, const char *decoder)
mp_set_avopts(da->log, lavc_context, opts->avopts);
- lavc_context->codec_tag = sh->codec_tag;
- lavc_context->sample_rate = sh_audio->samplerate;
- lavc_context->bit_rate = sh_audio->bitrate;
- lavc_context->block_align = sh_audio->block_align;
- lavc_context->bits_per_coded_sample = sh_audio->bits_per_coded_sample;
- lavc_context->channels = sh_audio->channels.num;
- if (!mp_chmap_is_unknown(&sh_audio->channels))
- lavc_context->channel_layout = mp_chmap_to_lavc(&sh_audio->channels);
+ lavc_context->codec_tag = c->codec_tag;
+ lavc_context->sample_rate = c->samplerate;
+ lavc_context->bit_rate = c->bitrate;
+ lavc_context->block_align = c->block_align;
+ lavc_context->bits_per_coded_sample = c->bits_per_coded_sample;
+ lavc_context->channels = c->channels.num;
+ if (!mp_chmap_is_unknown(&c->channels))
+ lavc_context->channel_layout = mp_chmap_to_lavc(&c->channels);
// demux_mkv
- mp_lavc_set_extradata(lavc_context, sh->extradata, sh->extradata_size);
+ mp_lavc_set_extradata(lavc_context, c->extradata, c->extradata_size);
- if (sh->lav_headers)
- mp_copy_lav_codec_headers(lavc_context, sh->lav_headers);
+ if (c->lav_headers)
+ mp_copy_lav_codec_headers(lavc_context, c->lav_headers);
mp_set_avcodec_threads(da->log, lavc_context, opts->threads);
@@ -228,9 +228,8 @@ static int decode_packet(struct dec_audio *da, struct mp_audio **out)
if (lavc_chmap.num != avctx->channels)
mp_chmap_from_channels(&lavc_chmap, avctx->channels);
if (priv->force_channel_map) {
- struct sh_audio *sh_audio = da->header->audio;
- if (lavc_chmap.num == sh_audio->channels.num)
- lavc_chmap = sh_audio->channels;
+ if (lavc_chmap.num == da->header->codec->channels.num)
+ lavc_chmap = da->header->codec->channels;
}
mp_audio_set_channels(mpframe, &lavc_chmap);
diff --git a/audio/decode/dec_audio.c b/audio/decode/dec_audio.c
index 03172ed294..f774ed1abd 100644
--- a/audio/decode/dec_audio.c
+++ b/audio/decode/dec_audio.c
@@ -88,7 +88,7 @@ struct mp_decoder_list *audio_decoder_list(void)
static struct mp_decoder_list *audio_select_decoders(struct dec_audio *d_audio)
{
struct MPOpts *opts = d_audio->opts;
- const char *codec = d_audio->header->codec;
+ const char *codec = d_audio->header->codec->codec;
struct mp_decoder_list *list = audio_decoder_list();
struct mp_decoder_list *new =
@@ -146,7 +146,7 @@ int audio_init_best_codec(struct dec_audio *d_audio)
MP_VERBOSE(d_audio, "Selected audio codec: %s\n", d_audio->decoder_desc);
} else {
MP_ERR(d_audio, "Failed to initialize an audio decoder for codec '%s'.\n",
- d_audio->header->codec ? d_audio->header->codec : "<unknown>");
+ d_audio->header->codec->codec);
}
talloc_free(list);
@@ -177,11 +177,21 @@ static int decode_new_frame(struct dec_audio *da)
da->pts += da->pts_offset / (double)da->waiting->rate;
da->pts_offset = 0;
}
+ double newpts = da->waiting->pts;
// Keep the interpolated timestamp if it doesn't deviate more
// than 1 ms from the real one. (MKV rounded timestamps.)
if (da->pts == MP_NOPTS_VALUE || da->pts_offset != 0 ||
- fabs(da->pts - da->waiting->pts) > 0.001)
+ fabs(da->pts - newpts) > 0.001)
{
+ // Attempt to detect jumps in PTS. Even for the lowest
+ // sample rates and with worst container rounded timestamp,
+ // this should be a margin more than enough.
+ if (da->pts != MP_NOPTS_VALUE && fabs(newpts - da->pts) > 0.1)
+ {
+ MP_WARN(da, "Invalid audio PTS: %f -> %f\n",
+ da->pts, newpts);
+ da->pts_reset = true;
+ }
da->pts = da->waiting->pts;
da->pts_offset = 0;
}
@@ -274,6 +284,7 @@ void audio_reset_decoding(struct dec_audio *d_audio)
af_seek_reset(d_audio->afilter);
d_audio->pts = MP_NOPTS_VALUE;
d_audio->pts_offset = 0;
+ d_audio->pts_reset = false;
if (d_audio->waiting) {
talloc_free(d_audio->waiting);
d_audio->waiting = NULL;
diff --git a/audio/decode/dec_audio.h b/audio/decode/dec_audio.h
index 0f7f4d239d..a8c66fa67e 100644
--- a/audio/decode/dec_audio.h
+++ b/audio/decode/dec_audio.h
@@ -45,6 +45,8 @@ struct dec_audio {
double pts;
// number of samples output by decoder after last known pts
int pts_offset;
+ // set every time a jump in timestamps is encountered
+ bool pts_reset;
// For free use by the ad_driver
void *priv;
};
diff --git a/audio/mixer.c b/audio/mixer.c
index 26f426c2b4..5f147872ab 100644
--- a/audio/mixer.c
+++ b/audio/mixer.c
@@ -27,7 +27,7 @@
#include "audio/filter/af.h"
#include "common/global.h"
#include "common/msg.h"
-#include "talloc.h"
+#include "mpv_talloc.h"
#include "mixer.h"
struct mixer {
@@ -120,8 +120,11 @@ void mixer_getvolume(struct mixer *mixer, float *l, float *r)
*r = mixer->vol_r;
}
-static void setvolume_internal(struct mixer *mixer, float l, float r)
+static void setvolume_internal(struct mixer *mixer)
{
+ float l = mixer->vol_l, r = mixer->vol_r;
+ if (mixer->emulate_mute && mixer->muted)
+ l = r = 0;
if (!mixer->softvol) {
MP_DBG(mixer, "Setting volume on AO.\n");
struct ao_control_vol vol = {.left = l, .right = r};
@@ -147,8 +150,8 @@ void mixer_setvolume(struct mixer *mixer, float l, float r)
float max = mixer_getmaxvolume(mixer);
mixer->vol_l = MPCLAMP(l, 0, max);
mixer->vol_r = MPCLAMP(r, 0, max);
- if (mixer->ao && !(mixer->emulate_mute && mixer->muted))
- setvolume_internal(mixer, mixer->vol_l, mixer->vol_r);
+ if (mixer->ao)
+ setvolume_internal(mixer);
}
void mixer_getbothvolume(struct mixer *mixer, float *b)
@@ -167,7 +170,7 @@ void mixer_setmute(struct mixer *mixer, bool mute)
mixer->muted = mute;
mixer->muted_by_us = mute;
if (mixer->emulate_mute) {
- setvolume_internal(mixer, mixer->vol_l*!mute, mixer->vol_r*!mute);
+ setvolume_internal(mixer);
} else {
ao_control(mixer->ao, AOCONTROL_SET_MUTE, &mute);
}
@@ -293,6 +296,8 @@ static void restore_volume(struct mixer *mixer)
const char *prev_driver = mixer->driver;
mixer->driver = mixer->softvol ? "softvol" : ao_get_name(ao);
+ if (!prev_driver[0])
+ prev_driver = mixer->driver;
// Restore old parameters if volume won't survive reinitialization.
// But not if volume scale is possibly different.
diff --git a/audio/out/ao.c b/audio/out/ao.c
index daa9c306b5..ffcc43ab79 100644
--- a/audio/out/ao.c
+++ b/audio/out/ao.c
@@ -20,7 +20,7 @@
#include <string.h>
#include <assert.h>
-#include "talloc.h"
+#include "mpv_talloc.h"
#include "config.h"
#include "ao.h"
@@ -45,7 +45,6 @@ extern const struct ao_driver audio_out_jack;
extern const struct ao_driver audio_out_openal;
extern const struct ao_driver audio_out_null;
extern const struct ao_driver audio_out_alsa;
-extern const struct ao_driver audio_out_dsound;
extern const struct ao_driver audio_out_wasapi;
extern const struct ao_driver audio_out_pcm;
extern const struct ao_driver audio_out_lavc;
@@ -65,9 +64,6 @@ static const struct ao_driver * const audio_out_drivers[] = {
#if HAVE_WASAPI
&audio_out_wasapi,
#endif
-#if HAVE_DSOUND
- &audio_out_dsound,
-#endif
#if HAVE_OSS_AUDIO
&audio_out_oss,
#endif
diff --git a/audio/out/ao_coreaudio.c b/audio/out/ao_coreaudio.c
index facbc601f6..471ab6d928 100644
--- a/audio/out/ao_coreaudio.c
+++ b/audio/out/ao_coreaudio.c
@@ -384,8 +384,8 @@ static int hotplug_init(struct ao *ao)
err = AudioObjectAddPropertyListener(
kAudioObjectSystemObject, &addr, hotplug_cb, (void *)ao);
if (err != noErr) {
- char *c1 = fourcc_repr(hotplug_properties[i]);
- char *c2 = fourcc_repr(err);
+ char *c1 = mp_tag_str(hotplug_properties[i]);
+ char *c2 = mp_tag_str(err);
MP_ERR(ao, "failed to set device listener %s (%s)", c1, c2);
goto coreaudio_error;
}
@@ -409,8 +409,8 @@ static void hotplug_uninit(struct ao *ao)
err = AudioObjectRemovePropertyListener(
kAudioObjectSystemObject, &addr, hotplug_cb, (void *)ao);
if (err != noErr) {
- char *c1 = fourcc_repr(hotplug_properties[i]);
- char *c2 = fourcc_repr(err);
+ char *c1 = mp_tag_str(hotplug_properties[i]);
+ char *c2 = mp_tag_str(err);
MP_ERR(ao, "failed to set device listener %s (%s)", c1, c2);
}
}
diff --git a/audio/out/ao_coreaudio_properties.c b/audio/out/ao_coreaudio_properties.c
index cf2b4d14a1..b74cf07289 100644
--- a/audio/out/ao_coreaudio_properties.c
+++ b/audio/out/ao_coreaudio_properties.c
@@ -21,7 +21,7 @@
#include "audio/out/ao_coreaudio_properties.h"
#include "audio/out/ao_coreaudio_utils.h"
-#include "talloc.h"
+#include "mpv_talloc.h"
OSStatus ca_get(AudioObjectID id, ca_scope scope, ca_sel selector,
uint32_t size, void *data)
diff --git a/audio/out/ao_coreaudio_utils.c b/audio/out/ao_coreaudio_utils.c
index dff672e7d3..6b5d8a7195 100644
--- a/audio/out/ao_coreaudio_utils.c
+++ b/audio/out/ao_coreaudio_utils.c
@@ -136,36 +136,11 @@ coreaudio_error:
return err;
}
-char *fourcc_repr_buf(char *buf, size_t buf_size, uint32_t code)
-{
- // Extract FourCC letters from the uint32_t and finde out if it's a valid
- // code that is made of letters.
- unsigned char fcc[4] = {
- (code >> 24) & 0xFF,
- (code >> 16) & 0xFF,
- (code >> 8) & 0xFF,
- code & 0xFF,
- };
-
- bool valid_fourcc = true;
- for (int i = 0; i < 4; i++) {
- if (fcc[i] < 32 || fcc[i] >= 128)
- valid_fourcc = false;
- }
-
- if (valid_fourcc)
- snprintf(buf, buf_size, "'%c%c%c%c'", fcc[0], fcc[1], fcc[2], fcc[3]);
- else
- snprintf(buf, buf_size, "%u", (unsigned int)code);
-
- return buf;
-}
-
bool check_ca_st(struct ao *ao, int level, OSStatus code, const char *message)
{
if (code == noErr) return true;
- mp_msg(ao->log, level, "%s (%s)\n", message, fourcc_repr(code));
+ mp_msg(ao->log, level, "%s (%s)\n", message, mp_tag_str(code));
return false;
}
@@ -258,7 +233,7 @@ void ca_print_asbd(struct ao *ao, const char *description,
const AudioStreamBasicDescription *asbd)
{
uint32_t flags = asbd->mFormatFlags;
- char *format = fourcc_repr(asbd->mFormatID);
+ char *format = mp_tag_str(asbd->mFormatID);
int mpfmt = ca_asbd_to_mp_format(asbd);
MP_VERBOSE(ao,
@@ -470,7 +445,7 @@ int64_t ca_get_device_latency_us(struct ao *ao, AudioDeviceID device)
if (err == noErr) {
latency_frames += temp;
MP_VERBOSE(ao, "Latency property %s: %d frames\n",
- fourcc_repr(latency_properties[n]), (int)temp);
+ mp_tag_str(latency_properties[n]), (int)temp);
}
}
diff --git a/audio/out/ao_coreaudio_utils.h b/audio/out/ao_coreaudio_utils.h
index a0b5aa002c..780c56864b 100644
--- a/audio/out/ao_coreaudio_utils.h
+++ b/audio/out/ao_coreaudio_utils.h
@@ -31,9 +31,6 @@
CFStringRef cfstr_from_cstr(char *str);
char *cfstr_get_cstr(CFStringRef cfstr);
-char *fourcc_repr_buf(char *buf, size_t buf_size, uint32_t code);
-#define fourcc_repr(code) fourcc_repr_buf((char[40]){0}, 40, code)
-
bool check_ca_st(struct ao *ao, int level, OSStatus code, const char *message);
#define CHECK_CA_ERROR_L(label, message) \
diff --git a/audio/out/ao_dsound.c b/audio/out/ao_dsound.c
deleted file mode 100644
index c581bf512e..0000000000
--- a/audio/out/ao_dsound.c
+++ /dev/null
@@ -1,707 +0,0 @@
-/*
- * Windows DirectSound interface
- *
- * Copyright (c) 2004 Gabor Szecsi <deje@miki.hu>
- *
- * This file is part of mpv.
- *
- * mpv is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * mpv is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with mpv. If not, see <http://www.gnu.org/licenses/>.
- */
-
-/**
-\todo verify/extend multichannel support
-*/
-
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <windows.h>
-#define DIRECTSOUND_VERSION 0x0600
-#include <dsound.h>
-#include <math.h>
-
-#include <libavutil/avutil.h>
-#include <libavutil/common.h>
-
-#include "config.h"
-#include "audio/format.h"
-#include "ao.h"
-#include "internal.h"
-#include "common/msg.h"
-#include "osdep/timer.h"
-#include "osdep/io.h"
-#include "options/m_option.h"
-
-/**
-\todo use the definitions from the win32 api headers when they define these
-*/
-#define WAVE_FORMAT_IEEE_FLOAT 0x0003
-#define WAVE_FORMAT_DOLBY_AC3_SPDIF 0x0092
-#define WAVE_FORMAT_EXTENSIBLE 0xFFFE
-
-static const GUID KSDATAFORMAT_SUBTYPE_PCM = {
- 0x1, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
-};
-
-#if 0
-#define DSSPEAKER_HEADPHONE 0x00000001
-#define DSSPEAKER_MONO 0x00000002
-#define DSSPEAKER_QUAD 0x00000003
-#define DSSPEAKER_STEREO 0x00000004
-#define DSSPEAKER_SURROUND 0x00000005
-#define DSSPEAKER_5POINT1 0x00000006
-#endif
-
-#ifndef _WAVEFORMATEXTENSIBLE_
-typedef struct {
- WAVEFORMATEX Format;
- union {
- WORD wValidBitsPerSample; /* bits of precision */
- WORD wSamplesPerBlock; /* valid if wBitsPerSample==0 */
- WORD wReserved; /* If neither applies, set to zero. */
- } Samples;
- DWORD dwChannelMask; /* which channels are */
- /* present in stream */
- GUID SubFormat;
-} WAVEFORMATEXTENSIBLE, *PWAVEFORMATEXTENSIBLE;
-#endif
-
-struct priv {
- HINSTANCE hdsound_dll; ///handle to the dll
- LPDIRECTSOUND hds; ///direct sound object
- LPDIRECTSOUNDBUFFER hdspribuf; ///primary direct sound buffer
- LPDIRECTSOUNDBUFFER hdsbuf; ///secondary direct sound buffer (stream buffer)
- int buffer_size; ///size in bytes of the direct sound buffer
- int write_offset; ///offset of the write cursor in the direct sound buffer
- int min_free_space; ///if the free space is below this value get_space() will return 0
- ///there will always be at least this amout of free space to prevent
- ///get_space() from returning wrong values when buffer is 100% full.
- ///will be replaced with nBlockAlign in init()
- int underrun_check; ///0 or last reported free space (underrun detection)
- int device_num; ///wanted device number
- GUID device; ///guid of the device
- int audio_volume;
-
- int device_index;
-
- int outburst; ///play in multiple of chunks of this size
-
- int cfg_device;
- int cfg_buffersize;
-
- struct ao_device_list *listing; ///temporary during list_devs()
-};
-
-/***************************************************************************************/
-
-/**
-\brief output error message
-\param err error code
-\return string with the error message
-*/
-static char * dserr2str(int err)
-{
- switch (err) {
- case DS_OK: return "DS_OK";
- case DS_NO_VIRTUALIZATION: return "DS_NO_VIRTUALIZATION";
- case DSERR_ALLOCATED: return "DS_NO_VIRTUALIZATION";
- case DSERR_CONTROLUNAVAIL: return "DSERR_CONTROLUNAVAIL";
- case DSERR_INVALIDPARAM: return "DSERR_INVALIDPARAM";
- case DSERR_INVALIDCALL: return "DSERR_INVALIDCALL";
- case DSERR_GENERIC: return "DSERR_GENERIC";
- case DSERR_PRIOLEVELNEEDED: return "DSERR_PRIOLEVELNEEDED";
- case DSERR_OUTOFMEMORY: return "DSERR_OUTOFMEMORY";
- case DSERR_BADFORMAT: return "DSERR_BADFORMAT";
- case DSERR_UNSUPPORTED: return "DSERR_UNSUPPORTED";
- case DSERR_NODRIVER: return "DSERR_NODRIVER";
- case DSERR_ALREADYINITIALIZED: return "DSERR_ALREADYINITIALIZED";
- case DSERR_NOAGGREGATION: return "DSERR_NOAGGREGATION";
- case DSERR_BUFFERLOST: return "DSERR_BUFFERLOST";
- case DSERR_OTHERAPPHASPRIO: return "DSERR_OTHERAPPHASPRIO";
- case DSERR_UNINITIALIZED: return "DSERR_UNINITIALIZED";
- case DSERR_NOINTERFACE: return "DSERR_NOINTERFACE";
- case DSERR_ACCESSDENIED: return "DSERR_ACCESSDENIED";
- }
- return "unknown";
-}
-
-/**
-\brief uninitialize direct sound
-*/
-static void UninitDirectSound(struct ao *ao)
-{
- struct priv *p = ao->priv;
-
- // finally release the DirectSound object
- if (p->hds) {
- IDirectSound_Release(p->hds);
- p->hds = NULL;
- }
- // free DSOUND.DLL
- if (p->hdsound_dll) {
- FreeLibrary(p->hdsound_dll);
- p->hdsound_dll = NULL;
- }
- MP_VERBOSE(ao, "DirectSound uninitialized\n");
-}
-
-/**
-\brief enumerate direct sound devices
-\return TRUE to continue with the enumeration
-*/
-static BOOL CALLBACK DirectSoundEnum(LPGUID guid, LPCSTR desc, LPCSTR module,
- LPVOID context)
-{
- struct ao *ao = context;
- struct priv *p = ao->priv;
-
- MP_VERBOSE(ao, "%i %s ", p->device_index, desc);
- if (p->device_num == p->device_index) {
- MP_VERBOSE(ao, "<--");
- if (guid)
- memcpy(&p->device, guid, sizeof(GUID));
- }
- char *guidstr = talloc_strdup(NULL, "");
- if (guid) {
- wchar_t guidwstr[80] = {0};
- StringFromGUID2(guid, guidwstr, MP_ARRAY_SIZE(guidwstr));
- char *nstr = mp_to_utf8(NULL, guidwstr);
- if (nstr) {
- talloc_free(guidstr);
- guidstr = nstr;
- }
- }
- if (p->device_num < 0 && ao->device) {
- if (strcmp(ao->device, guidstr) == 0) {
- MP_VERBOSE(ao, "<--");
- p->device_num = p->device_index;
- if (guid)
- memcpy(&p->device, guid, sizeof(GUID));
- }
- }
- if (p->listing) {
- struct ao_device_desc e = {guidstr, desc};
- ao_device_list_add(p->listing, ao, &e);
- }
- talloc_free(guidstr);
-
- MP_VERBOSE(ao, "\n");
- p->device_index++;
- return TRUE;
-}
-
-static void EnumDevs(struct ao *ao)
-{
- struct priv *p = ao->priv;
-
- p->device_index = 0;
- p->device_num = p->cfg_device;
-
- HRESULT (WINAPI *OurDirectSoundEnumerate)(LPDSENUMCALLBACKA, LPVOID);
- OurDirectSoundEnumerate = (void *)GetProcAddress(p->hdsound_dll,
- "DirectSoundEnumerateA");
-
- if (OurDirectSoundEnumerate == NULL) {
- MP_ERR(ao, "GetProcAddress FAILED\n");
- return;
- }
-
- // Enumerate all directsound p->devices
- MP_VERBOSE(ao, "Output Devices:\n");
- OurDirectSoundEnumerate(DirectSoundEnum, ao);
-}
-
-static int LoadDirectSound(struct ao *ao)
-{
- struct priv *p = ao->priv;
-
- // initialize directsound
- p->hdsound_dll = LoadLibrary(L"DSOUND.DLL");
- if (p->hdsound_dll == NULL) {
- MP_ERR(ao, "cannot load DSOUND.DLL\n");
- return 0;
- }
-
- return 1;
-}
-
-static void list_devs(struct ao *ao, struct ao_device_list *list)
-{
- struct priv *p = ao->priv;
- bool need_init = !p->hdsound_dll;
- if (need_init && !LoadDirectSound(ao))
- return;
-
- p->listing = list;
- EnumDevs(ao);
- p->listing = NULL;
-
- if (need_init)
- UninitDirectSound(ao);
-}
-
-/**
-\brief initilize direct sound
-\return 0 if error, 1 if ok
-*/
-static int InitDirectSound(struct ao *ao)
-{
- struct priv *p = ao->priv;
-
- DSCAPS dscaps;
-
- if (!LoadDirectSound(ao))
- return 0;
-
- HRESULT (WINAPI *OurDirectSoundCreate)(LPGUID, LPDIRECTSOUND *, LPUNKNOWN);
- OurDirectSoundCreate =
- (void *)GetProcAddress(p->hdsound_dll, "DirectSoundCreate");
-
- if (OurDirectSoundCreate == NULL) {
- MP_ERR(ao, "GetProcAddress FAILED\n");
- FreeLibrary(p->hdsound_dll);
- return 0;
- }
-
- EnumDevs(ao);
-
- // Create the direct sound object
- if (FAILED(OurDirectSoundCreate((p->device_num > 0) ? &p->device : NULL,
- &p->hds, NULL)))
- {
- MP_ERR(ao, "cannot create a DirectSound device\n");
- FreeLibrary(p->hdsound_dll);
- return 0;
- }
-
- /* Set DirectSound Cooperative level, ie what control we want over Windows
- * sound device. In our case, DSSCL_EXCLUSIVE means that we can modify the
- * settings of the primary buffer, but also that only the sound of our
- * application will be audible when it will have the focus.
- * !!! (this is not really working as intended yet because to set the
- * cooperative level you need the window handle of your application, and
- * I don't know of any easy way to get it. Especially since we might play
- * sound without any video, and so what window handle should we use ???
- * The hack for now is to use the Desktop window handle - it seems to be
- * working */
- if (IDirectSound_SetCooperativeLevel(p->hds, GetDesktopWindow(),
- DSSCL_EXCLUSIVE))
- {
- MP_ERR(ao, "cannot set direct sound cooperative level\n");
- IDirectSound_Release(p->hds);
- FreeLibrary(p->hdsound_dll);
- return 0;
- }
- MP_VERBOSE(ao, "DirectSound initialized\n");
-
- memset(&dscaps, 0, sizeof(DSCAPS));
- dscaps.dwSize = sizeof(DSCAPS);
- if (DS_OK == IDirectSound_GetCaps(p->hds, &dscaps)) {
- if (dscaps.dwFlags & DSCAPS_EMULDRIVER)
- MP_VERBOSE(ao, "DirectSound is emulated\n");
- } else {
- MP_VERBOSE(ao, "cannot get device capabilities\n");
- }
-
- return 1;
-}
-
-/**
-\brief destroy the direct sound buffer
-*/
-static void DestroyBuffer(struct ao *ao)
-{
- struct priv *p = ao->priv;
-
- if (p->hdsbuf) {
- IDirectSoundBuffer_Release(p->hdsbuf);
- p->hdsbuf = NULL;
- }
- if (p->hdspribuf) {
- IDirectSoundBuffer_Release(p->hdspribuf);
- p->hdspribuf = NULL;
- }
-}
-
-/**
-\brief fill sound buffer
-\param data pointer to the sound data to copy
-\param len length of the data to copy in bytes
-\return number of copyed bytes
-*/
-static int write_buffer(struct ao *ao, unsigned char *data, int len)
-{
- struct priv *p = ao->priv;
- HRESULT res;
- LPVOID lpvPtr1;
- DWORD dwBytes1;
- LPVOID lpvPtr2;
- DWORD dwBytes2;
-
- p->underrun_check = 0;
-
- // Lock the buffer
- res = IDirectSoundBuffer_Lock(p->hdsbuf, p->write_offset, len, &lpvPtr1,
- &dwBytes1, &lpvPtr2, &dwBytes2, 0);
- // If the buffer was lost, restore and retry lock.
- if (DSERR_BUFFERLOST == res) {
- IDirectSoundBuffer_Restore(p->hdsbuf);
- res = IDirectSoundBuffer_Lock(p->hdsbuf, p->write_offset, len, &lpvPtr1,
- &dwBytes1, &lpvPtr2, &dwBytes2, 0);
- }
-
-
- if (SUCCEEDED(res)) {
- memcpy(lpvPtr1, data, dwBytes1);
- if (NULL != lpvPtr2)
- memcpy(lpvPtr2, data + dwBytes1, dwBytes2);
- p->write_offset += dwBytes1 + dwBytes2;
- if (p->write_offset >= p->buffer_size)
- p->write_offset = dwBytes2;
-
- // Release the data back to DirectSound.
- res = IDirectSoundBuffer_Unlock(p->hdsbuf, lpvPtr1, dwBytes1, lpvPtr2,
- dwBytes2);
- if (SUCCEEDED(res)) {
- // Success.
- DWORD status;
- IDirectSoundBuffer_GetStatus(p->hdsbuf, &status);
- if (!(status & DSBSTATUS_PLAYING))
- res = IDirectSoundBuffer_Play(p->hdsbuf, 0, 0, DSBPLAY_LOOPING);
- return dwBytes1 + dwBytes2;
- }
- }
- // Lock, Unlock, or Restore failed.
- return 0;
-}
-
-/***************************************************************************************/
-
-/**
-\brief handle control commands
-\param cmd command
-\param arg argument
-\return CONTROL_OK or CONTROL_UNKNOWN in case the command is not supported
-*/
-static int control(struct ao *ao, enum aocontrol cmd, void *arg)
-{
- struct priv *p = ao->priv;
- DWORD volume;
- switch (cmd) {
- case AOCONTROL_GET_VOLUME: {
- ao_control_vol_t *vol = (ao_control_vol_t *)arg;
- vol->left = vol->right = p->audio_volume;
- return CONTROL_OK;
- }
- case AOCONTROL_SET_VOLUME: {
- ao_control_vol_t *vol = (ao_control_vol_t *)arg;
- volume = p->audio_volume = vol->right;
- if (volume < 1)
- volume = 1;
- volume = (DWORD)(log10(volume) * 5000.0) - 10000;
- IDirectSoundBuffer_SetVolume(p->hdsbuf, volume);
- return CONTROL_OK;
- }
- case AOCONTROL_HAS_SOFT_VOLUME:
- return CONTROL_TRUE;
- }
- return CONTROL_UNKNOWN;
-}
-
-/**
-\brief setup sound device
-\param rate samplerate
-\param channels number of channels
-\param format format</