DXR is a code search and navigation tool aimed at making sense of large projects. It supports full-text and regex searches as well as structural queries.

Implementation

Mercurial (56e7b9127e89)

VCS Links

Line Code
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 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* 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/. */
#ifndef MOZILLA_AUDIOBLOCK_H_
#define MOZILLA_AUDIOBLOCK_H_

#include "AudioSegment.h"

namespace mozilla {

/**
 * An AudioChunk whose buffer contents need to be valid only for one
 * processing block iteration, after which contents can be overwritten if the
 * buffer has not been passed to longer term storage or to another thread,
 * which may happen though AsAudioChunk() or AsMutableChunk().
 *
 * Use on graph thread only.
 */
class AudioBlock : private AudioChunk
{
public:
  AudioBlock() {
    mDuration = WEBAUDIO_BLOCK_SIZE;
    mBufferFormat = AUDIO_FORMAT_SILENCE;
  }
  // No effort is made in constructors to ensure that mBufferIsDownstreamRef
  // is set because the block is expected to be a temporary and so the
  // reference will be released before the next iteration.
  // The custom copy constructor is required so as not to set
  // mBufferIsDownstreamRef without notifying AudioBlockBuffer.
  AudioBlock(const AudioBlock& aBlock) : AudioChunk(aBlock.AsAudioChunk()) {}
  explicit AudioBlock(const AudioChunk& aChunk)
    : AudioChunk(aChunk)
  {
    MOZ_ASSERT(aChunk.mDuration == WEBAUDIO_BLOCK_SIZE);
  }
  ~AudioBlock();

  using AudioChunk::GetDuration;
  using AudioChunk::IsNull;
  using AudioChunk::ChannelCount;
  using AudioChunk::ChannelData;
  using AudioChunk::SizeOfExcludingThisIfUnshared;
  using AudioChunk::SizeOfExcludingThis;
  // mDuration is not exposed.  Use GetDuration().
  // mBuffer is not exposed.  Use SetBuffer().
  using AudioChunk::mChannelData;
  using AudioChunk::mVolume;
  using AudioChunk::mBufferFormat;

  const AudioChunk& AsAudioChunk() const { return *this; }
  AudioChunk* AsMutableChunk() {
    ClearDownstreamMark();
    return this;
  }

  /**
   * Allocates, if necessary, aChannelCount buffers of WEBAUDIO_BLOCK_SIZE float
   * samples for writing.
   */
  void AllocateChannels(uint32_t aChannelCount);

  /**
   * ChannelFloatsForWrite() should only be used when the buffers have been
   * created with AllocateChannels().
   */
  float* ChannelFloatsForWrite(size_t aChannel)
  {
    MOZ_ASSERT(mBufferFormat == AUDIO_FORMAT_FLOAT32);
    MOZ_ASSERT(CanWrite());
    return static_cast<float*>(const_cast<void*>(mChannelData[aChannel]));
  }

  void SetBuffer(ThreadSharedObject* aNewBuffer);
  void SetNull(StreamTime aDuration) {
    MOZ_ASSERT(aDuration == WEBAUDIO_BLOCK_SIZE);
    SetBuffer(nullptr);
    mChannelData.Clear();
    mVolume = 1.0f;
    mBufferFormat = AUDIO_FORMAT_SILENCE;
  }

  AudioBlock& operator=(const AudioBlock& aBlock) {
    // Instead of just copying, mBufferIsDownstreamRef must be first cleared
    // if set.  It is set again for the new mBuffer if possible.  This happens
    // in SetBuffer().
    return *this = aBlock.AsAudioChunk();
  }
  AudioBlock& operator=(const AudioChunk& aChunk) {
    MOZ_ASSERT(aChunk.mDuration == WEBAUDIO_BLOCK_SIZE);
    SetBuffer(aChunk.mBuffer);
    mChannelData = aChunk.mChannelData;
    mVolume = aChunk.mVolume;
    mBufferFormat = aChunk.mBufferFormat;
    return *this;
  }

  bool IsMuted() const { return mVolume == 0.0f; }

  bool IsSilentOrSubnormal() const
  {
    if (!mBuffer) {
      return true;
    }

    for (uint32_t i = 0, length = mChannelData.Length(); i < length; ++i) {
      const float* channel = static_cast<const float*>(mChannelData[i]);
      for (StreamTime frame = 0; frame < mDuration; ++frame) {
        if (fabs(channel[frame]) >= FLT_MIN) {
          return false;
        }
      }
    }

    return true;
  }

private:
  void ClearDownstreamMark();
  bool CanWrite();

  // mBufferIsDownstreamRef is set only when mBuffer references an
  // AudioBlockBuffer created in a different AudioBlock.  That can happen when
  // this AudioBlock is on a node downstream from the node which created the
  // buffer.  When this is set, the AudioBlockBuffer is notified that this
  // reference does not prevent the upstream node from re-using the buffer next
  // iteration and modifying its contents.  The AudioBlockBuffer is also
  // notified when mBuffer releases this reference.
  bool mBufferIsDownstreamRef = false;
};

} // namespace mozilla

DECLARE_USE_COPY_CONSTRUCTORS(mozilla::AudioBlock)

#endif // MOZILLA_AUDIOBLOCK_H_