예제 #1
0
nsresult AudioStream::SetPreservesPitch(bool aPreservesPitch)
{
    // MUST lock since the rate transposer is used from the cubeb callback,
    // and rate changes can cause the buffer to be reallocated
    MonitorAutoLock mon(mMonitor);

    // Avoid instantiating the timestretcher instance if not needed.
    if (aPreservesPitch == mAudioClock.GetPreservesPitch()) {
        return NS_OK;
    }

    if (EnsureTimeStretcherInitializedUnlocked() != NS_OK) {
        return NS_ERROR_FAILURE;
    }

    if (aPreservesPitch == true) {
        mTimeStretcher->setTempo(mAudioClock.GetPlaybackRate());
        mTimeStretcher->setRate(1.0f);
    } else {
        mTimeStretcher->setTempo(1.0f);
        mTimeStretcher->setRate(mAudioClock.GetPlaybackRate());
    }

    mAudioClock.SetPreservesPitch(aPreservesPitch);

    return NS_OK;
}
예제 #2
0
nsresult AudioStream::SetPlaybackRate(double aPlaybackRate)
{
    // MUST lock since the rate transposer is used from the cubeb callback,
    // and rate changes can cause the buffer to be reallocated
    MonitorAutoLock mon(mMonitor);

    NS_ASSERTION(aPlaybackRate > 0.0,
                 "Can't handle negative or null playbackrate in the AudioStream.");
    // Avoid instantiating the resampler if we are not changing the playback rate.
    // GetPreservesPitch/SetPreservesPitch don't need locking before calling
    if (aPlaybackRate == mAudioClock.GetPlaybackRate()) {
        return NS_OK;
    }

    if (EnsureTimeStretcherInitializedUnlocked() != NS_OK) {
        return NS_ERROR_FAILURE;
    }

    mAudioClock.SetPlaybackRateUnlocked(aPlaybackRate);
    mOutRate = mInRate / aPlaybackRate;

    if (mAudioClock.GetPreservesPitch()) {
        mTimeStretcher->setTempo(aPlaybackRate);
        mTimeStretcher->setRate(1.0f);
    } else {
        mTimeStretcher->setTempo(1.0f);
        mTimeStretcher->setRate(aPlaybackRate);
    }
    return NS_OK;
}
예제 #3
0
void
AudioStream::GetTimeStretched(AudioBufferWriter& aWriter)
{
    mMonitor.AssertCurrentThreadOwns();

    // We need to call the non-locking version, because we already have the lock.
    if (EnsureTimeStretcherInitializedUnlocked() != NS_OK) {
        return;
    }

    double playbackRate = static_cast<double>(mInRate) / mOutRate;
    uint32_t toPopFrames = ceil(aWriter.Available() * playbackRate);

    while (mTimeStretcher->numSamples() < aWriter.Available()) {
        UniquePtr<Chunk> c = mDataSource.PopFrames(toPopFrames);
        if (c->Frames() == 0) {
            break;
        }
        MOZ_ASSERT(c->Frames() <= toPopFrames);
        if (Downmix(c.get())) {
            mTimeStretcher->putSamples(c->Data(), c->Frames());
        } else {
            // Write silence if downmixing fails.
            nsAutoTArray<AudioDataValue, 1000> buf;
            buf.SetLength(mOutChannels * c->Frames());
            memset(buf.Elements(), 0, buf.Length() * sizeof(AudioDataValue));
            mTimeStretcher->putSamples(buf.Elements(), c->Frames());
        }
    }

    auto timeStretcher = mTimeStretcher;
    aWriter.Write([timeStretcher] (AudioDataValue* aPtr, uint32_t aFrames) {
        return timeStretcher->receiveSamples(aPtr, aFrames);
    }, aWriter.Available());
}
예제 #4
0
void
AudioStream::GetTimeStretched(AudioBufferWriter& aWriter)
{
  mMonitor.AssertCurrentThreadOwns();

  // We need to call the non-locking version, because we already have the lock.
  if (EnsureTimeStretcherInitializedUnlocked() != NS_OK) {
    return;
  }

  uint32_t toPopFrames =
    ceil(aWriter.Available() * mAudioClock.GetPlaybackRate());

  while (mTimeStretcher->numSamples() < aWriter.Available()) {
    UniquePtr<Chunk> c = mDataSource.PopFrames(toPopFrames);
    if (c->Frames() == 0) {
      break;
    }
    MOZ_ASSERT(c->Frames() <= toPopFrames);
    if (IsValidAudioFormat(c.get())) {
      mTimeStretcher->putSamples(c->Data(), c->Frames());
    } else {
      // Write silence if invalid format.
      AutoTArray<AudioDataValue, 1000> buf;
      auto size = CheckedUint32(mOutChannels) * c->Frames();
      if (!size.isValid()) {
        // The overflow should not happen in normal case.
        LOGW("Invalid member data: %d channels, %d frames", mOutChannels, c->Frames());
        return;
      }
      buf.SetLength(size.value());
      size = size * sizeof(AudioDataValue);
      if (!size.isValid()) {
        LOGW("The required memory size is too large.");
        return;
      }
      memset(buf.Elements(), 0, size.value());
      mTimeStretcher->putSamples(buf.Elements(), c->Frames());
    }
  }

  auto timeStretcher = mTimeStretcher;
  aWriter.Write([timeStretcher] (AudioDataValue* aPtr, uint32_t aFrames) {
    return timeStretcher->receiveSamples(aPtr, aFrames);
  }, aWriter.Available());
}
예제 #5
0
long
AudioStream::GetTimeStretched(void* aBuffer, long aFrames, int64_t &aTimeMs)
{
  mMonitor.AssertCurrentThreadOwns();
  long processedFrames = 0;

  // We need to call the non-locking version, because we already have the lock.
  if (EnsureTimeStretcherInitializedUnlocked() != NS_OK) {
    return 0;
  }

  uint8_t* wpos = reinterpret_cast<uint8_t*>(aBuffer);
  double playbackRate = static_cast<double>(mInRate) / mOutRate;
  uint32_t toPopBytes = FramesToBytes(ceil(aFrames * playbackRate));
  uint32_t available = 0;
  bool lowOnBufferedData = false;
  do {
    // Check if we already have enough data in the time stretcher pipeline.
    if (mTimeStretcher->numSamples() <= static_cast<uint32_t>(aFrames)) {
      void* input[2];
      uint32_t input_size[2];
      available = std::min(mBuffer.Length(), toPopBytes);
      if (available != toPopBytes) {
        lowOnBufferedData = true;
      }
      mBuffer.PopElements(available, &input[0], &input_size[0],
                                     &input[1], &input_size[1]);
      mReadPoint += BytesToFrames(available);
      for(uint32_t i = 0; i < 2; i++) {
        mTimeStretcher->putSamples(reinterpret_cast<AudioDataValue*>(input[i]), BytesToFrames(input_size[i]));
      }
    }
    uint32_t receivedFrames = mTimeStretcher->receiveSamples(reinterpret_cast<AudioDataValue*>(wpos), aFrames - processedFrames);
    wpos += FramesToBytes(receivedFrames);
    processedFrames += receivedFrames;
  } while (processedFrames < aFrames && !lowOnBufferedData);

  GetBufferInsertTime(aTimeMs);

  return processedFrames;
}
예제 #6
0
nsresult AudioStream::EnsureTimeStretcherInitialized()
{
  MonitorAutoLock mon(mMonitor);
  return EnsureTimeStretcherInitializedUnlocked();
}