mirror of
https://github.com/mpv-player/mpv
synced 2025-04-17 20:58:20 +00:00
directsound audio output plugin, patch by Gabor Szecsi <deje at miki.hu> some minor modifications by me
git-svn-id: svn://svn.mplayerhq.hu/mplayer/trunk@13461 b3059339-0415-0410-9bf9-f77b7e298cf2
This commit is contained in:
parent
ed19d7f62d
commit
b8c0aed043
4
configure
vendored
4
configure
vendored
@ -4025,6 +4025,7 @@ if test "$_directx" = auto ; then
|
||||
cat > $TMPC << EOF
|
||||
#include <windows.h>
|
||||
#include <ddraw.h>
|
||||
#include <dsound.h>
|
||||
int main(void) { return 0; }
|
||||
EOF
|
||||
_directx=no
|
||||
@ -4035,9 +4036,12 @@ if test "$_directx" = yes ; then
|
||||
_ld_win32libs="-lgdi32 $_ld_win32libs"
|
||||
_vosrc="$_vosrc vo_directx.c"
|
||||
_vomodules="directx $_vomodules"
|
||||
_aosrc="$_aosrc ao_dsound.c"
|
||||
_aomodules="dsound $_aomodules"
|
||||
else
|
||||
_def_directx='#undef HAVE_DIRECTX'
|
||||
_novomodules="directx $_novomodules"
|
||||
_noaomodules="dsound $_noaomodules"
|
||||
fi
|
||||
echores "$_directx"
|
||||
|
||||
|
489
libao2/ao_dsound.c
Normal file
489
libao2/ao_dsound.c
Normal file
@ -0,0 +1,489 @@
|
||||
/******************************************************************************
|
||||
* ao_dsound.c: Windows DirectSound interface for MPlayer
|
||||
* Copyright (c) 2004 Gabor Szecsi <deje@miki.hu>
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
|
||||
*
|
||||
*****************************************************************************/
|
||||
/**
|
||||
\todo verify/extend multichannel support
|
||||
*/
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <windows.h>
|
||||
#include <mmsystem.h>
|
||||
#include <dsound.h>
|
||||
|
||||
#include "afmt.h"
|
||||
#include "audio_out.h"
|
||||
#include "audio_out_internal.h"
|
||||
#include "../mp_msg.h"
|
||||
#include "../libvo/fastmemcpy.h"
|
||||
#include "osdep/timer.h"
|
||||
|
||||
|
||||
static 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
|
||||
*/
|
||||
#if 1
|
||||
#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
|
||||
|
||||
#define DSSPEAKER_HEADPHONE 0x00000001
|
||||
#define DSSPEAKER_MONO 0x00000002
|
||||
#define DSSPEAKER_QUAD 0x00000003
|
||||
#define DSSPEAKER_STEREO 0x00000004
|
||||
#define DSSPEAKER_SURROUND 0x00000005
|
||||
#define DSSPEAKER_5POINT1 0x00000006
|
||||
|
||||
#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
|
||||
|
||||
#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 hdsbuf = NULL; ///direct sound 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 = 4096; ///if the free space is below this value get_space() will return 0
|
||||
|
||||
#define BUFFERSIZE 32767 /// in samples - at 48khz 0.6 sec buffer, gets multiplied with nBlockAlign
|
||||
|
||||
/***************************************************************************************/
|
||||
|
||||
/**
|
||||
\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 initilize direct sound
|
||||
\return 0 if error, 1 if ok
|
||||
*/
|
||||
static int InitDirectSound(void)
|
||||
{
|
||||
DSCAPS dscaps;
|
||||
|
||||
// initialize directsound
|
||||
HRESULT (WINAPI *OurDirectSoundCreate)(LPGUID, LPDIRECTSOUND *, LPUNKNOWN);
|
||||
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");
|
||||
|
||||
if (OurDirectSoundCreate == NULL) {
|
||||
mp_msg(MSGT_AO, MSGL_ERR, "ao_dsound: GetProcAddress FAILED\n");
|
||||
FreeLibrary(hdsound_dll);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Create the direct sound object
|
||||
if FAILED(OurDirectSoundCreate(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;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
\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;
|
||||
|
||||
// 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))
|
||||
{
|
||||
// Write to pointers.
|
||||
memcpy(lpvPtr1,data,dwBytes1);
|
||||
if (NULL != lpvPtr2 )memcpy(lpvPtr2,data+dwBytes1,dwBytes2);
|
||||
write_offset+=dwBytes1+dwBytes2;
|
||||
if(write_offset>=buffer_size)write_offset-=buffer_size;
|
||||
|
||||
// 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;
|
||||
IDirectSoundBuffer_GetVolume(hdsbuf, &volume);
|
||||
vol->left = vol->right = (float)(volume+10000) / 100.0;
|
||||
//printf("ao_dsound: volume: %f\n",vol->left);
|
||||
return CONTROL_OK;
|
||||
}
|
||||
case AOCONTROL_SET_VOLUME: {
|
||||
ao_control_vol_t* vol = (ao_control_vol_t*)arg;
|
||||
volume = (vol->right * 100.0)-10000;
|
||||
IDirectSoundBuffer_SetVolume(hdsbuf, volume);
|
||||
//printf("ao_dsound: volume: %f\n",vol->left);
|
||||
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;
|
||||
|
||||
// ok, now create the primary buffer
|
||||
WAVEFORMATEXTENSIBLE wformat;
|
||||
DSBUFFERDESC dsbdesc;
|
||||
|
||||
//fill global ao_data
|
||||
ao_data.channels = channels;
|
||||
ao_data.samplerate = rate;
|
||||
ao_data.format = format;
|
||||
ao_data.bps = channels * rate * (audio_out_format_bits(format)>>3);
|
||||
if(ao_data.buffersize==-1)
|
||||
{
|
||||
ao_data.buffersize = audio_out_format_bits(format) >> 3;
|
||||
ao_data.buffersize *= channels;
|
||||
ao_data.buffersize *= BUFFERSIZE;
|
||||
}
|
||||
mp_msg(MSGT_AO, MSGL_V,"ao_dsound: Samplerate:%iHz Channels:%i Format:%s\n", rate, channels, audio_out_format_name(format));
|
||||
mp_msg(MSGT_AO, MSGL_V,"ao_dsound: Buffersize:%d bytes (%d msec)\n", ao_data.buffersize, BUFFERSIZE * 1000 / rate);
|
||||
|
||||
//fill waveformatex
|
||||
ZeroMemory(&wformat, sizeof(WAVEFORMATEXTENSIBLE));
|
||||
wformat.Format.cbSize = (channels > 2) ? sizeof(WAVEFORMATEXTENSIBLE) : 0;
|
||||
wformat.Format.nChannels = channels;
|
||||
wformat.Format.nSamplesPerSec = rate;
|
||||
if (format == AFMT_AC3) {
|
||||
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 = audio_out_format_bits(format);
|
||||
wformat.Format.nBlockAlign = wformat.Format.nChannels * (wformat.Format.wBitsPerSample >> 3);
|
||||
}
|
||||
|
||||
// fill in the direct sound 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 = audio_out_format_bits(format);
|
||||
// Needed for 5.1 on emu101k - shit soundblaster
|
||||
dsbdesc.dwFlags |= DSBCAPS_LOCHARDWARE;
|
||||
}
|
||||
wformat.Format.nAvgBytesPerSec = wformat.Format.nSamplesPerSec * wformat.Format.nBlockAlign;
|
||||
|
||||
dsbdesc.dwBufferBytes = wformat.Format.nBlockAlign * BUFFERSIZE;
|
||||
dsbdesc.lpwfxFormat = (WAVEFORMATEX *)&wformat;
|
||||
buffer_size = dsbdesc.dwBufferBytes;
|
||||
ao_data.outburst = wformat.Format.nBlockAlign * 512;
|
||||
|
||||
// now create the sound 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 buffer (%s)\n", dserr2str(res));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
mp_msg(MSGT_AO, MSGL_V, "ao_dsound: secondary buffer created\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
\brief stop playing and empty buffers (for seeking/pause)
|
||||
*/
|
||||
static void reset()
|
||||
{
|
||||
IDirectSoundBuffer_Stop(hdsbuf);
|
||||
// reset directsound buffer
|
||||
IDirectSoundBuffer_SetCurrentPosition(hdsbuf, 0);
|
||||
write_offset=0;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief stop playing, keep buffers (for pause)
|
||||
*/
|
||||
static void audio_pause()
|
||||
{
|
||||
IDirectSoundBuffer_Stop(hdsbuf);
|
||||
}
|
||||
|
||||
/**
|
||||
\brief resume playing, after audio_pause()
|
||||
*/
|
||||
static void audio_resume()
|
||||
{
|
||||
IDirectSoundBuffer_Play(hdsbuf, 0, 0, DSBPLAY_LOOPING);
|
||||
}
|
||||
|
||||
/**
|
||||
\brief close audio device
|
||||
\param immed stop playback immediately, currently not supported
|
||||
*/
|
||||
static void uninit(int immed)
|
||||
{
|
||||
reset();
|
||||
DestroyBuffer();
|
||||
UninitDirectSound();
|
||||
}
|
||||
|
||||
/**
|
||||
\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()
|
||||
{
|
||||
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
|
||||
if(space < min_free_space)return 0;
|
||||
return 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)
|
||||
{
|
||||
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()
|
||||
{
|
||||
DWORD play_offset;
|
||||
int space;
|
||||
IDirectSoundBuffer_GetCurrentPosition(hdsbuf,&play_offset,NULL);
|
||||
space=play_offset-write_offset;
|
||||
if(space <= 0)space += buffer_size;
|
||||
return (float)(buffer_size - space) / (float)ao_data.bps;
|
||||
}
|
@ -53,6 +53,9 @@ extern ao_functions_t audio_out_sgi;
|
||||
#ifdef HAVE_WIN32WAVEOUT
|
||||
extern ao_functions_t audio_out_win32;
|
||||
#endif
|
||||
#ifdef HAVE_DIRECTX
|
||||
extern ao_functions_t audio_out_dsound;
|
||||
#endif
|
||||
#ifdef HAVE_DXR2
|
||||
extern ao_functions_t audio_out_dxr2;
|
||||
#endif
|
||||
@ -69,6 +72,9 @@ ao_functions_t* audio_out_drivers[] =
|
||||
&audio_out_dxr2,
|
||||
#endif
|
||||
// native:
|
||||
#ifdef HAVE_DIRECTX
|
||||
&audio_out_dsound,
|
||||
#endif
|
||||
#ifdef HAVE_WIN32WAVEOUT
|
||||
&audio_out_win32,
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user