diff options
Diffstat (limited to 'audio')
-rw-r--r-- | audio/audio.c | 2 | ||||
-rw-r--r-- | audio/chmap_sel.c | 22 | ||||
-rw-r--r-- | audio/decode/ad_lavc.c | 33 | ||||
-rw-r--r-- | audio/decode/dec_audio.c | 17 | ||||
-rw-r--r-- | audio/decode/dec_audio.h | 2 | ||||
-rw-r--r-- | audio/mixer.c | 15 | ||||
-rw-r--r-- | audio/out/ao.c | 6 | ||||
-rw-r--r-- | audio/out/ao_coreaudio.c | 8 | ||||
-rw-r--r-- | audio/out/ao_coreaudio_properties.c | 2 | ||||
-rw-r--r-- | audio/out/ao_coreaudio_utils.c | 31 | ||||
-rw-r--r-- | audio/out/ao_coreaudio_utils.h | 3 | ||||
-rw-r--r-- | audio/out/ao_dsound.c | 707 | ||||
-rw-r--r-- | audio/out/ao_lavc.c | 2 | ||||
-rw-r--r-- | audio/out/ao_null.c | 2 | ||||
-rw-r--r-- | audio/out/ao_pcm.c | 2 | ||||
-rw-r--r-- | audio/out/ao_pulse.c | 55 | ||||
-rw-r--r-- | audio/out/ao_rsound.c | 2 | ||||
-rw-r--r-- | audio/out/ao_sdl.c | 2 | ||||
-rw-r--r-- | audio/out/ao_wasapi.c | 292 | ||||
-rw-r--r--[-rwxr-xr-x] | audio/out/ao_wasapi.h | 112 | ||||
-rw-r--r--[-rwxr-xr-x] | audio/out/ao_wasapi_changenotify.c | 62 | ||||
-rw-r--r--[-rwxr-xr-x] | audio/out/ao_wasapi_utils.c | 807 | ||||
-rwxr-xr-x | audio/out/ao_wasapi_utils.h | 49 | ||||
-rw-r--r-- | audio/out/pull.c | 2 |
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 |