From 3e90a5fe81229e4c0acd8e5afa8d59efaf942fa9 Mon Sep 17 00:00:00 2001 From: wm4 Date: Wed, 6 Jan 2016 13:48:43 +0100 Subject: ao_dsound: remove this audio output It existed for XP-compatibility only. There was also a time where ao_wasapi caused issues, but we're relatively confident that ao_wasapi works better or at least as good as ao_dsound on Windows Vista and later. --- audio/out/ao.c | 4 - audio/out/ao_dsound.c | 707 -------------------------------------------------- 2 files changed, 711 deletions(-) delete mode 100644 audio/out/ao_dsound.c (limited to 'audio') diff --git a/audio/out/ao.c b/audio/out/ao.c index daa9c306b5..c950b9e773 100644 --- a/audio/out/ao.c +++ b/audio/out/ao.c @@ -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_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 - * - * 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 . - */ - -/** -\todo verify/extend multichannel support -*/ - - -#include -#include -#include -#define DIRECTSOUND_VERSION 0x0600 -#include -#include - -#include -#include - -#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 -\param flags unused -\return 0=success -1=fail -*/ -static int init(struct ao *ao) -{ - struct priv *p = ao->priv; - int res; - - if (!InitDirectSound(ao)) - return -1; - - p->audio_volume = 100; - - // ok, now create the buffers - WAVEFORMATEXTENSIBLE wformat; - DSBUFFERDESC dsbpridesc; - DSBUFFERDESC dsbdesc; - int format = af_fmt_from_planar(ao->format); - int rate = ao->samplerate; - - if (!af_fmt_is_spdif(format)) { - struct mp_chmap_sel sel = {0}; - mp_chmap_sel_add_waveext(&sel); - if (!ao_chmap_sel_adjust(ao, &sel, &ao->channels)) - return -1; - } - switch (format) { - case AF_FORMAT_S24: - case AF_FORMAT_S16: - case AF_FORMAT_U8: - break; - default: - if (af_fmt_is_spdif(format)) - break; - MP_VERBOSE(ao, "format %s not supported defaulting to Signed 16-bit Little-Endian\n", - af_fmt_to_str(format)); - format = AF_FORMAT_S16; - } - //set our audio parameters - ao->samplerate = rate; - ao->format = format; - ao->bps = ao->channels.num * rate * af_fmt_to_bytes(format); - int buffersize = ao->bps * p->cfg_buffersize / 1000; - MP_VERBOSE(ao, "Samplerate:%iHz Channels:%i Format:%s\n", rate, - ao->channels.num, af_fmt_to_str(format)); - MP_VERBOSE(ao, "Buffersize:%d bytes (%f msec)\n", - buffersize, buffersize * 1000.0 / ao->bps); - - //fill waveformatex - ZeroMemory(&wformat, sizeof(WAVEFORMATEXTENSIBLE)); - wformat.Format.cbSize = (ao->channels.num > 2) - ? sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX) : 0; - wformat.Format.nChannels = ao->channels.num; - wformat.Format.nSamplesPerSec = rate; - if (af_fmt_is_spdif(format)) { - // Whether it also works with e.g. DTS is unknown, but probably does. - wformat.Format.wFormatTag = WAVE_FORMAT_DOLBY_AC3_SPDIF; - wformat.Format.wBitsPerSample = 16; - wformat.Format.nBlockAlign = 4; - } else { - wformat.Format.wFormatTag = (ao->channels.num > 2) - ? WAVE_FORMAT_EXTENSIBLE : WAVE_FORMAT_PCM; - int bps = af_fmt_to_bytes(format); - wformat.Format.wBitsPerSample = bps * 8; - wformat.Format.nBlockAlign = wformat.Format.nChannels * bps; - } - - // fill in primary sound buffer descriptor - memset(&dsbpridesc, 0, sizeof(DSBUFFERDESC)); - dsbpridesc.dwSize = sizeof(DSBUFFERDESC); - dsbpridesc.dwFlags = DSBCAPS_PRIMARYBUFFER; - dsbpridesc.dwBufferBytes = 0; - dsbpridesc.lpwfxFormat = NULL; - - // fill in the secondary sound buffer (=stream buffer) descriptor - memset(&dsbdesc, 0, sizeof(DSBUFFERDESC)); - dsbdesc.dwSize = sizeof(DSBUFFERDESC); - dsbdesc.dwFlags = DSBCAPS_GETCURRENTPOSITION2 /** Better position accuracy */ - | DSBCAPS_GLOBALFOCUS /** Allows background playing */ - | DSBCAPS_CTRLVOLUME; /** volume control enabled */ - - if (ao->channels.num > 2) { - wformat.dwChannelMask = mp_chmap_to_waveext(&ao->channels); - wformat.SubFormat = KSDATAFORMAT_SUBTYPE_PCM; - wformat.Samples.wValidBitsPerSample = wformat.Format.wBitsPerSample; - // Needed for 5.1 on emu101k - shit soundblaster - dsbdesc.dwFlags |= DSBCAPS_LOCHARDWARE; - } - wformat.Format.nAvgBytesPerSec = wformat.Format.nSamplesPerSec * - wformat.Format.nBlockAlign; - - dsbdesc.dwBufferBytes = buffersize; - dsbdesc.lpwfxFormat = (WAVEFORMATEX *)&wformat; - p->buffer_size = dsbdesc.dwBufferBytes; - p->write_offset = 0; - p->min_free_space = wformat.Format.nBlockAlign; - p->outburst = wformat.Format.nBlockAlign * 512; - - // create primary buffer and set its format - - res = IDirectSound_CreateSoundBuffer(p->hds, &dsbpridesc, &p->hdspribuf, NULL); - if (res != DS_OK) { - UninitDirectSound(ao); - MP_ERR(ao, "cannot create primary buffer (%s)\n", dserr2str(res)); - return -1; - } - res = IDirectSoundBuffer_SetFormat(p->hdspribuf, (WAVEFORMATEX *)&wformat); - if (res != DS_OK) { - MP_WARN(ao, "cannot set primary buffer format (%s), using " - "standard setting (bad quality)", dserr2str(res)); - } - - MP_VERBOSE(ao, "primary buffer created\n"); - - // now create the stream buffer - - res = IDirectSound_CreateSoundBuffer(p->hds, &dsbdesc, &p->hdsbuf, NULL); - if (res != DS_OK) { - if (dsbdesc.dwFlags & DSBCAPS_LOCHARDWARE) { - // Try without DSBCAPS_LOCHARDWARE - dsbdesc.dwFlags &= ~DSBCAPS_LOCHARDWARE; - res = IDirectSound_CreateSoundBuffer(p->hds, &dsbdesc, &p->hdsbuf, NULL); - } - if (res != DS_OK) { - UninitDirectSound(ao); - MP_ERR(ao, "cannot create secondary (stream)buffer (%s)\n", - dserr2str(res)); - return -1; - } - } - MP_VERBOSE(ao, "secondary (stream)buffer created\n"); - return 0; -} - - - -/** -\brief stop playing and empty buffers (for seeking/pause) -*/ -static void reset(struct ao *ao) -{ - struct priv *p = ao->priv; - - IDirectSoundBuffer_Stop(p->hdsbuf); - // reset directsound buffer - IDirectSoundBuffer_SetCurrentPosition(p->hdsbuf, 0); - p->write_offset = 0; - p->underrun_check = 0; -} - -/** -\brief stop playing, keep buffers (for pause) -*/ -static void audio_pause(struct ao *ao) -{ - struct priv *p = ao->priv; - - IDirectSoundBuffer_Stop(p->hdsbuf); -} - -/** -\brief resume playing, after audio_pause() -*/ -static void audio_resume(struct ao *ao) -{ - struct priv *p = ao->priv; - - IDirectSoundBuffer_Play(p->hdsbuf, 0, 0, DSBPLAY_LOOPING); -} - -/** -\brief close audio device -\param immed stop playback immediately -*/ -static void uninit(struct ao *ao) -{ - reset(ao); - - DestroyBuffer(ao); - UninitDirectSound(ao); -} - -// return exact number of free (safe to write) bytes -static int check_free_buffer_size(struct ao *ao) -{ - struct priv *p = ao->priv; - int space; - DWORD play_offset; - IDirectSoundBuffer_GetCurrentPosition(p->hdsbuf, &play_offset, NULL); - space = p->buffer_size - (p->write_offset - play_offset); - // | | <-- const --> | | | - // buffer start play_cursor write_cursor p->write_offset buffer end - // play_cursor is the actual position of the play cursor - // write_cursor is the position after which it is assumed to be save to write data - // p->write_offset is the position where we actually write the data to - if (space > p->buffer_size) - space -= p->buffer_size; // p->write_offset < play_offset - // Check for buffer underruns. An underrun happens if DirectSound - // started to play old data beyond the current p->write_offset. Detect this - // by checking whether the free space shrinks, even though no data was - // written (i.e. no write_buffer). Doesn't always work, but the only - // reason we need this is to deal with the situation when playback ends, - // and the buffer is only half-filled. - if (space < p->underrun_check) { - // there's no useful data in the buffers - space = p->buffer_size; - reset(ao); - } - p->underrun_check = space; - return space; -} - -/** - \brief find out how many bytes can be written into the audio buffer without - \return free space in bytes, has to return 0 if the buffer is almost full - */ -static int get_space(struct ao *ao) -{ - struct priv *p = ao->priv; - - int space = check_free_buffer_size(ao); - if (space < p->min_free_space) - return 0; - return (space - p->min_free_space) / p->outburst * p->outburst / ao->sstride; -} - -/** -\brief play 'len' bytes of 'data' -\param data pointer to the data to play -\param len size in bytes of the data buffer, gets rounded down to outburst*n -\param flags currently unused -\return number of played bytes -*/ -static int play(struct ao *ao, void **data, int samples, int flags) -{ - struct priv *p = ao->priv; - int len = samples * ao->sstride; - - int space = check_free_buffer_size(ao); - if (space < len) - len = space; - - if (!(flags & AOPLAY_FINAL_CHUNK)) - len = (len / p->outburst) * p->outburst; - return write_buffer(ao, data[0], len) / ao->sstride; -} - -/** -\brief get the delay between the first and last sample in the buffer -\return delay in seconds -*/ -static double get_delay(struct ao *ao) -{ - struct priv *p = ao->priv; - - int space = check_free_buffer_size(ao); - return (p->buffer_size - space) / (double)ao->bps; -} - -#define OPT_BASE_STRUCT struct priv - -const struct ao_driver audio_out_dsound = { - .description = "Windows DirectSound audio output", - .name = "dsound", - .init = init, - .uninit = uninit, - .control = control, - .get_space = get_space, - .play = play, - .get_delay = get_delay, - .pause = audio_pause, - .resume = audio_resume, - .reset = reset, - .list_devs = list_devs, - .priv_size = sizeof(struct priv), - .options = (const struct m_option[]) { - OPT_INT("device", cfg_device, 0, OPTDEF_INT(-1)), - OPT_INTRANGE("buffersize", cfg_buffersize, 0, 1, 10000, OPTDEF_INT(200)), - {0} - }, -}; -- cgit v1.2.3