📄 ao_dsound.c
字号:
/****************************************************************************** * 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>#define DIRECTSOUND_VERSION 0x0600#include <dsound.h>#include "config.h"#include "libaf/af_format.h"#include "audio_out.h"#include "audio_out_internal.h"#include "mp_msg.h"#include "libvo/fastmemcpy.h"#include "osdep/timer.h"#include "subopt-helper.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 0xFFFEstatic 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#endifstatic 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 dllstatic LPDIRECTSOUND hds = NULL; ///direct sound object static LPDIRECTSOUNDBUFFER hdspribuf = NULL; ///primary direct sound bufferstatic 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 bufferstatic 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 device_num = 0; ///wanted device numberstatic GUID device; ///guid of the device /***************************************************************************************//**\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(){ mp_msg(MSGT_AO, MSGL_FATAL, "\n-ao dsound commandline help:\n" "Example: mplayer -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; 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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -