Bug 564734 - Ensure all audio is queued before draining on win32. r=kinetik

This commit is contained in:
Chris Pearce 2010-05-13 12:59:42 +12:00
parent 48c6564be0
commit 8d537247f7
4 changed files with 203 additions and 18 deletions

View File

@ -29,3 +29,6 @@ bug526411_latency.patch: reduce requested latency to 250ms to match OGGPLAY_AUDI
sydney_aix.patch: Bug 499266 - add support for AIX 5.x
bug562488_oss_destroy_crash.patch: Fix crash in OSS backend when destroying stream.
bug564734-win32-drain.patch: Ensure we can drain audio stream when there's less
than one block's worth of data left to be written. Also ensure that data is played.

View File

@ -0,0 +1,149 @@
diff --git a/media/libsydneyaudio/src/sydney_audio_waveapi.c b/media/libsydneyaudio/src/sydney_audio_waveapi.c
--- a/media/libsydneyaudio/src/sydney_audio_waveapi.c
+++ b/media/libsydneyaudio/src/sydney_audio_waveapi.c
@@ -121,16 +121,17 @@ struct sa_stream {
};
/** Forward definitions of audio api specific functions */
int allocateBlocks(int size, int count, WAVEHDR** blocks);
int freeBlocks(WAVEHDR* blocks);
int openAudio(sa_stream_t *s);
int closeAudio(sa_stream_t * s);
+int writeBlock(sa_stream_t *s, WAVEHDR* current);
int writeAudio(sa_stream_t *s, LPSTR data, int bytes);
int getSAErrorCode(int waveErrorCode);
void CALLBACK waveOutProc(HWAVEOUT hWaveOut, UINT uMsg,
DWORD dwInstance, DWORD dwParam1, DWORD dwParam2);
/** Normal way to open a PCM device */
int sa_stream_create_pcm(sa_stream_t **s,
@@ -320,20 +321,32 @@ int sa_stream_pause(sa_stream_t *s) {
status = waveOutPause(s->hWaveOut);
HANDLE_WAVE_ERROR(status, "resuming audio playback");
s->playing = 0;
return SA_SUCCESS;
}
+
/** Block until all audio has been played */
int sa_stream_drain(sa_stream_t *s) {
+ int status;
+ WAVEHDR* current;
+
ERROR_IF_NO_INIT(s);
-
+
+ current = &(s->waveBlocks[s->waveCurrentBlock]);
+ if (current->dwUser) {
+ /* We've got pending audio which hasn't been written, we must write it to
+ the hardware, else it will never be played. */
+ status = writeBlock(s, current);
+ HANDLE_WAVE_ERROR(status, "writing audio to audio device");
+ }
+
if (!s->playing) {
return SA_ERROR_INVALID;
}
/* wait for all blocks to complete */
EnterCriticalSection(&(s->waveCriticalSection));
while(s->waveFreeBlockCount < BLOCK_COUNT) {
LeaveCriticalSection(&(s->waveCriticalSection));
@@ -502,16 +515,48 @@ int closeAudio(sa_stream_t * s) {
s->playing = 0;
DeleteCriticalSection(&(s->waveCriticalSection));
CloseHandle(s->callbackEvent);
return result;
}
+
+/**
+ * \brief - writes a WAVEHDR block of PCM audio samples to hardware.
+ * \param s - valid handle to opened sydney stream
+ * \param current - pointer to WAVEHDR storing audio samples to be played
+ * \return - completion status
+ */
+int writeBlock(sa_stream_t *s, WAVEHDR* current) {
+ int status;
+ ERROR_IF_NO_INIT(s);
+
+ current->dwBufferLength = current->dwUser;
+ /* write to audio device */
+ waveOutPrepareHeader(s->hWaveOut, current, sizeof(WAVEHDR));
+ status = waveOutWrite(s->hWaveOut, current, sizeof(WAVEHDR));
+ HANDLE_WAVE_ERROR(status, "writing audio to audio device");
+
+ EnterCriticalSection(&(s->waveCriticalSection));
+ s->waveFreeBlockCount--;
+ LeaveCriticalSection(&(s->waveCriticalSection));
+
+ /*
+ * point to the next block
+ */
+ (s->waveCurrentBlock)++;
+ (s->waveCurrentBlock) %= BLOCK_COUNT;
+
+ s->playing = 1;
+
+ return SA_SUCCESS;
+}
+
/**
* \brief - writes PCM audio samples to audio device
* \param s - valid handle to opened sydney stream
* \param data - pointer to memory storing audio samples to be played
* \param nsamples - number of samples in the memory pointed by previous parameter
* \return - completion status
*/
int writeAudio(sa_stream_t *s, LPSTR data, int bytes) {
@@ -536,40 +581,27 @@ int writeAudio(sa_stream_t *s, LPSTR dat
if(bytes < (int)(BLOCK_SIZE - current->dwUser)) {
memcpy(current->lpData + current->dwUser, data, bytes);
current->dwUser += bytes;
break;
}
/* remain is even as BLOCK_SIZE and dwUser are even too */
- remain = BLOCK_SIZE - current->dwUser;
+ remain = BLOCK_SIZE - current->dwUser;
memcpy(current->lpData + current->dwUser, data, remain);
+ current->dwUser += remain;
bytes -= remain;
data += remain;
- current->dwBufferLength = BLOCK_SIZE;
- /* write to audio device */
- waveOutPrepareHeader(s->hWaveOut, current, sizeof(WAVEHDR));
- status = waveOutWrite(s->hWaveOut, current, sizeof(WAVEHDR));
+
+ status = writeBlock(s, current);
HANDLE_WAVE_ERROR(status, "writing audio to audio device");
-
- EnterCriticalSection(&(s->waveCriticalSection));
- s->waveFreeBlockCount--;
- LeaveCriticalSection(&(s->waveCriticalSection));
-
- /*
- * point to the next block
- */
- (s->waveCurrentBlock)++;
- (s->waveCurrentBlock) %= BLOCK_COUNT;
current = &(s->waveBlocks[s->waveCurrentBlock]);
current->dwUser = 0;
-
- s->playing = 1;
}
return SA_SUCCESS;
}
/**
* \brief - audio callback function called when next WAVE header is played by audio device
*/
void CALLBACK waveOutProc(

View File

@ -126,6 +126,7 @@ int allocateBlocks(int size, int count, WAVEHDR** blocks);
int freeBlocks(WAVEHDR* blocks);
int openAudio(sa_stream_t *s);
int closeAudio(sa_stream_t * s);
int writeBlock(sa_stream_t *s, WAVEHDR* current);
int writeAudio(sa_stream_t *s, LPSTR data, int bytes);
int getSAErrorCode(int waveErrorCode);
@ -325,10 +326,22 @@ int sa_stream_pause(sa_stream_t *s) {
return SA_SUCCESS;
}
/** Block until all audio has been played */
int sa_stream_drain(sa_stream_t *s) {
int status;
WAVEHDR* current;
ERROR_IF_NO_INIT(s);
current = &(s->waveBlocks[s->waveCurrentBlock]);
if (current->dwUser) {
/* We've got pending audio which hasn't been written, we must write it to
the hardware, else it will never be played. */
status = writeBlock(s, current);
HANDLE_WAVE_ERROR(status, "writing audio to audio device");
}
if (!s->playing) {
return SA_ERROR_INVALID;
}
@ -507,6 +520,38 @@ int closeAudio(sa_stream_t * s) {
return result;
}
/**
* \brief - writes a WAVEHDR block of PCM audio samples to hardware.
* \param s - valid handle to opened sydney stream
* \param current - pointer to WAVEHDR storing audio samples to be played
* \return - completion status
*/
int writeBlock(sa_stream_t *s, WAVEHDR* current) {
int status;
ERROR_IF_NO_INIT(s);
current->dwBufferLength = current->dwUser;
/* write to audio device */
waveOutPrepareHeader(s->hWaveOut, current, sizeof(WAVEHDR));
status = waveOutWrite(s->hWaveOut, current, sizeof(WAVEHDR));
HANDLE_WAVE_ERROR(status, "writing audio to audio device");
EnterCriticalSection(&(s->waveCriticalSection));
s->waveFreeBlockCount--;
LeaveCriticalSection(&(s->waveCriticalSection));
/*
* point to the next block
*/
(s->waveCurrentBlock)++;
(s->waveCurrentBlock) %= BLOCK_COUNT;
s->playing = 1;
return SA_SUCCESS;
}
/**
* \brief - writes PCM audio samples to audio device
* \param s - valid handle to opened sydney stream
@ -541,30 +586,17 @@ int writeAudio(sa_stream_t *s, LPSTR data, int bytes) {
}
/* remain is even as BLOCK_SIZE and dwUser are even too */
remain = BLOCK_SIZE - current->dwUser;
remain = BLOCK_SIZE - current->dwUser;
memcpy(current->lpData + current->dwUser, data, remain);
current->dwUser += remain;
bytes -= remain;
data += remain;
current->dwBufferLength = BLOCK_SIZE;
/* write to audio device */
waveOutPrepareHeader(s->hWaveOut, current, sizeof(WAVEHDR));
status = waveOutWrite(s->hWaveOut, current, sizeof(WAVEHDR));
HANDLE_WAVE_ERROR(status, "writing audio to audio device");
EnterCriticalSection(&(s->waveCriticalSection));
s->waveFreeBlockCount--;
LeaveCriticalSection(&(s->waveCriticalSection));
/*
* point to the next block
*/
(s->waveCurrentBlock)++;
(s->waveCurrentBlock) %= BLOCK_COUNT;
status = writeBlock(s, current);
HANDLE_WAVE_ERROR(status, "writing audio to audio device");
current = &(s->waveBlocks[s->waveCurrentBlock]);
current->dwUser = 0;
s->playing = 1;
}
return SA_SUCCESS;
}

View File

@ -15,3 +15,4 @@ patch -p3 <bug525401_drain_deadlock.patch
patch -p3 <bug526411_latency.patch
patch -p3 <sydney_aix.patch
patch -p3 <bug562488_oss_destroy_crash.patch
patch -p3 <bug564734-win32-drain.patch