1
0
mirror of https://github.com/mpv-player/mpv synced 2025-04-01 23:00:41 +00:00

ao_dsound: uncrustify

This commit is contained in:
wm4 2013-06-04 00:51:07 +02:00
parent 92ae48db0f
commit cee56e8623

View File

@ -47,10 +47,10 @@
static const ao_info_t info = static const ao_info_t info =
{ {
"Windows DirectSound audio output", "Windows DirectSound audio output",
"dsound", "dsound",
"Gabor Szecsi <deje@miki.hu>", "Gabor Szecsi <deje@miki.hu>",
"" ""
}; };
LIBAO_EXTERN(dsound) LIBAO_EXTERN(dsound)
@ -62,7 +62,9 @@ LIBAO_EXTERN(dsound)
#define WAVE_FORMAT_DOLBY_AC3_SPDIF 0x0092 #define WAVE_FORMAT_DOLBY_AC3_SPDIF 0x0092
#define WAVE_FORMAT_EXTENSIBLE 0xFFFE #define WAVE_FORMAT_EXTENSIBLE 0xFFFE
static const GUID KSDATAFORMAT_SUBTYPE_PCM = {0x1,0x0000,0x0010, {0x80,0x00,0x00,0xaa,0x00,0x38,0x9b,0x71}}; static const GUID KSDATAFORMAT_SUBTYPE_PCM = {
0x1, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
};
#if 0 #if 0
#define DSSPEAKER_HEADPHONE 0x00000001 #define DSSPEAKER_HEADPHONE 0x00000001
@ -75,15 +77,15 @@ static const GUID KSDATAFORMAT_SUBTYPE_PCM = {0x1,0x0000,0x0010, {0x80,0x00,0x00
#ifndef _WAVEFORMATEXTENSIBLE_ #ifndef _WAVEFORMATEXTENSIBLE_
typedef struct { typedef struct {
WAVEFORMATEX Format; WAVEFORMATEX Format;
union { union {
WORD wValidBitsPerSample; /* bits of precision */ WORD wValidBitsPerSample; /* bits of precision */
WORD wSamplesPerBlock; /* valid if wBitsPerSample==0 */ WORD wSamplesPerBlock; /* valid if wBitsPerSample==0 */
WORD wReserved; /* If neither applies, set to zero. */ WORD wReserved; /* If neither applies, set to zero. */
} Samples; } Samples;
DWORD dwChannelMask; /* which channels are */ DWORD dwChannelMask; /* which channels are */
/* present in stream */ /* present in stream */
GUID SubFormat; GUID SubFormat;
} WAVEFORMATEXTENSIBLE, *PWAVEFORMATEXTENSIBLE; } WAVEFORMATEXTENSIBLE, *PWAVEFORMATEXTENSIBLE;
#endif #endif
@ -111,28 +113,28 @@ static int audio_volume;
*/ */
static char * dserr2str(int err) static char * dserr2str(int err)
{ {
switch (err) { switch (err) {
case DS_OK: return "DS_OK"; case DS_OK: return "DS_OK";
case DS_NO_VIRTUALIZATION: return "DS_NO_VIRTUALIZATION"; case DS_NO_VIRTUALIZATION: return "DS_NO_VIRTUALIZATION";
case DSERR_ALLOCATED: return "DS_NO_VIRTUALIZATION"; case DSERR_ALLOCATED: return "DS_NO_VIRTUALIZATION";
case DSERR_CONTROLUNAVAIL: return "DSERR_CONTROLUNAVAIL"; case DSERR_CONTROLUNAVAIL: return "DSERR_CONTROLUNAVAIL";
case DSERR_INVALIDPARAM: return "DSERR_INVALIDPARAM"; case DSERR_INVALIDPARAM: return "DSERR_INVALIDPARAM";
case DSERR_INVALIDCALL: return "DSERR_INVALIDCALL"; case DSERR_INVALIDCALL: return "DSERR_INVALIDCALL";
case DSERR_GENERIC: return "DSERR_GENERIC"; case DSERR_GENERIC: return "DSERR_GENERIC";
case DSERR_PRIOLEVELNEEDED: return "DSERR_PRIOLEVELNEEDED"; case DSERR_PRIOLEVELNEEDED: return "DSERR_PRIOLEVELNEEDED";
case DSERR_OUTOFMEMORY: return "DSERR_OUTOFMEMORY"; case DSERR_OUTOFMEMORY: return "DSERR_OUTOFMEMORY";
case DSERR_BADFORMAT: return "DSERR_BADFORMAT"; case DSERR_BADFORMAT: return "DSERR_BADFORMAT";
case DSERR_UNSUPPORTED: return "DSERR_UNSUPPORTED"; case DSERR_UNSUPPORTED: return "DSERR_UNSUPPORTED";
case DSERR_NODRIVER: return "DSERR_NODRIVER"; case DSERR_NODRIVER: return "DSERR_NODRIVER";
case DSERR_ALREADYINITIALIZED: return "DSERR_ALREADYINITIALIZED"; case DSERR_ALREADYINITIALIZED: return "DSERR_ALREADYINITIALIZED";
case DSERR_NOAGGREGATION: return "DSERR_NOAGGREGATION"; case DSERR_NOAGGREGATION: return "DSERR_NOAGGREGATION";
case DSERR_BUFFERLOST: return "DSERR_BUFFERLOST"; case DSERR_BUFFERLOST: return "DSERR_BUFFERLOST";
case DSERR_OTHERAPPHASPRIO: return "DSERR_OTHERAPPHASPRIO"; case DSERR_OTHERAPPHASPRIO: return "DSERR_OTHERAPPHASPRIO";
case DSERR_UNINITIALIZED: return "DSERR_UNINITIALIZED"; case DSERR_UNINITIALIZED: return "DSERR_UNINITIALIZED";
case DSERR_NOINTERFACE: return "DSERR_NOINTERFACE"; case DSERR_NOINTERFACE: return "DSERR_NOINTERFACE";
case DSERR_ACCESSDENIED: return "DSERR_ACCESSDENIED"; case DSERR_ACCESSDENIED: return "DSERR_ACCESSDENIED";
default: return "unknown"; }
} return "unknown";
} }
/** /**
@ -142,15 +144,15 @@ static void UninitDirectSound(void)
{ {
// finally release the DirectSound object // finally release the DirectSound object
if (hds) { if (hds) {
IDirectSound_Release(hds); IDirectSound_Release(hds);
hds = NULL; hds = NULL;
} }
// free DSOUND.DLL // free DSOUND.DLL
if (hdsound_dll) { if (hdsound_dll) {
FreeLibrary(hdsound_dll); FreeLibrary(hdsound_dll);
hdsound_dll = NULL; hdsound_dll = NULL;
} }
mp_msg(MSGT_AO, MSGL_V, "ao_dsound: DirectSound uninitialized\n"); mp_msg(MSGT_AO, MSGL_V, "ao_dsound: DirectSound uninitialized\n");
} }
/** /**
@ -158,7 +160,7 @@ static void UninitDirectSound(void)
*/ */
static void print_help(void) static void print_help(void)
{ {
mp_msg(MSGT_AO, MSGL_FATAL, mp_msg(MSGT_AO, MSGL_FATAL,
"\n-ao dsound commandline help:\n" "\n-ao dsound commandline help:\n"
"Example: mpv -ao dsound:device=1\n" "Example: mpv -ao dsound:device=1\n"
" sets 1st device\n" " sets 1st device\n"
@ -172,17 +174,17 @@ static void print_help(void)
\brief enumerate direct sound devices \brief enumerate direct sound devices
\return TRUE to continue with the enumeration \return TRUE to continue with the enumeration
*/ */
static BOOL CALLBACK DirectSoundEnum(LPGUID guid,LPCSTR desc,LPCSTR module,LPVOID context) static BOOL CALLBACK DirectSoundEnum(LPGUID guid, LPCSTR desc, LPCSTR module,
LPVOID context)
{ {
int* device_index=context; int *device_index = context;
mp_msg(MSGT_AO, MSGL_V,"%i %s ",*device_index,desc); mp_msg(MSGT_AO, MSGL_V, "%i %s ", *device_index, desc);
if(device_num==*device_index){ if (device_num == *device_index) {
mp_msg(MSGT_AO, MSGL_V,"<--"); mp_msg(MSGT_AO, MSGL_V, "<--");
if(guid){ if (guid)
memcpy(&device,guid,sizeof(GUID)); memcpy(&device, guid, sizeof(GUID));
}
} }
mp_msg(MSGT_AO, MSGL_V,"\n"); mp_msg(MSGT_AO, MSGL_V, "\n");
(*device_index)++; (*device_index)++;
return TRUE; return TRUE;
} }
@ -194,73 +196,83 @@ static BOOL CALLBACK DirectSoundEnum(LPGUID guid,LPCSTR desc,LPCSTR module,LPVOI
*/ */
static int InitDirectSound(void) static int InitDirectSound(void)
{ {
DSCAPS dscaps; DSCAPS dscaps;
// initialize directsound // initialize directsound
HRESULT (WINAPI *OurDirectSoundCreate)(LPGUID, LPDIRECTSOUND *, LPUNKNOWN); HRESULT (WINAPI *OurDirectSoundCreate)(LPGUID, LPDIRECTSOUND *, LPUNKNOWN);
HRESULT (WINAPI *OurDirectSoundEnumerate)(LPDSENUMCALLBACKA, LPVOID); HRESULT (WINAPI *OurDirectSoundEnumerate)(LPDSENUMCALLBACKA, LPVOID);
int device_index=0; int device_index = 0;
const opt_t subopts[] = { const opt_t subopts[] = {
{"device", OPT_ARG_INT, &device_num,NULL}, {"device", OPT_ARG_INT, &device_num, NULL},
{NULL} {NULL}
}; };
if (subopt_parse(ao_subdevice, subopts) != 0) { if (subopt_parse(ao_subdevice, subopts) != 0) {
print_help(); print_help();
return 0; return 0;
} }
hdsound_dll = LoadLibrary("DSOUND.DLL"); hdsound_dll = LoadLibrary("DSOUND.DLL");
if (hdsound_dll == NULL) { if (hdsound_dll == NULL) {
mp_msg(MSGT_AO, MSGL_ERR, "ao_dsound: cannot load DSOUND.DLL\n"); mp_msg(MSGT_AO, MSGL_ERR, "ao_dsound: cannot load DSOUND.DLL\n");
return 0; return 0;
} }
OurDirectSoundCreate = (void*)GetProcAddress(hdsound_dll, "DirectSoundCreate"); OurDirectSoundCreate = (void *)GetProcAddress(hdsound_dll,
OurDirectSoundEnumerate = (void*)GetProcAddress(hdsound_dll, "DirectSoundEnumerateA"); "DirectSoundCreate");
OurDirectSoundEnumerate = (void *)GetProcAddress(hdsound_dll,
"DirectSoundEnumerateA");
if (OurDirectSoundCreate == NULL || OurDirectSoundEnumerate == NULL) { if (OurDirectSoundCreate == NULL || OurDirectSoundEnumerate == NULL) {
mp_msg(MSGT_AO, MSGL_ERR, "ao_dsound: GetProcAddress FAILED\n"); mp_msg(MSGT_AO, MSGL_ERR, "ao_dsound: GetProcAddress FAILED\n");
FreeLibrary(hdsound_dll); FreeLibrary(hdsound_dll);
return 0; return 0;
} }
// Enumerate all directsound devices // Enumerate all directsound devices
mp_msg(MSGT_AO, MSGL_V,"ao_dsound: Output Devices:\n"); mp_msg(MSGT_AO, MSGL_V, "ao_dsound: Output Devices:\n");
OurDirectSoundEnumerate(DirectSoundEnum,&device_index); OurDirectSoundEnumerate(DirectSoundEnum, &device_index);
// Create the direct sound object // Create the direct sound object
if FAILED(OurDirectSoundCreate((device_num)?&device:NULL, &hds, NULL )) { if (FAILED(OurDirectSoundCreate((device_num) ? &device : NULL, &hds,
mp_msg(MSGT_AO, MSGL_ERR, "ao_dsound: cannot create a DirectSound device\n"); NULL)))
FreeLibrary(hdsound_dll); {
return 0; 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 /* Set DirectSound Cooperative level, ie what control we want over Windows
* sound device. In our case, DSSCL_EXCLUSIVE means that we can modify the * 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 * settings of the primary buffer, but also that only the sound of our
* application will be hearable when it will have the focus. * application will be hearable when it will have the focus.
* !!! (this is not really working as intended yet because to set the * !!! (this is not really working as intended yet because to set the
* cooperative level you need the window handle of your application, and * 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 * 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 ??? * 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 * The hack for now is to use the Desktop window handle - it seems to be
* working */ * working */
if (IDirectSound_SetCooperativeLevel(hds, GetDesktopWindow(), DSSCL_EXCLUSIVE)) { if (IDirectSound_SetCooperativeLevel(hds, GetDesktopWindow(),
mp_msg(MSGT_AO, MSGL_ERR, "ao_dsound: cannot set direct sound cooperative level\n"); DSSCL_EXCLUSIVE))
IDirectSound_Release(hds); {
FreeLibrary(hdsound_dll); mp_msg(MSGT_AO, MSGL_ERR,
return 0; "ao_dsound: cannot set direct sound cooperative level\n");
} IDirectSound_Release(hds);
mp_msg(MSGT_AO, MSGL_V, "ao_dsound: DirectSound initialized\n"); FreeLibrary(hdsound_dll);
return 0;
}
mp_msg(MSGT_AO, MSGL_V, "ao_dsound: DirectSound initialized\n");
memset(&dscaps, 0, sizeof(DSCAPS)); memset(&dscaps, 0, sizeof(DSCAPS));
dscaps.dwSize = sizeof(DSCAPS); dscaps.dwSize = sizeof(DSCAPS);
if (DS_OK == IDirectSound_GetCaps(hds, &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"); if (dscaps.dwFlags & DSCAPS_EMULDRIVER)
} else { mp_msg(MSGT_AO, MSGL_V,
mp_msg(MSGT_AO, MSGL_V, "ao_dsound: cannot get device capabilities\n"); "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; return 1;
} }
/** /**
@ -268,14 +280,14 @@ static int InitDirectSound(void)
*/ */
static void DestroyBuffer(void) static void DestroyBuffer(void)
{ {
if (hdsbuf) { if (hdsbuf) {
IDirectSoundBuffer_Release(hdsbuf); IDirectSoundBuffer_Release(hdsbuf);
hdsbuf = NULL; hdsbuf = NULL;
} }
if (hdspribuf) { if (hdspribuf) {
IDirectSoundBuffer_Release(hdspribuf); IDirectSoundBuffer_Release(hdspribuf);
hdspribuf = NULL; hdspribuf = NULL;
} }
} }
/** /**
@ -286,57 +298,58 @@ static void DestroyBuffer(void)
*/ */
static int write_buffer(unsigned char *data, int len) static int write_buffer(unsigned char *data, int len)
{ {
HRESULT res; HRESULT res;
LPVOID lpvPtr1; LPVOID lpvPtr1;
DWORD dwBytes1; DWORD dwBytes1;
LPVOID lpvPtr2; LPVOID lpvPtr2;
DWORD dwBytes2; DWORD dwBytes2;
underrun_check = 0; underrun_check = 0;
// Lock the buffer // Lock the buffer
res = IDirectSoundBuffer_Lock(hdsbuf,write_offset, len, &lpvPtr1, &dwBytes1, &lpvPtr2, &dwBytes2, 0); res = IDirectSoundBuffer_Lock(hdsbuf, write_offset, len, &lpvPtr1, &dwBytes1,
// If the buffer was lost, restore and retry lock. &lpvPtr2, &dwBytes2, 0);
if (DSERR_BUFFERLOST == res) // If the buffer was lost, restore and retry lock.
{ if (DSERR_BUFFERLOST == res) {
IDirectSoundBuffer_Restore(hdsbuf); IDirectSoundBuffer_Restore(hdsbuf);
res = IDirectSoundBuffer_Lock(hdsbuf,write_offset, len, &lpvPtr1, &dwBytes1, &lpvPtr2, &dwBytes2, 0); res = IDirectSoundBuffer_Lock(hdsbuf, write_offset, len, &lpvPtr1,
} &dwBytes1, &lpvPtr2, &dwBytes2, 0);
}
if (SUCCEEDED(res)) if (SUCCEEDED(res)) {
{ if (!AF_FORMAT_IS_AC3(ao_data.format)) {
if (!AF_FORMAT_IS_AC3(ao_data.format)) {
memcpy(lpvPtr1, data, dwBytes1); memcpy(lpvPtr1, data, dwBytes1);
if (lpvPtr2 != NULL) if (lpvPtr2 != NULL)
memcpy(lpvPtr2, (char *)data + dwBytes1, dwBytes2); memcpy(lpvPtr2, (char *)data + dwBytes1, dwBytes2);
write_offset+=dwBytes1+dwBytes2; write_offset += dwBytes1 + dwBytes2;
if(write_offset>=buffer_size) if (write_offset >= buffer_size)
write_offset=dwBytes2; write_offset = dwBytes2;
} else { } else {
// Write to pointers without reordering. // Write to pointers without reordering.
memcpy(lpvPtr1,data,dwBytes1); memcpy(lpvPtr1, data, dwBytes1);
if (NULL != lpvPtr2 )memcpy(lpvPtr2,data+dwBytes1,dwBytes2); if (NULL != lpvPtr2)
write_offset+=dwBytes1+dwBytes2; memcpy(lpvPtr2, data + dwBytes1, dwBytes2);
if(write_offset>=buffer_size)write_offset=dwBytes2; write_offset += dwBytes1 + dwBytes2;
} if (write_offset >= buffer_size)
write_offset = dwBytes2;
}
// Release the data back to DirectSound. // Release the data back to DirectSound.
res = IDirectSoundBuffer_Unlock(hdsbuf,lpvPtr1,dwBytes1,lpvPtr2,dwBytes2); res = IDirectSoundBuffer_Unlock(hdsbuf, lpvPtr1, dwBytes1, lpvPtr2,
if (SUCCEEDED(res)) dwBytes2);
{ if (SUCCEEDED(res)) {
// Success. // Success.
DWORD status; DWORD status;
IDirectSoundBuffer_GetStatus(hdsbuf, &status); IDirectSoundBuffer_GetStatus(hdsbuf, &status);
if (!(status & DSBSTATUS_PLAYING)){ if (!(status & DSBSTATUS_PLAYING))
res = IDirectSoundBuffer_Play(hdsbuf, 0, 0, DSBPLAY_LOOPING); res = IDirectSoundBuffer_Play(hdsbuf, 0, 0, DSBPLAY_LOOPING);
} return dwBytes1 + dwBytes2;
return dwBytes1+dwBytes2; }
} }
} // Lock, Unlock, or Restore failed.
// Lock, Unlock, or Restore failed. return 0;
return 0;
} }
/***************************************************************************************/ /***************************************************************************************/
@ -349,24 +362,24 @@ static int write_buffer(unsigned char *data, int len)
*/ */
static int control(int cmd, void *arg) static int control(int cmd, void *arg)
{ {
DWORD volume; DWORD volume;
switch (cmd) { switch (cmd) {
case AOCONTROL_GET_VOLUME: { case AOCONTROL_GET_VOLUME: {
ao_control_vol_t* vol = (ao_control_vol_t*)arg; ao_control_vol_t *vol = (ao_control_vol_t *)arg;
vol->left = vol->right = audio_volume; vol->left = vol->right = audio_volume;
return CONTROL_OK; return CONTROL_OK;
} }
case AOCONTROL_SET_VOLUME: { case AOCONTROL_SET_VOLUME: {
ao_control_vol_t* vol = (ao_control_vol_t*)arg; ao_control_vol_t *vol = (ao_control_vol_t *)arg;
volume = audio_volume = vol->right; volume = audio_volume = vol->right;
if (volume < 1) if (volume < 1)
volume = 1; volume = 1;
volume = (DWORD)(log10(volume) * 5000.0) - 10000; volume = (DWORD)(log10(volume) * 5000.0) - 10000;
IDirectSoundBuffer_SetVolume(hdsbuf, volume); IDirectSoundBuffer_SetVolume(hdsbuf, volume);
return CONTROL_OK; return CONTROL_OK;
} }
} }
return -1; return -1;
} }
/** /**
@ -380,118 +393,138 @@ static int control(int cmd, void *arg)
static int init(int rate, const struct mp_chmap *channels, int format, int flags) static int init(int rate, const struct mp_chmap *channels, int format, int flags)
{ {
int res; int res;
if (!InitDirectSound()) return 0; if (!InitDirectSound())
return 0;
global_ao->no_persistent_volume = true; global_ao->no_persistent_volume = true;
audio_volume = 100; audio_volume = 100;
// ok, now create the buffers // ok, now create the buffers
WAVEFORMATEXTENSIBLE wformat; WAVEFORMATEXTENSIBLE wformat;
DSBUFFERDESC dsbpridesc; DSBUFFERDESC dsbpridesc;
DSBUFFERDESC dsbdesc; DSBUFFERDESC dsbdesc;
if (AF_FORMAT_IS_AC3(format)) { if (AF_FORMAT_IS_AC3(format))
format = AF_FORMAT_AC3_NE; format = AF_FORMAT_AC3_NE;
} else { else {
struct mp_chmap_sel sel = {0}; struct mp_chmap_sel sel = {
mp_chmap_sel_add_waveext(&sel); 0
if (!ao_chmap_sel_adjust(&ao_data, &sel, &ao_data.channels)) };
return 0; mp_chmap_sel_add_waveext(&sel);
if (!ao_chmap_sel_adjust(&ao_data, &sel, &ao_data.channels))
return 0;
}
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.samplerate = rate;
ao_data.format = format;
ao_data.bps = ao_data.channels.num * 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,
ao_data.channels.num, 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 = (ao_data.channels.num > 2)
? sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX) : 0;
wformat.Format.nChannels = ao_data.channels.num;
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 = (ao_data.channels.num > 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 (ao_data.channels.num > 2) {
wformat.dwChannelMask = mp_chmap_to_waveext(&ao_data.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 = 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);
} }
switch(format){ if (res != DS_OK) {
case AF_FORMAT_AC3_NE: UninitDirectSound();
case AF_FORMAT_S24_LE: mp_msg(MSGT_AO, MSGL_ERR,
case AF_FORMAT_S16_LE: "ao_dsound: cannot create secondary (stream)buffer (%s)\n",
case AF_FORMAT_U8: dserr2str(res));
break; return 0;
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; mp_msg(MSGT_AO, MSGL_V, "ao_dsound: secondary (stream)buffer created\n");
} return 1;
//fill global ao_data
ao_data.samplerate = rate;
ao_data.format = format;
ao_data.bps = ao_data.channels.num * 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, ao_data.channels.num, 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 = (ao_data.channels.num > 2) ? sizeof(WAVEFORMATEXTENSIBLE)-sizeof(WAVEFORMATEX) : 0;
wformat.Format.nChannels = ao_data.channels.num;
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 = (ao_data.channels.num > 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 (ao_data.channels.num > 2) {
wformat.dwChannelMask = mp_chmap_to_waveext(&ao_data.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 = 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;
} }
@ -501,11 +534,11 @@ static int init(int rate, const struct mp_chmap *channels, int format, int flags
*/ */
static void reset(void) static void reset(void)
{ {
IDirectSoundBuffer_Stop(hdsbuf); IDirectSoundBuffer_Stop(hdsbuf);
// reset directsound buffer // reset directsound buffer
IDirectSoundBuffer_SetCurrentPosition(hdsbuf, 0); IDirectSoundBuffer_SetCurrentPosition(hdsbuf, 0);
write_offset=0; write_offset = 0;
underrun_check=0; underrun_check = 0;
} }
/** /**
@ -513,7 +546,7 @@ static void reset(void)
*/ */
static void audio_pause(void) static void audio_pause(void)
{ {
IDirectSoundBuffer_Stop(hdsbuf); IDirectSoundBuffer_Stop(hdsbuf);
} }
/** /**
@ -521,7 +554,7 @@ static void audio_pause(void)
*/ */
static void audio_resume(void) static void audio_resume(void)
{ {
IDirectSoundBuffer_Play(hdsbuf, 0, 0, DSBPLAY_LOOPING); IDirectSoundBuffer_Play(hdsbuf, 0, 0, DSBPLAY_LOOPING);
} }
/** /**
@ -530,51 +563,53 @@ static void audio_resume(void)
*/ */
static void uninit(int immed) static void uninit(int immed)
{ {
if (!immed) if (!immed)
mp_sleep_us(get_delay() * 1000000); mp_sleep_us(get_delay() * 1000000);
reset(); reset();
DestroyBuffer(); DestroyBuffer();
UninitDirectSound(); UninitDirectSound();
} }
// return exact number of free (safe to write) bytes // return exact number of free (safe to write) bytes
static int check_free_buffer_size(void) static int check_free_buffer_size(void)
{ {
int space; int space;
DWORD play_offset; DWORD play_offset;
IDirectSoundBuffer_GetCurrentPosition(hdsbuf,&play_offset,NULL); IDirectSoundBuffer_GetCurrentPosition(hdsbuf, &play_offset, NULL);
space=buffer_size-(write_offset-play_offset); space = buffer_size - (write_offset - play_offset);
// | | <-- const --> | | | // | | <-- const --> | | |
// buffer start play_cursor write_cursor write_offset buffer end // buffer start play_cursor write_cursor write_offset buffer end
// play_cursor is the actual postion of the play cursor // 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_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 // 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 > buffer_size)
// Check for buffer underruns. An underrun happens if DirectSound space -= buffer_size; // write_offset < play_offset
// started to play old data beyond the current write_offset. Detect this // Check for buffer underruns. An underrun happens if DirectSound
// by checking whether the free space shrinks, even though no data was // started to play old data beyond the current write_offset. Detect this
// written (i.e. no write_buffer). Doesn't always work, but the only // by checking whether the free space shrinks, even though no data was
// reason we need this is to deal with the situation when playback ends, // written (i.e. no write_buffer). Doesn't always work, but the only
// and the buffer is only half-filled. // reason we need this is to deal with the situation when playback ends,
if (space < underrun_check) { // and the buffer is only half-filled.
// there's no useful data in the buffers if (space < underrun_check) {
space = buffer_size; // there's no useful data in the buffers
reset(); space = buffer_size;
} reset();
underrun_check = space; }
return space; underrun_check = space;
return space;
} }
/** /**
\brief find out how many bytes can be written into the audio buffer without \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 \return free space in bytes, has to return 0 if the buffer is almost full
*/ */
static int get_space(void) static int get_space(void)
{ {
int space = check_free_buffer_size(); int space = check_free_buffer_size();
if(space < min_free_space)return 0; if (space < min_free_space)
return space-min_free_space; return 0;
return space - min_free_space;
} }
/** /**
@ -584,14 +619,15 @@ static int get_space(void)
\param flags currently unused \param flags currently unused
\return number of played bytes \return number of played bytes
*/ */
static int play(void* data, int len, int flags) static int play(void *data, int len, int flags)
{ {
int space = check_free_buffer_size(); int space = check_free_buffer_size();
if(space < len) len = space; if (space < len)
len = space;
if (!(flags & AOPLAY_FINAL_CHUNK)) if (!(flags & AOPLAY_FINAL_CHUNK))
len = (len / ao_data.outburst) * ao_data.outburst; len = (len / ao_data.outburst) * ao_data.outburst;
return write_buffer(data, len); return write_buffer(data, len);
} }
/** /**
@ -600,6 +636,6 @@ static int play(void* data, int len, int flags)
*/ */
static float get_delay(void) static float get_delay(void)
{ {
int space = check_free_buffer_size(); int space = check_free_buffer_size();
return (float)(buffer_size - space) / (float)ao_data.bps; return (float)(buffer_size - space) / (float)ao_data.bps;
} }