Bug 836599 - Part 7: Implement a non-realtime API in MediaStreamGraph; r=roc

This commit is contained in:
Ehsan Akhgari 2013-05-08 07:44:07 -04:00
Родитель 809128eeae
Коммит 9d8f56046a
3 изменённых файлов: 80 добавлений и 31 удалений

Просмотреть файл

@ -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;
};
}