ref: e98a69b9db88ef00994bbc7a95add426a36adcf6
dir: /frontend/wave_out.c/
/* Set TABS = 4 */
/*
** FAAD - Freeware Advanced Audio Decoder
** Copyright (C) 2002 M. Bakker
**
** 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-1307, USA.
********************************************************************
function: To provide playback of 16 bit PCM wave data in Win32
environments from decoded aac/mp4 files.
********************************************************************/
#include <string.h>
#include <errno.h>
#include "wave_out.h"
#ifdef _WIN32
#define MAXWAVESIZE 4294967040LU
#define MAX_WAVEBLOCKS 32
static CRITICAL_SECTION cs;
static HWAVEOUT dev = NULL;
static int ScheduledBlocks = 0;
static int PlayedWaveHeadersCount = 0; // free index
static WAVEHDR* PlayedWaveHeaders [MAX_WAVEBLOCKS];
static int
Box ( const char* msg )
{
MessageBox ( NULL, msg, " Error Message . . .", MB_OK | MB_ICONEXCLAMATION );
return -1;
}
/*
* This function registers already played WAVE chunks. Freeing is done by free_memory(),
*/
static void CALLBACK
wave_callback ( HWAVE hWave, UINT uMsg, DWORD dwInstance, DWORD dwParam1, DWORD dwParam2 )
{
if ( uMsg == WOM_DONE ) {
EnterCriticalSection ( &cs );
PlayedWaveHeaders [PlayedWaveHeadersCount++] = (WAVEHDR*) dwParam1;
LeaveCriticalSection ( &cs );
}
}
static void
free_memory ( void )
{
WAVEHDR* wh;
HGLOBAL hg;
EnterCriticalSection ( &cs );
wh = PlayedWaveHeaders [--PlayedWaveHeadersCount];
ScheduledBlocks--; // decrease the number of USED blocks
LeaveCriticalSection ( &cs );
waveOutUnprepareHeader ( dev, wh, sizeof (WAVEHDR) );
hg = GlobalHandle ( wh -> lpData ); // Deallocate the buffer memory
GlobalUnlock (hg);
GlobalFree (hg);
hg = GlobalHandle ( wh ); // Deallocate the header memory
GlobalUnlock (hg);
GlobalFree (hg);
}
int
Set_WIN_Params ( FILE_T dummyFile ,
long double SampleFreq,
unsigned int BitsPerSample,
unsigned int Channels,
unsigned int play_priority )
{
WAVEFORMATEX outFormat;
UINT deviceID = WAVE_MAPPER;
(void) dummyFile;
if ( waveOutGetNumDevs () == 0 )
return Box ( "No audio device present." );
outFormat.wFormatTag = WAVE_FORMAT_PCM;
outFormat.wBitsPerSample = BitsPerSample;
outFormat.nChannels = Channels;
outFormat.nSamplesPerSec = (unsigned long)(SampleFreq + 0.5);
outFormat.nBlockAlign = (outFormat.wBitsPerSample + 7) / 8 * outFormat.nChannels;
outFormat.nAvgBytesPerSec = outFormat.nSamplesPerSec * outFormat.nBlockAlign;
switch ( waveOutOpen ( &dev, deviceID, &outFormat, (DWORD)wave_callback, 0, CALLBACK_FUNCTION ) )
{
case MMSYSERR_ALLOCATED: return Box ( "Device is already open." );
case MMSYSERR_BADDEVICEID: return Box ( "The specified device is out of range." );
case MMSYSERR_NODRIVER: return Box ( "There is no audio driver in this system." );
case MMSYSERR_NOMEM: return Box ( "Unable to allocate sound memory." );
case WAVERR_BADFORMAT: return Box ( "This audio format is not supported." );
case WAVERR_SYNC: return Box ( "The device is synchronous." );
default: return Box ( "Unknown media error." );
case MMSYSERR_NOERROR: break;
}
waveOutReset ( dev );
InitializeCriticalSection ( &cs );
switch(play_priority)
{
case 0:
SetPriorityClass ( GetCurrentProcess (), NORMAL_PRIORITY_CLASS );
break;
case 1:
SetPriorityClass ( GetCurrentProcess (), HIGH_PRIORITY_CLASS );
break;
case 2:
SetPriorityClass ( GetCurrentProcess (), REALTIME_PRIORITY_CLASS );
break;
}
return 0;
}
int
WIN_Play_Samples ( const void* data, size_t len )
{
HGLOBAL hg;
HGLOBAL hg2;
LPWAVEHDR wh;
void* allocptr;
do {
while ( PlayedWaveHeadersCount > 0 ) // free used blocks ...
free_memory ();
if ( ScheduledBlocks < sizeof(PlayedWaveHeaders)/sizeof(*PlayedWaveHeaders) ) // wait for a free block ...
break;
Sleep (26);
} while (1);
if ( (hg2 = GlobalAlloc ( GMEM_MOVEABLE, len )) == NULL ) // allocate some memory for a copy of the buffer
return Box ( "GlobalAlloc failed." );
allocptr = GlobalLock (hg2);
CopyMemory ( allocptr, data, len ); // Here we can call any modification output functions we want....
if ( (hg = GlobalAlloc (GMEM_MOVEABLE | GMEM_ZEROINIT, sizeof (WAVEHDR))) == NULL ) // now make a header and WRITE IT!
return -1;
wh = GlobalLock (hg);
wh -> dwBufferLength = len;
wh -> lpData = allocptr;
if ( waveOutPrepareHeader ( dev, wh, sizeof (WAVEHDR)) != MMSYSERR_NOERROR ) {
GlobalUnlock (hg);
GlobalFree (hg);
return -1;
}
if ( waveOutWrite ( dev, wh, sizeof (WAVEHDR)) != MMSYSERR_NOERROR ) {
GlobalUnlock (hg);
GlobalFree (hg);
return -1;
}
EnterCriticalSection ( &cs );
ScheduledBlocks++;
LeaveCriticalSection ( &cs );
return len;
}
int
WIN_Audio_close ( void )
{
if ( dev != NULL ) {
while ( ScheduledBlocks > 0 ) {
Sleep (ScheduledBlocks);
while ( PlayedWaveHeadersCount > 0 ) // free used blocks ...
free_memory ();
}
waveOutReset (dev); // reset the device
waveOutClose (dev); // close the device
dev = NULL;
}
DeleteCriticalSection ( &cs );
ScheduledBlocks = 0;
return 0;
}
#endif
/* end of wave_out.c */