Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/dom/media/AudioCompactor.h
Line
Count
Source (jump to first uncovered line)
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/. */
6
#if !defined(AudioCompactor_h)
7
#define AudioCompactor_h
8
9
#include "MediaQueue.h"
10
#include "MediaData.h"
11
#include "VideoUtils.h"
12
13
namespace mozilla {
14
15
class AudioCompactor
16
{
17
public:
18
  explicit AudioCompactor(MediaQueue<AudioData>& aQueue)
19
    : mQueue(aQueue)
20
  {
21
    // Determine padding size used by AlignedBuffer.
22
    size_t paddedSize = AlignedAudioBuffer::AlignmentPaddingSize();
23
    mSamplesPadding = paddedSize / sizeof(AudioDataValue);
24
    if (mSamplesPadding * sizeof(AudioDataValue) < paddedSize) {
25
      // Round up.
26
      mSamplesPadding++;
27
    }
28
  }
29
30
  // Push audio data into the underlying queue with minimal heap allocation
31
  // slop.  This method is responsible for allocating AudioDataValue[] buffers.
32
  // The caller must provide a functor to copy the data into the buffers.  The
33
  // functor must provide the following signature:
34
  //
35
  //   uint32_t operator()(AudioDataValue *aBuffer, uint32_t aSamples);
36
  //
37
  // The functor must copy as many complete frames as possible to the provided
38
  // buffer given its length (in AudioDataValue elements).  The number of frames
39
  // copied must be returned.  This copy functor must support being called
40
  // multiple times in order to copy the audio data fully.  The copy functor
41
  // must copy full frames as partial frames will be ignored.
42
  template<typename CopyFunc>
43
  bool Push(int64_t aOffset, int64_t aTime, int32_t aSampleRate,
44
            uint32_t aFrames, uint32_t aChannels, CopyFunc aCopyFunc)
45
0
  {
46
0
    auto time = media::TimeUnit::FromMicroseconds(aTime);
47
0
48
0
    // If we are losing more than a reasonable amount to padding, try to chunk
49
0
    // the data.
50
0
    size_t maxSlop = AudioDataSize(aFrames, aChannels) / MAX_SLOP_DIVISOR;
51
0
52
0
    while (aFrames > 0) {
53
0
      uint32_t samples = GetChunkSamples(aFrames, aChannels, maxSlop);
54
0
      if (samples / aChannels > mSamplesPadding / aChannels + 1) {
55
0
        samples -= mSamplesPadding;
56
0
      }
57
0
      AlignedAudioBuffer buffer(samples);
58
0
      if (!buffer) {
59
0
        return false;
60
0
      }
61
0
62
0
      // Copy audio data to buffer using caller-provided functor.
63
0
      uint32_t framesCopied = aCopyFunc(buffer.get(), samples);
64
0
65
0
      NS_ASSERTION(framesCopied <= aFrames, "functor copied too many frames");
66
0
      buffer.SetLength(size_t(framesCopied) * aChannels);
67
0
68
0
      auto duration = FramesToTimeUnit(framesCopied, aSampleRate);
69
0
      if (!duration.IsValid()) {
70
0
        return false;
71
0
      }
72
0
73
0
      mQueue.Push(new AudioData(aOffset,
74
0
                                time,
75
0
                                duration,
76
0
                                framesCopied,
77
0
                                std::move(buffer),
78
0
                                aChannels,
79
0
                                aSampleRate));
80
0
81
0
      // Remove the frames we just pushed into the queue and loop if there is
82
0
      // more to be done.
83
0
      time += duration;
84
0
      aFrames -= framesCopied;
85
0
86
0
      // NOTE: No need to update aOffset as its only an approximation anyway.
87
0
    }
88
0
89
0
    return true;
90
0
  }
91
92
  // Copy functor suitable for copying audio samples already in the
93
  // AudioDataValue format/layout expected by AudioStream on this platform.
94
  class NativeCopy
95
  {
96
  public:
97
    NativeCopy(const uint8_t* aSource, size_t aSourceBytes,
98
               uint32_t aChannels)
99
      : mSource(aSource)
100
      , mSourceBytes(aSourceBytes)
101
      , mChannels(aChannels)
102
      , mNextByte(0)
103
    { }
104
105
    uint32_t operator()(AudioDataValue *aBuffer, uint32_t aSamples);
106
107
  private:
108
    const uint8_t* const mSource;
109
    const size_t mSourceBytes;
110
    const uint32_t mChannels;
111
    size_t mNextByte;
112
  };
113
114
  // Allow 12.5% slop before chunking kicks in.  Public so that the gtest can
115
  // access it.
116
  static const size_t MAX_SLOP_DIVISOR = 8;
117
118
private:
119
  // Compute the number of AudioDataValue samples that will be fit the most
120
  // frames while keeping heap allocation slop less than the given threshold.
121
  static uint32_t
122
  GetChunkSamples(uint32_t aFrames, uint32_t aChannels, size_t aMaxSlop);
123
124
  static size_t BytesPerFrame(uint32_t aChannels)
125
0
  {
126
0
    return sizeof(AudioDataValue) * aChannels;
127
0
  }
128
129
  static size_t AudioDataSize(uint32_t aFrames, uint32_t aChannels)
130
0
  {
131
0
    return aFrames * BytesPerFrame(aChannels);
132
0
  }
133
134
  MediaQueue<AudioData> &mQueue;
135
  size_t mSamplesPadding;
136
};
137
138
} // namespace mozilla
139
140
#endif // AudioCompactor_h