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

📄 wav_out.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 / wave audio 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 <gpac/modules/audio_out.h>#include <windows.h>#define MAX_AUDIO_BUFFER	30typedef struct {	HWAVEOUT hwo;	WAVEHDR wav_hdr[MAX_AUDIO_BUFFER];	WAVEFORMATEX fmt;	u32 num_buffers;	u32 buffer_size;	Bool exit_request;	HANDLE event;	u32 vol, pan;	u32 delay, total_length_ms;	Bool force_config;	u32 cfg_num_buffers, cfg_duration;	char *wav_buf;} WAVContext;#if !defined(DISABLE_WAVE_EX) && !defined(_WIN32_WCE)/*IF YOU CAN'T COMPILE WAVEOUT TRY TO COMMENT THIS - note waveOut & multichannel is likely not to work*/#define USE_WAVE_EXT#endif#ifdef USE_WAVE_EXT/*for channel codes*/#include <gpac/constants.h>#ifndef WAVE_FORMAT_EXTENSIBLE#define  WAVE_FORMAT_EXTENSIBLE   0xFFFE#endif#ifndef SPEAKER_FRONT_LEFT#   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#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;#endifconst static GUID  GPAC_KSDATAFORMAT_SUBTYPE_PCM = {0x00000001,0x0000,0x0010, {0x80,0x00,0x00,0xaa,0x00,0x38,0x9b,0x71} };#pragma message("Using multichannel audio extensions")#endif#define WAVCTX()	WAVContext *ctx = (WAVContext *)dr->opaque;static GF_Err WAV_Setup(GF_AudioOutput *dr, void *os_handle, u32 num_buffers, u32 total_duration){	WAVCTX();	ctx->force_config = (num_buffers && total_duration) ? 1 : 0;	ctx->cfg_num_buffers = num_buffers;	if (ctx->cfg_num_buffers <= 1) ctx->cfg_num_buffers = 2;	ctx->cfg_duration = total_duration;	if (!ctx->force_config) ctx->num_buffers = 6;	return GF_OK;}static void CALLBACK WaveProc(HWAVEOUT hwo, UINT uMsg, DWORD dwInstance, DWORD dwParam1, DWORD dwParam2){	GF_AudioOutput *dr = (GF_AudioOutput *) dwInstance;	WAVCTX();	if (uMsg != WOM_DONE) return;	if (ctx->exit_request) return;	SetEvent(ctx->event);} static void close_waveform(GF_AudioOutput *dr){	WAVCTX();    if (!ctx->event) return;	/*brute-force version, actually much safer on winCE*/#ifdef _WIN32_WCE	ctx->exit_request = 1;	SetEvent(ctx->event);	waveOutReset(ctx->hwo);	waveOutClose(ctx->hwo);	if (ctx->wav_buf) free(ctx->wav_buf);	ctx->wav_buf = NULL;    CloseHandle(ctx->event);	ctx->event = NULL;	ctx->exit_request = 0;#else	ctx->exit_request = 1;	SetEvent(ctx->event);	if (ctx->hwo) {		u32 i;		Bool not_done;		MMRESULT res;		/*wait for all buffers to complete, otherwise this locks waveOutReset*/		while (1) {			not_done = 0;			for (i=0 ; i< ctx->num_buffers; i++) {				if (! (ctx->wav_hdr[i].dwFlags & WHDR_DONE)) {					not_done = 1;					break;				}			}			if (!not_done) break;			gf_sleep(60);		}		/*waveOutReset gives unpredictable results on PocketPC, so just close right away*/		while (1) {			res = waveOutClose(ctx->hwo);			if (res == MMSYSERR_NOERROR) break;		}		ctx->hwo = NULL;	}	if (ctx->wav_buf) free(ctx->wav_buf);	ctx->wav_buf = NULL;    CloseHandle(ctx->event);	ctx->event = NULL;	ctx->exit_request = 0;#endif}static void WAV_Shutdown(GF_AudioOutput *dr){	close_waveform(dr);}/*we assume what was asked is what we got*/static GF_Err WAV_ConfigureOutput(GF_AudioOutput *dr, u32 *SampleRate, u32 *NbChannels, u32 *nbBitsPerSample, u32 channel_cfg){	u32 i, retry;	HRESULT	hr;	WAVEFORMATEX *fmt;#ifdef USE_WAVE_EXT	WAVEFORMATEXTENSIBLE format_ex;#endif	WAVCTX();	if (!ctx) return GF_BAD_PARAM;	/*reset*/	close_waveform(dr);#ifndef USE_WAVE_EXT	if (*NbChannels>2) *NbChannels=2;#endif	memset (&ctx->fmt, 0, sizeof(ctx->fmt));	ctx->fmt.cbSize = sizeof(WAVEFORMATEX);	ctx->fmt.wFormatTag = WAVE_FORMAT_PCM;	ctx->fmt.nChannels = *NbChannels;	ctx->fmt.wBitsPerSample = *nbBitsPerSample;	ctx->fmt.nSamplesPerSec = *SampleRate;	ctx->fmt.nBlockAlign = ctx->fmt.wBitsPerSample * ctx->fmt.nChannels / 8;	ctx->fmt.nAvgBytesPerSec = *SampleRate * ctx->fmt.nBlockAlign; 	fmt = &ctx->fmt;#ifdef USE_WAVE_EXT	if (channel_cfg && ctx->fmt.nChannels>2) {		memset(&format_ex, 0, sizeof(WAVEFORMATEXTENSIBLE));		format_ex.Format = ctx->fmt;		format_ex.Format.cbSize = 22;		format_ex.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;		format_ex.SubFormat = GPAC_KSDATAFORMAT_SUBTYPE_PCM;		format_ex.Samples.wValidBitsPerSample = ctx->fmt.wBitsPerSample;		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;		fmt = (WAVEFORMATEX *) &format_ex;	}#endif	/* Open a waveform device for output using window callback. */ 	retry = 10;	while (retry) {				hr = waveOutOpen((LPHWAVEOUT)&ctx->hwo, WAVE_MAPPER, &ctx->fmt, (DWORD) WaveProc, (DWORD) dr, 			CALLBACK_FUNCTION | WAVE_ALLOWSYNC | WAVE_FORMAT_DIRECT			);		if (hr == MMSYSERR_NOERROR) break;		/*couldn't open audio*/		if (hr != MMSYSERR_ALLOCATED) return GF_IO_ERR;		retry--;	}	if (hr != MMSYSERR_NOERROR) return GF_IO_ERR;	if (!ctx->force_config) {		/*one wave buffer size*/		ctx->buffer_size = 1024 * ctx->fmt.nBlockAlign;		ctx->num_buffers = 2;	} else {		ctx->num_buffers = ctx->cfg_num_buffers;		ctx->buffer_size = (ctx->fmt.nAvgBytesPerSec * ctx->cfg_duration) / (1000 * ctx->cfg_num_buffers);	}    ctx->event = CreateEvent( NULL, FALSE, FALSE, NULL);	/*make sure we're aligned*/	while (ctx->buffer_size % ctx->fmt.nBlockAlign) ctx->buffer_size++;	ctx->wav_buf = malloc(ctx->buffer_size*ctx->num_buffers*sizeof(char));	memset(ctx->wav_buf, 0, ctx->buffer_size*ctx->num_buffers*sizeof(char));	/*setup wave headers*/	for (i=0 ; i < ctx->num_buffers; i++) {		memset(& ctx->wav_hdr[i], 0, sizeof(WAVEHDR));		ctx->wav_hdr[i].dwBufferLength = ctx->buffer_size; 		ctx->wav_hdr[i].lpData = & ctx->wav_buf[i*ctx->buffer_size];		ctx->wav_hdr[i].dwFlags = WHDR_DONE;		waveOutPrepareHeader(ctx->hwo, &ctx->wav_hdr[i], sizeof(WAVEHDR));		waveOutWrite(ctx->hwo, &ctx->wav_hdr[i], sizeof(WAVEHDR));		Sleep(1);	}	ctx->total_length_ms = 1000 * ctx->num_buffers * ctx->buffer_size / ctx->fmt.nAvgBytesPerSec;	/*initial delay is full buffer size*/	ctx->delay = ctx->total_length_ms;	return GF_OK;}static void WAV_WriteAudio(GF_AudioOutput *dr){	LPWAVEHDR hdr;	HRESULT hr;	u32 i;	WAVCTX();	if (!ctx->hwo) return;	WaitForSingleObject(ctx->event, INFINITE);	if (ctx->exit_request) return;	for (i=0; i<ctx->num_buffers; i++) {		/*get buffer*/		hdr = &ctx->wav_hdr[i];		if (hdr->dwFlags & WHDR_DONE) {			waveOutUnprepareHeader(ctx->hwo, hdr, sizeof(WAVEHDR));			hdr->dwBufferLength = ctx->buffer_size;			/*update delay*/			ctx->delay = 1000 * i * ctx->buffer_size / ctx->fmt.nAvgBytesPerSec;			/*fill it*/			hdr->dwBufferLength = dr->FillBuffer(dr->audio_renderer, hdr->lpData, ctx->buffer_size);			hdr->dwFlags = 0;		    hr = waveOutPrepareHeader(ctx->hwo, hdr, sizeof(WAVEHDR));			/*write it*/			waveOutWrite(ctx->hwo, hdr, sizeof(WAVEHDR));		}	}}static void WAV_Play(GF_AudioOutput *dr, u32 PlayType){#if 0	u32 i;	WAVCTX();	switch (PlayType) {	case 0:		waveOutPause(ctx->hwo);		break;	case 2:		for (i=0; i<ctx->num_buffers; i++) {			LPWAVEHDR hdr = &ctx->wav_hdr[i];			memset(&hdr->lpData, 0, sizeof(char)*ctx->buffer_size);		}	case 1:		waveOutRestart(ctx->hwo);		break;	}#endif}#ifndef _WIN32_WCEstatic void set_vol_pan(WAVContext *ctx){	WORD rV, lV;	/*in wave, volume & pan are specified as a DWORD. LOW word is LEFT channel, HIGH is right - iPaq doesn't support that*/	lV = (WORD) (ctx->vol * ctx->pan / 100);	rV = (WORD) (ctx->vol * (100 - ctx->pan) / 100);	waveOutSetVolume(ctx->hwo, MAKELONG(lV, rV) );}static void WAV_SetVolume(GF_AudioOutput *dr, u32 Volume){	WAVCTX();	if (Volume > 100) Volume = 100;	ctx->vol = Volume * 0xFFFF / 100;	set_vol_pan(ctx);}static void WAV_SetPan(GF_AudioOutput *dr, u32 Pan){	WAVCTX();	if (Pan > 100) Pan = 100;	ctx->pan = Pan;	set_vol_pan(ctx);}#else/*too much trouble with iPaq ...*/static void WAV_SetVolume(GF_AudioOutput *dr, u32 Volume) { }static void WAV_SetPan(GF_AudioOutput *dr, u32 Pan) { }#endifstatic GF_Err WAV_QueryOutputSampleRate(GF_AudioOutput *dr, u32 *desired_samplerate, u32 *NbChannels, u32 *nbBitsPerSample){	/*iPaq's output frequencies available*/#ifdef _WIN32_WCE	switch (*desired_samplerate) {	case 11025:	case 22050:		*desired_samplerate = 22050;		break;	case 8000:	case 16000:	case 32000:		*desired_samplerate = 44100;		break;	case 24000:	case 48000:		*desired_samplerate = 44100;		break;	case 44100:		*desired_samplerate = 44100;		break;	default:		break;	}	return GF_OK;#else	return GF_OK;#endif}static u32 WAV_GetAudioDelay(GF_AudioOutput *dr){	WAVCTX();	return ctx->delay;}static u32 WAV_GetTotalBufferTime(GF_AudioOutput *dr){	WAVCTX();	return ctx->total_length_ms;}void *NewWAVRender(){	WAVContext *ctx;	GF_AudioOutput *driv;	ctx = malloc(sizeof(WAVContext));	memset(ctx, 0, sizeof(WAVContext));	ctx->num_buffers = 10;	ctx->pan = 50;	ctx->vol = 100;	driv = malloc(sizeof(GF_AudioOutput));	memset(driv, 0, sizeof(GF_AudioOutput));	GF_REGISTER_MODULE_INTERFACE(driv, GF_AUDIO_OUTPUT_INTERFACE, "Windows MME Output", "gpac distribution")	driv->opaque = ctx;	driv->SelfThreaded = 0;	driv->Setup = WAV_Setup;	driv->Shutdown = WAV_Shutdown;	driv->ConfigureOutput = WAV_ConfigureOutput;	driv->GetAudioDelay = WAV_GetAudioDelay;	driv->GetTotalBufferTime = WAV_GetTotalBufferTime;	driv->SetVolume = WAV_SetVolume;	driv->SetPan = WAV_SetPan;	driv->Play = WAV_Play;	driv->QueryOutputSampleRate = WAV_QueryOutputSampleRate;	driv->WriteAudio = WAV_WriteAudio;	return driv;}void DeleteWAVRender(void *ifce){	GF_AudioOutput *dr = (GF_AudioOutput *) ifce;	WAVContext *ctx = (WAVContext *)dr->opaque;	free(ctx);	free(dr);}Bool QueryInterface(u32 InterfaceType){	if (InterfaceType == GF_AUDIO_OUTPUT_INTERFACE) return 1;	return 0;}GF_BaseInterface *LoadInterface(u32 InterfaceType){	if (InterfaceType == GF_AUDIO_OUTPUT_INTERFACE) return NewWAVRender();	return NULL;}void ShutdownInterface(GF_BaseInterface *ifce){	switch (ifce->InterfaceType) {	case GF_AUDIO_OUTPUT_INTERFACE:		DeleteWAVRender((GF_AudioOutput *) ifce);		break;	}}

⌨️ 快捷键说明

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