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:
Andreas Pehrson 2016-04-06 14:46:56 +02:00
Родитель 2a7a664d3b
Коммит 9899305f28
15 изменённых файлов: 299 добавлений и 112 удалений

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

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