summaryrefslogtreecommitdiffstats
path: root/dom/media/driftcontrol/AudioChunkList.cpp
blob: e0010c2ff0e27e1eeebc4b017903a39f45721588 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
 * You can obtain one at http://mozilla.org/MPL/2.0/. */

#include "AudioChunkList.h"

namespace mozilla {

AudioChunkList::AudioChunkList(uint32_t aTotalDuration, uint32_t aChannels,
                               const PrincipalHandle& aPrincipalHandle)
    : mPrincipalHandle(aPrincipalHandle) {
  uint32_t numOfChunks = aTotalDuration / mChunkCapacity;
  if (aTotalDuration % mChunkCapacity) {
    ++numOfChunks;
  }
  CreateChunks(numOfChunks, aChannels);
}

void AudioChunkList::CreateChunks(uint32_t aNumOfChunks, uint32_t aChannels) {
  MOZ_ASSERT(!mChunks.Length());
  MOZ_ASSERT(aNumOfChunks);
  MOZ_ASSERT(aChannels);
  mChunks.AppendElements(aNumOfChunks);

  for (AudioChunk& chunk : mChunks) {
    AutoTArray<nsTArray<float>, 2> buffer;
    buffer.AppendElements(aChannels);

    AutoTArray<const float*, 2> bufferPtrs;
    bufferPtrs.AppendElements(aChannels);

    for (uint32_t i = 0; i < aChannels; ++i) {
      float* ptr = buffer[i].AppendElements(mChunkCapacity);
      bufferPtrs[i] = ptr;
    }

    chunk.mBuffer = new mozilla::SharedChannelArrayBuffer(std::move(buffer));
    chunk.mChannelData.AppendElements(aChannels);
    for (uint32_t i = 0; i < aChannels; ++i) {
      chunk.mChannelData[i] = bufferPtrs[i];
    }
  }
}

void AudioChunkList::UpdateToMonoOrStereo(uint32_t aChannels) {
  MOZ_ASSERT(mChunks.Length());
  MOZ_ASSERT(mSampleFormat == AUDIO_FORMAT_S16 ||
             mSampleFormat == AUDIO_FORMAT_FLOAT32);
  MOZ_ASSERT(aChannels == 1 || aChannels == 2);

  for (AudioChunk& chunk : mChunks) {
    MOZ_ASSERT(chunk.ChannelCount() != (uint32_t)aChannels);
    MOZ_ASSERT(chunk.ChannelCount() == 1 || chunk.ChannelCount() == 2);
    chunk.mChannelData.SetLengthAndRetainStorage(aChannels);
    if (mSampleFormat == AUDIO_FORMAT_S16) {
      SharedChannelArrayBuffer<short>* channelArray =
          static_cast<SharedChannelArrayBuffer<short>*>(chunk.mBuffer.get());
      channelArray->mBuffers.SetLengthAndRetainStorage(aChannels);
      if (aChannels == 2) {
        // This an indirect allocation, unfortunately.
        channelArray->mBuffers[1].SetLength(mChunkCapacity);
        chunk.mChannelData[1] = channelArray->mBuffers[1].Elements();
      }
    } else {
      SharedChannelArrayBuffer<float>* channelArray =
          static_cast<SharedChannelArrayBuffer<float>*>(chunk.mBuffer.get());
      channelArray->mBuffers.SetLengthAndRetainStorage(aChannels);
      if (aChannels == 2) {
        // This an indirect allocation, unfortunately.
        channelArray->mBuffers[1].SetLength(mChunkCapacity);
        chunk.mChannelData[1] = channelArray->mBuffers[1].Elements();
      }
    }
  }
}

void AudioChunkList::SetSampleFormat(AudioSampleFormat aFormat) {
  MOZ_ASSERT(mSampleFormat == AUDIO_FORMAT_SILENCE);
  MOZ_ASSERT(aFormat == AUDIO_FORMAT_S16 || aFormat == AUDIO_FORMAT_FLOAT32);
  mSampleFormat = aFormat;
  if (mSampleFormat == AUDIO_FORMAT_S16) {
    mChunkCapacity = 2 * mChunkCapacity;
  }
}

AudioChunk& AudioChunkList::GetNext() {
  AudioChunk& chunk = mChunks[mIndex];
  MOZ_ASSERT(!chunk.mChannelData.IsEmpty());
  MOZ_ASSERT(chunk.mBuffer);
  MOZ_ASSERT(!chunk.mBuffer->IsShared());
  MOZ_ASSERT(mSampleFormat == AUDIO_FORMAT_S16 ||
             mSampleFormat == AUDIO_FORMAT_FLOAT32);
  chunk.mDuration = 0;
  chunk.mVolume = 1.0f;
  chunk.mPrincipalHandle = mPrincipalHandle;
  chunk.mBufferFormat = mSampleFormat;
  IncrementIndex();
  return chunk;
}

void AudioChunkList::Update(uint32_t aChannels) {
  MOZ_ASSERT(mChunks.Length());
  if (mChunks[0].ChannelCount() == aChannels) {
    return;
  }

  // Special handling between mono and stereo to avoid reallocations.
  if (aChannels <= 2 && mChunks[0].ChannelCount() <= 2) {
    UpdateToMonoOrStereo(aChannels);
    return;
  }

  uint32_t numOfChunks = mChunks.Length();
  mChunks.ClearAndRetainStorage();
  CreateChunks(numOfChunks, aChannels);
}

}  // namespace mozilla