From 2fd6a865a4cac4c90fa553d419ddf8ee541fc3b3 Mon Sep 17 00:00:00 2001 From: "flamingice%sourmilk.net" Date: Fri, 25 Aug 2006 20:29:26 +0000 Subject: [PATCH] Bug 68804, Sound output cracks, r+sr=roc a=mconnor git-svn-id: svn://10.0.0.236/branches/MOZILLA_1_8_BRANCH@208457 18797224-902f-48f8-a5cc-f745e15eee43 --- mozilla/widget/src/gtk2/nsSound.cpp | 131 +++++++++++++++++----------- 1 file changed, 81 insertions(+), 50 deletions(-) diff --git a/mozilla/widget/src/gtk2/nsSound.cpp b/mozilla/widget/src/gtk2/nsSound.cpp index a5d4af49fcf..9c5ae129eb5 100644 --- a/mozilla/widget/src/gtk2/nsSound.cpp +++ b/mozilla/widget/src/gtk2/nsSound.cpp @@ -166,9 +166,10 @@ NS_IMETHODIMP nsSound::OnStreamComplete(nsIStreamLoader *aLoader, } int fd, mask = 0; - unsigned long samples_per_sec=0, avg_bytes_per_sec=0; - unsigned long rate=0; - unsigned short format, channels = 1, block_align, bits_per_sample=0; + PRUint32 samples_per_sec = 0, avg_bytes_per_sec = 0, chunk_len = 0; + PRUint16 format, channels = 1, bits_per_sample = 0; + const PRUint8 *audio = nsnull; + size_t audio_len = 0; if (memcmp(data, "RIFF", 4)) { #ifdef DEBUG @@ -182,48 +183,81 @@ NS_IMETHODIMP nsSound::OnStreamComplete(nsIStreamLoader *aLoader, return NS_ERROR_FAILURE; } - PRUint32 i; - for (i= 0; i < dataLen; i++) { - if (i+3 <= dataLen) - if ((data[i] == 'f') && - (data[i+1] == 'm') && - (data[i+2] == 't') && - (data[i+3] == ' ')) { - i += 4; + PRUint32 i = 12; + while (i + 7 < dataLen) { + if (!memcmp(data + i, "fmt ", 4) && !chunk_len) { + i += 4; - /* length of the rest of this subblock (should be 16 for PCM data */ - i+=4; - - format = GET_WORD(data, i); - i+=2; + /* length of the rest of this subblock (should be 16 for PCM data */ + chunk_len = GET_DWORD(data, i); + i += 4; - channels = GET_WORD(data, i); - i+=2; - - samples_per_sec = GET_DWORD(data, i); - i+=4; - - avg_bytes_per_sec = GET_DWORD(data, i); - i+=4; - - block_align = GET_WORD(data, i); - i+=2; - - bits_per_sample = GET_WORD(data, i); - i+=2; - - rate = samples_per_sec; - - break; + if (chunk_len < 16 || i + chunk_len >= dataLen) { + NS_WARNING("Invalid WAV file: bad fmt chunk."); + return NS_ERROR_FAILURE; } + + format = GET_WORD(data, i); + i += 2; + + channels = GET_WORD(data, i); + i += 2; + + samples_per_sec = GET_DWORD(data, i); + i += 4; + + avg_bytes_per_sec = GET_DWORD(data, i); + i += 4; + + // block align + i += 2; + + bits_per_sample = GET_WORD(data, i); + i += 2; + + /* we don't support WAVs with odd compression codes */ + if (chunk_len != 16) + NS_WARNING("Extra format bits found in WAV. Ignoring"); + + i += chunk_len - 16; + } else if (!memcmp(data + i, "data", 4)) { + i += 4; + if (!chunk_len) { + NS_WARNING("Invalid WAV file: no fmt chunk found"); + return NS_ERROR_FAILURE; + } + + audio_len = GET_DWORD(data, i); + i += 4; + + /* try to play truncated WAVs */ + if (i + audio_len > dataLen) + audio_len = dataLen - i; + + audio = data + i; + break; + } else { + i += 4; + i += GET_DWORD(data, i); + i += 4; + } } + if (!audio) { + NS_WARNING("Invalid WAV file: no data chunk found"); + return NS_ERROR_FAILURE; + } + + /* No audio data? well, at least the WAV was valid. */ + if (!audio_len) + return NS_OK; + #if 0 printf("f: %d | c: %d | sps: %li | abps: %li | ba: %d | bps: %d | rate: %li\n", format, channels, samples_per_sec, avg_bytes_per_sec, block_align, bits_per_sample, rate); #endif - /* open up conneciton to esd */ + /* open up connection to esd */ EsdPlayStreamType EsdPlayStream = (EsdPlayStreamType) PR_FindSymbol(elib, "esd_play_stream"); @@ -247,22 +281,19 @@ NS_IMETHODIMP nsSound::OnStreamComplete(nsIStreamLoader *aLoader, // Swap the byte order if we're on a big-endian architecture. #ifdef IS_BIG_ENDIAN if (bits_per_sample != 8) { - buf = new PRUint8[dataLen - WAV_MIN_LENGTH]; - // According to the wav file format, the first 44 bytes are headers. - // We don't really need to send them. + buf = new PRUint8[audio_len]; if (!buf) return NS_ERROR_OUT_OF_MEMORY; - for (PRUint32 j = 0; j < dataLen - WAV_MIN_LENGTH - 1; j += 2) { - buf[j] = data[j + WAV_MIN_LENGTH + 1]; - buf[j + 1] = data[j + WAV_MIN_LENGTH]; + for (PRUint32 j = 0; j + 2 < audio_len; j += 2) { + buf[j] = audio[j + 1]; + buf[j + 1] = audio[j]; } - data = buf; - dataLen -= WAV_MIN_LENGTH; + audio = buf; } #endif - fd = (*EsdPlayStream)(mask, rate, NULL, "mozillaSound"); + fd = (*EsdPlayStream)(mask, samples_per_sec, NULL, "mozillaSound"); if (fd < 0) { int *esd_audio_format = (int *) PR_FindSymbol(elib, "esd_audio_format"); @@ -272,21 +303,21 @@ NS_IMETHODIMP nsSound::OnStreamComplete(nsIStreamLoader *aLoader, EsdAudioCloseType EsdAudioClose = (EsdAudioCloseType) PR_FindSymbol(elib, "esd_audio_close"); *esd_audio_format = mask; - *esd_audio_rate = rate; + *esd_audio_rate = samples_per_sec; fd = (*EsdAudioOpen)(); if (fd < 0) return NS_ERROR_FAILURE; - (*EsdAudioWrite)(data, dataLen); + (*EsdAudioWrite)(audio, audio_len); (*EsdAudioClose)(); } else { - while (dataLen > 0) { - size_t written = write(fd, data, dataLen); + while (audio_len > 0) { + size_t written = write(fd, audio, audio_len); if (written <= 0) break; - data += written; - dataLen -= written; + audio += written; + audio_len -= written; } close(fd); }