Commit a58c8bd6 authored by Guido Urdaneta's avatar Guido Urdaneta Committed by Commit Bot

Serialize MediaStreamTrack.stop() with getUserMedia()

When multiple getUserMedia and stop() requests are active concurrently, 
getUserMedia() sometimes fails with TrackStartError.
The reason is that the underlying video capture subsystem does not keep
a count of how many sources have opened a video device.
It can happen that a stop request stops video capture while a 
getUserMedia() request is being processed, with the result being that
the video device is closed before getUserMedia() starts the new video
track, resulting in an error.

One solution to this problem is to make sure that stop requests and
getUserMedia() requests cannot run concurrently, which is the approach
followed by this CL.

This CL basically moves handling of MediaStramTrack.stop() from 
MediaStreamCenter to UserMediaClient, and puts stop() requests in the
same queue used for getUserMedia() and applyConstraints() requests.


Bug: 778039
Change-Id: Id7e0ee38e40265fd599dc6dd0712f0b667d2e1a5
Reviewed-on: https://chromium-review.googlesource.com/751981Reviewed-by: default avatarKentaro Hara <haraken@chromium.org>
Reviewed-by: default avatarHenrik Boström <hbos@chromium.org>
Commit-Queue: Guido Urdaneta <guidou@chromium.org>
Cr-Commit-Position: refs/heads/master@{#515494}
parent 7facf42c
......@@ -812,4 +812,12 @@ IN_PROC_BROWSER_TEST_F(WebRtcGetUserMediaBrowserTest,
ExecuteJavascriptAndWaitForOk("applyConstraintsNonDevice()");
}
IN_PROC_BROWSER_TEST_F(WebRtcGetUserMediaBrowserTest,
ConcurrentGetUserMediaStop) {
ASSERT_TRUE(embedded_test_server()->Start());
GURL url(embedded_test_server()->GetURL("/media/getusermedia.html"));
NavigateToURL(shell(), url);
ExecuteJavascriptAndWaitForOk("concurrentGetUserMediaStop()");
}
} // namespace content
......@@ -4,6 +4,7 @@
#include "content/renderer/media/media_stream_audio_track.h"
#include <utility>
#include <vector>
#include "base/callback_helpers.h"
......@@ -102,7 +103,7 @@ void MediaStreamAudioTrack::Start(const base::Closure& stop_callback) {
stop_callback_ = stop_callback;
}
void MediaStreamAudioTrack::Stop() {
void MediaStreamAudioTrack::StopAndNotify(base::OnceClosure callback) {
DCHECK(thread_checker_.CalledOnValidThread());
DVLOG(1) << "Stopping MediaStreamAudioTrack@" << this << '.';
......@@ -116,6 +117,8 @@ void MediaStreamAudioTrack::Stop() {
sink->OnReadyStateChanged(blink::WebMediaStreamSource::kReadyStateEnded);
}
if (callback)
std::move(callback).Run();
weak_factory_.InvalidateWeakPtrs();
}
......
......@@ -61,7 +61,7 @@ class CONTENT_EXPORT MediaStreamAudioTrack : public MediaStreamTrack {
// Halts the flow of audio data from the source (and to the sinks), and then
// notifies all sinks of the "ended" state.
void Stop() final;
void StopAndNotify(base::OnceClosure callback) final;
// MediaStreamTrack override.
void SetEnabled(bool enabled) override;
......
......@@ -154,14 +154,6 @@ void MediaStreamCenter::DidDisableMediaStreamTrack(
native_track->SetEnabled(false);
}
bool MediaStreamCenter::DidStopMediaStreamTrack(
const blink::WebMediaStreamTrack& track) {
DVLOG(1) << "MediaStreamCenter::didStopMediaStreamTrack";
MediaStreamTrack* native_track = MediaStreamTrack::GetTrack(track);
native_track->Stop();
return true;
}
blink::WebAudioSourceProvider*
MediaStreamCenter::CreateWebAudioSourceFromMediaStreamTrack(
const blink::WebMediaStreamTrack& track) {
......
......@@ -46,9 +46,6 @@ class CONTENT_EXPORT MediaStreamCenter : public blink::WebMediaStreamCenter {
void DidDisableMediaStreamTrack(
const blink::WebMediaStreamTrack& track) override;
bool DidStopMediaStreamTrack(
const blink::WebMediaStreamTrack& track) override;
blink::WebAudioSourceProvider* CreateWebAudioSourceFromMediaStreamTrack(
const blink::WebMediaStreamTrack& track) override;
......
......@@ -22,6 +22,10 @@ MediaStreamSource::~MediaStreamSource() {
void MediaStreamSource::StopSource() {
DCHECK(thread_checker_.CalledOnValidThread());
DoStopSource();
FinalizeStopSource();
}
void MediaStreamSource::FinalizeStopSource() {
if (!stop_callback_.is_null())
base::ResetAndReturn(&stop_callback_).Run(Owner());
Owner().SetReadyState(blink::WebMediaStreamSource::kReadyStateEnded);
......
......@@ -36,9 +36,7 @@ class CONTENT_EXPORT MediaStreamSource
// JavaScript call to GetUserMedia, e.g., a camera or microphone.
const MediaStreamDevice& device() const { return device_; }
// Stops the source (by calling DoStopSource()). This runs the
// |stop_callback_| (if set), and then sets the
// WebMediaStreamSource::readyState to ended.
// Stops the source (by calling DoStopSource()) and runs FinalizeStopSource().
void StopSource();
// Sets the source's state to muted or to live.
......@@ -60,6 +58,11 @@ class CONTENT_EXPORT MediaStreamSource
// its own Stop method.
virtual void DoStopSource() = 0;
// Runs the stop callback (if set) and sets the
// WebMediaStreamSource::readyState to ended. This can be used by
// implementations to implement custom stop methods.
void FinalizeStopSource();
private:
MediaStreamDevice device_;
SourceStoppedCallback stop_callback_;
......
......@@ -7,6 +7,7 @@
#include <string>
#include "base/callback.h"
#include "base/compiler_specific.h"
#include "base/macros.h"
#include "base/threading/thread_checker.h"
......@@ -32,7 +33,10 @@ class CONTENT_EXPORT MediaStreamTrack
virtual void SetContentHint(
blink::WebMediaStreamTrack::ContentHintType content_hint) = 0;
virtual void Stop() = 0;
// If |callback| is not null, it is invoked when the track has stopped.
virtual void StopAndNotify(base::OnceClosure callback) = 0;
void Stop() { StopAndNotify(base::OnceClosure()); }
// TODO(hta): Make method pure virtual when all tracks have the method.
void GetSettings(blink::WebMediaStreamTrack::Settings& settings) override {}
......
......@@ -153,6 +153,10 @@ class MediaStreamVideoCapturerSourceTest : public testing::Test {
source_->OnRunStateChanged(delegate_->capture_params(), result);
}
void SetStopCaptureFlag() { stop_capture_flag_ = true; }
MOCK_METHOD0(MockNotification, void());
protected:
void OnConstraintsApplied(MediaStreamSource* source,
MediaStreamRequestResult result,
......@@ -170,6 +174,7 @@ class MediaStreamVideoCapturerSourceTest : public testing::Test {
MockVideoCapturerSource* delegate_; // owned by |source_|.
blink::WebString webkit_source_id_;
bool source_stopped_;
bool stop_capture_flag_ = false;
};
TEST_F(MediaStreamVideoCapturerSourceTest, StartAndStop) {
......@@ -318,4 +323,34 @@ TEST_F(MediaStreamVideoCapturerSourceTest, Restart) {
EXPECT_FALSE(source_->IsRunning());
}
TEST_F(MediaStreamVideoCapturerSourceTest, StartStopAndNotify) {
InSequence s;
EXPECT_CALL(mock_delegate(), MockStartCapture(_, _, _));
blink::WebMediaStreamTrack web_track =
StartSource(VideoTrackAdapterSettings(), base::nullopt, false, 0.0);
base::RunLoop().RunUntilIdle();
EXPECT_EQ(blink::WebMediaStreamSource::kReadyStateLive,
webkit_source_.GetReadyState());
EXPECT_FALSE(source_stopped_);
stop_capture_flag_ = false;
EXPECT_CALL(mock_delegate(), MockStopCapture())
.WillOnce(InvokeWithoutArgs(
this, &MediaStreamVideoCapturerSourceTest::SetStopCaptureFlag));
EXPECT_CALL(*this, MockNotification());
MediaStreamTrack* track = MediaStreamTrack::GetTrack(web_track);
track->StopAndNotify(
base::BindOnce(&MediaStreamVideoCapturerSourceTest::MockNotification,
base::Unretained(this)));
EXPECT_EQ(blink::WebMediaStreamSource::kReadyStateEnded,
webkit_source_.GetReadyState());
EXPECT_TRUE(source_stopped_);
// It is a requirement that StopCapture() gets called in the same task as
// StopAndNotify(), as CORS security checks for element capture rely on this.
EXPECT_TRUE(stop_capture_flag_);
// The readyState is updated in the current task, but the notification is
// received on a separate task.
base::RunLoop().RunUntilIdle();
}
} // namespace content
......@@ -82,7 +82,8 @@ void MediaStreamVideoSource::AddTrack(
}
}
void MediaStreamVideoSource::RemoveTrack(MediaStreamVideoTrack* video_track) {
void MediaStreamVideoSource::RemoveTrack(MediaStreamVideoTrack* video_track,
base::OnceClosure callback) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
std::vector<MediaStreamVideoTrack*>::iterator it =
std::find(tracks_.begin(), tracks_.end(), video_track);
......@@ -101,8 +102,67 @@ void MediaStreamVideoSource::RemoveTrack(MediaStreamVideoTrack* video_track) {
// failed and |frame_adapter_->AddCallback| has not been called.
track_adapter_->RemoveTrack(video_track);
if (tracks_.empty())
if (tracks_.empty()) {
if (callback) {
// Using StopForRestart() in order to get a notification of when the
// source is actually stopped (if supported). The source will not be
// restarted.
// The intent is to have the same effect as StopSource() (i.e., having
// the readyState updated and invoking the source's stop callback on this
// task), but getting a notification of when the source has actually
// stopped so that clients have a mechanism to serialize the creation and
// destruction of video sources. Without such serialization it is possible
// that concurrent creation and destruction of sources that share the same
// underlying implementation results in failed source creation since
// stopping a source with StopSource() can have side effects that affect
// sources created after that StopSource() call, but before the actual
// stop takes place. See http://crbug.com/778039.
StopForRestart(base::BindOnce(&MediaStreamVideoSource::DidRemoveLastTrack,
weak_factory_.GetWeakPtr(),
std::move(callback)));
if (state_ == STOPPING_FOR_RESTART || state_ == STOPPED_FOR_RESTART) {
// If the source supports restarting, it is necessary to call
// FinalizeStopSource() to ensure the same behavior as StopSource(),
// even if the underlying implementation takes longer to actually stop.
// In particular, Tab capture and capture from element require the
// source's stop callback to be invoked on this task in order to ensure
// correct behavior.
FinalizeStopSource();
} else {
// If the source does not support restarting, call StopSource()
// to ensure stop on this task. DidRemoveLastTrack() will be called on
// another task even if the source does not support restarting, as
// StopForRestart() always posts a task to run its callback.
StopSource();
}
} else {
StopSource();
}
} else if (callback) {
std::move(callback).Run();
}
}
void MediaStreamVideoSource::DidRemoveLastTrack(base::OnceClosure callback,
RestartResult result) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(callback);
DCHECK(tracks_.empty());
DCHECK_EQ(Owner().GetReadyState(),
blink::WebMediaStreamSource::kReadyStateEnded);
if (result == RestartResult::IS_STOPPED) {
state_ = ENDED;
}
if (state_ != ENDED) {
// This can happen if a source that supports StopForRestart() fails to
// actually stop the source after trying to stop it. The contract for
// StopForRestart() allows this, but it should not happen in practice.
LOG(WARNING) << "Source unexpectedly failed to stop. Force stopping and "
"sending notification anyway";
StopSource();
}
std::move(callback).Run();
}
void MediaStreamVideoSource::ReconfigureTrack(
......@@ -139,8 +199,9 @@ void MediaStreamVideoSource::StopSourceForRestartImpl() {
void MediaStreamVideoSource::OnStopForRestartDone(bool did_stop_for_restart) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (state_ == ENDED)
if (state_ == ENDED) {
return;
}
DCHECK_EQ(state_, STOPPING_FOR_RESTART);
if (did_stop_for_restart) {
......
......@@ -66,7 +66,7 @@ class CONTENT_EXPORT MediaStreamVideoSource : public MediaStreamSource {
const VideoTrackAdapterSettings& track_adapter_settings,
const VideoCaptureDeliverFrameCB& frame_callback,
const ConstraintsCallback& callback);
void RemoveTrack(MediaStreamVideoTrack* track);
void RemoveTrack(MediaStreamVideoTrack* track, base::OnceClosure callback);
// Reconfigures this MediaStreamVideoSource to use |adapter_settings| on
// |track|, as long as |track| is connected to this source.
......@@ -253,6 +253,7 @@ class CONTENT_EXPORT MediaStreamVideoSource : public MediaStreamSource {
void StartFrameMonitoring();
void UpdateTrackSettings(MediaStreamVideoTrack* track,
const VideoTrackAdapterSettings& adapter_settings);
void DidRemoveLastTrack(base::OnceClosure callback, RestartResult result);
State state_;
......
......@@ -70,6 +70,8 @@ class MediaStreamVideoSourceTest : public ::testing::Test {
blink::WebHeap::CollectAllGarbageForTesting();
}
MOCK_METHOD0(MockNotification, void());
protected:
MediaStreamVideoSource* source() { return mock_source_; }
......@@ -637,4 +639,38 @@ TEST_F(MediaStreamVideoSourceTest, FailedRestartAfterStopForRestart) {
blink::WebMediaStreamSource::kReadyStateEnded);
}
TEST_F(MediaStreamVideoSourceTest, StartStopAndNotifyRestartSupported) {
blink::WebMediaStreamTrack web_track = CreateTrack("123");
mock_source()->EnableStopForRestart();
mock_source()->StartMockedSource();
EXPECT_EQ(NumberOfSuccessConstraintsCallbacks(), 1);
EXPECT_EQ(web_track.Source().GetReadyState(),
blink::WebMediaStreamSource::kReadyStateLive);
EXPECT_CALL(*this, MockNotification());
MediaStreamTrack* track = MediaStreamTrack::GetTrack(web_track);
track->StopAndNotify(base::BindOnce(
&MediaStreamVideoSourceTest::MockNotification, base::Unretained(this)));
EXPECT_EQ(web_track.Source().GetReadyState(),
blink::WebMediaStreamSource::kReadyStateEnded);
base::RunLoop().RunUntilIdle();
}
TEST_F(MediaStreamVideoSourceTest, StartStopAndNotifyRestartNotSupported) {
blink::WebMediaStreamTrack web_track = CreateTrack("123");
mock_source()->DisableStopForRestart();
mock_source()->StartMockedSource();
EXPECT_EQ(NumberOfSuccessConstraintsCallbacks(), 1);
EXPECT_EQ(web_track.Source().GetReadyState(),
blink::WebMediaStreamSource::kReadyStateLive);
EXPECT_CALL(*this, MockNotification());
MediaStreamTrack* track = MediaStreamTrack::GetTrack(web_track);
track->StopAndNotify(base::BindOnce(
&MediaStreamVideoSourceTest::MockNotification, base::Unretained(this)));
EXPECT_EQ(web_track.Source().GetReadyState(),
blink::WebMediaStreamSource::kReadyStateEnded);
base::RunLoop().RunUntilIdle();
}
} // namespace content
......@@ -348,10 +348,10 @@ void MediaStreamVideoTrack::SetContentHint(
sink->OnContentHintChanged(content_hint);
}
void MediaStreamVideoTrack::Stop() {
void MediaStreamVideoTrack::StopAndNotify(base::OnceClosure callback) {
DCHECK(main_render_thread_checker_.CalledOnValidThread());
if (source_) {
source_->RemoveTrack(this);
source_->RemoveTrack(this, std::move(callback));
source_ = nullptr;
}
OnReadyStateChanged(blink::WebMediaStreamSource::kReadyStateEnded);
......
......@@ -77,7 +77,7 @@ class CONTENT_EXPORT MediaStreamVideoTrack : public MediaStreamTrack {
void SetEnabled(bool enabled) override;
void SetContentHint(
blink::WebMediaStreamTrack::ContentHintType content_hint) override;
void Stop() override;
void StopAndNotify(base::OnceClosure callback) override;
void GetSettings(blink::WebMediaStreamTrack::Settings& settings) override;
void OnReadyStateChanged(blink::WebMediaStreamSource::ReadyState state);
......
......@@ -57,6 +57,7 @@ UserMediaClientImpl::Request::Request(std::unique_ptr<UserMediaRequest> request)
: user_media_request_(std::move(request)) {
DCHECK(user_media_request_);
DCHECK(apply_constraints_request_.IsNull());
DCHECK(web_track_to_stop_.IsNull());
}
UserMediaClientImpl::Request::Request(
......@@ -64,12 +65,32 @@ UserMediaClientImpl::Request::Request(
: apply_constraints_request_(request) {
DCHECK(!apply_constraints_request_.IsNull());
DCHECK(!user_media_request_);
DCHECK(web_track_to_stop_.IsNull());
}
UserMediaClientImpl::Request::Request(
const blink::WebMediaStreamTrack& web_track_to_stop)
: web_track_to_stop_(web_track_to_stop) {
DCHECK(!web_track_to_stop_.IsNull());
DCHECK(!user_media_request_);
DCHECK(apply_constraints_request_.IsNull());
}
UserMediaClientImpl::Request::Request(Request&& other)
: user_media_request_(std::move(other.user_media_request_)),
apply_constraints_request_(other.apply_constraints_request_) {
DCHECK(!IsApplyConstraints() || !IsUserMedia());
apply_constraints_request_(other.apply_constraints_request_),
web_track_to_stop_(other.web_track_to_stop_) {
#if DCHECK_IS_ON()
int num_types = 0;
if (IsUserMedia())
num_types++;
if (IsApplyConstraints())
num_types++;
if (IsStopTrack())
num_types++;
DCHECK_EQ(num_types, 1);
#endif
}
UserMediaClientImpl::Request& UserMediaClientImpl::Request::operator=(
......@@ -176,6 +197,17 @@ void UserMediaClientImpl::ApplyConstraints(
}
}
void UserMediaClientImpl::StopTrack(
const blink::WebMediaStreamTrack& web_track) {
pending_request_infos_.push_back(Request(web_track));
if (!is_processing_request_) {
base::SequencedTaskRunnerHandle::Get()->PostTask(
FROM_HERE,
base::BindOnce(&UserMediaClientImpl::MaybeProcessNextRequestInfo,
weak_factory_.GetWeakPtr()));
}
}
void UserMediaClientImpl::MaybeProcessNextRequestInfo() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (is_processing_request_ || pending_request_infos_.empty())
......@@ -192,12 +224,22 @@ void UserMediaClientImpl::MaybeProcessNextRequestInfo() {
current_request.MoveUserMediaRequest(),
base::BindOnce(&UserMediaClientImpl::CurrentRequestCompleted,
base::Unretained(this)));
} else {
DCHECK(current_request.IsApplyConstraints());
} else if (current_request.IsApplyConstraints()) {
apply_constraints_processor_->ProcessRequest(
current_request.apply_constraints_request(),
base::BindOnce(&UserMediaClientImpl::CurrentRequestCompleted,
base::Unretained(this)));
} else {
DCHECK(current_request.IsStopTrack());
MediaStreamTrack* track =
MediaStreamTrack::GetTrack(current_request.web_track_to_stop());
if (track) {
track->StopAndNotify(
base::BindOnce(&UserMediaClientImpl::CurrentRequestCompleted,
weak_factory_.GetWeakPtr()));
} else {
CurrentRequestCompleted();
}
}
}
......
......@@ -69,6 +69,7 @@ class CONTENT_EXPORT UserMediaClientImpl : public RenderFrameObserver,
const blink::WebMediaDeviceChangeObserver& observer) override;
void ApplyConstraints(
const blink::WebApplyConstraintsRequest& web_request) override;
void StopTrack(const blink::WebMediaStreamTrack& web_track) override;
// RenderFrameObserver override
void WillCommitProvisionalLoad() override;
......@@ -89,6 +90,7 @@ class CONTENT_EXPORT UserMediaClientImpl : public RenderFrameObserver,
public:
explicit Request(std::unique_ptr<UserMediaRequest> request);
explicit Request(const blink::WebApplyConstraintsRequest& request);
explicit Request(const blink::WebMediaStreamTrack& request);
Request(Request&& other);
Request& operator=(Request&& other);
~Request();
......@@ -98,20 +100,23 @@ class CONTENT_EXPORT UserMediaClientImpl : public RenderFrameObserver,
UserMediaRequest* user_media_request() const {
return user_media_request_.get();
}
const blink::WebApplyConstraintsRequest& apply_constraints_request() const {
return apply_constraints_request_;
}
const blink::WebMediaStreamTrack& web_track_to_stop() const {
return web_track_to_stop_;
}
bool IsUserMedia() const { return !!user_media_request_; }
bool IsApplyConstraints() const {
return !apply_constraints_request_.IsNull();
}
bool IsUserMedia() const { return !!user_media_request_; }
bool IsStopTrack() const { return !web_track_to_stop_.IsNull(); }
private:
std::unique_ptr<UserMediaRequest> user_media_request_;
blink::WebApplyConstraintsRequest apply_constraints_request_;
blink::WebMediaStreamTrack web_track_to_stop_;
};
void MaybeProcessNextRequestInfo();
......
......@@ -869,6 +869,20 @@
}
video.srcObject = canvas_stream;
}
function concurrentGetUserMediaStop() {
var num_stopped = 0;
const N = 250;
for (var i = 0; i < N; i++) {
navigator.mediaDevices.getUserMedia({video: true}).then(s => {
setTimeout(() => {
s.getVideoTracks()[0].stop();
if (++num_stopped == N)
reportTestSuccess();
}, 1);
}).catch(e => failTest("getUserMedia failed: " + e.name));
}
}
</script>
</head>
<body>
......
......@@ -61,7 +61,7 @@ void MediaElementEventListener::handleEvent(ExecutionContext* context,
if (event->type() == EventTypeNames::ended) {
const MediaStreamTrackVector tracks = media_stream_->getTracks();
for (const auto& track : tracks) {
track->stopTrack(ASSERT_NO_EXCEPTION);
track->stopTrack(context);
media_stream_->RemoveTrackByComponent(track->Component());
}
......@@ -75,7 +75,7 @@ void MediaElementEventListener::handleEvent(ExecutionContext* context,
if (media_element_->GetLoadType() == WebMediaPlayer::kLoadTypeMediaStream) {
const MediaStreamTrackVector tracks = media_stream_->getTracks();
for (const auto& track : tracks) {
track->stopTrack(ASSERT_NO_EXCEPTION);
track->stopTrack(context);
media_stream_->RemoveTrackByComponent(track->Component());
}
MediaStreamDescriptor* const descriptor =
......
......@@ -275,12 +275,17 @@ String MediaStreamTrack::readyState() const {
return String();
}
void MediaStreamTrack::stopTrack(ExceptionState& exception_state) {
void MediaStreamTrack::stopTrack(ExecutionContext* execution_context) {
if (Ended())
return;
ready_state_ = MediaStreamSource::kReadyStateEnded;
MediaStreamCenter::Instance().DidStopMediaStreamTrack(Component());
Document* document = ToDocument(execution_context);
UserMediaController* user_media =
UserMediaController::From(document->GetFrame());
if (user_media)
user_media->StopTrack(Component());
PropagateTrackEnded();
}
......
......@@ -39,7 +39,6 @@
namespace blink {
class AudioSourceProvider;
class ExceptionState;
class ImageCapture;
class MediaTrackCapabilities;
class MediaTrackConstraints;
......@@ -74,7 +73,7 @@ class MODULES_EXPORT MediaStreamTrack
String readyState() const;
void stopTrack(ExceptionState&);
void stopTrack(ExecutionContext*);
virtual MediaStreamTrack* clone(ScriptState*);
// This function is called when constrains have been successfully applied.
......
......@@ -48,7 +48,7 @@ enum MediaStreamTrackState {
attribute EventHandler onended;
[CallWith=ScriptState] MediaStreamTrack clone();
[ImplementedAs=stopTrack, RaisesException] void stop();
[ImplementedAs=stopTrack, CallWith=ExecutionContext] void stop();
MediaTrackCapabilities getCapabilities();
MediaTrackConstraints getConstraints();
......
......@@ -75,4 +75,10 @@ void UserMediaClient::ApplyConstraints(ApplyConstraintsRequest* request) {
}
}
void UserMediaClient::StopTrack(MediaStreamComponent* track) {
if (client_) {
client_->StopTrack(WebMediaStreamTrack(track));
}
}
} // namespace blink
......@@ -44,6 +44,7 @@ class ApplyConstraintsRequest;
class LocalFrame;
class MediaDevices;
class MediaDevicesRequest;
class MediaStreamComponent;
class UserMediaRequest;
class WebUserMediaClient;
......@@ -58,6 +59,7 @@ class MODULES_EXPORT UserMediaClient {
void RequestMediaDevices(MediaDevicesRequest*);
void SetMediaDeviceChangeObserver(MediaDevices*);
void ApplyConstraints(ApplyConstraintsRequest*);
void StopTrack(MediaStreamComponent*);
private:
explicit UserMediaClient(WebUserMediaClient*);
......
......@@ -35,6 +35,7 @@ namespace blink {
class ApplyConstraintsRequest;
class MediaDevices;
class MediaDevicesRequest;
class MediaStreamComponent;
class UserMediaRequest;
class UserMediaController final
......@@ -53,6 +54,7 @@ class UserMediaController final
void RequestMediaDevices(MediaDevicesRequest*);
void SetMediaDeviceChangeObserver(MediaDevices*);
void ApplyConstraints(ApplyConstraintsRequest*);
void StopTrack(MediaStreamComponent*);
static const char* SupplementName();
static UserMediaController* From(LocalFrame* frame) {
......@@ -88,6 +90,10 @@ inline void UserMediaController::ApplyConstraints(
client_->ApplyConstraints(request);
}
inline void UserMediaController::StopTrack(MediaStreamComponent* track) {
client_->StopTrack(track);
}
} // namespace blink
#endif // UserMediaController_h
......@@ -68,10 +68,6 @@ void MediaStreamCenter::DidSetMediaStreamTrackEnabled(
}
}
bool MediaStreamCenter::DidStopMediaStreamTrack(MediaStreamComponent* track) {
return private_ && private_->DidStopMediaStreamTrack(track);
}
void MediaStreamCenter::DidCreateMediaStreamAndTracks(
MediaStreamDescriptor* stream) {
if (!private_)
......
......@@ -63,7 +63,6 @@ class PLATFORM_EXPORT MediaStreamCenter final
MediaStreamComponent* clone);
void DidSetMediaStreamTrackEnabled(MediaStreamComponent*);
void DidSetContentHint(MediaStreamComponent*);
bool DidStopMediaStreamTrack(MediaStreamComponent*);
std::unique_ptr<AudioSourceProvider> CreateWebAudioSourceFromMediaStreamTrack(
MediaStreamComponent*);
......
......@@ -49,9 +49,6 @@ class WebMediaStreamCenter {
virtual void DidSetContentHint(const WebMediaStreamTrack&) {}
virtual void DidEnableMediaStreamTrack(const WebMediaStreamTrack&) {}
virtual void DidDisableMediaStreamTrack(const WebMediaStreamTrack&) {}
virtual bool DidStopMediaStreamTrack(const WebMediaStreamTrack&) {
return false;
}
// Source functionality.
virtual void DidStopMediaStreamSource(const WebMediaStreamSource&) {}
......
......@@ -35,6 +35,7 @@ namespace blink {
class WebApplyConstraintsRequest;
class WebMediaDevicesRequest;
class WebMediaStreamTrack;
class WebUserMediaRequest;
class WebMediaDeviceChangeObserver;
......@@ -48,6 +49,7 @@ class WebUserMediaClient {
virtual void SetMediaDeviceChangeObserver(
const WebMediaDeviceChangeObserver&) = 0;
virtual void ApplyConstraints(const WebApplyConstraintsRequest&) = 0;
virtual void StopTrack(const WebMediaStreamTrack&) = 0;
};
} // namespace blink
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment