1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #if !defined(WavDumper_h_)
11 # include <nsTArray.h>
12 # include <nsString.h>
13 # include <mozilla/Unused.h>
14 # include <mozilla/Atomics.h>
15 # include <mozilla/DebugOnly.h>
16 # include <mozilla/Sprintf.h>
17 # include <ByteWriter.h>
20 * If MOZ_DUMP_AUDIO is set, this dumps a file to disk containing the output of
21 * an audio stream, in 16bits integers.
23 * The sandbox needs to be disabled for this to work.
27 WavDumper() = default;
34 void Open(const char* aBaseName
, uint32_t aChannels
, uint32_t aRate
) {
35 using namespace mozilla
;
37 if (!getenv("MOZ_DUMP_AUDIO")) {
41 static mozilla::Atomic
<int> sDumpedAudioCount(0);
44 SprintfLiteral(buf
, "%s-%d.wav", aBaseName
, ++sDumpedAudioCount
);
45 OpenExplicit(buf
, aChannels
, aRate
);
48 void OpenExplicit(const char* aPath
, uint32_t aChannels
, uint32_t aRate
) {
50 nsAutoString widePath
= NS_ConvertUTF8toUTF16(aPath
);
51 mFile
= _wfopen(widePath
.get(), L
"wb");
53 mFile
= fopen(aPath
, "wb");
56 NS_WARNING("Could not open file to DUMP a wav. Is sandboxing disabled?");
59 const uint8_t riffHeader
[] = {
61 0x52, 0x49, 0x46, 0x46, 0x00, 0x00, 0x00, 0x00, 0x57, 0x41, 0x56, 0x45,
62 // fmt chunk. We always write 16-bit samples.
63 0x66, 0x6d, 0x74, 0x20, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0xFF, 0xFF,
64 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x10, 0x00,
66 0x64, 0x61, 0x74, 0x61, 0xFE, 0xFF, 0xFF, 0x7F};
67 AutoTArray
<uint8_t, sizeof(riffHeader
)> header
;
68 mozilla::ByteWriter
<mozilla::LittleEndian
> writer(header
);
69 static const int CHANNEL_OFFSET
= 22;
70 static const int SAMPLE_RATE_OFFSET
= 24;
71 static const int BLOCK_ALIGN_OFFSET
= 32;
73 mozilla::DebugOnly
<bool> rv
;
74 // Then number of bytes written in each iteration.
76 for (size_t i
= 0; i
!= sizeof(riffHeader
);) {
79 rv
= writer
.WriteU16(aChannels
);
83 case SAMPLE_RATE_OFFSET
:
84 rv
= writer
.WriteU32(aRate
);
88 case BLOCK_ALIGN_OFFSET
:
89 rv
= writer
.WriteU16(aChannels
* 2);
94 // copy from the riffHeader struct above
95 rv
= writer
.WriteU8(riffHeader
[i
]);
102 mozilla::Unused
<< fwrite(header
.Elements(), header
.Length(), 1, mFile
);
105 template <typename T
>
106 void Write(const T
* aBuffer
, uint32_t aSamples
) {
111 WriteDumpFileHelper(aBuffer
, aSamples
);
113 constexpr size_t blockSize
= 128;
114 T block
[blockSize
] = {};
115 for (size_t remaining
= aSamples
; remaining
;) {
116 size_t toWrite
= std::min(remaining
, blockSize
);
117 fwrite(block
, sizeof(T
), toWrite
, mFile
);
118 remaining
-= toWrite
;
125 void WriteDumpFileHelper(const int16_t* aInput
, size_t aSamples
) {
126 mozilla::Unused
<< fwrite(aInput
, sizeof(int16_t), aSamples
, mFile
);
129 void WriteDumpFileHelper(const float* aInput
, size_t aSamples
) {
130 using namespace mozilla
;
132 AutoTArray
<uint8_t, 1024 * 2> buf
;
133 mozilla::ByteWriter
<mozilla::LittleEndian
> writer(buf
);
134 for (uint32_t i
= 0; i
< aSamples
; ++i
) {
135 mozilla::DebugOnly
<bool> rv
=
136 writer
.WriteU16(int16_t(aInput
[i
] * 32767.0f
));
139 mozilla::Unused
<< fwrite(buf
.Elements(), buf
.Length(), 1, mFile
);
142 FILE* mFile
= nullptr;
145 #endif // WavDumper_h_