LCOV - code coverage report
Current view: top level - dom/media - AudioSegment.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 99 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 7 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* This Source Code Form is subject to the terms of the Mozilla Public
       3             :  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
       4             :  * You can obtain one at http://mozilla.org/MPL/2.0/. */
       5             : 
       6             : #include "AudioSegment.h"
       7             : 
       8             : #include "AudioMixer.h"
       9             : #include "AudioChannelFormat.h"
      10             : #include "Latency.h"
      11             : #include <speex/speex_resampler.h>
      12             : 
      13             : namespace mozilla {
      14             : 
      15             : const uint8_t SilentChannel::gZeroChannel[MAX_AUDIO_SAMPLE_SIZE*SilentChannel::AUDIO_PROCESSING_FRAMES] = {0};
      16             : 
      17             : template<>
      18           0 : const float* SilentChannel::ZeroChannel<float>()
      19             : {
      20           0 :   return reinterpret_cast<const float*>(SilentChannel::gZeroChannel);
      21             : }
      22             : 
      23             : template<>
      24           0 : const int16_t* SilentChannel::ZeroChannel<int16_t>()
      25             : {
      26           0 :   return reinterpret_cast<const int16_t*>(SilentChannel::gZeroChannel);
      27             : }
      28             : 
      29             : void
      30           0 : AudioSegment::ApplyVolume(float aVolume)
      31             : {
      32           0 :   for (ChunkIterator ci(*this); !ci.IsEnded(); ci.Next()) {
      33           0 :     ci->mVolume *= aVolume;
      34             :   }
      35           0 : }
      36             : 
      37           0 : void AudioSegment::ResampleChunks(SpeexResamplerState* aResampler, uint32_t aInRate, uint32_t aOutRate)
      38             : {
      39           0 :   if (mChunks.IsEmpty()) {
      40           0 :     return;
      41             :   }
      42             : 
      43           0 :   MOZ_ASSERT(aResampler || IsNull(), "We can only be here without a resampler if this segment is null.");
      44             : 
      45           0 :   AudioSampleFormat format = AUDIO_FORMAT_SILENCE;
      46           0 :   for (ChunkIterator ci(*this); !ci.IsEnded(); ci.Next()) {
      47           0 :     if (ci->mBufferFormat != AUDIO_FORMAT_SILENCE) {
      48           0 :       format = ci->mBufferFormat;
      49             :     }
      50             :   }
      51             : 
      52           0 :   switch (format) {
      53             :     // If the format is silence at this point, all the chunks are silent. The
      54             :     // actual function we use does not matter, it's just a matter of changing
      55             :     // the chunks duration.
      56             :     case AUDIO_FORMAT_SILENCE:
      57             :     case AUDIO_FORMAT_FLOAT32:
      58           0 :       Resample<float>(aResampler, aInRate, aOutRate);
      59           0 :     break;
      60             :     case AUDIO_FORMAT_S16:
      61           0 :       Resample<int16_t>(aResampler, aInRate, aOutRate);
      62           0 :     break;
      63             :     default:
      64           0 :       MOZ_ASSERT(false);
      65             :     break;
      66             :   }
      67             : }
      68             : 
      69             : // This helps to to safely get a pointer to the position we want to start
      70             : // writing a planar audio buffer, depending on the channel and the offset in the
      71             : // buffer.
      72             : static AudioDataValue*
      73           0 : PointerForOffsetInChannel(AudioDataValue* aData, size_t aLengthSamples,
      74             :                           uint32_t aChannelCount, uint32_t aChannel,
      75             :                           uint32_t aOffsetSamples)
      76             : {
      77           0 :   size_t samplesPerChannel = aLengthSamples / aChannelCount;
      78           0 :   size_t beginningOfChannel = samplesPerChannel * aChannel;
      79           0 :   MOZ_ASSERT(aChannel * samplesPerChannel + aOffsetSamples < aLengthSamples,
      80             :              "Offset request out of bounds.");
      81           0 :   return aData + beginningOfChannel + aOffsetSamples;
      82             : }
      83             : 
      84             : void
      85           0 : AudioSegment::Mix(AudioMixer& aMixer, uint32_t aOutputChannels,
      86             :                   uint32_t aSampleRate)
      87             : {
      88             :   AutoTArray<AudioDataValue, SilentChannel::AUDIO_PROCESSING_FRAMES* GUESS_AUDIO_CHANNELS>
      89           0 :   buf;
      90           0 :   AutoTArray<const AudioDataValue*, GUESS_AUDIO_CHANNELS> channelData;
      91           0 :   uint32_t offsetSamples = 0;
      92           0 :   uint32_t duration = GetDuration();
      93             : 
      94           0 :   if (duration <= 0) {
      95           0 :     MOZ_ASSERT(duration == 0);
      96           0 :     return;
      97             :   }
      98             : 
      99           0 :   uint32_t outBufferLength = duration * aOutputChannels;
     100           0 :   buf.SetLength(outBufferLength);
     101             : 
     102           0 :   for (ChunkIterator ci(*this); !ci.IsEnded(); ci.Next()) {
     103           0 :     AudioChunk& c = *ci;
     104           0 :     uint32_t frames = c.mDuration;
     105             : 
     106             :     // If the chunk is silent, simply write the right number of silence in the
     107             :     // buffers.
     108           0 :     if (c.mBufferFormat == AUDIO_FORMAT_SILENCE) {
     109           0 :       for (uint32_t channel = 0; channel < aOutputChannels; channel++) {
     110             :         AudioDataValue* ptr =
     111           0 :           PointerForOffsetInChannel(buf.Elements(), outBufferLength,
     112           0 :                                     aOutputChannels, channel, offsetSamples);
     113           0 :         PodZero(ptr, frames);
     114             :       }
     115             :     } else {
     116             :       // Othewise, we need to upmix or downmix appropriately, depending on the
     117             :       // desired input and output channels.
     118           0 :       channelData.SetLength(c.mChannelData.Length());
     119           0 :       for (uint32_t i = 0; i < channelData.Length(); ++i) {
     120           0 :         channelData[i] = static_cast<const AudioDataValue*>(c.mChannelData[i]);
     121             :       }
     122           0 :       if (channelData.Length() < aOutputChannels) {
     123             :         // Up-mix.
     124           0 :         AudioChannelsUpMix(&channelData, aOutputChannels, SilentChannel::ZeroChannel<AudioDataValue>());
     125           0 :         for (uint32_t channel = 0; channel < aOutputChannels; channel++) {
     126             :           AudioDataValue* ptr =
     127           0 :             PointerForOffsetInChannel(buf.Elements(), outBufferLength,
     128           0 :                                       aOutputChannels, channel, offsetSamples);
     129           0 :           PodCopy(ptr, reinterpret_cast<const AudioDataValue*>(channelData[channel]),
     130           0 :                   frames);
     131             :         }
     132           0 :         MOZ_ASSERT(channelData.Length() == aOutputChannels);
     133           0 :       } else if (channelData.Length() > aOutputChannels) {
     134             :         // Down mix.
     135           0 :         AutoTArray<AudioDataValue*, GUESS_AUDIO_CHANNELS> outChannelPtrs;
     136           0 :         outChannelPtrs.SetLength(aOutputChannels);
     137           0 :         uint32_t offsetSamples = 0;
     138           0 :         for (uint32_t channel = 0; channel < aOutputChannels; channel++) {
     139           0 :           outChannelPtrs[channel] =
     140           0 :             PointerForOffsetInChannel(buf.Elements(), outBufferLength,
     141             :                                       aOutputChannels, channel, offsetSamples);
     142             :         }
     143           0 :         AudioChannelsDownMix(channelData, outChannelPtrs.Elements(),
     144           0 :                              aOutputChannels, frames);
     145             :       } else {
     146             :         // The channel count is already what we want, just copy it over.
     147           0 :         for (uint32_t channel = 0; channel < aOutputChannels; channel++) {
     148             :           AudioDataValue* ptr =
     149           0 :             PointerForOffsetInChannel(buf.Elements(), outBufferLength,
     150           0 :                                       aOutputChannels, channel, offsetSamples);
     151           0 :           PodCopy(ptr, reinterpret_cast<const AudioDataValue*>(channelData[channel]),
     152           0 :                   frames);
     153             :         }
     154             :       }
     155             :     }
     156           0 :     offsetSamples += frames;
     157             :   }
     158             : 
     159           0 :   if (offsetSamples) {
     160           0 :     MOZ_ASSERT(offsetSamples == outBufferLength / aOutputChannels,
     161             :                "We forgot to write some samples?");
     162           0 :     aMixer.Mix(buf.Elements(), aOutputChannels, offsetSamples, aSampleRate);
     163             :   }
     164             : }
     165             : 
     166             : void
     167           0 : AudioSegment::WriteTo(uint64_t aID, AudioMixer& aMixer, uint32_t aOutputChannels, uint32_t aSampleRate)
     168             : {
     169           0 :   AutoTArray<AudioDataValue,SilentChannel::AUDIO_PROCESSING_FRAMES*GUESS_AUDIO_CHANNELS> buf;
     170             :   // Offset in the buffer that will be written to the mixer, in samples.
     171           0 :   uint32_t offset = 0;
     172             : 
     173           0 :   if (GetDuration() <= 0) {
     174           0 :     MOZ_ASSERT(GetDuration() == 0);
     175           0 :     return;
     176             :   }
     177             : 
     178           0 :   uint32_t outBufferLength = GetDuration() * aOutputChannels;
     179           0 :   buf.SetLength(outBufferLength);
     180             : 
     181             : 
     182           0 :   for (ChunkIterator ci(*this); !ci.IsEnded(); ci.Next()) {
     183           0 :     AudioChunk& c = *ci;
     184             : 
     185           0 :     switch (c.mBufferFormat) {
     186             :       case AUDIO_FORMAT_S16:
     187           0 :         WriteChunk<int16_t>(c, aOutputChannels, buf.Elements() + offset);
     188           0 :         break;
     189             :       case AUDIO_FORMAT_FLOAT32:
     190           0 :         WriteChunk<float>(c, aOutputChannels, buf.Elements() + offset);
     191           0 :         break;
     192             :       case AUDIO_FORMAT_SILENCE:
     193             :         // The mixer is expecting interleaved data, so this is ok.
     194           0 :         PodZero(buf.Elements() + offset, c.mDuration * aOutputChannels);
     195           0 :         break;
     196             :       default:
     197           0 :         MOZ_ASSERT(false, "Not handled");
     198             :     }
     199             : 
     200           0 :     offset += c.mDuration * aOutputChannels;
     201             : 
     202           0 :     if (!c.mTimeStamp.IsNull()) {
     203           0 :       TimeStamp now = TimeStamp::Now();
     204             :       // would be more efficient to c.mTimeStamp to ms on create time then pass here
     205           0 :       LogTime(AsyncLatencyLogger::AudioMediaStreamTrack, aID,
     206           0 :               (now - c.mTimeStamp).ToMilliseconds(), c.mTimeStamp);
     207             :     }
     208             :   }
     209             : 
     210           0 :   if (offset) {
     211           0 :     aMixer.Mix(buf.Elements(), aOutputChannels, offset / aOutputChannels, aSampleRate);
     212             :   }
     213             : }
     214             : 
     215             : } // namespace mozilla

Generated by: LCOV version 1.13