⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 dx_audio.c

📁 一个用于智能手机的多媒体库适合S60 WinCE的跨平台开发库
💻 C
字号:
/* *			GPAC - Multimedia Framework C SDK * *			Copyright (c) Jean Le Feuvre 2000-2005 *					All rights reserved * *  This file is part of GPAC / DirectX audio and video render module * *  GPAC is free software; you can redistribute it and/or modify *  it under the terms of the GNU Lesser General Public License as published by *  the Free Software Foundation; either version 2, or (at your option) *  any later version. *    *  GPAC 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 Lesser General Public License for more details. *    *  You should have received a copy of the GNU Lesser General Public *  License along with this library; see the file COPYING.  If not, write to *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  *		 */#include "dx_hw.h"#include <process.h>#if (DIRECTSOUND_VERSION >= 0x0800)#define USE_WAVE_EX#endif#ifdef USE_WAVE_EX#include <ks.h>#include <ksmedia.h>const static GUID  GPAC_KSDATAFORMAT_SUBTYPE_PCM = {0x00000001,0x0000,0x0010,{0x80,0x00,0x00,0xaa,0x00,0x38,0x9b,0x71}};#endif/*		DirectSound audio output*/#define MAX_NUM_BUFFERS		20typedef struct {	Bool force_config;	u32 cfg_num_buffers, cfg_duration;	HWND hWnd;	LPDIRECTSOUND pDS;	WAVEFORMATEX format;	IDirectSoundBuffer *pOutput;	u32 buffer_size, num_audio_buffer, total_audio_buffer_ms;		/*notifs*/	Bool use_notif;    u32 frame_state[MAX_NUM_BUFFERS];    DSBPOSITIONNOTIFY notif_events[MAX_NUM_BUFFERS];    HANDLE events[MAX_NUM_BUFFERS];} DSContext;#define DSCONTEXT()		DSContext *ctx = (DSContext *)dr->opaque;void DS_WriteAudio(GF_AudioOutput *dr);void DS_WriteAudio_Notifs(GF_AudioOutput *dr);static GF_Err DS_Setup(GF_AudioOutput *dr, void *os_handle, u32 num_buffers, u32 total_duration){	DWORD flags;    HRESULT hr;	DSCONTEXT();	ctx->hWnd = (HWND) os_handle;	/*check if we have created a HWND (this requires that video is handled by the DX module*/	if (!ctx->hWnd) ctx->hWnd = DD_GetGlobalHWND();	/*too bad, use desktop as window*/	if (!ctx->hWnd) ctx->hWnd = GetDesktopWindow();	ctx->force_config = (num_buffers && total_duration) ? 1 : 0;	ctx->cfg_num_buffers = num_buffers;	ctx->cfg_duration = total_duration;	if (ctx->cfg_num_buffers <= 1) ctx->cfg_num_buffers = 2;	if ( FAILED( hr = DirectSoundCreate( NULL, &ctx->pDS, NULL ) ) ) return GF_IO_ERR;	flags = DSSCL_EXCLUSIVE;	if( FAILED( hr = IDirectSound_SetCooperativeLevel(ctx->pDS, ctx->hWnd, DSSCL_EXCLUSIVE) ) ) {		SAFE_DS_RELEASE( ctx->pDS ); 		return GF_IO_ERR;	}	return GF_OK;}void DS_ResetBuffer(DSContext *ctx){    VOID *pLock = NULL;    DWORD size;    if( FAILED(IDirectSoundBuffer_Lock(ctx->pOutput, 0, ctx->buffer_size*ctx->num_audio_buffer, &pLock, &size, NULL, NULL, 0 ) ) )        return;	memset(pLock, 0, (size_t) size);	IDirectSoundBuffer_Unlock(ctx->pOutput, pLock, size, NULL, 0L); }void DS_ReleaseBuffer(GF_AudioOutput *dr){	u32 i;	DSCONTEXT();	/*stop playing and notif proc*/	if (ctx->pOutput) IDirectSoundBuffer_Stop(ctx->pOutput);	SAFE_DS_RELEASE(ctx->pOutput);		/*use notif, shutdown notifier and event watcher*/	if (ctx->use_notif) {		for (i=0; i<ctx->num_audio_buffer; i++) CloseHandle(ctx->events[i]);	}	ctx->use_notif = 0;}static void DS_Shutdown(GF_AudioOutput *dr){	DSCONTEXT();	DS_ReleaseBuffer(dr);	SAFE_DS_RELEASE(ctx->pDS ); }/*we assume what was asked is what we got*/static GF_Err DS_ConfigureOutput(GF_AudioOutput *dr, u32 *SampleRate, u32 *NbChannels, u32 *nbBitsPerSample, u32 channel_cfg){    u32 i;	HRESULT hr; 	const char *sOpt;	DSBUFFERDESC dsbBufferDesc;	IDirectSoundNotify *pNotify;#ifdef USE_WAVE_EX	WAVEFORMATEXTENSIBLE format_ex;#endif	DSCONTEXT();	DS_ReleaseBuffer(dr);	ctx->format.nChannels = *NbChannels;	ctx->format.wBitsPerSample = *nbBitsPerSample;	ctx->format.nSamplesPerSec = *SampleRate;	ctx->format.cbSize = sizeof (WAVEFORMATEX);	ctx->format.wFormatTag = WAVE_FORMAT_PCM;	ctx->format.nBlockAlign = ctx->format.nChannels * ctx->format.wBitsPerSample / 8;	ctx->format.nAvgBytesPerSec = ctx->format.nSamplesPerSec * ctx->format.nBlockAlign;	if (!ctx->force_config) {		ctx->buffer_size = ctx->format.nBlockAlign * 1024;		ctx->num_audio_buffer = 2;	} else {		ctx->num_audio_buffer = ctx->cfg_num_buffers;		ctx->buffer_size = (ctx->format.nAvgBytesPerSec * ctx->cfg_duration) / (1000 * ctx->cfg_num_buffers);	}	/*make sure we're aligned*/	while (ctx->buffer_size % ctx->format.nBlockAlign) ctx->buffer_size++;	ctx->use_notif = 1;	sOpt = gf_modules_get_option((GF_BaseInterface *)dr, "Audio", "DisableNotification");	if (sOpt && !stricmp(sOpt, "yes")) ctx->use_notif = 0;	memset(&dsbBufferDesc, 0, sizeof(DSBUFFERDESC));	dsbBufferDesc.dwSize = sizeof (DSBUFFERDESC);	dsbBufferDesc.dwBufferBytes = ctx->buffer_size * ctx->num_audio_buffer;	dsbBufferDesc.lpwfxFormat = &ctx->format;	dsbBufferDesc.dwFlags = DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_GLOBALFOCUS | DSBCAPS_CTRLVOLUME;	if (ctx->use_notif) dsbBufferDesc.dwFlags |= DSBCAPS_CTRLPOSITIONNOTIFY;#ifdef USE_WAVE_EX	if (channel_cfg && ctx->format.nChannels>2) {		memset(&format_ex, 0, sizeof(WAVEFORMATEXTENSIBLE));		format_ex.Format = ctx->format;		format_ex.Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE);		format_ex.SubFormat = GPAC_KSDATAFORMAT_SUBTYPE_PCM;		format_ex.Samples.wValidBitsPerSample = *nbBitsPerSample;		format_ex.dwChannelMask = 0;		if (channel_cfg & GF_AUDIO_CH_FRONT_LEFT) format_ex.dwChannelMask |= SPEAKER_FRONT_LEFT;		if (channel_cfg & GF_AUDIO_CH_FRONT_RIGHT) format_ex.dwChannelMask |= SPEAKER_FRONT_RIGHT;		if (channel_cfg & GF_AUDIO_CH_FRONT_CENTER) format_ex.dwChannelMask |= SPEAKER_FRONT_CENTER;		if (channel_cfg & GF_AUDIO_CH_LFE) format_ex.dwChannelMask |= SPEAKER_LOW_FREQUENCY;		if (channel_cfg & GF_AUDIO_CH_BACK_LEFT) format_ex.dwChannelMask |= SPEAKER_BACK_LEFT;		if (channel_cfg & GF_AUDIO_CH_BACK_RIGHT) format_ex.dwChannelMask |= SPEAKER_BACK_RIGHT;		if (channel_cfg & GF_AUDIO_CH_BACK_CENTER) format_ex.dwChannelMask |= SPEAKER_BACK_CENTER;		if (channel_cfg & GF_AUDIO_CH_SIDE_LEFT) format_ex.dwChannelMask |= SPEAKER_SIDE_LEFT;		if (channel_cfg & GF_AUDIO_CH_SIDE_RIGHT) format_ex.dwChannelMask |= SPEAKER_SIDE_RIGHT;		dsbBufferDesc.lpwfxFormat = (WAVEFORMATEX *) &format_ex;	}#endif	hr = IDirectSound_CreateSoundBuffer(ctx->pDS, &dsbBufferDesc, &ctx->pOutput, NULL );	if (FAILED(hr)) {retry:		if (ctx->use_notif) gf_modules_set_option((GF_BaseInterface *)dr, "Audio", "DisableNotification", "yes");		ctx->use_notif = 0;		dsbBufferDesc.dwFlags = DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_GLOBALFOCUS;		hr = IDirectSound_CreateSoundBuffer(ctx->pDS, &dsbBufferDesc, &ctx->pOutput, NULL );		if (FAILED(hr)) return GF_IO_ERR;	}	for (i=0; i<ctx->num_audio_buffer; i++) ctx->frame_state[i] = 0;	if (ctx->use_notif) {		hr = IDirectSoundBuffer_QueryInterface(ctx->pOutput, &IID_IDirectSoundNotify , (void **)&pNotify);		if (hr == S_OK) {			/*setup the notification positions*/			for (i=0; i<ctx->num_audio_buffer; i++) {				ctx->events[i] = CreateEvent( NULL, FALSE, FALSE, NULL );				ctx->notif_events[i].hEventNotify = ctx->events[i];				ctx->notif_events[i].dwOffset = ctx->buffer_size * i;			}			/*Tell DirectSound when to notify us*/			hr = IDirectSoundNotify_SetNotificationPositions(pNotify, ctx->num_audio_buffer, ctx->notif_events);			if (hr != S_OK) {				IDirectSoundNotify_Release(pNotify);				for (i=0; i<ctx->num_audio_buffer; i++) CloseHandle(ctx->events[i]);				SAFE_DS_RELEASE(ctx->pOutput);				goto retry;			}			IDirectSoundNotify_Release(pNotify);		} else {			ctx->use_notif = 0;		}	}	if (ctx->use_notif) {		dr->WriteAudio = DS_WriteAudio_Notifs;	} else {		dr->WriteAudio = DS_WriteAudio;	}	ctx->total_audio_buffer_ms = 1000 * ctx->buffer_size * ctx->num_audio_buffer / ctx->format.nAvgBytesPerSec;	/*reset*/	DS_ResetBuffer(ctx);	/*play*/	IDirectSoundBuffer_Play(ctx->pOutput, 0, 0, DSBPLAY_LOOPING );		return GF_OK;}static Bool DS_RestoreBuffer(LPDIRECTSOUNDBUFFER pDSBuffer){	DWORD dwStatus;    IDirectSoundBuffer_GetStatus(pDSBuffer, &dwStatus );    if( dwStatus & DSBSTATUS_BUFFERLOST ) {		GF_LOG(GF_LOG_ERROR, GF_LOG_MMIO, ("[DirectSound] buffer lost\n"));		IDirectSoundBuffer_Restore(pDSBuffer);	    IDirectSoundBuffer_GetStatus(pDSBuffer, &dwStatus);		if( dwStatus & DSBSTATUS_BUFFERLOST ) return 1;    }	return 0;}void DS_FillBuffer(GF_AudioOutput *dr, u32 buffer) {	HRESULT hr;    VOID *pLock;	u32 pos;    DWORD size;	DSCONTEXT();	/*restoring*/    if (DS_RestoreBuffer(ctx->pOutput)) {		GF_LOG(GF_LOG_ERROR, GF_LOG_MMIO, ("[DirectSound] restoring sound buffer\n"));		return;	}		/*lock and fill from current pos*/	pos = buffer * ctx->buffer_size;	pLock = NULL;    if( FAILED( hr = IDirectSoundBuffer_Lock(ctx->pOutput, pos, ctx->buffer_size,  			&pLock,  &size, NULL, NULL, 0L ) ) ) {		GF_LOG(GF_LOG_ERROR, GF_LOG_MMIO, ("[DirectSound] Error locking sound buffer\n"));        return;	}	assert(size == ctx->buffer_size);	dr->FillBuffer(dr->audio_renderer, pLock, size);	/*update current pos*/    if( FAILED( hr = IDirectSoundBuffer_Unlock(ctx->pOutput, pLock, size, NULL, 0)) ) {		GF_LOG(GF_LOG_ERROR, GF_LOG_MMIO, ("[DirectSound] Error unlocking sound buffer\n"));	}	ctx->frame_state[buffer] = 1;}void DS_WriteAudio_Notifs(GF_AudioOutput *dr){	s32 i, inframe, nextframe;	DSCONTEXT();	inframe = WaitForMultipleObjects(ctx->num_audio_buffer, ctx->events, 0, 1000);	if (inframe==WAIT_TIMEOUT) return;	inframe -= WAIT_OBJECT_0;	/*reset state*/	ctx->frame_state[ (inframe + ctx->num_audio_buffer - 1) % ctx->num_audio_buffer] = 0;	nextframe = (inframe + 1) % ctx->num_audio_buffer;	for (i=nextframe; (i % ctx->num_audio_buffer) != (u32) inframe; i++) {		u32 buf = i % ctx->num_audio_buffer;		if (ctx->frame_state[buf]) continue;		DS_FillBuffer(dr, buf);	}}void DS_WriteAudio(GF_AudioOutput *dr){	u32 retry;    DWORD in_play, cur_play;	DSCONTEXT();	/*wait for end of current play buffer*/	if (IDirectSoundBuffer_GetCurrentPosition(ctx->pOutput, &in_play, NULL) != DS_OK ) {		GF_LOG(GF_LOG_ERROR, GF_LOG_MMIO, ("[DirectSound] error getting sound buffer poitions\n"));		return;	}	in_play = (in_play / ctx->buffer_size);	retry = 6;	while (retry) {		if (IDirectSoundBuffer_GetCurrentPosition(ctx->pOutput, &cur_play, NULL) != DS_OK ) {			GF_LOG(GF_LOG_ERROR, GF_LOG_MMIO, ("[DirectSound] error getting sound buffer poitions\n"));			return;		}		cur_play = (cur_play / ctx->buffer_size);		if (cur_play == in_play) {			gf_sleep(20);			retry--;		} else {			/**/			ctx->frame_state[in_play] = 0;			DS_FillBuffer(dr, in_play);			return;		}	}}static GF_Err DS_QueryOutputSampleRate(GF_AudioOutput *dr, u32 *desired_samplerate, u32 *NbChannels, u32 *nbBitsPerSample){	/*all sample rates supported for now ... */	return GF_OK;}static void DS_Play(GF_AudioOutput *dr, u32 PlayType){	DSCONTEXT();	switch (PlayType) {	case 0:		IDirectSoundBuffer_Stop(ctx->pOutput);		break;	case 2:		DS_ResetBuffer(ctx);	case 1:		IDirectSoundBuffer_Play(ctx->pOutput, 0, 0, DSBPLAY_LOOPING);		break;	}}static void DS_SetVolume(GF_AudioOutput *dr, u32 Volume){	LONG Vol;	DSCONTEXT();	if (Volume > 100) Volume = 100;	Vol = DSBVOLUME_MIN/2 + Volume * (DSBVOLUME_MAX-DSBVOLUME_MIN/2) / 100;	IDirectSoundBuffer_SetVolume(ctx->pOutput, Vol);}static void DS_SetPan(GF_AudioOutput *dr, u32 Pan){	LONG dspan;	DSCONTEXT();	if (Pan > 100) Pan = 100;	if (Pan > 50) {		dspan = DSBPAN_RIGHT * (Pan - 50) / 50;	} else if (Pan < 50) {		dspan = DSBPAN_LEFT * (50 - Pan) / 50;	} else {		dspan = 0;	}	IDirectSoundBuffer_SetPan(ctx->pOutput, dspan);}static void DS_SetPriority(GF_AudioOutput *dr, u32 Priority){}static u32 DS_GetAudioDelay(GF_AudioOutput *dr){	DSCONTEXT();	return ctx->total_audio_buffer_ms;}static u32 DS_GetTotalBufferTime(GF_AudioOutput *dr){	DSCONTEXT();	return ctx->total_audio_buffer_ms;}void *NewAudioOutput(){	HRESULT hr;	DSContext *ctx;	GF_AudioOutput *driv;	if( FAILED( hr = CoInitialize(NULL) ) ) return NULL;		ctx = malloc(sizeof(DSContext));	memset(ctx, 0, sizeof(DSContext));	driv = malloc(sizeof(GF_AudioOutput));	memset(driv, 0, sizeof(GF_AudioOutput));	GF_REGISTER_MODULE_INTERFACE(driv, GF_AUDIO_OUTPUT_INTERFACE, "DirectSound Audio Output", "gpac distribution");	driv->opaque = ctx;	driv->Setup = DS_Setup;	driv->Shutdown = DS_Shutdown;	driv->ConfigureOutput = DS_ConfigureOutput;	driv->SetVolume = DS_SetVolume;	driv->SetPan = DS_SetPan;	driv->Play = DS_Play;	driv->SetPriority = DS_SetPriority;	driv->GetAudioDelay = DS_GetAudioDelay;	driv->GetTotalBufferTime = DS_GetTotalBufferTime;	driv->WriteAudio = DS_WriteAudio;	driv->QueryOutputSampleRate = DS_QueryOutputSampleRate;	/*never threaded*/	driv->SelfThreaded = 0;	return driv;}void DeleteAudioOutput(void *ifce){	GF_AudioOutput *dr = (GF_AudioOutput *)ifce;	DSCONTEXT();	free(ctx);	free(ifce);	CoUninitialize();}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -