static FILE* OpenDumpFile(AudioStream* aStream) { if (!getenv("MOZ_DUMP_AUDIO")) return nullptr; char buf[100]; snprintf_literal(buf, "dumped-audio-%d.wav", gDumpedAudioCount); FILE* f = fopen(buf, "wb"); if (!f) return nullptr; ++gDumpedAudioCount; uint8_t header[] = { // RIFF header 0x52, 0x49, 0x46, 0x46, 0x00, 0x00, 0x00, 0x00, 0x57, 0x41, 0x56, 0x45, // fmt chunk. We always write 16-bit samples. 0x66, 0x6d, 0x74, 0x20, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x10, 0x00, // data chunk 0x64, 0x61, 0x74, 0x61, 0xFE, 0xFF, 0xFF, 0x7F }; static const int CHANNEL_OFFSET = 22; static const int SAMPLE_RATE_OFFSET = 24; static const int BLOCK_ALIGN_OFFSET = 32; SetUint16LE(header + CHANNEL_OFFSET, aStream->GetChannels()); SetUint32LE(header + SAMPLE_RATE_OFFSET, aStream->GetRate()); SetUint16LE(header + BLOCK_ALIGN_OFFSET, aStream->GetChannels()*2); fwrite(header, sizeof(header), 1, f); return f; }
typename EnableIf<IsSame<T, float>::value, void>::Type WriteDumpFileHelper(T* aInput, size_t aSamples, FILE* aFile) { AutoTArray<uint8_t, 1024*2> buf; buf.SetLength(aSamples*2); uint8_t* output = buf.Elements(); for (uint32_t i = 0; i < aSamples; ++i) { SetUint16LE(output + i*2, int16_t(aInput[i]*32767.0f)); } fwrite(output, 2, aSamples, aFile); fflush(aFile); }
static FILE* OpenDumpFile(uint32_t aChannels, uint32_t aRate) { /** * When MOZ_DUMP_AUDIO is set in the environment (to anything), * we'll drop a series of files in the current working directory named * dumped-audio-<nnn>.wav, one per AudioStream created, containing * the audio for the stream including any skips due to underruns. */ static Atomic<int> gDumpedAudioCount(0); if (!getenv("MOZ_DUMP_AUDIO")) return nullptr; char buf[100]; snprintf_literal(buf, "dumped-audio-%d.wav", ++gDumpedAudioCount); FILE* f = fopen(buf, "wb"); if (!f) return nullptr; uint8_t header[] = { // RIFF header 0x52, 0x49, 0x46, 0x46, 0x00, 0x00, 0x00, 0x00, 0x57, 0x41, 0x56, 0x45, // fmt chunk. We always write 16-bit samples. 0x66, 0x6d, 0x74, 0x20, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x10, 0x00, // data chunk 0x64, 0x61, 0x74, 0x61, 0xFE, 0xFF, 0xFF, 0x7F }; static const int CHANNEL_OFFSET = 22; static const int SAMPLE_RATE_OFFSET = 24; static const int BLOCK_ALIGN_OFFSET = 32; SetUint16LE(header + CHANNEL_OFFSET, aChannels); SetUint32LE(header + SAMPLE_RATE_OFFSET, aRate); SetUint16LE(header + BLOCK_ALIGN_OFFSET, aChannels * 2); fwrite(header, sizeof(header), 1, f); return f; }
static void WriteDumpFile(FILE* aDumpFile, AudioStream* aStream, uint32_t aFrames, void* aBuffer) { if (!aDumpFile) return; uint32_t samples = aStream->GetOutChannels()*aFrames; if (AUDIO_OUTPUT_FORMAT == AUDIO_FORMAT_S16) { fwrite(aBuffer, 2, samples, aDumpFile); return; } NS_ASSERTION(AUDIO_OUTPUT_FORMAT == AUDIO_FORMAT_FLOAT32, "bad format"); nsAutoTArray<uint8_t, 1024*2> buf; buf.SetLength(samples*2); float* input = static_cast<float*>(aBuffer); uint8_t* output = buf.Elements(); for (uint32_t i = 0; i < samples; ++i) { SetUint16LE(output + i*2, int16_t(input[i]*32767.0f)); } fwrite(output, 2, samples, aDumpFile); fflush(aDumpFile); }
static void SetUint32LE(uint8_t* aDest, uint32_t aValue) { SetUint16LE(aDest, aValue & 0xFFFF); SetUint16LE(aDest + 2, aValue >> 16); }
static void SetUint32LE(PRUint8* aDest, PRUint32 aValue) { SetUint16LE(aDest, aValue & 0xFFFF); SetUint16LE(aDest + 2, aValue >> 16); }