bug 1391482 delay conversion of output of decodeAudioData() from int16_t to float until necessary r?padenot draft
authorKarl Tomlinson <karlt+@karlt.net>
Thu, 17 Aug 2017 13:28:25 +1200
changeset 654733 cc8f6e9008cbcb1994b45853582fc42ff36ac1c0
parent 654732 1f4e95b5ef0fcb10d3aed6ca023ee630882dd29c
child 728641 288a6430aba3d5fdf54552e579305f5179131bee
push id76658
push userktomlinson@mozilla.com
push dateTue, 29 Aug 2017 06:20:42 +0000
reviewerspadenot
bugs1391482
milestone57.0a1
bug 1391482 delay conversion of output of decodeAudioData() from int16_t to float until necessary r?padenot On platforms with MOZ_SAMPLE_TYPE_S16, decode and resampling was already performed in 16-bit arithmetic. Keeping the potentially large buffer in 16-bit format halves the memory usage. This patch does not affect other platforms. MozReview-Commit-ID: DWZdiPNasie
dom/media/webaudio/MediaBufferDecoder.cpp
--- a/dom/media/webaudio/MediaBufferDecoder.cpp
+++ b/dom/media/webaudio/MediaBufferDecoder.cpp
@@ -342,82 +342,100 @@ MediaDecodeTask::FinishDecode()
     resampler = speex_resampler_init(channelCount,
                                      sampleRate,
                                      destSampleRate,
                                      SPEEX_RESAMPLER_QUALITY_DEFAULT, nullptr);
     speex_resampler_skip_zeros(resampler);
     resampledFrames += speex_resampler_get_output_latency(resampler);
   }
 
-  // Allocate the channel buffers.  Note that if we end up resampling, we may
-  // write fewer bytes than mResampledFrames to the output buffer, in which
-  // case writeIndex will tell us how many valid samples we have.
+  // Allocate contiguous channel buffers.  Note that if we end up resampling,
+  // we may write fewer bytes than mResampledFrames to the output buffer, in
+  // which case writeIndex will tell us how many valid samples we have.
+  mDecodeJob.mBuffer.mChannelData.SetLength(channelCount);
+#if AUDIO_OUTPUT_FORMAT == AUDIO_FORMAT_FLOAT32
+  // This buffer has separate channel arrays that could be transferred to
+  // JS_NewArrayBufferWithContents(), but AudioBuffer::RestoreJSChannelData()
+  // does not yet take advantage of this.
   RefPtr<ThreadSharedFloatArrayBufferList> buffer =
     ThreadSharedFloatArrayBufferList::
     Create(channelCount, resampledFrames, fallible);
   if (!buffer) {
     ReportFailureOnMainThread(WebAudioDecodeJob::UnknownError);
     return;
   }
-  mDecodeJob.mBuffer.mChannelData.SetLength(channelCount);
   for (uint32_t i = 0; i < channelCount; ++i) {
     mDecodeJob.mBuffer.mChannelData[i] = buffer->GetData(i);
   }
+#else
+  RefPtr<SharedBuffer> buffer =
+    SharedBuffer::Create(sizeof(AudioDataValue) *
+                         resampledFrames * channelCount);
+  if (!buffer) {
+    ReportFailureOnMainThread(WebAudioDecodeJob::UnknownError);
+    return;
+  }
+  auto data = static_cast<AudioDataValue*>(floatBuffer->Data());
+  for (uint32_t i = 0; i < channelCount; ++i) {
+    mDecodeJob.mBuffer.mChannelData[i] = data;
+    data += resampledFrames;
+  }
+#endif
   mDecodeJob.mBuffer.mBuffer = buffer.forget();
   mDecodeJob.mBuffer.mVolume = 1.0f;
-  mDecodeJob.mBuffer.mBufferFormat = AUDIO_FORMAT_FLOAT32;
+  mDecodeJob.mBuffer.mBufferFormat = AUDIO_OUTPUT_FORMAT;
 
   uint32_t writeIndex = 0;
   RefPtr<AudioData> audioData;
   while ((audioData = mAudioQueue.PopFront())) {
     audioData->EnsureAudioBuffer(); // could lead to a copy :(
-    AudioDataValue* bufferData = static_cast<AudioDataValue*>
+    const AudioDataValue* bufferData = static_cast<AudioDataValue*>
       (audioData->mAudioBuffer->Data());
 
     if (sampleRate != destSampleRate) {
       const uint32_t maxOutSamples = resampledFrames - writeIndex;
 
       for (uint32_t i = 0; i < audioData->mChannels; ++i) {
         uint32_t inSamples = audioData->mFrames;
         uint32_t outSamples = maxOutSamples;
-        float* outData =
-          mDecodeJob.mBuffer.ChannelDataForWrite<float>(i) + writeIndex;
+        AudioDataValue* outData = mDecodeJob.mBuffer.
+          ChannelDataForWrite<AudioDataValue>(i) + writeIndex;
 
         WebAudioUtils::SpeexResamplerProcess(
             resampler, i, &bufferData[i * audioData->mFrames], &inSamples,
             outData, &outSamples);
 
         if (i == audioData->mChannels - 1) {
           writeIndex += outSamples;
           MOZ_ASSERT(writeIndex <= resampledFrames);
           MOZ_ASSERT(inSamples == audioData->mFrames);
         }
       }
     } else {
       for (uint32_t i = 0; i < audioData->mChannels; ++i) {
-        float* outData =
-          mDecodeJob.mBuffer.ChannelDataForWrite<float>(i) + writeIndex;
-        ConvertAudioSamples(&bufferData[i * audioData->mFrames],
-                            outData, audioData->mFrames);
+        AudioDataValue* outData = mDecodeJob.mBuffer.
+          ChannelDataForWrite<AudioDataValue>(i) + writeIndex;
+        PodCopy(outData, &bufferData[i * audioData->mFrames],
+                audioData->mFrames);
 
         if (i == audioData->mChannels - 1) {
           writeIndex += audioData->mFrames;
         }
       }
     }
   }
 
   if (sampleRate != destSampleRate) {
     uint32_t inputLatency = speex_resampler_get_input_latency(resampler);
     const uint32_t maxOutSamples = resampledFrames - writeIndex;
     for (uint32_t i = 0; i < channelCount; ++i) {
       uint32_t inSamples = inputLatency;
       uint32_t outSamples = maxOutSamples;
-      float* outData =
-        mDecodeJob.mBuffer.ChannelDataForWrite<float>(i) + writeIndex;
+      AudioDataValue* outData =
+        mDecodeJob.mBuffer.ChannelDataForWrite<AudioDataValue>(i) + writeIndex;
 
       WebAudioUtils::SpeexResamplerProcess(
           resampler, i, (AudioDataValue*)nullptr, &inSamples,
           outData, &outSamples);
 
       if (i == channelCount - 1) {
         writeIndex += outSamples;
         MOZ_ASSERT(writeIndex <= resampledFrames);