Example #1
0
// aTime is the time in ms the samples were inserted into MediaStreamGraph
nsresult
AudioStream::Write(const AudioDataValue* aBuf, uint32_t aFrames)
{
    MonitorAutoLock mon(mMonitor);

    if (mState == ERRORED) {
        return NS_ERROR_FAILURE;
    }
    NS_ASSERTION(mState == INITIALIZED || mState == STARTED || mState == RUNNING,
                 "Stream write in unexpected state.");

    // Downmix to Stereo.
    if (mChannels > 2 && mChannels <= 8) {
        DownmixAudioToStereo(const_cast<AudioDataValue*> (aBuf), mChannels, aFrames);
    } else if (mChannels > 8) {
        return NS_ERROR_FAILURE;
    }

    if (mChannels >= 2 && mIsMonoAudioEnabled) {
        DownmixStereoToMono(const_cast<AudioDataValue*> (aBuf), aFrames);
    }

    const uint8_t* src = reinterpret_cast<const uint8_t*>(aBuf);
    uint32_t bytesToCopy = FramesToBytes(aFrames);

    while (bytesToCopy > 0) {
        uint32_t available = std::min(bytesToCopy, mBuffer.Available());
        MOZ_ASSERT(available % mBytesPerFrame == 0,
                   "Must copy complete frames.");

        mBuffer.AppendElements(src, available);
        src += available;
        bytesToCopy -= available;

        if (bytesToCopy > 0) {
            // If we are not playing, but our buffer is full, start playing to make
            // room for soon-to-be-decoded data.
            if (mState != STARTED && mState != RUNNING) {
                MOZ_LOG(gAudioStreamLog, LogLevel::Warning, ("Starting stream %p in Write (%u waiting)",
                        this, bytesToCopy));
                StartUnlocked();
                if (mState == ERRORED) {
                    return NS_ERROR_FAILURE;
                }
            }
            MOZ_LOG(gAudioStreamLog, LogLevel::Warning, ("Stream %p waiting in Write() (%u waiting)",
                    this, bytesToCopy));
            mon.Wait();
        }
    }

    mWritten += aFrames;
    return NS_OK;
}
Example #2
0
void
AudioStream::CheckForStart()
{
  if (mState == INITIALIZED) {
    // Start the stream right away when low latency has been requested. This means
    // that the DataCallback will feed silence to cubeb, until the first frames
    // are written to this AudioStream.  Also start if a start has been queued.
    if (mLatencyRequest == LowLatency || mNeedsStart) {
      StartUnlocked(); // mState = STARTED or ERRORED
      mNeedsStart = false;
      PR_LOG(gAudioStreamLog, PR_LOG_WARNING,
             ("Started waiting %s-latency stream",
              mLatencyRequest == LowLatency ? "low" : "high"));
    } else {
      // high latency, not full - OR Pause() was called before we got here
      PR_LOG(gAudioStreamLog, PR_LOG_DEBUG,
             ("Not starting waiting %s-latency stream",
              mLatencyRequest == LowLatency ? "low" : "high"));
    }
  }
}
nsresult
BufferedAudioStream::Write(const AudioDataValue* aBuf, uint32_t aFrames)
{
  MonitorAutoLock mon(mMonitor);
  if (!mCubebStream || mState == ERRORED) {
    return NS_ERROR_FAILURE;
  }
  NS_ASSERTION(mState == INITIALIZED || mState == STARTED,
    "Stream write in unexpected state.");

  const uint8_t* src = reinterpret_cast<const uint8_t*>(aBuf);
  uint32_t bytesToCopy = FramesToBytes(aFrames);

  while (bytesToCopy > 0) {
    uint32_t available = std::min(bytesToCopy, mBuffer.Available());
    NS_ABORT_IF_FALSE(available % mBytesPerFrame == 0,
        "Must copy complete frames.");

    mBuffer.AppendElements(src, available);
    src += available;
    bytesToCopy -= available;

    if (bytesToCopy > 0) {
      // If we are not playing, but our buffer is full, start playing to make
      // room for soon-to-be-decoded data.
      if (mState != STARTED) {
        StartUnlocked();
        if (mState != STARTED) {
          return NS_ERROR_FAILURE;
        }
      }
      mon.Wait();
    }
  }

  mWritten += aFrames;

  return NS_OK;
}
Example #4
0
void
AudioStream::Start()
{
    MonitorAutoLock mon(mMonitor);
    StartUnlocked();
}
Example #5
0
// aTime is the time in ms the samples were inserted into MediaStreamGraph
nsresult
AudioStream::Write(const AudioDataValue* aBuf, uint32_t aFrames, TimeStamp *aTime)
{
  MonitorAutoLock mon(mMonitor);
  if (mState == ERRORED) {
    return NS_ERROR_FAILURE;
  }
  NS_ASSERTION(mState == INITIALIZED || mState == STARTED || mState == RUNNING,
    "Stream write in unexpected state.");

  // See if we need to start() the stream, since we must do that from this thread
  CheckForStart();

  // Downmix to Stereo.
  if (mChannels > 2 && mChannels <= 8) {
    DownmixAudioToStereo(const_cast<AudioDataValue*> (aBuf), mChannels, aFrames);
  }
  else if (mChannels > 8) {
    return NS_ERROR_FAILURE;
  }

  const uint8_t* src = reinterpret_cast<const uint8_t*>(aBuf);
  uint32_t bytesToCopy = FramesToBytes(aFrames);

  // XXX this will need to change if we want to enable this on-the-fly!
  if (PR_LOG_TEST(GetLatencyLog(), PR_LOG_DEBUG)) {
    // Record the position and time this data was inserted
    int64_t timeMs;
    if (aTime && !aTime->IsNull()) {
      if (mStartTime.IsNull()) {
        AsyncLatencyLogger::Get(true)->GetStartTime(mStartTime);
      }
      timeMs = (*aTime - mStartTime).ToMilliseconds();
    } else {
      timeMs = 0;
    }
    struct Inserts insert = { timeMs, aFrames};
    mInserts.AppendElement(insert);
  }

  while (bytesToCopy > 0) {
    uint32_t available = std::min(bytesToCopy, mBuffer.Available());
    NS_ABORT_IF_FALSE(available % mBytesPerFrame == 0,
        "Must copy complete frames.");

    mBuffer.AppendElements(src, available);
    src += available;
    bytesToCopy -= available;

    if (bytesToCopy > 0) {
      // Careful - the CubebInit thread may not have gotten to STARTED yet
      if ((mState == INITIALIZED || mState == STARTED) && mLatencyRequest == LowLatency) {
        // don't ever block MediaStreamGraph low-latency streams
        uint32_t remains = 0; // we presume the buffer is full
        if (mBuffer.Length() > bytesToCopy) {
          remains = mBuffer.Length() - bytesToCopy; // Free up just enough space
        }
        // account for dropping samples
        PR_LOG(gAudioStreamLog, PR_LOG_WARNING, ("Stream %p dropping %u bytes (%u frames)in Write()",
            this, mBuffer.Length() - remains, BytesToFrames(mBuffer.Length() - remains)));
        mReadPoint += BytesToFrames(mBuffer.Length() - remains);
        mBuffer.ContractTo(remains);
      } else { // RUNNING or high latency
        // If we are not playing, but our buffer is full, start playing to make
        // room for soon-to-be-decoded data.
        if (mState != STARTED && mState != RUNNING) {
          PR_LOG(gAudioStreamLog, PR_LOG_WARNING, ("Starting stream %p in Write (%u waiting)",
                                                 this, bytesToCopy));
          StartUnlocked();
          if (mState == ERRORED) {
            return NS_ERROR_FAILURE;
          }
        }
        PR_LOG(gAudioStreamLog, PR_LOG_WARNING, ("Stream %p waiting in Write() (%u waiting)",
                                                 this, bytesToCopy));
        mon.Wait();
      }
    }
  }

  mWritten += aFrames;
  return NS_OK;
}
Example #6
0
// aTime is the time in ms the samples were inserted into MediaStreamGraph
nsresult
AudioStream::Write(const AudioDataValue* aBuf, uint32_t aFrames, TimeStamp *aTime)
{
  MonitorAutoLock mon(mMonitor);
  if (!mCubebStream || mState == ERRORED) {
    return NS_ERROR_FAILURE;
  }
  NS_ASSERTION(mState == INITIALIZED || mState == STARTED,
    "Stream write in unexpected state.");

  // Downmix to Stereo.
  if (mChannels > 2 && mChannels <= 8) {
    DownmixAudioToStereo(const_cast<AudioDataValue*> (aBuf), mChannels, aFrames);
  }
  else if (mChannels > 8) {
    return NS_ERROR_FAILURE;
  }

  const uint8_t* src = reinterpret_cast<const uint8_t*>(aBuf);
  uint32_t bytesToCopy = FramesToBytes(aFrames);

  // XXX this will need to change if we want to enable this on-the-fly!
  if (PR_LOG_TEST(GetLatencyLog(), PR_LOG_DEBUG)) {
    // Record the position and time this data was inserted
    int64_t timeMs;
    if (aTime && !aTime->IsNull()) {
      if (mStartTime.IsNull()) {
        AsyncLatencyLogger::Get(true)->GetStartTime(mStartTime);
      }
      timeMs = (*aTime - mStartTime).ToMilliseconds();
    } else {
      timeMs = 0;
    }
    struct Inserts insert = { timeMs, aFrames};
    mInserts.AppendElement(insert);
  }

  while (bytesToCopy > 0) {
    uint32_t available = std::min(bytesToCopy, mBuffer.Available());
    NS_ABORT_IF_FALSE(available % mBytesPerFrame == 0,
        "Must copy complete frames.");

    mBuffer.AppendElements(src, available);
    src += available;
    bytesToCopy -= available;

    if (bytesToCopy > 0) {
      // If we are not playing, but our buffer is full, start playing to make
      // room for soon-to-be-decoded data.
      if (mState != STARTED) {
        StartUnlocked();
        if (mState != STARTED) {
          return NS_ERROR_FAILURE;
        }
      }
      mon.Wait();
    }
  }

  mWritten += aFrames;
  return NS_OK;
}