зеркало из https://github.com/mozilla/gecko-dev.git
Bug 836599 - Part 7: Implement a non-realtime API in MediaStreamGraph; r=roc
This commit is contained in:
Родитель
809128eeae
Коммит
9d8f56046a
|
@ -676,6 +676,8 @@ void
|
|||
MediaStreamGraphImpl::CreateOrDestroyAudioStreams(GraphTime aAudioOutputStartTime,
|
||||
MediaStream* aStream)
|
||||
{
|
||||
MOZ_ASSERT(mRealtime, "Should only attempt to create audio streams in real-time mode");
|
||||
|
||||
nsAutoTArray<bool,2> audioOutputStreamsFound;
|
||||
for (uint32_t i = 0; i < aStream->mAudioOutputStreams.Length(); ++i) {
|
||||
audioOutputStreamsFound.AppendElement(false);
|
||||
|
@ -732,6 +734,8 @@ void
|
|||
MediaStreamGraphImpl::PlayAudio(MediaStream* aStream,
|
||||
GraphTime aFrom, GraphTime aTo)
|
||||
{
|
||||
MOZ_ASSERT(mRealtime, "Should only attempt to play audio in realtime mode");
|
||||
|
||||
if (aStream->mAudioOutputStreams.IsEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
@ -805,6 +809,8 @@ MediaStreamGraphImpl::PlayAudio(MediaStream* aStream,
|
|||
void
|
||||
MediaStreamGraphImpl::PlayVideo(MediaStream* aStream)
|
||||
{
|
||||
MOZ_ASSERT(mRealtime, "Should only attempt to play video in realtime mode");
|
||||
|
||||
if (aStream->mVideoOutputs.IsEmpty())
|
||||
return;
|
||||
|
||||
|
@ -1010,10 +1016,13 @@ MediaStreamGraphImpl::RunThread()
|
|||
}
|
||||
}
|
||||
NotifyHasCurrentData(stream);
|
||||
CreateOrDestroyAudioStreams(prevComputedTime, stream);
|
||||
PlayAudio(stream, prevComputedTime, mStateComputedTime);
|
||||
audioStreamsActive += stream->mAudioOutputStreams.Length();
|
||||
PlayVideo(stream);
|
||||
if (mRealtime) {
|
||||
// Only playback audio and video in real-time mode
|
||||
CreateOrDestroyAudioStreams(prevComputedTime, stream);
|
||||
PlayAudio(stream, prevComputedTime, mStateComputedTime);
|
||||
audioStreamsActive += stream->mAudioOutputStreams.Length();
|
||||
PlayVideo(stream);
|
||||
}
|
||||
SourceMediaStream* is = stream->AsSourceStream();
|
||||
if (is) {
|
||||
UpdateBufferSufficiencyState(is);
|
||||
|
@ -1030,8 +1039,6 @@ MediaStreamGraphImpl::RunThread()
|
|||
// Send updates to the main thread and wait for the next control loop
|
||||
// iteration.
|
||||
{
|
||||
// Not using MonitorAutoLock since we need to unlock in a way
|
||||
// that doesn't match lexical scopes.
|
||||
MonitorAutoLock lock(mMonitor);
|
||||
PrepareUpdatesToMainThreadState();
|
||||
if (mForceShutDown || (IsEmpty() && mMessageQueue.IsEmpty())) {
|
||||
|
@ -1045,26 +1052,30 @@ MediaStreamGraphImpl::RunThread()
|
|||
return;
|
||||
}
|
||||
|
||||
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));
|
||||
LOG(PR_LOG_DEBUG, ("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) {
|
||||
mMonitor.Wait(timeout);
|
||||
LOG(PR_LOG_DEBUG, ("Resuming after timeout; at %f, elapsed=%f",
|
||||
(TimeStamp::Now() - mInitialTimeStamp).ToSeconds(),
|
||||
(TimeStamp::Now() - now).ToSeconds()));
|
||||
// No need to wait in non-realtime mode, just churn through the input as soon
|
||||
// as possible.
|
||||
if (mRealtime) {
|
||||
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));
|
||||
LOG(PR_LOG_DEBUG, ("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) {
|
||||
mMonitor.Wait(timeout);
|
||||
LOG(PR_LOG_DEBUG, ("Resuming after timeout; at %f, elapsed=%f",
|
||||
(TimeStamp::Now() - mInitialTimeStamp).ToSeconds(),
|
||||
(TimeStamp::Now() - now).ToSeconds()));
|
||||
}
|
||||
}
|
||||
mWaitState = WAITSTATE_RUNNING;
|
||||
mNeedAnotherIteration = false;
|
||||
|
@ -1939,7 +1950,7 @@ ProcessedMediaStream::DestroyImpl()
|
|||
*/
|
||||
static const int32_t INITIAL_CURRENT_TIME = 1;
|
||||
|
||||
MediaStreamGraphImpl::MediaStreamGraphImpl()
|
||||
MediaStreamGraphImpl::MediaStreamGraphImpl(bool aRealtime)
|
||||
: mCurrentTime(INITIAL_CURRENT_TIME)
|
||||
, mStateComputedTime(INITIAL_CURRENT_TIME)
|
||||
, mProcessingGraphUpdateIndex(0)
|
||||
|
@ -1952,6 +1963,7 @@ MediaStreamGraphImpl::MediaStreamGraphImpl()
|
|||
, mPostedRunInStableStateEvent(false)
|
||||
, mDetectedNotRunning(false)
|
||||
, mPostedRunInStableState(false)
|
||||
, mRealtime(aRealtime)
|
||||
{
|
||||
#ifdef PR_LOGGING
|
||||
if (!gMediaStreamGraphLog) {
|
||||
|
@ -1992,13 +2004,33 @@ MediaStreamGraph::GetInstance()
|
|||
nsContentUtils::RegisterShutdownObserver(new MediaStreamGraphShutdownObserver());
|
||||
}
|
||||
|
||||
gGraph = new MediaStreamGraphImpl();
|
||||
gGraph = new MediaStreamGraphImpl(true);
|
||||
LOG(PR_LOG_DEBUG, ("Starting up MediaStreamGraph %p", gGraph));
|
||||
}
|
||||
|
||||
return gGraph;
|
||||
}
|
||||
|
||||
MediaStreamGraph*
|
||||
MediaStreamGraph::CreateNonRealtimeInstance()
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Main thread only");
|
||||
|
||||
MediaStreamGraphImpl* graph = new MediaStreamGraphImpl(false);
|
||||
return graph;
|
||||
}
|
||||
|
||||
void
|
||||
MediaStreamGraph::DestroyNonRealtimeInstance(MediaStreamGraph* aGraph)
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Main thread only");
|
||||
MOZ_ASSERT(aGraph != gGraph, "Should not destroy the global graph here");
|
||||
|
||||
MediaStreamGraphImpl* graph = static_cast<MediaStreamGraphImpl*>(aGraph);
|
||||
graph->ForceShutDown();
|
||||
delete graph;
|
||||
}
|
||||
|
||||
SourceMediaStream*
|
||||
MediaStreamGraph::CreateSourceStream(DOMMediaStream* aWrapper)
|
||||
{
|
||||
|
|
|
@ -887,7 +887,8 @@ inline TrackRate IdealAudioRate() { return 48000; }
|
|||
|
||||
/**
|
||||
* Initially, at least, we will have a singleton MediaStreamGraph per
|
||||
* process.
|
||||
* process. Each OfflineAudioContext object creates its own MediaStreamGraph
|
||||
* object too.
|
||||
*/
|
||||
class MediaStreamGraph {
|
||||
public:
|
||||
|
@ -898,6 +899,9 @@ public:
|
|||
|
||||
// Main thread only
|
||||
static MediaStreamGraph* GetInstance();
|
||||
static MediaStreamGraph* CreateNonRealtimeInstance();
|
||||
static void DestroyNonRealtimeInstance(MediaStreamGraph* aGraph);
|
||||
|
||||
// Control API.
|
||||
/**
|
||||
* Create a stream that a media decoder (or some other source of
|
||||
|
|
|
@ -103,11 +103,19 @@ protected:
|
|||
* file. It's not in the anonymous namespace because MediaStream needs to
|
||||
* be able to friend it.
|
||||
*
|
||||
* Currently we only have one per process.
|
||||
* Currently we have one global instance per process, and one per each
|
||||
* OfflineAudioContext object.
|
||||
*/
|
||||
class MediaStreamGraphImpl : public MediaStreamGraph {
|
||||
public:
|
||||
MediaStreamGraphImpl();
|
||||
/**
|
||||
* Set aRealtime to true in order to create a MediaStreamGraph which provides
|
||||
* support for real-time audio and video. Set it to false in order to create
|
||||
* a non-realtime instance which just churns through its inputs and produces
|
||||
* output. Those objects currently only support audio, and are used to
|
||||
* implement OfflineAudioContext. They do not support MediaStream inputs.
|
||||
*/
|
||||
explicit MediaStreamGraphImpl(bool aRealtime);
|
||||
~MediaStreamGraphImpl()
|
||||
{
|
||||
NS_ASSERTION(IsEmpty(),
|
||||
|
@ -506,6 +514,11 @@ public:
|
|||
* RunInStableState at the next stable state.
|
||||
*/
|
||||
bool mPostedRunInStableState;
|
||||
/**
|
||||
* True when processing real-time audio/video. False when processing non-realtime
|
||||
* audio.
|
||||
*/
|
||||
bool mRealtime;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче