Commit 680b827c authored by hclam@chromium.org's avatar hclam@chromium.org

Make sure ReadyStateEnded is fired when video stream stops

A regression was introduced in the refactoring change in r269020.
VideoCaptureDelegate::started_callback_ is used to notify that the
stream has started and ran into error. However in change r269020 the
callback was reset after sending the started signal. This prevented
error signal from firing.

In this change |started_callback_| is renamed to |running_callback| to
avoid confusion. Also added a test to verify that ReadyStateEnded is
reached when a camera stops.

BUG=374495

Review URL: https://codereview.chromium.org/295483002

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@271359 0039d316-1c4b-4281-b951-d872f2087c98
parent e331cece
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
// found in the LICENSE file. // found in the LICENSE file.
#include "base/bind.h" #include "base/bind.h"
#include "base/message_loop/message_loop.h"
#include "base/strings/utf_string_conversions.h" #include "base/strings/utf_string_conversions.h"
#include "content/child/child_process.h" #include "content/child/child_process.h"
#include "content/renderer/media/media_stream_video_capturer_source.h" #include "content/renderer/media/media_stream_video_capturer_source.h"
...@@ -21,8 +22,8 @@ class MockVideoCapturerDelegate : public VideoCapturerDelegate { ...@@ -21,8 +22,8 @@ class MockVideoCapturerDelegate : public VideoCapturerDelegate {
MOCK_METHOD3(StartCapture, MOCK_METHOD3(StartCapture,
void(const media::VideoCaptureParams& params, void(const media::VideoCaptureParams& params,
const VideoCaptureDeliverFrameCB& new_frame_callback, const VideoCaptureDeliverFrameCB& new_frame_callback,
const StartedCallback& started_callback)); const RunningCallback& running_callback));
MOCK_METHOD0(StopCapture,void()); MOCK_METHOD0(StopCapture, void());
private: private:
virtual ~MockVideoCapturerDelegate() {} virtual ~MockVideoCapturerDelegate() {}
...@@ -60,14 +61,19 @@ class MediaStreamVideoCapturerSourceTest : public testing::Test { ...@@ -60,14 +61,19 @@ class MediaStreamVideoCapturerSourceTest : public testing::Test {
enabled); enabled);
} }
MockVideoCapturerDelegate& mock_delegate() {
return *static_cast<MockVideoCapturerDelegate*>(delegate_.get());
}
protected: protected:
void OnConstraintsApplied(MediaStreamSource* source, bool success) { void OnConstraintsApplied(MediaStreamSource* source, bool success) {
} }
base::MessageLoop message_loop_;
scoped_ptr<ChildProcess> child_process_; scoped_ptr<ChildProcess> child_process_;
blink::WebMediaStreamSource webkit_source_; blink::WebMediaStreamSource webkit_source_;
MediaStreamVideoCapturerSource* source_; // owned by webkit_source. MediaStreamVideoCapturerSource* source_; // owned by webkit_source.
scoped_refptr<MockVideoCapturerDelegate> delegate_; scoped_refptr<VideoCapturerDelegate> delegate_;
}; };
TEST_F(MediaStreamVideoCapturerSourceTest, TabCaptureAllowResolutionChange) { TEST_F(MediaStreamVideoCapturerSourceTest, TabCaptureAllowResolutionChange) {
...@@ -75,13 +81,13 @@ TEST_F(MediaStreamVideoCapturerSourceTest, TabCaptureAllowResolutionChange) { ...@@ -75,13 +81,13 @@ TEST_F(MediaStreamVideoCapturerSourceTest, TabCaptureAllowResolutionChange) {
device_info.device.type = MEDIA_TAB_VIDEO_CAPTURE; device_info.device.type = MEDIA_TAB_VIDEO_CAPTURE;
InitWithDeviceInfo(device_info); InitWithDeviceInfo(device_info);
EXPECT_CALL(*delegate_, StartCapture( EXPECT_CALL(mock_delegate(), StartCapture(
testing::Field(&media::VideoCaptureParams::allow_resolution_change, true), testing::Field(&media::VideoCaptureParams::allow_resolution_change, true),
testing::_, testing::_,
testing::_)).Times(1); testing::_)).Times(1);
blink::WebMediaStreamTrack track = StartSource(); blink::WebMediaStreamTrack track = StartSource();
// When the track goes out of scope, the source will be stopped. // When the track goes out of scope, the source will be stopped.
EXPECT_CALL(*delegate_, StopCapture()); EXPECT_CALL(mock_delegate(), StopCapture());
} }
TEST_F(MediaStreamVideoCapturerSourceTest, TEST_F(MediaStreamVideoCapturerSourceTest,
...@@ -90,13 +96,39 @@ TEST_F(MediaStreamVideoCapturerSourceTest, ...@@ -90,13 +96,39 @@ TEST_F(MediaStreamVideoCapturerSourceTest,
device_info.device.type = MEDIA_DESKTOP_VIDEO_CAPTURE; device_info.device.type = MEDIA_DESKTOP_VIDEO_CAPTURE;
InitWithDeviceInfo(device_info); InitWithDeviceInfo(device_info);
EXPECT_CALL(*delegate_, StartCapture( EXPECT_CALL(mock_delegate(), StartCapture(
testing::Field(&media::VideoCaptureParams::allow_resolution_change, true), testing::Field(&media::VideoCaptureParams::allow_resolution_change, true),
testing::_, testing::_,
testing::_)).Times(1); testing::_)).Times(1);
blink::WebMediaStreamTrack track = StartSource(); blink::WebMediaStreamTrack track = StartSource();
// When the track goes out of scope, the source will be stopped. // When the track goes out of scope, the source will be stopped.
EXPECT_CALL(*delegate_, StopCapture()); EXPECT_CALL(mock_delegate(), StopCapture());
}
TEST_F(MediaStreamVideoCapturerSourceTest, Ended) {
StreamDeviceInfo device_info;
device_info.device.type = MEDIA_DESKTOP_VIDEO_CAPTURE;
delegate_ = new VideoCapturerDelegate(device_info);
source_ = new MediaStreamVideoCapturerSource(
device_info,
MediaStreamSource::SourceStoppedCallback(),
delegate_);
webkit_source_.initialize(base::UTF8ToUTF16("dummy_source_id"),
blink::WebMediaStreamSource::TypeVideo,
base::UTF8ToUTF16("dummy_source_name"));
webkit_source_.setExtraData(source_);
blink::WebMediaStreamTrack track = StartSource();
message_loop_.RunUntilIdle();
delegate_->OnStateUpdateOnRenderThread(VIDEO_CAPTURE_STATE_STARTED);
message_loop_.RunUntilIdle();
EXPECT_EQ(blink::WebMediaStreamSource::ReadyStateLive,
webkit_source_.readyState());
delegate_->OnStateUpdateOnRenderThread(VIDEO_CAPTURE_STATE_ERROR);
message_loop_.RunUntilIdle();
EXPECT_EQ(blink::WebMediaStreamSource::ReadyStateEnded,
webkit_source_.readyState());
} }
} // namespace content } // namespace content
...@@ -98,10 +98,10 @@ void VideoCapturerDelegate::GetCurrentSupportedFormats( ...@@ -98,10 +98,10 @@ void VideoCapturerDelegate::GetCurrentSupportedFormats(
void VideoCapturerDelegate::StartCapture( void VideoCapturerDelegate::StartCapture(
const media::VideoCaptureParams& params, const media::VideoCaptureParams& params,
const VideoCaptureDeliverFrameCB& new_frame_callback, const VideoCaptureDeliverFrameCB& new_frame_callback,
const StartedCallback& started_callback) { const RunningCallback& running_callback) {
DCHECK(params.requested_format.IsValid()); DCHECK(params.requested_format.IsValid());
DCHECK(thread_checker_.CalledOnValidThread()); DCHECK(thread_checker_.CalledOnValidThread());
started_callback_ = started_callback; running_callback_ = running_callback;
got_first_frame_ = false; got_first_frame_ = false;
// NULL in unit test. // NULL in unit test.
...@@ -127,7 +127,7 @@ void VideoCapturerDelegate::StopCapture() { ...@@ -127,7 +127,7 @@ void VideoCapturerDelegate::StopCapture() {
if (!stop_capture_cb_.is_null()) { if (!stop_capture_cb_.is_null()) {
base::ResetAndReturn(&stop_capture_cb_).Run(); base::ResetAndReturn(&stop_capture_cb_).Run();
} }
started_callback_.Reset(); running_callback_.Reset();
source_formats_callback_.Reset(); source_formats_callback_.Reset();
} }
...@@ -135,9 +135,12 @@ void VideoCapturerDelegate::OnStateUpdateOnRenderThread( ...@@ -135,9 +135,12 @@ void VideoCapturerDelegate::OnStateUpdateOnRenderThread(
VideoCaptureState state) { VideoCaptureState state) {
DCHECK(thread_checker_.CalledOnValidThread()); DCHECK(thread_checker_.CalledOnValidThread());
DVLOG(3) << "OnStateUpdateOnRenderThread state = " << state; DVLOG(3) << "OnStateUpdateOnRenderThread state = " << state;
if (state > VIDEO_CAPTURE_STATE_STARTING && !started_callback_.is_null()) { if (state == VIDEO_CAPTURE_STATE_STARTED && !running_callback_.is_null()) {
base::ResetAndReturn(&started_callback_).Run( running_callback_.Run(true);
state == VIDEO_CAPTURE_STATE_STARTED); return;
}
if (state > VIDEO_CAPTURE_STATE_STARTED && !running_callback_.is_null()) {
base::ResetAndReturn(&running_callback_).Run(false);
} }
} }
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#define CONTENT_RENDERER_MEDIA_MEDIA_STREAM_VIDEO_CAPTURER_SOURCE_H_ #define CONTENT_RENDERER_MEDIA_MEDIA_STREAM_VIDEO_CAPTURER_SOURCE_H_
#include "base/callback.h" #include "base/callback.h"
#include "base/gtest_prod_util.h"
#include "base/message_loop/message_loop_proxy.h" #include "base/message_loop/message_loop_proxy.h"
#include "base/threading/thread_checker.h" #include "base/threading/thread_checker.h"
#include "content/common/media/video_capture.h" #include "content/common/media/video_capture.h"
...@@ -21,7 +22,7 @@ namespace content { ...@@ -21,7 +22,7 @@ namespace content {
class CONTENT_EXPORT VideoCapturerDelegate class CONTENT_EXPORT VideoCapturerDelegate
: public base::RefCountedThreadSafe<VideoCapturerDelegate> { : public base::RefCountedThreadSafe<VideoCapturerDelegate> {
public: public:
typedef base::Callback<void(bool running)> StartedCallback; typedef base::Callback<void(bool running)> RunningCallback;
explicit VideoCapturerDelegate( explicit VideoCapturerDelegate(
const StreamDeviceInfo& device_info); const StreamDeviceInfo& device_info);
...@@ -37,18 +38,21 @@ class CONTENT_EXPORT VideoCapturerDelegate ...@@ -37,18 +38,21 @@ class CONTENT_EXPORT VideoCapturerDelegate
// Starts capturing frames using the resolution in |params|. // Starts capturing frames using the resolution in |params|.
// |new_frame_callback| is triggered when a new video frame is available. // |new_frame_callback| is triggered when a new video frame is available.
// |started_callback| is triggered before the first video frame is received // If capturing is started successfully then |running_callback| will be
// or if the underlying video capturer fails to start. // called with a parameter of true.
// If capturing fails to start or stopped due to an external event then
// |running_callback| will be called with a parameter of false.
virtual void StartCapture( virtual void StartCapture(
const media::VideoCaptureParams& params, const media::VideoCaptureParams& params,
const VideoCaptureDeliverFrameCB& new_frame_callback, const VideoCaptureDeliverFrameCB& new_frame_callback,
const StartedCallback& started_callback); const RunningCallback& running_callback);
// Stops capturing frames and clears all callbacks including the // Stops capturing frames and clears all callbacks including the
// SupportedFormatsCallback callback. // SupportedFormatsCallback callback.
virtual void StopCapture(); virtual void StopCapture();
private: private:
FRIEND_TEST_ALL_PREFIXES(MediaStreamVideoCapturerSourceTest, Ended);
friend class base::RefCountedThreadSafe<VideoCapturerDelegate>; friend class base::RefCountedThreadSafe<VideoCapturerDelegate>;
friend class MockVideoCapturerDelegate; friend class MockVideoCapturerDelegate;
...@@ -68,9 +72,9 @@ class CONTENT_EXPORT VideoCapturerDelegate ...@@ -68,9 +72,9 @@ class CONTENT_EXPORT VideoCapturerDelegate
bool is_screen_cast_; bool is_screen_cast_;
bool got_first_frame_; bool got_first_frame_;
// |started_callback| is provided to this class in StartCapture and must be // |running_callback| is provided to this class in StartCapture and must be
// valid until StopCapture is called. // valid until StopCapture is called.
StartedCallback started_callback_; RunningCallback running_callback_;
VideoCaptureDeviceFormatsCB source_formats_callback_; VideoCaptureDeviceFormatsCB source_formats_callback_;
......
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