diff options
author | wm4 <wm4@nowhere> | 2012-11-05 17:02:04 +0100 |
---|---|---|
committer | wm4 <wm4@nowhere> | 2012-11-12 20:06:14 +0100 |
commit | d4bdd0473d6f43132257c9fb3848d829755167a3 (patch) | |
tree | 8021c2f7da1841393c8c832105e20cd527826d6c /libao2/ao_dsound.c | |
parent | bd48deba77bd5582c5829d6fe73a7d2571088aba (diff) | |
download | mpv-d4bdd0473d6f43132257c9fb3848d829755167a3.tar.bz2 mpv-d4bdd0473d6f43132257c9fb3848d829755167a3.tar.xz |
Rename directories, move files (step 1 of 2) (does not compile)
Tis drops the silly lib prefixes, and attempts to organize the tree in
a more logical way. Make the top-level directory less cluttered as
well.
Renames the following directories:
libaf -> audio/filter
libao2 -> audio/out
libvo -> video/out
libmpdemux -> demux
Split libmpcodecs:
vf* -> video/filter
vd*, dec_video.* -> video/decode
mp_image*, img_format*, ... -> video/
ad*, dec_audio.* -> audio/decode
libaf/format.* is moved to audio/ - this is similar to how mp_image.*
is located in video/.
Move most top-level .c/.h files to core. (talloc.c/.h is left on top-
level, because it's external.) Park some of the more annoying files
in compat/. Some of these are relicts from the time mplayer used
ffmpeg internals.
sub/ is not split, because it's too much of a mess (subtitle code is
mixed with OSD display and rendering).
Maybe the organization of core is not ideal: it mixes playback core
(like mplayer.c) and utility helpers (like bstr.c/h). Should the need
arise, the playback core will be moved somewhere else, while core
contains all helper and common code.
Diffstat (limited to 'libao2/ao_dsound.c')
-rw-r--r-- | libao2/ao_dsound.c | 648 |
1 files changed, 0 insertions, 648 deletions
diff --git a/libao2/ao_dsound.c b/libao2/ao_dsound.c deleted file mode 100644 index f2f44dd401..0000000000 --- a/libao2/ao_dsound.c +++ /dev/null @@ -1,648 +0,0 @@ -/* - * Windows DirectSound interface - * - * Copyright (c) 2004 Gabor Szecsi <deje@miki.hu> - * - * This file is part of MPlayer. - * - * MPlayer 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. - * - * MPlayer 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 MPlayer; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -/** -\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 "config.h" -#include "libaf/format.h" -#include "audio_out.h" -#include "audio_out_internal.h" -#include "mp_msg.h" -#include "osdep/timer.h" -#include "subopt-helper.h" - - -static const ao_info_t info = -{ - "Windows DirectSound audio output", - "dsound", - "Gabor Szecsi <deje@miki.hu>", - "" -}; - -LIBAO_EXTERN(dsound) - -/** -\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}}; - -#define SPEAKER_FRONT_LEFT 0x1 -#define SPEAKER_FRONT_RIGHT 0x2 -#define SPEAKER_FRONT_CENTER 0x4 -#define SPEAKER_LOW_FREQUENCY 0x8 -#define SPEAKER_BACK_LEFT 0x10 -#define SPEAKER_BACK_RIGHT 0x20 -#define SPEAKER_FRONT_LEFT_OF_CENTER 0x40 -#define SPEAKER_FRONT_RIGHT_OF_CENTER 0x80 -#define SPEAKER_BACK_CENTER 0x100 -#define SPEAKER_SIDE_LEFT 0x200 -#define SPEAKER_SIDE_RIGHT 0x400 -#define SPEAKER_TOP_CENTER 0x800 -#define SPEAKER_TOP_FRONT_LEFT 0x1000 -#define SPEAKER_TOP_FRONT_CENTER 0x2000 -#define SPEAKER_TOP_FRONT_RIGHT 0x4000 -#define SPEAKER_TOP_BACK_LEFT 0x8000 -#define SPEAKER_TOP_BACK_CENTER 0x10000 -#define SPEAKER_TOP_BACK_RIGHT 0x20000 -#define SPEAKER_RESERVED 0x80000000 - -#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 - -static const int channel_mask[] = { - SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_LOW_FREQUENCY, - SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT, - SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT | SPEAKER_LOW_FREQUENCY, - SPEAKER_FRONT_LEFT | SPEAKER_FRONT_CENTER | SPEAKER_FRONT_RIGHT | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT | SPEAKER_LOW_FREQUENCY -}; - -static HINSTANCE hdsound_dll = NULL; ///handle to the dll -static LPDIRECTSOUND hds = NULL; ///direct sound object -static LPDIRECTSOUNDBUFFER hdspribuf = NULL; ///primary direct sound buffer -static LPDIRECTSOUNDBUFFER hdsbuf = NULL; ///secondary direct sound buffer (stream buffer) -static int buffer_size = 0; ///size in bytes of the direct sound buffer -static int write_offset = 0; ///offset of the write cursor in the direct sound buffer -static int min_free_space = 0; ///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() -static int underrun_check = 0; ///0 or last reported free space (underrun detection) -static int device_num = 0; ///wanted device number -static GUID device; ///guid of the device -static int audio_volume; - -/***************************************************************************************/ - -/** -\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"; - default: return "unknown"; - } -} - -/** -\brief uninitialize direct sound -*/ -static void UninitDirectSound(void) -{ - // finally release the DirectSound object - if (hds) { - IDirectSound_Release(hds); - hds = NULL; - } - // free DSOUND.DLL - if (hdsound_dll) { - FreeLibrary(hdsound_dll); - hdsound_dll = NULL; - } - mp_msg(MSGT_AO, MSGL_V, "ao_dsound: DirectSound uninitialized\n"); -} - -/** -\brief print the commandline help -*/ -static void print_help(void) -{ - mp_msg(MSGT_AO, MSGL_FATAL, - "\n-ao dsound commandline help:\n" - "Example: mpv -ao dsound:device=1\n" - " sets 1st device\n" - "\nOptions:\n" - " device=<device-number>\n" - " Sets device number, use -v to get a list\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) -{ - int* device_index=context; - mp_msg(MSGT_AO, MSGL_V,"%i %s ",*device_index,desc); - if(device_num==*device_index){ - mp_msg(MSGT_AO, MSGL_V,"<--"); - if(guid){ - memcpy(&device,guid,sizeof(GUID)); - } - } - mp_msg(MSGT_AO, MSGL_V,"\n"); - (*device_index)++; - return TRUE; -} - - -/** -\brief initilize direct sound -\return 0 if error, 1 if ok -*/ -static int InitDirectSound(void) -{ - DSCAPS dscaps; - - // initialize directsound - HRESULT (WINAPI *OurDirectSoundCreate)(LPGUID, LPDIRECTSOUND *, LPUNKNOWN); - HRESULT (WINAPI *OurDirectSoundEnumerate)(LPDSENUMCALLBACKA, LPVOID); - int device_index=0; - const opt_t subopts[] = { - {"device", OPT_ARG_INT, &device_num,NULL}, - {NULL} - }; - if (subopt_parse(ao_subdevice, subopts) != 0) { - print_help(); - return 0; - } - - hdsound_dll = LoadLibrary("DSOUND.DLL"); - if (hdsound_dll == NULL) { - mp_msg(MSGT_AO, MSGL_ERR, "ao_dsound: cannot load DSOUND.DLL\n"); - return 0; - } - OurDirectSoundCreate = (void*)GetProcAddress(hdsound_dll, "DirectSoundCreate"); - OurDirectSoundEnumerate = (void*)GetProcAddress(hdsound_dll, "DirectSoundEnumerateA"); - - if (OurDirectSoundCreate == NULL || OurDirectSoundEnumerate == NULL) { - mp_msg(MSGT_AO, MSGL_ERR, "ao_dsound: GetProcAddress FAILED\n"); - FreeLibrary(hdsound_dll); - return 0; - } - - // Enumerate all directsound devices - mp_msg(MSGT_AO, MSGL_V,"ao_dsound: Output Devices:\n"); - OurDirectSoundEnumerate(DirectSoundEnum,&device_index); - - // Create the direct sound object - if FAILED(OurDirectSoundCreate((device_num)?&device:NULL, &hds, NULL )) { - mp_msg(MSGT_AO, MSGL_ERR, "ao_dsound: cannot create a DirectSound device\n"); - FreeLibrary(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 hearable 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(hds, GetDesktopWindow(), DSSCL_EXCLUSIVE)) { - mp_msg(MSGT_AO, MSGL_ERR, "ao_dsound: cannot set direct sound cooperative level\n"); - IDirectSound_Release(hds); - FreeLibrary(hdsound_dll); - return 0; - } - mp_msg(MSGT_AO, MSGL_V, "ao_dsound: DirectSound initialized\n"); - - memset(&dscaps, 0, sizeof(DSCAPS)); - dscaps.dwSize = sizeof(DSCAPS); - if (DS_OK == IDirectSound_GetCaps(hds, &dscaps)) { - if (dscaps.dwFlags & DSCAPS_EMULDRIVER) mp_msg(MSGT_AO, MSGL_V, "ao_dsound: DirectSound is emulated, waveOut may give better performance\n"); - } else { - mp_msg(MSGT_AO, MSGL_V, "ao_dsound: cannot get device capabilities\n"); - } - - return 1; -} - -/** -\brief destroy the direct sound buffer -*/ -static void DestroyBuffer(void) -{ - if (hdsbuf) { - IDirectSoundBuffer_Release(hdsbuf); - hdsbuf = NULL; - } - if (hdspribuf) { - IDirectSoundBuffer_Release(hdspribuf); - 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(unsigned char *data, int len) -{ - HRESULT res; - LPVOID lpvPtr1; - DWORD dwBytes1; - LPVOID lpvPtr2; - DWORD dwBytes2; - - underrun_check = 0; - - // Lock the buffer - res = IDirectSoundBuffer_Lock(hdsbuf,write_offset, len, &lpvPtr1, &dwBytes1, &lpvPtr2, &dwBytes2, 0); - // If the buffer was lost, restore and retry lock. - if (DSERR_BUFFERLOST == res) - { - IDirectSoundBuffer_Restore(hdsbuf); - res = IDirectSoundBuffer_Lock(hdsbuf,write_offset, len, &lpvPtr1, &dwBytes1, &lpvPtr2, &dwBytes2, 0); - } - - - if (SUCCEEDED(res)) - { - if( (ao_data.channels == 6) && !AF_FORMAT_IS_AC3(ao_data.format) ) { - // reorder channels while writing to pointers. - // it's this easy because buffer size and len are always - // aligned to multiples of channels*bytespersample - // there's probably some room for speed improvements here - const int chantable[6] = {0, 1, 4, 5, 2, 3}; // reorder "matrix" - int i, j; - int numsamp,sampsize; - - sampsize = af_fmt2bits(ao_data.format)>>3; // bytes per sample - numsamp = dwBytes1 / (ao_data.channels * sampsize); // number of samples for each channel in this buffer - - for( i = 0; i < numsamp; i++ ) for( j = 0; j < ao_data.channels; j++ ) { - memcpy((char*)lpvPtr1+(i*ao_data.channels*sampsize)+(chantable[j]*sampsize),data+(i*ao_data.channels*sampsize)+(j*sampsize),sampsize); - } - - if (NULL != lpvPtr2 ) - { - numsamp = dwBytes2 / (ao_data.channels * sampsize); - for( i = 0; i < numsamp; i++ ) for( j = 0; j < ao_data.channels; j++ ) { - memcpy((char*)lpvPtr2+(i*ao_data.channels*sampsize)+(chantable[j]*sampsize),data+dwBytes1+(i*ao_data.channels*sampsize)+(j*sampsize),sampsize); - } - } - - write_offset+=dwBytes1+dwBytes2; - if(write_offset>=buffer_size)write_offset=dwBytes2; - } else { - // Write to pointers without reordering. - memcpy(lpvPtr1,data,dwBytes1); - if (NULL != lpvPtr2 )memcpy(lpvPtr2,data+dwBytes1,dwBytes2); - write_offset+=dwBytes1+dwBytes2; - if(write_offset>=buffer_size)write_offset=dwBytes2; - } - - // Release the data back to DirectSound. - res = IDirectSoundBuffer_Unlock(hdsbuf,lpvPtr1,dwBytes1,lpvPtr2,dwBytes2); - if (SUCCEEDED(res)) - { - // Success. - DWORD status; - IDirectSoundBuffer_GetStatus(hdsbuf, &status); - if (!(status & DSBSTATUS_PLAYING)){ - res = IDirectSoundBuffer_Play(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 -1 in case the command can't be handled -*/ -static int control(int cmd, void *arg) -{ - DWORD volume; - switch (cmd) { - case AOCONTROL_GET_VOLUME: { - ao_control_vol_t* vol = (ao_control_vol_t*)arg; - vol->left = vol->right = audio_volume; - return CONTROL_OK; - } - case AOCONTROL_SET_VOLUME: { - ao_control_vol_t* vol = (ao_control_vol_t*)arg; - volume = audio_volume = vol->right; - if (volume < 1) - volume = 1; - volume = (DWORD)(log10(volume) * 5000.0) - 10000; - IDirectSoundBuffer_SetVolume(hdsbuf, volume); - return CONTROL_OK; - } - } - return -1; -} - -/** -\brief setup sound device -\param rate samplerate -\param channels number of channels -\param format format -\param flags unused -\return 1=success 0=fail -*/ -static int init(int rate, int channels, int format, int flags) -{ - int res; - if (!InitDirectSound()) return 0; - - global_ao->no_persistent_volume = true; - audio_volume = 100; - - // ok, now create the buffers - WAVEFORMATEXTENSIBLE wformat; - DSBUFFERDESC dsbpridesc; - DSBUFFERDESC dsbdesc; - - //check if the channel count and format is supported in general - if (channels > 6) { - UninitDirectSound(); - mp_msg(MSGT_AO, MSGL_ERR, "ao_dsound: 8 channel audio not yet supported\n"); - return 0; - } - - if (AF_FORMAT_IS_AC3(format)) - format = AF_FORMAT_AC3_NE; - switch(format){ - case AF_FORMAT_AC3_NE: - case AF_FORMAT_S24_LE: - case AF_FORMAT_S16_LE: - case AF_FORMAT_U8: - break; - default: - mp_msg(MSGT_AO, MSGL_V,"ao_dsound: format %s not supported defaulting to Signed 16-bit Little-Endian\n",af_fmt2str_short(format)); - format=AF_FORMAT_S16_LE; - } - //fill global ao_data - ao_data.channels = channels; - ao_data.samplerate = rate; - ao_data.format = format; - ao_data.bps = channels * rate * (af_fmt2bits(format)>>3); - if(ao_data.buffersize==-1) ao_data.buffersize = ao_data.bps; // space for 1 sec - mp_msg(MSGT_AO, MSGL_V,"ao_dsound: Samplerate:%iHz Channels:%i Format:%s\n", rate, channels, af_fmt2str_short(format)); - mp_msg(MSGT_AO, MSGL_V,"ao_dsound: Buffersize:%d bytes (%d msec)\n", ao_data.buffersize, ao_data.buffersize / ao_data.bps * 1000); - - //fill waveformatex - ZeroMemory(&wformat, sizeof(WAVEFORMATEXTENSIBLE)); - wformat.Format.cbSize = (channels > 2) ? sizeof(WAVEFORMATEXTENSIBLE)-sizeof(WAVEFORMATEX) : 0; - wformat.Format.nChannels = channels; - wformat.Format.nSamplesPerSec = rate; - if (AF_FORMAT_IS_AC3(format)) { - wformat.Format.wFormatTag = WAVE_FORMAT_DOLBY_AC3_SPDIF; - wformat.Format.wBitsPerSample = 16; - wformat.Format.nBlockAlign = 4; - } else { - wformat.Format.wFormatTag = (channels > 2) ? WAVE_FORMAT_EXTENSIBLE : WAVE_FORMAT_PCM; - wformat.Format.wBitsPerSample = af_fmt2bits(format); - wformat.Format.nBlockAlign = wformat.Format.nChannels * (wformat.Format.wBitsPerSample >> 3); - } - - // 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 (channels > 2) { - wformat.dwChannelMask = channel_mask[channels - 3]; - 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 = ao_data.buffersize; - dsbdesc.lpwfxFormat = (WAVEFORMATEX *)&wformat; - buffer_size = dsbdesc.dwBufferBytes; - write_offset = 0; - min_free_space = wformat.Format.nBlockAlign; - ao_data.outburst = wformat.Format.nBlockAlign * 512; - - // create primary buffer and set its format - - res = IDirectSound_CreateSoundBuffer( hds, &dsbpridesc, &hdspribuf, NULL ); - if ( res != DS_OK ) { - UninitDirectSound(); - mp_msg(MSGT_AO, MSGL_ERR,"ao_dsound: cannot create primary buffer (%s)\n", dserr2str(res)); - return 0; - } - res = IDirectSoundBuffer_SetFormat( hdspribuf, (WAVEFORMATEX *)&wformat ); - if ( res != DS_OK ) mp_msg(MSGT_AO, MSGL_WARN,"ao_dsound: cannot set primary buffer format (%s), using standard setting (bad quality)", dserr2str(res)); - - mp_msg(MSGT_AO, MSGL_V, "ao_dsound: primary buffer created\n"); - - // now create the stream buffer - - res = IDirectSound_CreateSoundBuffer(hds, &dsbdesc, &hdsbuf, NULL); - if (res != DS_OK) { - if (dsbdesc.dwFlags & DSBCAPS_LOCHARDWARE) { - // Try without DSBCAPS_LOCHARDWARE - dsbdesc.dwFlags &= ~DSBCAPS_LOCHARDWARE; - res = IDirectSound_CreateSoundBuffer(hds, &dsbdesc, &hdsbuf, NULL); - } - if (res != DS_OK) { - UninitDirectSound(); - mp_msg(MSGT_AO, MSGL_ERR, "ao_dsound: cannot create secondary (stream)buffer (%s)\n", dserr2str(res)); - return 0; - } - } - mp_msg(MSGT_AO, MSGL_V, "ao_dsound: secondary (stream)buffer created\n"); - return 1; -} - - - -/** -\brief stop playing and empty buffers (for seeking/pause) -*/ -static void reset(void) -{ - IDirectSoundBuffer_Stop(hdsbuf); - // reset directsound buffer - IDirectSoundBuffer_SetCurrentPosition(hdsbuf, 0); - write_offset=0; - underrun_check=0; -} - -/** -\brief stop playing, keep buffers (for pause) -*/ -static void audio_pause(void) -{ - IDirectSoundBuffer_Stop(hdsbuf); -} - -/** -\brief resume playing, after audio_pause() -*/ -static void audio_resume(void) -{ - IDirectSoundBuffer_Play(hdsbuf, 0, 0, DSBPLAY_LOOPING); -} - -/** -\brief close audio device -\param immed stop playback immediately -*/ -static void uninit(int immed) -{ - if (!immed) - usec_sleep(get_delay() * 1000000); - reset(); - - DestroyBuffer(); - UninitDirectSound(); -} - -// return exact number of free (safe to write) bytes -static int check_free_buffer_size(void) -{ - int space; - DWORD play_offset; - IDirectSoundBuffer_GetCurrentPosition(hdsbuf,&play_offset,NULL); - space=buffer_size-(write_offset-play_offset); - // | | <-- const --> | | | - // buffer start play_cursor write_cursor write_offset buffer end - // play_cursor is the actual postion of the play cursor - // write_cursor is the position after which it is assumed to be save to write data - // write_offset is the postion where we actually write the data to - if(space > buffer_size)space -= buffer_size; // write_offset < play_offset - // Check for buffer underruns. An underrun happens if DirectSound - // started to play old data beyond the current 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 < underrun_check) { - // there's no useful data in the buffers - space = buffer_size; - reset(); - } - 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(void) -{ - int space = check_free_buffer_size(); - if(space < min_free_space)return 0; - return space-min_free_space; -} - -/** -\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(void* data, int len, int flags) -{ - int space = check_free_buffer_size(); - if(space < len) len = space; - - if (!(flags & AOPLAY_FINAL_CHUNK)) - len = (len / ao_data.outburst) * ao_data.outburst; - return write_buffer(data, len); -} - -/** -\brief get the delay between the first and last sample in the buffer -\return delay in seconds -*/ -static float get_delay(void) -{ - int space = check_free_buffer_size(); - return (float)(buffer_size - space) / (float)ao_data.bps; -} |