LCOV - code coverage report
Current view: top level - dom/media - AudioPacketizer.h (source / functions) Hit Total Coverage
Test: output.info Lines: 0 62 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 22 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             : #ifndef AudioPacketizer_h_
       7             : #define AudioPacketizer_h_
       8             : 
       9             : #include <mozilla/PodOperations.h>
      10             : #include <mozilla/Assertions.h>
      11             : #include <mozilla/UniquePtr.h>
      12             : #include <AudioSampleFormat.h>
      13             : 
      14             : // Enable this to warn when `Output` has been called but not enough data was
      15             : // buffered.
      16             : // #define LOG_PACKETIZER_UNDERRUN
      17             : 
      18             : namespace mozilla {
      19             : /**
      20             :  * This class takes arbitrary input data, and returns packets of a specific
      21             :  * size. In the process, it can convert audio samples from 16bit integers to
      22             :  * float (or vice-versa).
      23             :  *
      24             :  * Input and output, as well as length units in the public interface are
      25             :  * interleaved frames.
      26             :  *
      27             :  * Allocations of output buffer can be performed by this class.  Buffers can
      28             :  * simply be delete-d.  This is because packets are intended to be sent off to
      29             :  * non-gecko code using normal pointers/length pairs
      30             :  *
      31             :  * Alternatively, consumers can pass in a buffer in which the output is copied.
      32             :  * The buffer needs to be large enough to store a packet worth of audio.
      33             :  *
      34             :  * The implementation uses a circular buffer using absolute virtual indices.
      35             :  */
      36             : template <typename InputType, typename OutputType>
      37           0 : class AudioPacketizer
      38             : {
      39             : public:
      40           0 :   AudioPacketizer(uint32_t aPacketSize, uint32_t aChannels)
      41             :     : mPacketSize(aPacketSize)
      42             :     , mChannels(aChannels)
      43             :     , mReadIndex(0)
      44             :     , mWriteIndex(0)
      45             :     // Start off with a single packet
      46           0 :     , mStorage(new InputType[aPacketSize * aChannels])
      47           0 :     , mLength(aPacketSize * aChannels)
      48             :   {
      49           0 :      MOZ_ASSERT(aPacketSize > 0 && aChannels > 0,
      50             :        "The packet size and the number of channel should be strictly positive");
      51           0 :   }
      52             : 
      53           0 :   void Input(const InputType* aFrames, uint32_t aFrameCount)
      54             :   {
      55           0 :     uint32_t inputSamples = aFrameCount * mChannels;
      56             :     // Need to grow the storage. This should rarely happen, if at all, once the
      57             :     // array has the right size.
      58           0 :     if (inputSamples > EmptySlots()) {
      59             :       // Calls to Input and Output are roughtly interleaved
      60             :       // (Input,Output,Input,Output, etc.), or balanced
      61             :       // (Input,Input,Input,Output,Output,Output), so we update the buffer to
      62             :       // the exact right size in order to not waste space.
      63           0 :       uint32_t newLength = AvailableSamples() + inputSamples;
      64           0 :       uint32_t toCopy = AvailableSamples();
      65           0 :       UniquePtr<InputType[]> oldStorage = mozilla::Move(mStorage);
      66           0 :       mStorage = mozilla::MakeUnique<InputType[]>(newLength);
      67             :       // Copy the old data at the beginning of the new storage.
      68           0 :       if (WriteIndex() >= ReadIndex()) {
      69           0 :         PodCopy(mStorage.get(),
      70           0 :                 oldStorage.get() + ReadIndex(),
      71           0 :                 AvailableSamples());
      72             :       } else {
      73           0 :         uint32_t firstPartLength = mLength - ReadIndex();
      74           0 :         uint32_t secondPartLength = AvailableSamples() - firstPartLength;
      75           0 :         PodCopy(mStorage.get(),
      76           0 :                 oldStorage.get() + ReadIndex(),
      77             :                 firstPartLength);
      78           0 :         PodCopy(mStorage.get() + firstPartLength,
      79             :                 oldStorage.get(),
      80             :                 secondPartLength);
      81             :       }
      82           0 :       mWriteIndex = toCopy;
      83           0 :       mReadIndex = 0;
      84           0 :       mLength = newLength;
      85             :     }
      86             : 
      87           0 :     if (WriteIndex() + inputSamples <= mLength) {
      88           0 :       PodCopy(mStorage.get() + WriteIndex(), aFrames, aFrameCount * mChannels);
      89             :     } else {
      90           0 :       uint32_t firstPartLength = mLength - WriteIndex();
      91           0 :       uint32_t secondPartLength = inputSamples - firstPartLength;
      92           0 :       PodCopy(mStorage.get() + WriteIndex(), aFrames, firstPartLength);
      93           0 :       PodCopy(mStorage.get(), aFrames + firstPartLength, secondPartLength);
      94             :     }
      95             : 
      96           0 :     mWriteIndex += inputSamples;
      97           0 :   }
      98             : 
      99             :   OutputType* Output()
     100             :   {
     101             :     uint32_t samplesNeeded = mPacketSize * mChannels;
     102             :     OutputType* out = new OutputType[samplesNeeded];
     103             : 
     104             :     Output(out);
     105             : 
     106             :     return out;
     107             :   }
     108             : 
     109           0 :   void Output(OutputType* aOutputBuffer)
     110             :   {
     111           0 :     uint32_t samplesNeeded = mPacketSize * mChannels;
     112             : 
     113             :     // Under-run. Pad the end of the buffer with silence.
     114           0 :     if (AvailableSamples() < samplesNeeded) {
     115             : #ifdef LOG_PACKETIZER_UNDERRUN
     116             :       char buf[256];
     117             :       snprintf(buf, 256,
     118             :                "AudioPacketizer %p underrun: available: %u, needed: %u\n",
     119             :                this, AvailableSamples(), samplesNeeded);
     120             :       NS_WARNING(buf);
     121             : #endif
     122           0 :       uint32_t zeros = samplesNeeded - AvailableSamples();
     123           0 :       PodZero(aOutputBuffer + AvailableSamples(), zeros);
     124           0 :       samplesNeeded -= zeros;
     125             :     }
     126           0 :     if (ReadIndex() + samplesNeeded <= mLength) {
     127           0 :       ConvertAudioSamples<InputType,OutputType>(mStorage.get() + ReadIndex(),
     128             :                                                 aOutputBuffer,
     129             :                                                 samplesNeeded);
     130             :     } else {
     131           0 :       uint32_t firstPartLength = mLength - ReadIndex();
     132           0 :       uint32_t secondPartLength = samplesNeeded - firstPartLength;
     133           0 :       ConvertAudioSamples<InputType, OutputType>(mStorage.get() + ReadIndex(),
     134             :                                                  aOutputBuffer,
     135             :                                                  firstPartLength);
     136           0 :       ConvertAudioSamples<InputType, OutputType>(mStorage.get(),
     137           0 :                                                  aOutputBuffer + firstPartLength,
     138             :                                                  secondPartLength);
     139             :     }
     140           0 :     mReadIndex += samplesNeeded;
     141           0 :   }
     142             : 
     143           0 :   uint32_t PacketsAvailable() const {
     144           0 :     return AvailableSamples() / mChannels / mPacketSize;
     145             :   }
     146             : 
     147             :   bool Empty() const {
     148             :    return mWriteIndex == mReadIndex;
     149             :   }
     150             : 
     151             :   bool Full() const {
     152             :     return mWriteIndex - mReadIndex == mLength;
     153             :   }
     154             : 
     155           0 :   uint32_t PacketSize() const {
     156           0 :     return mPacketSize;
     157             :   }
     158             : 
     159           0 :   uint32_t Channels() const {
     160           0 :     return mChannels;
     161             :   }
     162             : 
     163             : private:
     164           0 :   uint32_t ReadIndex() const {
     165           0 :     return mReadIndex % mLength;
     166             :   }
     167             : 
     168           0 :   uint32_t WriteIndex() const {
     169           0 :     return mWriteIndex % mLength;
     170             :   }
     171             : 
     172           0 :   uint32_t AvailableSamples() const {
     173           0 :     return mWriteIndex - mReadIndex;
     174             :   }
     175             : 
     176           0 :   uint32_t EmptySlots() const {
     177           0 :     return mLength - AvailableSamples();
     178             :   }
     179             : 
     180             :   // Size of one packet of audio, in frames
     181             :   uint32_t mPacketSize;
     182             :   // Number of channels of the stream flowing through this packetizer
     183             :   uint32_t mChannels;
     184             :   // Two virtual index into the buffer: the read position and the write
     185             :   // position.
     186             :   uint64_t mReadIndex;
     187             :   uint64_t mWriteIndex;
     188             :   // Storage for the samples
     189             :   mozilla::UniquePtr<InputType[]> mStorage;
     190             :   // Length of the buffer, in samples
     191             :   uint32_t mLength;
     192             : };
     193             : 
     194             : } // mozilla
     195             : 
     196             : #endif // AudioPacketizer_h_

Generated by: LCOV version 1.13