LCOV - code coverage report
Current view: top level - dom/media - AudioConverter.h (source / functions) Hit Total Coverage
Test: output.info Lines: 0 51 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 12 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             : /* 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/. */
       6             : 
       7             : #if !defined(AudioConverter_h)
       8             : #define AudioConverter_h
       9             : 
      10             : #include "MediaInfo.h"
      11             : 
      12             : // Forward declaration
      13             : typedef struct SpeexResamplerState_ SpeexResamplerState;
      14             : 
      15             : namespace mozilla {
      16             : 
      17             : template <AudioConfig::SampleFormat T> struct AudioDataBufferTypeChooser;
      18             : template <> struct AudioDataBufferTypeChooser<AudioConfig::FORMAT_U8>
      19             : { typedef uint8_t Type; };
      20             : template <> struct AudioDataBufferTypeChooser<AudioConfig::FORMAT_S16>
      21             : { typedef int16_t Type; };
      22             : template <> struct AudioDataBufferTypeChooser<AudioConfig::FORMAT_S24LSB>
      23             : { typedef int32_t Type; };
      24             : template <> struct AudioDataBufferTypeChooser<AudioConfig::FORMAT_S24>
      25             : { typedef int32_t Type; };
      26             : template <> struct AudioDataBufferTypeChooser<AudioConfig::FORMAT_S32>
      27             : { typedef int32_t Type; };
      28             : template <> struct AudioDataBufferTypeChooser<AudioConfig::FORMAT_FLT>
      29             : { typedef float Type; };
      30             : 
      31             : // 'Value' is the type used externally to deal with stored value.
      32             : // AudioDataBuffer can perform conversion between different SampleFormat content.
      33             : template <AudioConfig::SampleFormat Format, typename Value = typename AudioDataBufferTypeChooser<Format>::Type>
      34           0 : class AudioDataBuffer
      35             : {
      36             : public:
      37             :   AudioDataBuffer() {}
      38             :   AudioDataBuffer(Value* aBuffer, size_t aLength)
      39             :     : mBuffer(aBuffer, aLength)
      40             :   {}
      41             :   explicit AudioDataBuffer(const AudioDataBuffer& aOther)
      42             :     : mBuffer(aOther.mBuffer)
      43             :   {}
      44           0 :   AudioDataBuffer(AudioDataBuffer&& aOther)
      45           0 :     : mBuffer(Move(aOther.mBuffer))
      46           0 :   {}
      47             :   template <AudioConfig::SampleFormat OtherFormat, typename OtherValue>
      48             :   explicit AudioDataBuffer(const AudioDataBuffer<OtherFormat, OtherValue>& other)
      49             :   {
      50             :     // TODO: Convert from different type, may use asm routines.
      51             :     MOZ_CRASH("Conversion not implemented yet");
      52             :   }
      53             : 
      54             :   // A u8, s16 and float aligned buffer can only be treated as
      55             :   // FORMAT_U8, FORMAT_S16 and FORMAT_FLT respectively.
      56             :   // So allow them as copy and move constructors.
      57             :   explicit AudioDataBuffer(const AlignedByteBuffer& aBuffer)
      58             :     : mBuffer(aBuffer)
      59             :   {
      60             :     static_assert(Format == AudioConfig::FORMAT_U8,
      61             :                   "Conversion not implemented yet");
      62             :   }
      63             :   explicit AudioDataBuffer(const AlignedShortBuffer& aBuffer)
      64             :     : mBuffer(aBuffer)
      65             :   {
      66             :     static_assert(Format == AudioConfig::FORMAT_S16,
      67             :                   "Conversion not implemented yet");
      68             :   }
      69             :   explicit AudioDataBuffer(const AlignedFloatBuffer& aBuffer)
      70             :     : mBuffer(aBuffer)
      71             :   {
      72             :     static_assert(Format == AudioConfig::FORMAT_FLT,
      73             :                   "Conversion not implemented yet");
      74             :   }
      75             :   explicit AudioDataBuffer(AlignedByteBuffer&& aBuffer)
      76             :     : mBuffer(Move(aBuffer))
      77             :   {
      78             :     static_assert(Format == AudioConfig::FORMAT_U8,
      79             :                   "Conversion not implemented yet");
      80             :   }
      81             :   explicit AudioDataBuffer(AlignedShortBuffer&& aBuffer)
      82             :     : mBuffer(Move(aBuffer))
      83             :   {
      84             :     static_assert(Format == AudioConfig::FORMAT_S16,
      85             :                   "Conversion not implemented yet");
      86             :   }
      87           0 :   explicit AudioDataBuffer(AlignedFloatBuffer&& aBuffer)
      88           0 :     : mBuffer(Move(aBuffer))
      89             :   {
      90             :     static_assert(Format == AudioConfig::FORMAT_FLT,
      91             :                   "Conversion not implemented yet");
      92           0 :   }
      93           0 :   AudioDataBuffer& operator=(AudioDataBuffer&& aOther)
      94             :   {
      95           0 :     mBuffer = Move(aOther.mBuffer);
      96           0 :     return *this;
      97             :   }
      98             :   AudioDataBuffer& operator=(const AudioDataBuffer& aOther)
      99             :   {
     100             :     mBuffer = aOther.mBuffer;
     101             :     return *this;
     102             :   }
     103             : 
     104           0 :   Value* Data() const { return mBuffer.Data(); }
     105           0 :   size_t Length() const { return mBuffer.Length(); }
     106             :   size_t Size() const { return mBuffer.Size(); }
     107           0 :   AlignedBuffer<Value> Forget()
     108             :   {
     109             :     // Correct type -> Just give values as-is.
     110           0 :     return Move(mBuffer);
     111             :   }
     112             : private:
     113             :   AlignedBuffer<Value> mBuffer;
     114             : };
     115             : 
     116             : typedef AudioDataBuffer<AudioConfig::FORMAT_DEFAULT> AudioSampleBuffer;
     117             : 
     118             : class AudioConverter {
     119             : public:
     120             :   AudioConverter(const AudioConfig& aIn, const AudioConfig& aOut);
     121             :   ~AudioConverter();
     122             : 
     123             :   // Convert the AudioDataBuffer.
     124             :   // Conversion will be done in place if possible. Otherwise a new buffer will
     125             :   // be returned.
     126             :   // Providing an empty buffer and resampling is expected, the resampler
     127             :   // will be drained.
     128             :   template <AudioConfig::SampleFormat Format, typename Value>
     129           0 :   AudioDataBuffer<Format, Value> Process(AudioDataBuffer<Format, Value>&& aBuffer)
     130             :   {
     131           0 :     MOZ_DIAGNOSTIC_ASSERT(mIn.Format() == mOut.Format() && mIn.Format() == Format);
     132           0 :     AudioDataBuffer<Format, Value> buffer = Move(aBuffer);
     133           0 :     if (CanWorkInPlace()) {
     134           0 :       size_t frames = SamplesInToFrames(buffer.Length());
     135           0 :       frames = ProcessInternal(buffer.Data(), buffer.Data(), frames);
     136           0 :       if (frames && mIn.Rate() != mOut.Rate()) {
     137           0 :         frames = ResampleAudio(buffer.Data(), buffer.Data(), frames);
     138             :       }
     139           0 :       AlignedBuffer<Value> temp = buffer.Forget();
     140           0 :       temp.SetLength(FramesOutToSamples(frames));
     141           0 :       return AudioDataBuffer<Format, Value>(Move(temp));;
     142             :     }
     143           0 :     return Process(buffer);
     144             :   }
     145             : 
     146             :   template <AudioConfig::SampleFormat Format, typename Value>
     147           0 :   AudioDataBuffer<Format, Value> Process(const AudioDataBuffer<Format, Value>& aBuffer)
     148             :   {
     149           0 :     MOZ_DIAGNOSTIC_ASSERT(mIn.Format() == mOut.Format() && mIn.Format() == Format);
     150             :     // Perform the downmixing / reordering in temporary buffer.
     151           0 :     size_t frames = SamplesInToFrames(aBuffer.Length());
     152           0 :     AlignedBuffer<Value> temp1;
     153           0 :     if (!temp1.SetLength(FramesOutToSamples(frames))) {
     154           0 :       return AudioDataBuffer<Format, Value>(Move(temp1));
     155             :     }
     156           0 :     frames = ProcessInternal(temp1.Data(), aBuffer.Data(), frames);
     157           0 :     if (mIn.Rate() == mOut.Rate()) {
     158           0 :       MOZ_ALWAYS_TRUE(temp1.SetLength(FramesOutToSamples(frames)));
     159           0 :       return AudioDataBuffer<Format, Value>(Move(temp1));
     160             :     }
     161             : 
     162             :     // At this point, temp1 contains the buffer reordered and downmixed.
     163             :     // If we are downsampling we can re-use it.
     164           0 :     AlignedBuffer<Value>* outputBuffer = &temp1;
     165           0 :     AlignedBuffer<Value> temp2;
     166           0 :     if (!frames || mOut.Rate() > mIn.Rate()) {
     167             :       // We are upsampling or about to drain, we can't work in place.
     168             :       // Allocate another temporary buffer where the upsampling will occur.
     169           0 :       if (!temp2.SetLength(FramesOutToSamples(ResampleRecipientFrames(frames)))) {
     170           0 :         return AudioDataBuffer<Format, Value>(Move(temp2));
     171             :       }
     172           0 :       outputBuffer = &temp2;
     173             :     }
     174           0 :     if (!frames) {
     175           0 :       frames = DrainResampler(outputBuffer->Data());
     176             :     } else {
     177           0 :       frames = ResampleAudio(outputBuffer->Data(), temp1.Data(), frames);
     178             :     }
     179           0 :     MOZ_ALWAYS_TRUE(outputBuffer->SetLength(FramesOutToSamples(frames)));
     180           0 :     return AudioDataBuffer<Format, Value>(Move(*outputBuffer));
     181             :   }
     182             : 
     183             :   // Attempt to convert the AudioDataBuffer in place.
     184             :   // Will return 0 if the conversion wasn't possible.
     185             :   template <typename Value>
     186             :   size_t Process(Value* aBuffer, size_t aFrames)
     187             :   {
     188             :     MOZ_DIAGNOSTIC_ASSERT(mIn.Format() == mOut.Format());
     189             :     if (!CanWorkInPlace()) {
     190             :       return 0;
     191             :     }
     192             :     size_t frames = ProcessInternal(aBuffer, aBuffer, aFrames);
     193             :     if (frames && mIn.Rate() != mOut.Rate()) {
     194             :       frames = ResampleAudio(aBuffer, aBuffer, aFrames);
     195             :     }
     196             :     return frames;
     197             :   }
     198             : 
     199             :   bool CanWorkInPlace() const;
     200           0 :   bool CanReorderAudio() const
     201             :   {
     202           0 :     return mIn.Layout().MappingTable(mOut.Layout());
     203             :   }
     204             : 
     205           0 :   const AudioConfig& InputConfig() const { return mIn; }
     206           0 :   const AudioConfig& OutputConfig() const { return mOut; }
     207             : 
     208             : private:
     209             :   const AudioConfig mIn;
     210             :   const AudioConfig mOut;
     211             :   uint8_t mChannelOrderMap[MAX_AUDIO_CHANNELS];
     212             :   /**
     213             :    * ProcessInternal
     214             :    * Parameters:
     215             :    * aOut  : destination buffer where converted samples will be copied
     216             :    * aIn   : source buffer
     217             :    * aSamples: number of frames in source buffer
     218             :    *
     219             :    * Return Value: number of frames converted or 0 if error
     220             :    */
     221             :   size_t ProcessInternal(void* aOut, const void* aIn, size_t aFrames);
     222             :   void ReOrderInterleavedChannels(void* aOut, const void* aIn, size_t aFrames) const;
     223             :   size_t DownmixAudio(void* aOut, const void* aIn, size_t aFrames) const;
     224             :   size_t UpmixAudio(void* aOut, const void* aIn, size_t aFrames) const;
     225             : 
     226             :   size_t FramesOutToSamples(size_t aFrames) const;
     227             :   size_t SamplesInToFrames(size_t aSamples) const;
     228             :   size_t FramesOutToBytes(size_t aFrames) const;
     229             : 
     230             :   // Resampler context.
     231             :   SpeexResamplerState* mResampler;
     232             :   size_t ResampleAudio(void* aOut, const void* aIn, size_t aFrames);
     233             :   size_t ResampleRecipientFrames(size_t aFrames) const;
     234             :   void RecreateResampler();
     235             :   size_t DrainResampler(void* aOut);
     236             : };
     237             : 
     238             : } // namespace mozilla
     239             : 
     240             : #endif /* AudioConverter_h */

Generated by: LCOV version 1.13