예제 #1
0
ssize_t mailstream_low_write(mailstream_low * s,
    const void * buf, size_t count)
{
  ssize_t r;
  
  if (s == NULL)
    return -1;

#ifdef STREAM_DEBUG
  STREAM_LOG(s, 1, ">>>>>>> send >>>>>>\n");
  if (s->privacy) {
    STREAM_LOG_BUF(s, 1, buf, count);
  }
  else {
    STREAM_LOG_BUF(s, 2, buf, count);
  }
  STREAM_LOG(s, 1, "\n");
  STREAM_LOG(s, 1, ">>>>>>> end send >>>>>>\n");
#endif

  r = s->driver->mailstream_write(s, buf, count);
  
  if (r < 0) {
    STREAM_LOG_ERROR(s, 4 | 1, buf, 0);
  }
  
  return r;
}
예제 #2
0
void
AudioCallbackDriver::Start()
{
    // If this is running on the main thread, we can't open the stream directly,
    // because it is a blocking operation.
    if (NS_IsMainThread()) {
        STREAM_LOG(LogLevel::Debug, ("Starting audio threads for MediaStreamGraph %p from a new thread.", mGraphImpl));
        RefPtr<AsyncCubebTask> initEvent =
            new AsyncCubebTask(this, AsyncCubebOperation::INIT);
        initEvent->Dispatch();
    } else {
        STREAM_LOG(LogLevel::Debug, ("Starting audio threads for MediaStreamGraph %p from the previous driver's thread", mGraphImpl));
        Init();

        // Check if we need to resolve promises because the driver just got switched
        // because of a resuming AudioContext
        if (!mPromisesForOperation.IsEmpty()) {
            CompleteAudioContextOperations(AsyncCubebOperation::INIT);
        }

        if (mPreviousDriver) {
            nsCOMPtr<nsIRunnable> event =
                new MediaStreamGraphShutdownThreadRunnable(mPreviousDriver);
            mPreviousDriver = nullptr;
            NS_DispatchToMainThread(event);
        }
    }
}
예제 #3
0
void
SystemClockDriver::WaitForNextIteration()
{
  mGraphImpl->GetMonitor().AssertCurrentThreadOwns();

  PRIntervalTime timeout = PR_INTERVAL_NO_TIMEOUT;
  TimeStamp now = TimeStamp::Now();
  if (mNeedAnotherIteration) {
    int64_t timeoutMS = MEDIA_GRAPH_TARGET_PERIOD_MS -
      int64_t((now - mCurrentTimeStamp).ToMilliseconds());
    // Make sure timeoutMS doesn't overflow 32 bits by waking up at
    // least once a minute, if we need to wake up at all
    timeoutMS = std::max<int64_t>(0, std::min<int64_t>(timeoutMS, 60*1000));
    timeout = PR_MillisecondsToInterval(uint32_t(timeoutMS));
    STREAM_LOG(PR_LOG_DEBUG+1, ("Waiting for next iteration; at %f, timeout=%f", (now - mInitialTimeStamp).ToSeconds(), timeoutMS/1000.0));
    mWaitState = WAITSTATE_WAITING_FOR_NEXT_ITERATION;
  } else {
    mWaitState = WAITSTATE_WAITING_INDEFINITELY;
  }
  if (timeout > 0) {
    mGraphImpl->GetMonitor().Wait(timeout);
    STREAM_LOG(PR_LOG_DEBUG+1, ("Resuming after timeout; at %f, elapsed=%f",
          (TimeStamp::Now() - mInitialTimeStamp).ToSeconds(),
          (TimeStamp::Now() - now).ToSeconds()));
  }

  mWaitState = WAITSTATE_RUNNING;
  mNeedAnotherIteration = false;
}
예제 #4
0
void
ThreadedDriver::RunThread()
{
  AutoProfilerUnregisterThread autoUnregister;

  bool stillProcessing = true;
  while (stillProcessing) {
    GraphTime prevCurrentTime, nextCurrentTime;
    GetIntervalForIteration(prevCurrentTime, nextCurrentTime);

    mStateComputedTime = mNextStateComputedTime;
    mNextStateComputedTime =
      mGraphImpl->RoundUpToNextAudioBlock(
        nextCurrentTime + mGraphImpl->MillisecondsToMediaTime(AUDIO_TARGET_MS));
    STREAM_LOG(PR_LOG_DEBUG,
               ("interval[%ld; %ld] state[%ld; %ld]",
               (long)mIterationStart, (long)mIterationEnd,
               (long)mStateComputedTime, (long)mNextStateComputedTime));

    stillProcessing = mGraphImpl->OneIteration(prevCurrentTime,
                                               nextCurrentTime,
                                               StateComputedTime(),
                                               mNextStateComputedTime);

    if (mNextDriver && stillProcessing) {
      STREAM_LOG(PR_LOG_DEBUG, ("Switching to AudioCallbackDriver"));
      mNextDriver->SetGraphTime(this, mIterationStart, mIterationEnd,
                                 mStateComputedTime, mNextStateComputedTime);
      mGraphImpl->SetCurrentDriver(mNextDriver);
      mNextDriver->Start();
      return;
    }
  }
}
예제 #5
0
void
SystemClockDriver::GetIntervalForIteration(GraphTime& aFrom, GraphTime& aTo)
{
  TimeStamp now = TimeStamp::Now();
  aFrom = mIterationStart = IterationEnd();
  aTo = mIterationEnd = mGraphImpl->SecondsToMediaTime((now - mCurrentTimeStamp).ToSeconds()) + IterationEnd();

  mCurrentTimeStamp = now;

  PR_LOG(gMediaStreamGraphLog, PR_LOG_DEBUG+1, ("Updating current time to %f (real %f, mStateComputedTime %f)",
         mGraphImpl->MediaTimeToSeconds(aTo),
         (now - mInitialTimeStamp).ToSeconds(),
         mGraphImpl->MediaTimeToSeconds(StateComputedTime())));

  if (mStateComputedTime < aTo) {
    STREAM_LOG(PR_LOG_WARNING, ("Media graph global underrun detected"));
    aTo = mIterationEnd = mStateComputedTime;
  }

  if (aFrom >= aTo) {
    NS_ASSERTION(aFrom == aTo , "Time can't go backwards!");
    // This could happen due to low clock resolution, maybe?
    STREAM_LOG(PR_LOG_DEBUG, ("Time did not advance"));
  }
}
예제 #6
0
void
TrackUnionStream::SetTrackEnabledImpl(TrackID aTrackID, DisabledTrackMode aMode) {
  bool enabled = aMode == DisabledTrackMode::ENABLED;
  for (TrackMapEntry& entry : mTrackMap) {
    if (entry.mOutputTrackID == aTrackID) {
      STREAM_LOG(LogLevel::Info, ("TrackUnionStream %p track %d was explicitly %s",
                                   this, aTrackID, enabled ? "enabled" : "disabled"));
      for (DirectMediaStreamTrackListener* listener : entry.mOwnedDirectListeners) {
        DisabledTrackMode oldMode = GetDisabledTrackMode(aTrackID);
        bool oldEnabled = oldMode == DisabledTrackMode::ENABLED;
        if (!oldEnabled && enabled) {
          STREAM_LOG(LogLevel::Debug, ("TrackUnionStream %p track %d setting "
                                       "direct listener enabled",
                                       this, aTrackID));
          listener->DecreaseDisabled(oldMode);
        } else if (oldEnabled && !enabled) {
          STREAM_LOG(LogLevel::Debug, ("TrackUnionStream %p track %d setting "
                                       "direct listener disabled",
                                       this, aTrackID));
          listener->IncreaseDisabled(aMode);
        }
      }
    }
  }
  MediaStream::SetTrackEnabledImpl(aTrackID, aMode);
}
예제 #7
0
void TrackUnionStream::RemoveInput(MediaInputPort* aPort)
{
    STREAM_LOG(LogLevel::Debug, ("TrackUnionStream %p removing input %p", this, aPort));
    for (int32_t i = mTrackMap.Length() - 1; i >= 0; --i) {
        if (mTrackMap[i].mInputPort == aPort) {
            STREAM_LOG(LogLevel::Debug, ("TrackUnionStream %p removing trackmap entry %d", this, i));
            EndTrack(i);
            mTrackMap.RemoveElementAt(i);
        }
    }
    ProcessedMediaStream::RemoveInput(aPort);
}
예제 #8
0
void
ThreadedDriver::RunThread()
{
    AutoProfilerUnregisterThread autoUnregister;

    bool stillProcessing = true;
    while (stillProcessing) {
        mIterationStart = IterationEnd();
        mIterationEnd += GetIntervalForIteration();

        GraphTime stateComputedTime = StateComputedTime();
        if (stateComputedTime < mIterationEnd) {
            STREAM_LOG(LogLevel::Warning, ("Media graph global underrun detected"));
            mIterationEnd = stateComputedTime;
        }

        if (mIterationStart >= mIterationEnd) {
            NS_ASSERTION(mIterationStart == mIterationEnd ,
                         "Time can't go backwards!");
            // This could happen due to low clock resolution, maybe?
            STREAM_LOG(LogLevel::Debug, ("Time did not advance"));
        }

        GraphTime nextStateComputedTime =
            mGraphImpl->RoundUpToNextAudioBlock(
                mIterationEnd + mGraphImpl->MillisecondsToMediaTime(AUDIO_TARGET_MS));
        if (nextStateComputedTime < stateComputedTime) {
            // A previous driver may have been processing further ahead of
            // iterationEnd.
            STREAM_LOG(LogLevel::Warning,
                       ("Prevent state from going backwards. interval[%ld; %ld] state[%ld; %ld]",
                        (long)mIterationStart, (long)mIterationEnd,
                        (long)stateComputedTime, (long)nextStateComputedTime));
            nextStateComputedTime = stateComputedTime;
        }
        STREAM_LOG(LogLevel::Debug,
                   ("interval[%ld; %ld] state[%ld; %ld]",
                    (long)mIterationStart, (long)mIterationEnd,
                    (long)stateComputedTime, (long)nextStateComputedTime));

        stillProcessing = mGraphImpl->OneIteration(nextStateComputedTime);

        if (mNextDriver && stillProcessing) {
            STREAM_LOG(LogLevel::Debug, ("Switching to AudioCallbackDriver"));
            mNextDriver->SetGraphTime(this, mIterationStart, mIterationEnd);
            mGraphImpl->SetCurrentDriver(mNextDriver);
            mNextDriver->Start();
            return;
        }
    }
}
예제 #9
0
void
StreamBuffer::DumpTrackInfo() const
{
  STREAM_LOG(PR_LOG_ALWAYS, ("DumpTracks: mTracksKnownTime %lld", mTracksKnownTime));
  for (uint32_t i = 0; i < mTracks.Length(); ++i) {
    Track* track = mTracks[i];
    if (track->IsEnded()) {
      STREAM_LOG(PR_LOG_ALWAYS, ("Track[%d] %d: ended", i, track->GetID()));
    } else {
      STREAM_LOG(PR_LOG_ALWAYS, ("Track[%d] %d: %lld", i, track->GetID(),
                                 track->GetEndTimeRoundDown()));
    }
  }
}
예제 #10
0
 void TrackUnionStream::RemoveInput(MediaInputPort* aPort)
 {
   STREAM_LOG(LogLevel::Debug, ("TrackUnionStream %p removing input %p", this, aPort));
   for (int32_t i = mTrackMap.Length() - 1; i >= 0; --i) {
     if (mTrackMap[i].mInputPort == aPort) {
       STREAM_LOG(LogLevel::Debug, ("TrackUnionStream %p removing trackmap entry %d", this, i));
       EndTrack(i);
       for (auto listener : mTrackMap[i].mOwnedDirectListeners) {
         // Remove listeners while the entry still exists.
         RemoveDirectTrackListenerImpl(listener, mTrackMap[i].mOutputTrackID);
       }
       mTrackMap.RemoveElementAt(i);
     }
   }
   ProcessedMediaStream::RemoveInput(aPort);
 }
예제 #11
0
 NS_IMETHOD Run()
 {
     char aLocal;
     STREAM_LOG(LogLevel::Debug, ("Starting system thread"));
     profiler_register_thread("MediaStreamGraph", &aLocal);
     LIFECYCLE_LOG("Starting a new system driver for graph %p\n",
                   mDriver->mGraphImpl);
     if (mDriver->mPreviousDriver) {
         LIFECYCLE_LOG("%p releasing an AudioCallbackDriver(%p), for graph %p\n",
                       mDriver,
                       mDriver->mPreviousDriver.get(),
                       mDriver->GraphImpl());
         MOZ_ASSERT(!mDriver->AsAudioCallbackDriver());
         // Stop and release the previous driver off-main-thread, but only if we're
         // not in the situation where we've fallen back to a system clock driver
         // because the osx audio stack is currently switching output device.
         if (!mDriver->mPreviousDriver->AsAudioCallbackDriver()->IsSwitchingDevice()) {
             RefPtr<AsyncCubebTask> releaseEvent =
                 new AsyncCubebTask(mDriver->mPreviousDriver->AsAudioCallbackDriver(), AsyncCubebOperation::SHUTDOWN);
             mDriver->mPreviousDriver = nullptr;
             releaseEvent->Dispatch();
         }
     } else {
         MonitorAutoLock mon(mDriver->mGraphImpl->GetMonitor());
         MOZ_ASSERT(mDriver->mGraphImpl->MessagesQueued(), "Don't start a graph without messages queued.");
         mDriver->mGraphImpl->SwapMessageQueues();
     }
     mDriver->RunThread();
     return NS_OK;
 }
예제 #12
0
bool
AudioCallbackDriver::OSXDeviceSwitchingWorkaround()
{
    MonitorAutoLock mon(GraphImpl()->GetMonitor());
    if (mSelfReference) {
        // Apparently, depending on the osx version, on device switch, the
        // callback is called "some" number of times, and then stops being called,
        // and then gets called again. 10 is to be safe, it's a low-enough number
        // of milliseconds anyways (< 100ms)
        //STREAM_LOG(LogLevel::Debug, ("Callbacks during switch: %d", mCallbackReceivedWhileSwitching+1));
        if (mCallbackReceivedWhileSwitching++ >= 10) {
            STREAM_LOG(LogLevel::Debug, ("Got %d callbacks, switching back to CallbackDriver", mCallbackReceivedWhileSwitching));
            // If we have a self reference, we have fallen back temporarily on a
            // system clock driver, but we just got called back, that means the osx
            // audio backend has switched to the new device.
            // Ask the graph to switch back to the previous AudioCallbackDriver
            // (`this`), and when the graph has effectively switched, we can drop
            // the self reference and unref the SystemClockDriver we fallen back on.
            if (GraphImpl()->CurrentDriver() == this) {
                mSelfReference.Drop(this);
                mNextDriver = nullptr;
            } else {
                GraphImpl()->CurrentDriver()->SwitchAtNextIteration(this);
            }

        }
        return true;
    }

    return false;
}
예제 #13
0
 NS_IMETHOD Run()
 {
   char aLocal;
   STREAM_LOG(PR_LOG_DEBUG, ("Starting system thread"));
   profiler_register_thread("MediaStreamGraph", &aLocal);
   LIFECYCLE_LOG("Starting a new system driver for graph %p\n",
                 mDriver->mGraphImpl);
   if (mDriver->mPreviousDriver) {
     LIFECYCLE_LOG("%p releasing an AudioCallbackDriver(%p), for graph %p\n",
                   mDriver,
                   mDriver->mPreviousDriver.get(),
                   mDriver->GraphImpl());
     MOZ_ASSERT(!mDriver->AsAudioCallbackDriver());
     // Stop and release the previous driver off-main-thread.
     nsRefPtr<AsyncCubebTask> releaseEvent =
       new AsyncCubebTask(mDriver->mPreviousDriver->AsAudioCallbackDriver(), AsyncCubebTask::SHUTDOWN);
     mDriver->mPreviousDriver = nullptr;
     releaseEvent->Dispatch();
   } else {
     MonitorAutoLock mon(mDriver->mGraphImpl->GetMonitor());
     MOZ_ASSERT(mDriver->mGraphImpl->MessagesQueued(), "Don't start a graph without messages queued.");
     mDriver->mGraphImpl->SwapMessageQueues();
   }
   mDriver->RunThread();
   return NS_OK;
 }
예제 #14
0
void
AudioCallbackDriver::DeviceChangedCallback() {
    MonitorAutoLock mon(mGraphImpl->GetMonitor());
    PanOutputIfNeeded(mMicrophoneActive);
    // On OSX, changing the output device causes the audio thread to no call the
    // audio callback, so we're unable to process real-time input data, and this
    // results in latency building up.
    // We switch to a system driver until audio callbacks are called again, so we
    // still pull from the input stream, so that everything works apart from the
    // audio output.
#ifdef XP_MACOSX
    // Don't bother doing the device switching dance if the graph is not RUNNING
    // (starting up, shutting down), because we haven't started pulling from the
    // SourceMediaStream.
    if (!GraphImpl()->Running()) {
        return;
    }

    if (mSelfReference) {
        return;
    }
    STREAM_LOG(LogLevel::Error, ("Switching to SystemClockDriver during output switch"));
    mSelfReference.Take(this);
    mCallbackReceivedWhileSwitching = 0;
    mNextDriver = new SystemClockDriver(GraphImpl());
    mNextDriver->SetGraphTime(this, mIterationStart, mIterationEnd);
    mGraphImpl->SetCurrentDriver(mNextDriver);
    mNextDriver->Start();
#endif
}
예제 #15
0
void
TrackUnionStream::AddDirectTrackListenerImpl(already_AddRefed<DirectMediaStreamTrackListener> aListener,
                                             TrackID aTrackID)
{
  RefPtr<DirectMediaStreamTrackListener> listener = aListener;

  for (TrackMapEntry& entry : mTrackMap) {
    if (entry.mOutputTrackID == aTrackID) {
      MediaStream* source = entry.mInputPort->GetSource();
      STREAM_LOG(LogLevel::Debug, ("TrackUnionStream %p adding direct listener "
                                   "%p for track %d. Forwarding to input "
                                   "stream %p track %d.",
                                   this, listener.get(), aTrackID, source,
                                   entry.mInputTrackID));
      entry.mOwnedDirectListeners.AppendElement(listener);
      DisabledTrackMode currentMode = GetDisabledTrackMode(aTrackID);
      if (currentMode != DisabledTrackMode::ENABLED) {
        listener->IncreaseDisabled(currentMode);
      }
      source->AddDirectTrackListenerImpl(listener.forget(),
                                         entry.mInputTrackID);
      return;
    }
  }

  TrackBound<DirectMediaStreamTrackListener>* bound =
    mPendingDirectTrackListeners.AppendElement();
  bound->mListener = listener.forget();
  bound->mTrackID = aTrackID;
}
예제 #16
0
void
OfflineClockDriver::GetIntervalForIteration(GraphTime& aFrom, GraphTime& aTo)
{
  aFrom = mIterationStart = IterationEnd();
  aTo = mIterationEnd = IterationEnd() + mGraphImpl->MillisecondsToMediaTime(mSlice);

  if (mStateComputedTime < aTo) {
    STREAM_LOG(PR_LOG_WARNING, ("Media graph global underrun detected"));
    aTo = mIterationEnd = mStateComputedTime;
  }

  if (aFrom >= aTo) {
    NS_ASSERTION(aFrom == aTo , "Time can't go backwards!");
    // This could happen due to low clock resolution, maybe?
    STREAM_LOG(PR_LOG_DEBUG, ("Time did not advance"));
  }
}
예제 #17
0
void TrackUnionStream::EndTrack(uint32_t aIndex) {
  StreamTracks::Track* outputTrack =
      mTracks.FindTrack(mTrackMap[aIndex].mOutputTrackID);
  if (!outputTrack || outputTrack->IsEnded()) return;
  STREAM_LOG(LogLevel::Debug, ("TrackUnionStream %p ending track %d", this,
                               outputTrack->GetID()));
  outputTrack->SetEnded();
}
예제 #18
0
void
AudioCallbackDriver::Resume()
{
    STREAM_LOG(LogLevel::Debug, ("Resuming audio threads for MediaStreamGraph %p", mGraphImpl));
    if (cubeb_stream_start(mAudioStream) != CUBEB_OK) {
        NS_WARNING("Could not start cubeb stream for MSG.");
    }
}
예제 #19
0
AudioCallbackDriver::AudioCallbackDriver(MediaStreamGraphImpl* aGraphImpl, dom::AudioChannel aChannel)
  : GraphDriver(aGraphImpl)
  , mStarted(false)
  , mAudioChannel(aChannel)
  , mInCallback(false)
  , mPauseRequested(false)
{
  STREAM_LOG(PR_LOG_DEBUG, ("AudioCallbackDriver ctor for graph %p", aGraphImpl));
}
예제 #20
0
  void TrackUnionStream::CopyTrackData(StreamBuffer::Track* aInputTrack,
                     uint32_t aMapIndex, GraphTime aFrom, GraphTime aTo,
                     bool* aOutputTrackFinished)
  {
    TrackMapEntry* map = &mTrackMap[aMapIndex];
    StreamBuffer::Track* outputTrack = mBuffer.FindTrack(map->mOutputTrackID);
    MOZ_ASSERT(outputTrack && !outputTrack->IsEnded(), "Can't copy to ended track");

    MediaSegment* segment = map->mSegment;
    MediaStream* source = map->mInputPort->GetSource();

    GraphTime next;
    *aOutputTrackFinished = false;
    for (GraphTime t = aFrom; t < aTo; t = next) {
      MediaInputPort::InputInterval interval = map->mInputPort->GetNextInputInterval(t);
      interval.mEnd = std::min(interval.mEnd, aTo);
      StreamTime inputEnd = source->GraphTimeToStreamTime(interval.mEnd);
      StreamTime inputTrackEndPoint = STREAM_TIME_MAX;

      if (aInputTrack->IsEnded() &&
          aInputTrack->GetEnd() <= inputEnd) {
        inputTrackEndPoint = aInputTrack->GetEnd();
        *aOutputTrackFinished = true;
      }

      if (interval.mStart >= interval.mEnd) {
        break;
      }
      StreamTime ticks = interval.mEnd - interval.mStart;
      next = interval.mEnd;

      StreamTime outputStart = outputTrack->GetEnd();

      if (interval.mInputIsBlocked) {
        // Maybe the input track ended?
        segment->AppendNullData(ticks);
        STREAM_LOG(PR_LOG_DEBUG+1, ("TrackUnionStream %p appending %lld ticks of null data to track %d",
                   this, (long long)ticks, outputTrack->GetID()));
      } else if (InMutedCycle()) {
        segment->AppendNullData(ticks);
      } else {
        MOZ_ASSERT(outputTrack->GetEnd() == GraphTimeToStreamTime(interval.mStart),
                   "Samples missing");
        StreamTime inputStart = source->GraphTimeToStreamTime(interval.mStart);
        segment->AppendSlice(*aInputTrack->GetSegment(),
                             std::min(inputTrackEndPoint, inputStart),
                             std::min(inputTrackEndPoint, inputEnd));
      }
      ApplyTrackDisabling(outputTrack->GetID(), segment);
      for (uint32_t j = 0; j < mListeners.Length(); ++j) {
        MediaStreamListener* l = mListeners[j];
        l->NotifyQueuedTrackChanges(Graph(), outputTrack->GetID(),
                                    outputStart, 0, *segment);
      }
      outputTrack->GetSegment()->AppendFrom(segment);
    }
  }
예제 #21
0
ssize_t mailstream_low_read(mailstream_low * s, void * buf, size_t count)
{
  ssize_t r;
  
  if (s == NULL)
    return -1;
  r = s->driver->mailstream_read(s, buf, count);
  
#ifdef STREAM_DEBUG
  if (r > 0) {
    STREAM_LOG(s, 0, "<<<<<<< read <<<<<<\n");
    STREAM_LOG_BUF(s, 0, buf, r);
    STREAM_LOG(s, 0, "\n");
    STREAM_LOG(s, 0, "<<<<<<< end read <<<<<<\n");
  }
#endif
  
  return r;
}
예제 #22
0
void
AudioCallbackDriver::Revive()
{
    // Note: only called on MainThread, without monitor
    // We know were weren't in a running state
    STREAM_LOG(LogLevel::Debug, ("AudioCallbackDriver reviving."));
    // If we were switching, switch now. Otherwise, start the audio thread again.
    MonitorAutoLock mon(mGraphImpl->GetMonitor());
    if (mNextDriver) {
        mNextDriver->SetGraphTime(this, mIterationStart, mIterationEnd);
        mGraphImpl->SetCurrentDriver(mNextDriver);
        mNextDriver->Start();
    } else {
        STREAM_LOG(LogLevel::Debug, ("Starting audio threads for MediaStreamGraph %p from a new thread.", mGraphImpl));
        RefPtr<AsyncCubebTask> initEvent =
            new AsyncCubebTask(this, AsyncCubebOperation::INIT);
        initEvent->Dispatch();
    }
}
예제 #23
0
NS_IMETHODIMP
AsyncCubebTask::Run()
{
  MOZ_ASSERT(mThread);
  if (NS_IsMainThread()) {
    mThread->Shutdown(); // can't shutdown from the thread itself, darn
    // don't null out mThread!
    // See bug 999104.  we must hold a ref to the thread across Dispatch()
    // since the internal mthread ref could be released while processing
    // the Dispatch(), and Dispatch/PutEvent itself doesn't hold a ref; it
    // assumes the caller does.
    return NS_OK;
  }

  MOZ_ASSERT(mDriver);

  switch(mOperation) {
    case AsyncCubebOperation::INIT:
      LIFECYCLE_LOG("AsyncCubebOperation::INIT\n");
      mDriver->Init();
      break;
    case AsyncCubebOperation::SHUTDOWN:
      LIFECYCLE_LOG("AsyncCubebOperation::SHUTDOWN\n");
      mDriver->Stop();
      mDriver = nullptr;
      mShutdownGrip = nullptr;
      break;
    case AsyncCubebOperation::SLEEP: {
      {
        LIFECYCLE_LOG("AsyncCubebOperation::SLEEP\n");
        MonitorAutoLock mon(mDriver->mGraphImpl->GetMonitor());
        // We might just have been awoken
        if (mDriver->mNeedAnotherIteration) {
          mDriver->mPauseRequested = false;
          mDriver->mWaitState = AudioCallbackDriver::WAITSTATE_RUNNING;
          break;
        }
        mDriver->Stop();
        mDriver->mWaitState = AudioCallbackDriver::WAITSTATE_WAITING_INDEFINITELY;
        mDriver->mPauseRequested = false;
        mDriver->mGraphImpl->GetMonitor().Wait(PR_INTERVAL_NO_TIMEOUT);
      }
      STREAM_LOG(PR_LOG_DEBUG, ("Restarting audio stream from sleep."));
      mDriver->StartStream();
      break;
    }
    default:
      MOZ_CRASH("Operation not implemented.");
  }

  // and now kill this thread
  NS_DispatchToMainThread(this);

  return NS_OK;
}
예제 #24
0
void
ThreadedDriver::Stop()
{
  NS_ASSERTION(NS_IsMainThread(), "Must be called on main thread");
  // mGraph's thread is not running so it's OK to do whatever here
  STREAM_LOG(PR_LOG_DEBUG, ("Stopping threads for MediaStreamGraph %p", this));

  if (mThread) {
    mThread->Shutdown();
  }
}
예제 #25
0
void
AudioCallbackDriver::Init()
{
  cubeb_stream_params params;
  uint32_t latency;

  MOZ_ASSERT(!NS_IsMainThread(),
      "This is blocking and should never run on the main thread.");

  mSampleRate = params.rate = CubebUtils::PreferredSampleRate();

#if defined(__ANDROID__)
#if defined(MOZ_B2G)
  params.stream_type = CubebUtils::ConvertChannelToCubebType(mAudioChannel);
#else
  params.stream_type = CUBEB_STREAM_TYPE_MUSIC;
#endif
  if (params.stream_type == CUBEB_STREAM_TYPE_MAX) {
    NS_WARNING("Bad stream type");
    return;
  }
#else
  (void)mAudioChannel;
#endif

  params.channels = mGraphImpl->AudioChannelCount();
  if (AUDIO_OUTPUT_FORMAT == AUDIO_FORMAT_S16) {
    params.format = CUBEB_SAMPLE_S16NE;
  } else {
    params.format = CUBEB_SAMPLE_FLOAT32NE;
  }

  if (cubeb_get_min_latency(CubebUtils::GetCubebContext(), params, &latency) != CUBEB_OK) {
    NS_WARNING("Could not get minimal latency from cubeb.");
    return;
  }

  cubeb_stream* stream;
  if (cubeb_stream_init(CubebUtils::GetCubebContext(), &stream,
                        "AudioCallbackDriver", params, latency,
                        DataCallback_s, StateCallback_s, this) == CUBEB_OK) {
    mAudioStream.own(stream);
  } else {
    NS_WARNING("Could not create a cubeb stream for MediaStreamGraph.");
    return;
  }

  cubeb_stream_register_device_changed_callback(mAudioStream,
                                                AudioCallbackDriver::DeviceChangedCallback_s);

  StartStream();

  STREAM_LOG(PR_LOG_DEBUG, ("AudioCallbackDriver started."));
}
예제 #26
0
  uint32_t TrackUnionStream::AddTrack(MediaInputPort* aPort, StreamBuffer::Track* aTrack,
                    GraphTime aFrom)
  {
    TrackID id = aTrack->GetID();
    if (id > mNextAvailableTrackID &&
       mUsedTracks.BinaryIndexOf(id) == mUsedTracks.NoIndex) {
      // Input id available. Mark it used in mUsedTracks.
      mUsedTracks.InsertElementSorted(id);
    } else {
      // Input id taken, allocate a new one.
      id = mNextAvailableTrackID;

      // Update mNextAvailableTrackID and prune any mUsedTracks members it now
      // covers.
      while (1) {
        if (!mUsedTracks.RemoveElementSorted(++mNextAvailableTrackID)) {
          // Not in use. We're done.
          break;
        }
      }
    }

    // Round up the track start time so the track, if anything, starts a
    // little later than the true time. This means we'll have enough
    // samples in our input stream to go just beyond the destination time.
    StreamTime outputStart = GraphTimeToStreamTimeWithBlocking(aFrom);

    nsAutoPtr<MediaSegment> segment;
    segment = aTrack->GetSegment()->CreateEmptyClone();
    for (uint32_t j = 0; j < mListeners.Length(); ++j) {
      MediaStreamListener* l = mListeners[j];
      l->NotifyQueuedTrackChanges(Graph(), id, outputStart,
                                  MediaStreamListener::TRACK_EVENT_CREATED,
                                  *segment,
                                  aPort->GetSource(), aTrack->GetID());
    }
    segment->AppendNullData(outputStart);
    StreamBuffer::Track* track =
      &mBuffer.AddTrack(id, outputStart, segment.forget());
    STREAM_LOG(LogLevel::Debug, ("TrackUnionStream %p adding track %d for input stream %p track %d, start ticks %lld",
                              this, id, aPort->GetSource(), aTrack->GetID(),
                              (long long)outputStart));

    TrackMapEntry* map = mTrackMap.AppendElement();
    map->mEndOfConsumedInputTicks = 0;
    map->mEndOfLastInputIntervalInInputStream = -1;
    map->mEndOfLastInputIntervalInOutputStream = -1;
    map->mInputPort = aPort;
    map->mInputTrackID = aTrack->GetID();
    map->mOutputTrackID = track->GetID();
    map->mSegment = aTrack->GetSegment()->CreateEmptyClone();
    return mTrackMap.Length() - 1;
  }
예제 #27
0
  uint32_t TrackUnionStream::AddTrack(MediaInputPort* aPort, StreamBuffer::Track* aTrack,
                    GraphTime aFrom)
  {
    // Use the ID of the source track if it's not already assigned to a track,
    // otherwise allocate a new unique ID.
    TrackID id = aTrack->GetID();
    TrackID maxTrackID = 0;
    for (uint32_t i = 0; i < mTrackMap.Length(); ++i) {
      TrackID outID = mTrackMap[i].mOutputTrackID;
      maxTrackID = std::max(maxTrackID, outID);
    }
    // Note: we might have removed it here, but it might still be in the
    // StreamBuffer if the TrackUnionStream sees its input stream flip from
    // A to B, where both A and B have a track with the same ID
    while (1) {
      // search until we find one not in use here, and not in mBuffer
      if (!mBuffer.FindTrack(id)) {
        break;
      }
      id = ++maxTrackID;
    }

    // Round up the track start time so the track, if anything, starts a
    // little later than the true time. This means we'll have enough
    // samples in our input stream to go just beyond the destination time.
    StreamTime outputStart = GraphTimeToStreamTime(aFrom);

    nsAutoPtr<MediaSegment> segment;
    segment = aTrack->GetSegment()->CreateEmptyClone();
    for (uint32_t j = 0; j < mListeners.Length(); ++j) {
      MediaStreamListener* l = mListeners[j];
      l->NotifyQueuedTrackChanges(Graph(), id, outputStart,
                                  MediaStreamListener::TRACK_EVENT_CREATED,
                                  *segment);
    }
    segment->AppendNullData(outputStart);
    StreamBuffer::Track* track =
      &mBuffer.AddTrack(id, outputStart, segment.forget());
    STREAM_LOG(PR_LOG_DEBUG, ("TrackUnionStream %p adding track %d for input stream %p track %d, start ticks %lld",
                              this, id, aPort->GetSource(), aTrack->GetID(),
                              (long long)outputStart));

    TrackMapEntry* map = mTrackMap.AppendElement();
    map->mEndOfConsumedInputTicks = 0;
    map->mEndOfLastInputIntervalInInputStream = -1;
    map->mEndOfLastInputIntervalInOutputStream = -1;
    map->mInputPort = aPort;
    map->mInputTrackID = aTrack->GetID();
    map->mOutputTrackID = track->GetID();
    map->mSegment = aTrack->GetSegment()->CreateEmptyClone();
    return mTrackMap.Length() - 1;
  }
예제 #28
0
void
AudioCallbackDriver::Start()
{
  // If this is running on the main thread, we can't open the stream directly,
  // because it is a blocking operation.
  if (NS_IsMainThread()) {
    STREAM_LOG(PR_LOG_DEBUG, ("Starting audio threads for MediaStreamGraph %p from a new thread.", mGraphImpl));
    nsRefPtr<AsyncCubebTask> initEvent =
      new AsyncCubebTask(this, AsyncCubebTask::INIT);
    initEvent->Dispatch();
  } else {
    STREAM_LOG(PR_LOG_DEBUG, ("Starting audio threads for MediaStreamGraph %p from the previous driver's thread", mGraphImpl));
    Init();

    if (mPreviousDriver) {
      nsCOMPtr<nsIRunnable> event =
        new MediaStreamGraphShutdownThreadRunnable(mPreviousDriver);
      mPreviousDriver = nullptr;
      NS_DispatchToMainThread(event);
    }
  }
}
예제 #29
0
void GraphDriver::SetGraphTime(GraphDriver* aPreviousDriver,
                               GraphTime aLastSwitchNextIterationStart,
                               GraphTime aLastSwitchNextIterationEnd)
{
    // We set mIterationEnd here, because the first thing a driver do when it
    // does an iteration is to update graph times, so we are in fact setting
    // mIterationStart of the next iteration by setting the end of the previous
    // iteration.
    mIterationStart = aLastSwitchNextIterationStart;
    mIterationEnd = aLastSwitchNextIterationEnd;

    STREAM_LOG(LogLevel::Debug, ("Setting previous driver: %p (%s)", aPreviousDriver, aPreviousDriver->AsAudioCallbackDriver() ? "AudioCallbackDriver" : "SystemClockDriver"));
    MOZ_ASSERT(!mPreviousDriver);
    mPreviousDriver = aPreviousDriver;
}
예제 #30
0
AudioCallbackDriver::AudioCallbackDriver(MediaStreamGraphImpl* aGraphImpl)
    : GraphDriver(aGraphImpl)
    , mSampleRate(0)
    , mIterationDurationMS(MEDIA_GRAPH_TARGET_PERIOD_MS)
    , mStarted(false)
    , mAudioChannel(aGraphImpl->AudioChannel())
    , mInCallback(false)
    , mPauseRequested(false)
    , mMicrophoneActive(false)
#ifdef XP_MACOSX
    , mCallbackReceivedWhileSwitching(0)
#endif
{
    STREAM_LOG(LogLevel::Debug, ("AudioCallbackDriver ctor for graph %p", aGraphImpl));
}