home *** CD-ROM | disk | FTP | other *** search
- /*
- * AudioPlayback.cpp
- *
- * Copyright (C) Alberto Vigata - January 2000 - ultraflask@yahoo.com
- *
- * This file is part of FlasKMPEG, a free MPEG to MPEG/AVI converter
- *
- * FlasKMPEG 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, or (at your option)
- * any later version.
- *
- * FlasKMPEG 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 GNU Make; see the file COPYING. If not, write to
- * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- */
-
- #include <windows.h>
- #include <mmsystem.h>
- #include <malloc.h>
- #include <winbase.h>
-
- #include "AudioPlayback.h"
- #include "../debug.h"
-
- #define BUFFER_COUNT 20
- #define BUFFER_SIZE 16384
- #define BUFFER_SIZE_TOTAL (BUFFER_SIZE*BUFFER_COUNT)
-
- // #define PRINT_STATS
-
- #define WHDR_READYTOSEND 0x1
-
- // Global static module variables
- static HWAVEOUT hWaveOut;
- static HANDLE hAudioEv;
- static unsigned char buffers[BUFFER_COUNT][BUFFER_SIZE];
- static WAVEHDR wav_hdr[BUFFER_COUNT];
-
- // Init sound output system
- int AudioPlaybackStart(TAudioPlayback *ap)
- {
- WAVEFORMATEX waveFormat;
- int i;
-
- if(!ap)
- return 0;
- // chunk_size must be a multiple of the audio buffer
- if(ap->chunk_size%BUFFER_SIZE != 0)
- return 0;
-
- waveFormat.wFormatTag = WAVE_FORMAT_PCM;
- waveFormat.nChannels = ap->n_channels;
- waveFormat.nSamplesPerSec = ap->sample_freq;
- waveFormat.wBitsPerSample = 16;
- waveFormat.nBlockAlign = waveFormat.nChannels *
- waveFormat.wBitsPerSample /8;
- waveFormat.nAvgBytesPerSec = waveFormat.nSamplesPerSec *
- waveFormat.nBlockAlign;
- waveFormat.cbSize = 0;
-
-
- // Create an event for signaling finished work with audio blocks
- hAudioEv = CreateEvent(NULL, FALSE, FALSE, NULL);
-
- if( waveOutOpen( &hWaveOut,
- WAVE_MAPPER,
- &waveFormat,
- (DWORD)hAudioEv,
- 0,
- CALLBACK_EVENT)
- != MMSYSERR_NOERROR )
- return 0;
-
- // Prepare audio blocks
- for(i=0; i<BUFFER_COUNT; i++)
- {
- wav_hdr[i].lpData = (LPSTR) buffers[i];
- wav_hdr[i].dwBufferLength = BUFFER_SIZE;
- if( waveOutPrepareHeader( hWaveOut, &wav_hdr[i], sizeof(wav_hdr[i]) )
- != MMSYSERR_NOERROR )
- return 0;
- // if no error, set the audio blocks as done
- wav_hdr[i].dwFlags |= WHDR_DONE;
- wav_hdr[i].dwUser = 0;
- }
-
-
- return 1;
- }
-
- // Removes all buffers, and resets audio playback
- int AudioPlayBackReset()
- {
- waveOutReset( hWaveOut );
- return 0;
- }
-
-
- int AudioGetBufferDelay(TAudioPlayback *ap)
- {
- int i, nBufferedData = 0;
- for(i=0; i<BUFFER_COUNT; i++)
- {
- // If the buffer is not done
- if( !(wav_hdr[i].dwFlags & WHDR_DONE) )
- nBufferedData += wav_hdr[i].dwBufferLength;
- }
- return (nBufferedData * 1000)/(ap->sample_freq * ap->n_channels * 2);
- }
-
- int PrintStats(TAudioPlayback *ap)
- {
- // Gather amount of data in buffers
- int i, nBufferedData = 0;
- for(i=0; i<BUFFER_COUNT; i++)
- {
- // If the buffer is not done
- if( !(wav_hdr[i].dwFlags & WHDR_DONE) )
- nBufferedData += wav_hdr[i].dwBufferLength;
- }
-
-
- int nPercent = (nBufferedData * 100)/BUFFER_SIZE_TOTAL;
- int nDelayBuffer = (nBufferedData * 1000)/(ap->sample_freq * ap->n_channels * 2);
- // Spit stats
- DBG_STR((str, "Audio Buffer State: %d/%d -> %d%%, %d ms\n", nBufferedData,
- BUFFER_SIZE_TOTAL,
- nPercent,
- nDelayBuffer))
- return 0;
- }
-
-
- int AudioPlaybackWrite(TAudioPlayback *ap, unsigned char *data)
- {
- int remaining_bytes = ap->chunk_size;
- int i;
- #ifdef PRINT_STATS
- DBG_STR(( str, "------------\n"))
- PrintStats(ap);
- #endif
-
-
- // fill those blocks that have been played
- // and put them into the queue
- for(i=0; i<BUFFER_COUNT; i++)
- if( (wav_hdr[i].dwFlags & WHDR_DONE) && remaining_bytes)
- {
- memcpy(buffers[i], &data[ ap->chunk_size - remaining_bytes ], BUFFER_SIZE);
- wav_hdr[i].dwUser = WHDR_READYTOSEND;
- remaining_bytes -= BUFFER_SIZE;
- }
-
-
- // Now send the ones that are ready to send
- for(i=0; i<BUFFER_COUNT; i++)
- if( (wav_hdr[i].dwUser & WHDR_READYTOSEND) )
- {
- waveOutWrite( hWaveOut, &wav_hdr[i], sizeof(wav_hdr[i]) );
- wav_hdr[i].dwUser = 0;
- }
-
- // And now keep sending blocks until you are
- // finished with your data
- while( remaining_bytes )
- {
- // fill those blocks that have been played
- // and put them into the queue
- for(i=0; i<BUFFER_COUNT; i++)
- if( (wav_hdr[i].dwFlags & WHDR_DONE) && remaining_bytes)
- {
- memcpy(buffers[i], &data[ ap->chunk_size - remaining_bytes ], BUFFER_SIZE);
- waveOutWrite( hWaveOut, &wav_hdr[i], sizeof(wav_hdr[i]) );
- remaining_bytes -= BUFFER_SIZE;
- }
- // if there is no more data to write, exit
- if(!remaining_bytes)
- break;
- // wait for finished buffers
- WaitForSingleObject(hAudioEv, INFINITE);
- }
-
- #ifdef PRINT_STATS
- PrintStats(ap);
- DBG_STR(( str, "------------\n"))
- #endif
-
- return 1;
- }
-
- int AudioPlaybackStop(TAudioPlayback *ap)
- {
- int i;
- waveOutReset( hWaveOut );
- waveOutClose( hWaveOut );
- // UnPrepare audio blocks
- for(i=0; i<BUFFER_COUNT; i++)
- {
- waveOutUnprepareHeader( hWaveOut, &wav_hdr[i], sizeof(wav_hdr[i]) );
- }
- return 1;
- }