зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1208371 - Add a MediaStreamTrackSource interface. r=roc
This lets a MediaStreamTrack communicate with its source/producer on the main thread. It's for now used for stopping a track at the source and retrieving some metadata, but it could also be a link between actual sinks of a track and the source, to for instance let the source optimize by scaling down the resolution when all sinks want lowres-video. MozReview-Commit-ID: D4SJLr0aqhJ --HG-- extra : rebase_source : ea511b5c86ca4836bfa980825f04617fef498261
This commit is contained in:
Родитель
2a7a664d3b
Коммит
9899305f28
|
@ -529,7 +529,8 @@ nsDOMCameraControl::TrackCreated(TrackID aTrackID) {
|
|||
// This track is not connected through a port.
|
||||
MediaInputPort* inputPort = nullptr;
|
||||
dom::VideoStreamTrack* track =
|
||||
new dom::VideoStreamTrack(this, aTrackID, nsString());
|
||||
new dom::VideoStreamTrack(this, aTrackID, nsString(),
|
||||
new BasicUnstoppableTrackSource());
|
||||
RefPtr<TrackPort> port =
|
||||
new TrackPort(inputPort, track,
|
||||
TrackPort::InputPortOwnership::OWNED);
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#include "mozilla/dom/CanvasRenderingContext2D.h"
|
||||
#include "mozilla/dom/File.h"
|
||||
#include "mozilla/dom/HTMLCanvasElementBinding.h"
|
||||
#include "mozilla/dom/MediaStreamTrack.h"
|
||||
#include "mozilla/dom/MouseEvent.h"
|
||||
#include "mozilla/dom/OffscreenCanvas.h"
|
||||
#include "mozilla/EventDispatcher.h"
|
||||
|
@ -682,7 +683,8 @@ HTMLCanvasElement::CaptureStream(const Optional<double>& aFrameRate,
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
stream->CreateOwnDOMTrack(videoTrackId, MediaSegment::VIDEO, nsString());
|
||||
stream->CreateOwnDOMTrack(videoTrackId, MediaSegment::VIDEO, nsString(),
|
||||
new BasicUnstoppableTrackSource());
|
||||
|
||||
rv = RegisterFrameCaptureListener(stream->FrameCaptureListener());
|
||||
if (NS_FAILED(rv)) {
|
||||
|
|
|
@ -1905,11 +1905,15 @@ HTMLMediaElement::CaptureStreamInternal(bool aFinishWhenEnded,
|
|||
// Expose the tracks to JS directly.
|
||||
if (HasAudio()) {
|
||||
TrackID audioTrackId = mMediaInfo.mAudio.mTrackId;
|
||||
out->mStream->CreateOwnDOMTrack(audioTrackId, MediaSegment::AUDIO, nsString());
|
||||
RefPtr<MediaStreamTrackSource> trackSource = new BasicUnstoppableTrackSource();
|
||||
out->mStream->CreateOwnDOMTrack(audioTrackId, MediaSegment::AUDIO,
|
||||
nsString(), trackSource);
|
||||
}
|
||||
if (HasVideo()) {
|
||||
TrackID videoTrackId = mMediaInfo.mVideo.mTrackId;
|
||||
out->mStream->CreateOwnDOMTrack(videoTrackId, MediaSegment::VIDEO, nsString());
|
||||
RefPtr<MediaStreamTrackSource> trackSource = new BasicUnstoppableTrackSource();
|
||||
out->mStream->CreateOwnDOMTrack(videoTrackId, MediaSegment::VIDEO,
|
||||
nsString(), trackSource);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,8 +14,9 @@ namespace dom {
|
|||
|
||||
class AudioStreamTrack : public MediaStreamTrack {
|
||||
public:
|
||||
AudioStreamTrack(DOMMediaStream* aStream, TrackID aTrackID, const nsString& aLabel)
|
||||
: MediaStreamTrack(aStream, aTrackID, aLabel) {}
|
||||
AudioStreamTrack(DOMMediaStream* aStream, TrackID aTrackID,
|
||||
const nsString& aLabel, MediaStreamTrackSource* aSource)
|
||||
: MediaStreamTrack(aStream, aTrackID, aLabel, aSource) {}
|
||||
|
||||
JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
|
||||
|
||||
|
|
|
@ -128,15 +128,16 @@ public:
|
|||
|
||||
MediaStreamTrack* track = mStream->FindOwnedDOMTrack(
|
||||
mStream->GetOwnedStream(), aTrackId);
|
||||
if (track) {
|
||||
// This track has already been manually created. Abort.
|
||||
return;
|
||||
if (!track) {
|
||||
// Track had not been created on main thread before, create it now.
|
||||
NS_WARN_IF_FALSE(!mStream->mTracks.IsEmpty(),
|
||||
"A new track was detected on the input stream; creating "
|
||||
"a corresponding MediaStreamTrack. Initial tracks "
|
||||
"should be added manually to immediately and "
|
||||
"synchronously be available to JS.");
|
||||
track = mStream->CreateOwnDOMTrack(aTrackId, aType, nsString(),
|
||||
new BasicUnstoppableTrackSource());
|
||||
}
|
||||
|
||||
NS_WARN_IF_FALSE(!mStream->mTracks.IsEmpty(),
|
||||
"A new track was detected on the input stream; creating a corresponding MediaStreamTrack. "
|
||||
"Initial tracks should be added manually to immediately and synchronously be available to JS.");
|
||||
mStream->CreateOwnDOMTrack(aTrackId, aType, nsString());
|
||||
}
|
||||
|
||||
void DoNotifyTrackEnded(TrackID aTrackId)
|
||||
|
@ -617,12 +618,15 @@ DOMMediaStream::InitAudioCaptureStream(MediaStreamGraph* aGraph)
|
|||
{
|
||||
const TrackID AUDIO_TRACK = 1;
|
||||
|
||||
RefPtr<BasicUnstoppableTrackSource> audioCaptureSource =
|
||||
new BasicUnstoppableTrackSource(MediaSourceEnum::AudioCapture);
|
||||
|
||||
AudioCaptureStream* audioCaptureStream =
|
||||
static_cast<AudioCaptureStream*>(aGraph->CreateAudioCaptureStream(this, AUDIO_TRACK));
|
||||
InitInputStreamCommon(audioCaptureStream, aGraph);
|
||||
InitOwnedStreamCommon(aGraph);
|
||||
InitPlaybackStreamCommon(aGraph);
|
||||
CreateOwnDOMTrack(AUDIO_TRACK, MediaSegment::AUDIO, nsString());
|
||||
CreateOwnDOMTrack(AUDIO_TRACK, MediaSegment::AUDIO, nsString(), audioCaptureSource);
|
||||
audioCaptureStream->Start();
|
||||
}
|
||||
|
||||
|
@ -705,14 +709,6 @@ DOMMediaStream::SetTrackEnabled(TrackID aTrackID, bool aEnabled)
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
DOMMediaStream::StopTrack(TrackID aTrackID)
|
||||
{
|
||||
if (mInputStream && mInputStream->AsSourceStream()) {
|
||||
mInputStream->AsSourceStream()->EndTrack(aTrackID);
|
||||
}
|
||||
}
|
||||
|
||||
already_AddRefed<Promise>
|
||||
DOMMediaStream::ApplyConstraintsToTrack(TrackID aTrackID,
|
||||
const MediaTrackConstraints& aConstraints,
|
||||
|
@ -784,7 +780,9 @@ DOMMediaStream::RemovePrincipalChangeObserver(PrincipalChangeObserver* aObserver
|
|||
}
|
||||
|
||||
MediaStreamTrack*
|
||||
DOMMediaStream::CreateOwnDOMTrack(TrackID aTrackID, MediaSegment::Type aType, const nsString& aLabel)
|
||||
DOMMediaStream::CreateOwnDOMTrack(TrackID aTrackID, MediaSegment::Type aType,
|
||||
const nsString& aLabel,
|
||||
MediaStreamTrackSource* aSource)
|
||||
{
|
||||
MOZ_RELEASE_ASSERT(mInputStream);
|
||||
MOZ_RELEASE_ASSERT(mOwnedStream);
|
||||
|
@ -794,10 +792,10 @@ DOMMediaStream::CreateOwnDOMTrack(TrackID aTrackID, MediaSegment::Type aType, co
|
|||
MediaStreamTrack* track;
|
||||
switch (aType) {
|
||||
case MediaSegment::AUDIO:
|
||||
track = new AudioStreamTrack(this, aTrackID, aLabel);
|
||||
track = new AudioStreamTrack(this, aTrackID, aLabel, aSource);
|
||||
break;
|
||||
case MediaSegment::VIDEO:
|
||||
track = new VideoStreamTrack(this, aTrackID, aLabel);
|
||||
track = new VideoStreamTrack(this, aTrackID, aLabel, aSource);
|
||||
break;
|
||||
default:
|
||||
MOZ_CRASH("Unhandled track type");
|
||||
|
|
|
@ -35,7 +35,6 @@ class DOMHwMediaStream;
|
|||
class DOMLocalMediaStream;
|
||||
class DOMMediaStream;
|
||||
class MediaStream;
|
||||
class MediaEngineSource;
|
||||
class MediaInputPort;
|
||||
class MediaStreamGraph;
|
||||
class ProcessedMediaStream;
|
||||
|
@ -46,6 +45,7 @@ class HTMLCanvasElement;
|
|||
class MediaStreamTrack;
|
||||
class AudioStreamTrack;
|
||||
class VideoStreamTrack;
|
||||
class MediaStreamTrackSource;
|
||||
class AudioTrack;
|
||||
class VideoTrack;
|
||||
class AudioTrackList;
|
||||
|
@ -184,6 +184,7 @@ class DOMMediaStream : public DOMEventTargetHelper
|
|||
typedef dom::MediaStreamTrack MediaStreamTrack;
|
||||
typedef dom::AudioStreamTrack AudioStreamTrack;
|
||||
typedef dom::VideoStreamTrack VideoStreamTrack;
|
||||
typedef dom::MediaStreamTrackSource MediaStreamTrackSource;
|
||||
typedef dom::AudioTrack AudioTrack;
|
||||
typedef dom::VideoTrack VideoTrack;
|
||||
typedef dom::AudioTrackList AudioTrackList;
|
||||
|
@ -381,8 +382,6 @@ public:
|
|||
*/
|
||||
virtual void SetTrackEnabled(TrackID aTrackID, bool aEnabled);
|
||||
|
||||
virtual void StopTrack(TrackID aTrackID);
|
||||
|
||||
virtual already_AddRefed<dom::Promise>
|
||||
ApplyConstraintsToTrack(TrackID aTrackID,
|
||||
const MediaTrackConstraints& aConstraints,
|
||||
|
@ -483,7 +482,9 @@ public:
|
|||
*
|
||||
* Creates a MediaStreamTrack, adds it to mTracks and returns it.
|
||||
*/
|
||||
MediaStreamTrack* CreateOwnDOMTrack(TrackID aTrackID, MediaSegment::Type aType, const nsString& aLabel);
|
||||
MediaStreamTrack* CreateOwnDOMTrack(TrackID aTrackID, MediaSegment::Type aType,
|
||||
const nsString& aLabel,
|
||||
MediaStreamTrackSource* aSource);
|
||||
|
||||
// When the initial set of tracks has been added, run
|
||||
// aCallback->NotifyTracksAvailable.
|
||||
|
@ -641,8 +642,6 @@ public:
|
|||
|
||||
void Stop();
|
||||
|
||||
virtual MediaEngineSource* GetMediaEngine(TrackID aTrackID) { return nullptr; }
|
||||
|
||||
/**
|
||||
* Create an nsDOMLocalMediaStream whose underlying stream is a SourceMediaStream.
|
||||
*/
|
||||
|
|
|
@ -141,6 +141,7 @@ using dom::MediaSourceEnum;
|
|||
using dom::MediaStreamConstraints;
|
||||
using dom::MediaStreamError;
|
||||
using dom::MediaStreamTrack;
|
||||
using dom::MediaStreamTrackSource;
|
||||
using dom::MediaTrackConstraints;
|
||||
using dom::MediaTrackConstraintSet;
|
||||
using dom::OwningBooleanOrMediaTrackConstraints;
|
||||
|
@ -666,26 +667,18 @@ public:
|
|||
static already_AddRefed<nsDOMUserMediaStream>
|
||||
CreateSourceStream(nsPIDOMWindowInner* aWindow,
|
||||
GetUserMediaCallbackMediaStreamListener* aListener,
|
||||
AudioDevice* aAudioDevice,
|
||||
VideoDevice* aVideoDevice,
|
||||
MediaStreamGraph* aMSG)
|
||||
{
|
||||
RefPtr<nsDOMUserMediaStream> stream = new nsDOMUserMediaStream(aWindow,
|
||||
aListener,
|
||||
aAudioDevice,
|
||||
aVideoDevice);
|
||||
aListener);
|
||||
stream->InitSourceStream(aMSG);
|
||||
return stream.forget();
|
||||
}
|
||||
|
||||
nsDOMUserMediaStream(nsPIDOMWindowInner* aWindow,
|
||||
GetUserMediaCallbackMediaStreamListener* aListener,
|
||||
AudioDevice *aAudioDevice,
|
||||
VideoDevice *aVideoDevice) :
|
||||
GetUserMediaCallbackMediaStreamListener* aListener) :
|
||||
DOMLocalMediaStream(aWindow),
|
||||
mListener(aListener),
|
||||
mAudioDevice(aAudioDevice),
|
||||
mVideoDevice(aVideoDevice)
|
||||
mListener(aListener)
|
||||
{}
|
||||
|
||||
virtual ~nsDOMUserMediaStream()
|
||||
|
@ -697,26 +690,6 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
// For gUM streams, we have a trackunion which assigns TrackIDs. However, for a
|
||||
// single-source trackunion like we have here, the TrackUnion will assign trackids
|
||||
// that match the source's trackids, so we can avoid needing a mapping function.
|
||||
// XXX This will not handle more complex cases well.
|
||||
void StopTrack(TrackID aTrackID) override
|
||||
{
|
||||
if (GetSourceStream()) {
|
||||
GetSourceStream()->EndTrack(aTrackID);
|
||||
// We could override NotifyMediaStreamTrackEnded(), and maybe should, but it's
|
||||
// risky to do late in a release since that will affect all track ends, and not
|
||||
// just StopTrack()s.
|
||||
RefPtr<dom::MediaStreamTrack> ownedTrack = FindOwnedDOMTrack(mOwnedStream, aTrackID);
|
||||
if (ownedTrack) {
|
||||
mListener->StopTrack(aTrackID);
|
||||
} else {
|
||||
LOG(("StopTrack(%d) on non-existent track", aTrackID));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
already_AddRefed<Promise>
|
||||
ApplyConstraintsToTrack(TrackID aTrackID,
|
||||
const MediaTrackConstraints& aConstraints,
|
||||
|
@ -784,20 +757,6 @@ public:
|
|||
return this;
|
||||
}
|
||||
|
||||
MediaEngineSource* GetMediaEngine(TrackID aTrackID) override
|
||||
{
|
||||
// MediaEngine supports only one video and on video track now and TrackID is
|
||||
// fixed in MediaEngine.
|
||||
if (aTrackID == kVideoTrack) {
|
||||
return mVideoDevice ? mVideoDevice->GetSource() : nullptr;
|
||||
}
|
||||
else if (aTrackID == kAudioTrack) {
|
||||
return mAudioDevice ? mAudioDevice->GetSource() : nullptr;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
SourceMediaStream* GetSourceStream()
|
||||
{
|
||||
if (GetInputStream()) {
|
||||
|
@ -807,8 +766,6 @@ public:
|
|||
}
|
||||
|
||||
RefPtr<GetUserMediaCallbackMediaStreamListener> mListener;
|
||||
RefPtr<AudioDevice> mAudioDevice; // so we can turn on AEC
|
||||
RefPtr<VideoDevice> mVideoDevice;
|
||||
};
|
||||
|
||||
|
||||
|
@ -949,21 +906,60 @@ public:
|
|||
mWindowID, domStream->GetInputStream()->AsProcessedStream());
|
||||
window->SetAudioCapture(true);
|
||||
} else {
|
||||
class LocalTrackSource : public MediaStreamTrackSource
|
||||
{
|
||||
public:
|
||||
LocalTrackSource(GetUserMediaCallbackMediaStreamListener* aListener,
|
||||
const MediaSourceEnum aSource,
|
||||
const TrackID aTrackID)
|
||||
: MediaStreamTrackSource(false), mListener(aListener),
|
||||
mSource(aSource), mTrackID(aTrackID) {}
|
||||
|
||||
MediaSourceEnum GetMediaSource() const override
|
||||
{
|
||||
return mSource;
|
||||
}
|
||||
|
||||
void Stop() override
|
||||
{
|
||||
if (mListener) {
|
||||
mListener->StopTrack(mTrackID);
|
||||
mListener = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
~LocalTrackSource() {}
|
||||
|
||||
RefPtr<GetUserMediaCallbackMediaStreamListener> mListener;
|
||||
const MediaSourceEnum mSource;
|
||||
const TrackID mTrackID;
|
||||
};
|
||||
|
||||
// Normal case, connect the source stream to the track union stream to
|
||||
// avoid us blocking
|
||||
domStream = nsDOMUserMediaStream::CreateSourceStream(window, mListener,
|
||||
mAudioDevice, mVideoDevice,
|
||||
msg);
|
||||
|
||||
if (mAudioDevice) {
|
||||
nsString audioDeviceName;
|
||||
mAudioDevice->GetName(audioDeviceName);
|
||||
domStream->CreateOwnDOMTrack(kAudioTrack, MediaSegment::AUDIO, audioDeviceName);
|
||||
const MediaSourceEnum source =
|
||||
mAudioDevice->GetSource()->GetMediaSource();
|
||||
RefPtr<MediaStreamTrackSource> audioSource =
|
||||
new LocalTrackSource(mListener, source, kAudioTrack);
|
||||
domStream->CreateOwnDOMTrack(kAudioTrack, MediaSegment::AUDIO,
|
||||
audioDeviceName, audioSource);
|
||||
}
|
||||
if (mVideoDevice) {
|
||||
nsString videoDeviceName;
|
||||
mVideoDevice->GetName(videoDeviceName);
|
||||
domStream->CreateOwnDOMTrack(kVideoTrack, MediaSegment::VIDEO, videoDeviceName);
|
||||
const MediaSourceEnum source =
|
||||
mVideoDevice->GetSource()->GetMediaSource();
|
||||
RefPtr<MediaStreamTrackSource> videoSource =
|
||||
new LocalTrackSource(mListener, source, kVideoTrack);
|
||||
domStream->CreateOwnDOMTrack(kVideoTrack, MediaSegment::VIDEO,
|
||||
videoDeviceName, videoSource);
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIPrincipal> principal;
|
||||
|
|
|
@ -19,14 +19,27 @@ static PRLogModuleInfo* gMediaStreamTrackLog;
|
|||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
MediaStreamTrack::MediaStreamTrack(DOMMediaStream* aStream, TrackID aTrackID, const nsString& aLabel)
|
||||
: mOwningStream(aStream), mTrackID(aTrackID), mLabel(aLabel), mEnded(false), mEnabled(true)
|
||||
NS_IMPL_CYCLE_COLLECTING_ADDREF(MediaStreamTrackSource)
|
||||
NS_IMPL_CYCLE_COLLECTING_RELEASE(MediaStreamTrackSource)
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(MediaStreamTrackSource)
|
||||
NS_INTERFACE_MAP_ENTRY(nsISupports)
|
||||
NS_INTERFACE_MAP_END
|
||||
NS_IMPL_CYCLE_COLLECTION_0(MediaStreamTrackSource)
|
||||
|
||||
MediaStreamTrack::MediaStreamTrack(DOMMediaStream* aStream, TrackID aTrackID,
|
||||
const nsString& aLabel,
|
||||
MediaStreamTrackSource* aSource)
|
||||
: mOwningStream(aStream), mTrackID(aTrackID), mLabel(aLabel), mSource(aSource),
|
||||
mEnded(false), mEnabled(true), mRemote(aSource->IsRemote()), mStopped(false)
|
||||
{
|
||||
|
||||
if (!gMediaStreamTrackLog) {
|
||||
gMediaStreamTrackLog = PR_NewLogModule("MediaStreamTrack");
|
||||
}
|
||||
|
||||
MOZ_RELEASE_ASSERT(mSource);
|
||||
mSource->RegisterSink();
|
||||
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIUUIDGenerator> uuidgen =
|
||||
do_GetService("@mozilla.org/uuid-generator;1", &rv);
|
||||
|
@ -46,8 +59,22 @@ MediaStreamTrack::~MediaStreamTrack()
|
|||
{
|
||||
}
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_INHERITED(MediaStreamTrack, DOMEventTargetHelper,
|
||||
mOwningStream, mOriginalTrack)
|
||||
NS_IMPL_CYCLE_COLLECTION_CLASS(MediaStreamTrack)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(MediaStreamTrack,
|
||||
DOMEventTargetHelper)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mOwningStream)
|
||||
tmp->mSource->UnregisterSink();
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mSource)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mOriginalTrack)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(MediaStreamTrack,
|
||||
DOMEventTargetHelper)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOwningStream)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSource)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOriginalTrack)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||
|
||||
NS_IMPL_ADDREF_INHERITED(MediaStreamTrack, DOMEventTargetHelper)
|
||||
NS_IMPL_RELEASE_INHERITED(MediaStreamTrack, DOMEventTargetHelper)
|
||||
|
@ -75,7 +102,23 @@ MediaStreamTrack::Stop()
|
|||
{
|
||||
LOG(LogLevel::Info, ("MediaStreamTrack %p Stop()", this));
|
||||
|
||||
mOwningStream->StopTrack(mTrackID);
|
||||
if (mStopped) {
|
||||
LOG(LogLevel::Warning, ("MediaStreamTrack %p Already stopped", this));
|
||||
return;
|
||||
}
|
||||
|
||||
if (mRemote) {
|
||||
LOG(LogLevel::Warning, ("MediaStreamTrack %p is remote. Can't be stopped.", this));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!mSource) {
|
||||
MOZ_ASSERT(false);
|
||||
return;
|
||||
}
|
||||
|
||||
mSource->UnregisterSink();
|
||||
mStopped = true;
|
||||
}
|
||||
|
||||
already_AddRefed<Promise>
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#define MEDIASTREAMTRACK_H_
|
||||
|
||||
#include "mozilla/DOMEventTargetHelper.h"
|
||||
#include "nsError.h"
|
||||
#include "nsID.h"
|
||||
#include "StreamBuffer.h"
|
||||
#include "MediaTrackConstraints.h"
|
||||
|
@ -14,12 +15,119 @@
|
|||
namespace mozilla {
|
||||
|
||||
class DOMMediaStream;
|
||||
class MediaEnginePhotoCallback;
|
||||
|
||||
namespace dom {
|
||||
|
||||
class AudioStreamTrack;
|
||||
class VideoStreamTrack;
|
||||
|
||||
/**
|
||||
* Common interface through which a MediaStreamTrack can communicate with its
|
||||
* producer on the main thread.
|
||||
*
|
||||
* Kept alive by a strong ref in all MediaStreamTracks (original and clones)
|
||||
* sharing this source.
|
||||
*/
|
||||
class MediaStreamTrackSource : public nsISupports
|
||||
{
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
NS_DECL_CYCLE_COLLECTION_CLASS(MediaStreamTrackSource)
|
||||
|
||||
public:
|
||||
explicit MediaStreamTrackSource(const bool aIsRemote)
|
||||
: mNrSinks(0), mIsRemote(aIsRemote), mStopped(false)
|
||||
{
|
||||
MOZ_COUNT_CTOR(MediaStreamTrackSource);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the source's MediaSourceEnum for usage by PeerConnections.
|
||||
*/
|
||||
virtual MediaSourceEnum GetMediaSource() const = 0;
|
||||
|
||||
/**
|
||||
* Indicates whether the track is remote or not per the MediaCapture and
|
||||
* Streams spec.
|
||||
*/
|
||||
virtual bool IsRemote() const { return mIsRemote; }
|
||||
|
||||
/**
|
||||
* Forwards a photo request to backends that support it. Other backends return
|
||||
* NS_ERROR_NOT_IMPLEMENTED to indicate that a MediaStreamGraph-based fallback
|
||||
* should be used.
|
||||
*/
|
||||
virtual nsresult TakePhoto(MediaEnginePhotoCallback*) const { return NS_ERROR_NOT_IMPLEMENTED; }
|
||||
|
||||
/**
|
||||
* Called by the source interface when all registered sinks have unregistered.
|
||||
*/
|
||||
virtual void Stop() = 0;
|
||||
|
||||
/**
|
||||
* Called by each MediaStreamTrack clone on initialization.
|
||||
*/
|
||||
void RegisterSink()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
if (mStopped) {
|
||||
return;
|
||||
}
|
||||
++mNrSinks;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by each MediaStreamTrack clone on track.Stop().
|
||||
*/
|
||||
void UnregisterSink()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
NS_ASSERTION(mNrSinks > 0, "Unmatched UnregisterSink()");
|
||||
--mNrSinks;
|
||||
if (mNrSinks == 0 && !IsRemote()) {
|
||||
Stop();
|
||||
mStopped = true;
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual ~MediaStreamTrackSource()
|
||||
{
|
||||
MOZ_COUNT_DTOR(MediaStreamTrackSource);
|
||||
NS_ASSERTION(mNrSinks == 0, "Some sinks did not unregister");
|
||||
}
|
||||
|
||||
// Number of currently registered sinks.
|
||||
size_t mNrSinks;
|
||||
|
||||
// True if this is a remote track source, i.e., a PeerConnection.
|
||||
const bool mIsRemote;
|
||||
|
||||
// True if this source is not remote, all MediaStreamTrack users have
|
||||
// unregistered from this source and Stop() has been called.
|
||||
bool mStopped;
|
||||
};
|
||||
|
||||
/**
|
||||
* Basic implementation of MediaStreamTrackSource that ignores Stop().
|
||||
*/
|
||||
class BasicUnstoppableTrackSource : public MediaStreamTrackSource
|
||||
{
|
||||
public:
|
||||
explicit BasicUnstoppableTrackSource(const MediaSourceEnum aMediaSource =
|
||||
MediaSourceEnum::Other)
|
||||
: MediaStreamTrackSource(true), mMediaSource(aMediaSource) {}
|
||||
|
||||
MediaSourceEnum GetMediaSource() const override { return mMediaSource; }
|
||||
|
||||
void Stop() override {}
|
||||
|
||||
protected:
|
||||
~BasicUnstoppableTrackSource() {}
|
||||
|
||||
const MediaSourceEnum mMediaSource;
|
||||
};
|
||||
|
||||
/**
|
||||
* Class representing a track in a DOMMediaStream.
|
||||
*/
|
||||
|
@ -29,7 +137,9 @@ public:
|
|||
* aTrackID is the MediaStreamGraph track ID for the track in the
|
||||
* MediaStream owned by aStream.
|
||||
*/
|
||||
MediaStreamTrack(DOMMediaStream* aStream, TrackID aTrackID, const nsString& aLabel);
|
||||
MediaStreamTrack(DOMMediaStream* aStream, TrackID aTrackID,
|
||||
const nsString& aLabel,
|
||||
MediaStreamTrackSource* aSource);
|
||||
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(MediaStreamTrack,
|
||||
|
@ -65,6 +175,12 @@ public:
|
|||
// Notifications from the MediaStreamGraph
|
||||
void NotifyEnded() { mEnded = true; }
|
||||
|
||||
MediaStreamTrackSource& GetSource() const
|
||||
{
|
||||
MOZ_RELEASE_ASSERT(mSource, "The track source is only removed on destruction");
|
||||
return *mSource;
|
||||
}
|
||||
|
||||
// Webrtc allows the remote side to name tracks whatever it wants, and we
|
||||
// need to surface this to content.
|
||||
void AssignId(const nsAString& aID) { mID = aID; }
|
||||
|
@ -74,11 +190,15 @@ protected:
|
|||
|
||||
RefPtr<DOMMediaStream> mOwningStream;
|
||||
TrackID mTrackID;
|
||||
TrackID mInputTrackID;
|
||||
RefPtr<MediaStreamTrackSource> mSource;
|
||||
RefPtr<MediaStreamTrack> mOriginalTrack;
|
||||
nsString mID;
|
||||
nsString mLabel;
|
||||
bool mEnded;
|
||||
bool mEnabled;
|
||||
const bool mRemote;
|
||||
bool mStopped;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
|
|
|
@ -14,8 +14,10 @@ namespace dom {
|
|||
|
||||
class VideoStreamTrack : public MediaStreamTrack {
|
||||
public:
|
||||
VideoStreamTrack(DOMMediaStream* aStream, TrackID aTrackID, const nsString& aLabel)
|
||||
: MediaStreamTrack(aStream, aTrackID, aLabel) {}
|
||||
VideoStreamTrack(DOMMediaStream* aStream, TrackID aTrackID,
|
||||
const nsString& aLabel,
|
||||
MediaStreamTrackSource* aSource)
|
||||
: MediaStreamTrack(aStream, aTrackID, aLabel, aSource) {}
|
||||
|
||||
JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
|
||||
|
||||
|
|
|
@ -81,13 +81,14 @@ ImageCapture::TakePhotoByMediaEngine()
|
|||
public DOMMediaStream::PrincipalChangeObserver
|
||||
{
|
||||
public:
|
||||
TakePhotoCallback(DOMMediaStream* aStream, ImageCapture* aImageCapture)
|
||||
: mStream(aStream)
|
||||
TakePhotoCallback(VideoStreamTrack* aVideoTrack, ImageCapture* aImageCapture)
|
||||
: mVideoTrack(aVideoTrack)
|
||||
, mImageCapture(aImageCapture)
|
||||
, mPrincipalChanged(false)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
mStream->AddPrincipalChangeObserver(this);
|
||||
MOZ_RELEASE_ASSERT(mVideoTrack->GetStream());
|
||||
mVideoTrack->GetStream()->AddPrincipalChangeObserver(this);
|
||||
}
|
||||
|
||||
void PrincipalChanged(DOMMediaStream* aMediaStream) override
|
||||
|
@ -114,25 +115,18 @@ ImageCapture::TakePhotoByMediaEngine()
|
|||
~TakePhotoCallback()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
mStream->RemovePrincipalChangeObserver(this);
|
||||
MOZ_RELEASE_ASSERT(mVideoTrack->GetStream());
|
||||
mVideoTrack->GetStream()->RemovePrincipalChangeObserver(this);
|
||||
}
|
||||
|
||||
RefPtr<DOMMediaStream> mStream;
|
||||
RefPtr<VideoStreamTrack> mVideoTrack;
|
||||
RefPtr<ImageCapture> mImageCapture;
|
||||
bool mPrincipalChanged;
|
||||
};
|
||||
|
||||
RefPtr<DOMMediaStream> domStream = mVideoStreamTrack->GetStream();
|
||||
DOMLocalMediaStream* domLocalStream = domStream->AsDOMLocalMediaStream();
|
||||
if (domLocalStream) {
|
||||
RefPtr<MediaEngineSource> mediaEngine =
|
||||
domLocalStream->GetMediaEngine(mVideoStreamTrack->GetTrackID());
|
||||
RefPtr<MediaEnginePhotoCallback> callback =
|
||||
new TakePhotoCallback(domStream, this);
|
||||
return mediaEngine->TakePhoto(callback);
|
||||
}
|
||||
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
RefPtr<MediaEnginePhotoCallback> callback =
|
||||
new TakePhotoCallback(mVideoStreamTrack, this);
|
||||
return mVideoStreamTrack->GetSource().TakePhoto(callback);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include "AudioNodeEngine.h"
|
||||
#include "AudioNodeStream.h"
|
||||
#include "DOMMediaStream.h"
|
||||
#include "MediaStreamTrack.h"
|
||||
#include "TrackUnionStream.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
@ -34,7 +35,10 @@ MediaStreamAudioDestinationNode::MediaStreamAudioDestinationNode(AudioContext* a
|
|||
aContext->Graph()))
|
||||
{
|
||||
// Ensure an audio track with the correct ID is exposed to JS
|
||||
mDOMStream->CreateOwnDOMTrack(AudioNodeStream::AUDIO_TRACK, MediaSegment::AUDIO, nsString());
|
||||
RefPtr<MediaStreamTrackSource> source =
|
||||
new BasicUnstoppableTrackSource(MediaSourceEnum::AudioCapture);
|
||||
mDOMStream->CreateOwnDOMTrack(AudioNodeStream::AUDIO_TRACK,
|
||||
MediaSegment::AUDIO, nsString(), source);
|
||||
|
||||
ProcessedMediaStream* outputStream = mDOMStream->GetInputStream()->AsProcessedStream();
|
||||
MOZ_ASSERT(!!outputStream);
|
||||
|
|
|
@ -849,10 +849,7 @@ MediaPipelineFactory::ConfigureVideoCodecMode(const JsepTrack& aTrack,
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
MediaEngineSource *engine =
|
||||
domLocalStream->GetMediaEngine(videotrack->GetTrackID());
|
||||
|
||||
dom::MediaSourceEnum source = engine->GetMediaSource();
|
||||
dom::MediaSourceEnum source = videotrack->GetSource().GetMediaSource();
|
||||
webrtc::VideoCodecMode mode = webrtc::kRealtimeVideo;
|
||||
switch (source) {
|
||||
case dom::MediaSourceEnum::Browser:
|
||||
|
|
|
@ -1879,6 +1879,19 @@ PeerConnectionImpl::SetRemoteDescription(int32_t action, const char* aSDP)
|
|||
continue;
|
||||
}
|
||||
info->AddTrack(track->GetTrackId());
|
||||
#if !defined(MOZILLA_EXTERNAL_LINKAGE)
|
||||
RefPtr<MediaStreamTrackSource> source =
|
||||
new BasicUnstoppableTrackSource(MediaSourceEnum::Other);
|
||||
if (track->GetMediaType() == SdpMediaSection::kAudio) {
|
||||
info->GetMediaStream()->CreateOwnDOMTrack(
|
||||
info->GetNumericTrackId(track->GetTrackId()),
|
||||
MediaSegment::AUDIO, nsString(), source);
|
||||
} else {
|
||||
info->GetMediaStream()->CreateOwnDOMTrack(
|
||||
info->GetNumericTrackId(track->GetTrackId()),
|
||||
MediaSegment::VIDEO, nsString(), source);
|
||||
}
|
||||
#endif
|
||||
CSFLogDebug(logTag, "Added remote track %s/%s",
|
||||
info->GetId().c_str(), track->GetTrackId().c_str());
|
||||
} else {
|
||||
|
|
|
@ -286,6 +286,14 @@ class Fake_SourceMediaStream : public Fake_MediaStream {
|
|||
|
||||
class Fake_DOMMediaStream;
|
||||
|
||||
class Fake_MediaStreamTrackSource
|
||||
{
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(Fake_MediaStreamTrackSource)
|
||||
|
||||
protected:
|
||||
virtual ~Fake_MediaStreamTrackSource() {}
|
||||
};
|
||||
|
||||
class Fake_MediaStreamTrack
|
||||
{
|
||||
public:
|
||||
|
@ -423,7 +431,8 @@ public:
|
|||
void SetTrackEnabled(mozilla::TrackID aTrackID, bool aEnabled) {}
|
||||
|
||||
Fake_MediaStreamTrack*
|
||||
CreateOwnDOMTrack(mozilla::TrackID aTrackID, mozilla::MediaSegment::Type aType)
|
||||
CreateOwnDOMTrack(mozilla::TrackID aTrackID, mozilla::MediaSegment::Type aType,
|
||||
const nsString& aLabel, Fake_MediaStreamTrackSource* aSource)
|
||||
{
|
||||
switch(aType) {
|
||||
case mozilla::MediaSegment::AUDIO: {
|
||||
|
@ -503,6 +512,10 @@ typedef Fake_MediaStreamListener MediaStreamListener;
|
|||
typedef Fake_MediaStreamDirectListener MediaStreamDirectListener;
|
||||
typedef Fake_DOMMediaStream DOMMediaStream;
|
||||
typedef Fake_DOMMediaStream DOMLocalMediaStream;
|
||||
|
||||
namespace dom {
|
||||
typedef Fake_MediaStreamTrackSource MediaStreamTrackSource;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
Загрузка…
Ссылка в новой задаче