Bug 1199155. Part 1 - move dom/media/DecodedStream.* to dom/media/mediasink/ and implement the interface of MediaSink. r=roc.

This commit is contained in:
JW Wang 2015-09-07 19:31:51 +08:00
parent c351478cef
commit bbfaf9763e
2 changed files with 108 additions and 41 deletions

View File

@ -4,6 +4,9 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "mozilla/CheckedInt.h"
#include "mozilla/gfx/Point.h"
#include "AudioSegment.h"
#include "DecodedStream.h"
#include "MediaData.h"
@ -358,7 +361,6 @@ DecodedStream::DecodedStream(AbstractThread* aOwnerThread,
: mOwnerThread(aOwnerThread)
, mShuttingDown(false)
, mPlaying(false)
, mVolume(1.0)
, mSameOrigin(false)
, mAudioQueue(aAudioQueue)
, mVideoQueue(aVideoQueue)
@ -370,21 +372,52 @@ DecodedStream::~DecodedStream()
MOZ_ASSERT(mStartTime.isNothing(), "playback should've ended.");
}
const media::MediaSink::PlaybackParams&
DecodedStream::GetPlaybackParams() const
{
AssertOwnerThread();
return mParams;
}
void
DecodedStream::Shutdown()
DecodedStream::SetPlaybackParams(const PlaybackParams& aParams)
{
AssertOwnerThread();
mParams = aParams;
}
nsRefPtr<GenericPromise>
DecodedStream::OnEnded(TrackType aType)
{
AssertOwnerThread();
MOZ_ASSERT(mStartTime.isSome());
if (aType == TrackInfo::kAudioTrack) {
// TODO: we should return a promise which is resolved when the audio track
// is finished. For now this promise is resolved when the whole stream is
// finished.
return mFinishPromise;
}
// TODO: handle video track.
return nullptr;
}
void
DecodedStream::BeginShutdown()
{
MOZ_ASSERT(NS_IsMainThread());
mShuttingDown = true;
}
nsRefPtr<GenericPromise>
DecodedStream::StartPlayback(int64_t aStartTime, const MediaInfo& aInfo)
void
DecodedStream::Start(int64_t aStartTime, const MediaInfo& aInfo)
{
AssertOwnerThread();
MOZ_ASSERT(mStartTime.isNothing(), "playback already started.");
mStartTime.emplace(aStartTime);
mInfo = aInfo;
mPlaying = true;
ConnectListener();
class R : public nsRunnable {
@ -408,30 +441,33 @@ DecodedStream::StartPlayback(int64_t aStartTime, const MediaInfo& aInfo)
};
MozPromiseHolder<GenericPromise> promise;
nsRefPtr<GenericPromise> rv = promise.Ensure(__func__);
mFinishPromise = promise.Ensure(__func__);
nsCOMPtr<nsIRunnable> r = new R(this, &DecodedStream::CreateData, Move(promise));
AbstractThread::MainThread()->Dispatch(r.forget());
return rv.forget();
}
void DecodedStream::StopPlayback()
void
DecodedStream::Stop()
{
AssertOwnerThread();
// Playback didn't even start at all.
if (mStartTime.isNothing()) {
return;
}
MOZ_ASSERT(mStartTime.isSome(), "playback not started.");
mStartTime.reset();
DisconnectListener();
mFinishPromise = nullptr;
// Clear mData immediately when this playback session ends so we won't
// send data to the wrong stream in SendData() in next playback session.
DestroyData(Move(mData));
}
bool
DecodedStream::IsStarted() const
{
AssertOwnerThread();
return mStartTime.isSome();
}
void
DecodedStream::DestroyData(UniquePtr<DecodedStreamData> aData)
{
@ -531,6 +567,12 @@ void
DecodedStream::SetPlaying(bool aPlaying)
{
AssertOwnerThread();
// Resume/pause matters only when playback started.
if (mStartTime.isNothing()) {
return;
}
mPlaying = aPlaying;
if (mData) {
mData->SetPlaying(aPlaying);
@ -541,7 +583,21 @@ void
DecodedStream::SetVolume(double aVolume)
{
AssertOwnerThread();
mVolume = aVolume;
mParams.volume = aVolume;
}
void
DecodedStream::SetPlaybackRate(double aPlaybackRate)
{
AssertOwnerThread();
mParams.playbackRate = aPlaybackRate;
}
void
DecodedStream::SetPreservesPitch(bool aPreservesPitch)
{
AssertOwnerThread();
mParams.preservesPitch = aPreservesPitch;
}
void
@ -815,7 +871,7 @@ DecodedStream::SendData()
}
InitTracks();
SendAudio(mVolume, mSameOrigin);
SendAudio(mParams.volume, mSameOrigin);
SendVideo(mSameOrigin);
AdvanceTracks();
@ -829,26 +885,31 @@ DecodedStream::SendData()
}
int64_t
DecodedStream::AudioEndTime() const
DecodedStream::GetEndTime(TrackType aType) const
{
AssertOwnerThread();
if (mStartTime.isSome() && mInfo.HasAudio() && mData) {
if (aType == TrackInfo::kAudioTrack && mInfo.HasAudio() && mData) {
CheckedInt64 t = mStartTime.ref() +
FramesToUsecs(mData->mAudioFramesWritten, mInfo.mAudio.mRate);
if (t.isValid()) {
return t.value();
}
} else if (aType == TrackInfo::kVideoTrack && mData) {
return mData->mNextVideoTime;
}
return -1;
}
int64_t
DecodedStream::GetPosition() const
DecodedStream::GetPosition(TimeStamp* aTimeStamp) const
{
AssertOwnerThread();
// This is only called after MDSM starts playback. So mStartTime is
// guaranteed to be something.
MOZ_ASSERT(mStartTime.isSome());
if (aTimeStamp) {
*aTimeStamp = TimeStamp::Now();
}
return mStartTime.ref() + (mData ? mData->GetPosition() : 0);
}

View File

@ -10,15 +10,13 @@
#include "nsTArray.h"
#include "MediaEventSource.h"
#include "MediaInfo.h"
#include "MediaSink.h"
#include "mozilla/AbstractThread.h"
#include "mozilla/CheckedInt.h"
#include "mozilla/Maybe.h"
#include "mozilla/MozPromise.h"
#include "mozilla/nsRefPtr.h"
#include "mozilla/ReentrantMonitor.h"
#include "mozilla/UniquePtr.h"
#include "mozilla/gfx/Point.h"
namespace mozilla {
@ -31,7 +29,7 @@ class MediaStreamGraph;
class OutputStreamListener;
class OutputStreamManager;
class ProcessedMediaStream;
class ReentrantMonitor;
class TimeStamp;
template <class T> class MediaQueue;
@ -99,34 +97,41 @@ private:
nsTArray<OutputStreamData> mStreams;
};
class DecodedStream {
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(DecodedStream);
class DecodedStream : public media::MediaSink {
using media::MediaSink::PlaybackParams;
public:
DecodedStream(AbstractThread* aOwnerThread,
MediaQueue<MediaData>& aAudioQueue,
MediaQueue<MediaData>& aVideoQueue);
void Shutdown();
// MediaSink functions.
const PlaybackParams& GetPlaybackParams() const override;
void SetPlaybackParams(const PlaybackParams& aParams) override;
// Mimic MDSM::StartAudioThread.
// Must be called before any calls to SendData().
//
// Return a promise which will be resolved when the stream is finished
// or rejected if any error.
nsRefPtr<GenericPromise> StartPlayback(int64_t aStartTime,
const MediaInfo& aInfo);
// Mimic MDSM::StopAudioThread.
void StopPlayback();
nsRefPtr<GenericPromise> OnEnded(TrackType aType) override;
int64_t GetEndTime(TrackType aType) const override;
int64_t GetPosition(TimeStamp* aTimeStamp = nullptr) const override;
bool HasUnplayedFrames(TrackType aType) const override
{
// TODO: implement this.
return false;
}
void SetVolume(double aVolume) override;
void SetPlaybackRate(double aPlaybackRate) override;
void SetPreservesPitch(bool aPreservesPitch) override;
void SetPlaying(bool aPlaying) override;
void Start(int64_t aStartTime, const MediaInfo& aInfo) override;
void Stop() override;
bool IsStarted() const override;
// TODO: fix these functions that don't fit into the interface of MediaSink.
void BeginShutdown();
void AddOutput(ProcessedMediaStream* aStream, bool aFinishWhenEnded);
void RemoveOutput(MediaStream* aStream);
void SetPlaying(bool aPlaying);
void SetVolume(double aVolume);
void SetSameOrigin(bool aSameOrigin);
int64_t AudioEndTime() const;
int64_t GetPosition() const;
bool IsFinished() const;
bool HasConsumers() const;
@ -164,10 +169,11 @@ private:
* Worker thread only members.
*/
UniquePtr<DecodedStreamData> mData;
nsRefPtr<GenericPromise> mFinishPromise;
bool mPlaying;
double mVolume;
bool mSameOrigin;
PlaybackParams mParams;
Maybe<int64_t> mStartTime;
MediaInfo mInfo;