1// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include <string>
6#include <queue>
7
8#include "base/bind.h"
9#include "base/callback_helpers.h"
10#include "base/message_loop/message_loop.h"
11#include "base/run_loop.h"
12#include "content/browser/browser_thread_impl.h"
13#include "content/browser/renderer_host/media/media_stream_dispatcher_host.h"
14#include "content/browser/renderer_host/media/media_stream_manager.h"
15#include "content/browser/renderer_host/media/media_stream_ui_proxy.h"
16#include "content/common/media/media_stream_messages.h"
17#include "content/common/media/media_stream_options.h"
18#include "content/public/browser/media_device_id.h"
19#include "content/public/test/mock_resource_context.h"
20#include "content/public/test/test_browser_context.h"
21#include "content/public/test/test_browser_thread_bundle.h"
22#include "content/test/test_content_browser_client.h"
23#include "content/test/test_content_client.h"
24#include "ipc/ipc_message_macros.h"
25#include "media/audio/mock_audio_manager.h"
26#include "media/video/capture/fake_video_capture_device.h"
27#include "net/url_request/url_request_context.h"
28#include "testing/gmock/include/gmock/gmock.h"
29#include "testing/gtest/include/gtest/gtest.h"
30
31using ::testing::_;
32using ::testing::DeleteArg;
33using ::testing::DoAll;
34using ::testing::Return;
35using ::testing::SaveArg;
36
37const int kProcessId = 5;
38const int kRenderId = 6;
39const int kPageRequestId = 7;
40
41namespace content {
42
43class MockMediaStreamDispatcherHost : public MediaStreamDispatcherHost,
44                                      public TestContentBrowserClient {
45 public:
46  MockMediaStreamDispatcherHost(
47      const ResourceContext::SaltCallback salt_callback,
48      const scoped_refptr<base::MessageLoopProxy>& message_loop,
49      MediaStreamManager* manager)
50      : MediaStreamDispatcherHost(kProcessId, salt_callback, manager),
51        message_loop_(message_loop) {}
52
53  // A list of mock methods.
54  MOCK_METHOD4(OnStreamGenerated,
55               void(int routing_id, int request_id, int audio_array_size,
56                    int video_array_size));
57  MOCK_METHOD2(OnStreamGenerationFailed, void(int routing_id, int request_id));
58  MOCK_METHOD1(OnDeviceStopped, void(int routing_id));
59  MOCK_METHOD2(OnDeviceOpened, void(int routing_id, int request_id));
60
61  // Accessor to private functions.
62  void OnGenerateStream(int render_view_id,
63                        int page_request_id,
64                        const StreamOptions& components,
65                        const GURL& security_origin,
66                        const base::Closure& quit_closure) {
67    quit_closures_.push(quit_closure);
68    MediaStreamDispatcherHost::OnGenerateStream(
69        render_view_id, page_request_id, components, security_origin);
70  }
71
72  void OnStopStreamDevice(int render_view_id,
73                          const std::string& device_id) {
74    MediaStreamDispatcherHost::OnStopStreamDevice(render_view_id, device_id);
75  }
76
77  void OnOpenDevice(int render_view_id,
78                    int page_request_id,
79                    const std::string& device_id,
80                    MediaStreamType type,
81                    const GURL& security_origin,
82                    const base::Closure& quit_closure) {
83    quit_closures_.push(quit_closure);
84    MediaStreamDispatcherHost::OnOpenDevice(
85        render_view_id, page_request_id, device_id, type, security_origin);
86  }
87
88  void OnEnumerateDevices(int render_view_id,
89                          int page_request_id,
90                          MediaStreamType type,
91                          const GURL& security_origin,
92                          const base::Closure& quit_closure) {
93    quit_closures_.push(quit_closure);
94    MediaStreamDispatcherHost::OnEnumerateDevices(
95        render_view_id, page_request_id, type, security_origin);
96  }
97
98  std::string label_;
99  StreamDeviceInfoArray audio_devices_;
100  StreamDeviceInfoArray video_devices_;
101  StreamDeviceInfo opened_device_;
102  StreamDeviceInfoArray enumerated_devices_;
103
104 private:
105  virtual ~MockMediaStreamDispatcherHost() {}
106
107  // This method is used to dispatch IPC messages to the renderer. We intercept
108  // these messages here and dispatch to our mock methods to verify the
109  // conversation between this object and the renderer.
110  virtual bool Send(IPC::Message* message) OVERRIDE {
111    CHECK(message);
112
113    // In this method we dispatch the messages to the according handlers as if
114    // we are the renderer.
115    bool handled = true;
116    IPC_BEGIN_MESSAGE_MAP(MockMediaStreamDispatcherHost, *message)
117      IPC_MESSAGE_HANDLER(MediaStreamMsg_StreamGenerated, OnStreamGenerated)
118      IPC_MESSAGE_HANDLER(MediaStreamMsg_StreamGenerationFailed,
119                          OnStreamGenerationFailed)
120      IPC_MESSAGE_HANDLER(MediaStreamMsg_DeviceStopped, OnDeviceStopped)
121      IPC_MESSAGE_HANDLER(MediaStreamMsg_DeviceOpened, OnDeviceOpened)
122      IPC_MESSAGE_HANDLER(MediaStreamMsg_DevicesEnumerated,
123                          OnDevicesEnumerated)
124      IPC_MESSAGE_UNHANDLED(handled = false)
125    IPC_END_MESSAGE_MAP()
126    EXPECT_TRUE(handled);
127
128    delete message;
129    return true;
130  }
131
132  // These handler methods do minimal things and delegate to the mock methods.
133  void OnStreamGenerated(
134      const IPC::Message& msg,
135      int request_id,
136      std::string label,
137      StreamDeviceInfoArray audio_device_list,
138      StreamDeviceInfoArray video_device_list) {
139    OnStreamGenerated(msg.routing_id(), request_id, audio_device_list.size(),
140        video_device_list.size());
141    // Notify that the event have occurred.
142    base::Closure quit_closure = quit_closures_.front();
143    quit_closures_.pop();
144    message_loop_->PostTask(FROM_HERE, base::ResetAndReturn(&quit_closure));
145
146    label_ = label;
147    audio_devices_ = audio_device_list;
148    video_devices_ = video_device_list;
149  }
150
151  void OnStreamGenerationFailed(const IPC::Message& msg, int request_id) {
152    OnStreamGenerationFailed(msg.routing_id(), request_id);
153    if (!quit_closures_.empty()) {
154      base::Closure quit_closure = quit_closures_.front();
155      quit_closures_.pop();
156      message_loop_->PostTask(FROM_HERE, base::ResetAndReturn(&quit_closure));
157    }
158
159    label_= "";
160  }
161
162  void OnDeviceStopped(const IPC::Message& msg,
163                       const std::string& label,
164                       const content::StreamDeviceInfo& device) {
165    if (IsVideoMediaType(device.device.type))
166      EXPECT_TRUE(StreamDeviceInfo::IsEqual(device, video_devices_[0]));
167    if (IsAudioMediaType(device.device.type))
168      EXPECT_TRUE(StreamDeviceInfo::IsEqual(device, audio_devices_[0]));
169
170    OnDeviceStopped(msg.routing_id());
171  }
172
173  void OnDeviceOpened(const IPC::Message& msg,
174                      int request_id,
175                      const std::string& label,
176                      const StreamDeviceInfo& device) {
177    base::Closure quit_closure = quit_closures_.front();
178    quit_closures_.pop();
179    message_loop_->PostTask(FROM_HERE, base::ResetAndReturn(&quit_closure));
180    label_ = label;
181    opened_device_ = device;
182  }
183
184  void OnDevicesEnumerated(const IPC::Message& msg,
185                           int request_id,
186                           const StreamDeviceInfoArray& devices) {
187    base::Closure quit_closure = quit_closures_.front();
188    quit_closures_.pop();
189    message_loop_->PostTask(FROM_HERE, base::ResetAndReturn(&quit_closure));
190    enumerated_devices_ = devices;
191  }
192
193  scoped_refptr<base::MessageLoopProxy> message_loop_;
194
195  std::queue<base::Closure> quit_closures_;
196};
197
198class MockMediaStreamUIProxy : public FakeMediaStreamUIProxy {
199 public:
200  MOCK_METHOD1(OnStarted, void(const base::Closure& stop));
201};
202
203class MediaStreamDispatcherHostTest : public testing::Test {
204 public:
205  MediaStreamDispatcherHostTest()
206      : old_browser_client_(NULL),
207        thread_bundle_(content::TestBrowserThreadBundle::IO_MAINLOOP),
208        origin_("https://test.com") {
209    audio_manager_.reset(
210        new media::MockAudioManager(base::MessageLoopProxy::current()));
211    // Create our own MediaStreamManager.
212    media_stream_manager_.reset(new MediaStreamManager(audio_manager_.get()));
213    // Make sure we use fake devices to avoid long delays.
214    media_stream_manager_->UseFakeDevice();
215
216    host_ = new MockMediaStreamDispatcherHost(
217        browser_context_.GetResourceContext()->GetMediaDeviceIDSalt(),
218        base::MessageLoopProxy::current(),
219        media_stream_manager_.get());
220
221    // Use the fake content client and browser.
222    content_client_.reset(new TestContentClient());
223    SetContentClient(content_client_.get());
224    old_browser_client_ = SetBrowserClientForTesting(host_.get());
225  }
226
227  virtual ~MediaStreamDispatcherHostTest() {
228  }
229
230  virtual void SetUp() OVERRIDE {
231    media::FakeVideoCaptureDevice::GetDeviceNames(&physical_video_devices_);
232    ASSERT_GT(physical_video_devices_.size(), 0u);
233
234    audio_manager_->GetAudioInputDeviceNames(&physical_audio_devices_);
235    ASSERT_GT(physical_audio_devices_.size(), 0u);
236  }
237
238  virtual void TearDown() OVERRIDE {
239    host_->OnChannelClosing();
240  }
241
242 protected:
243  virtual void SetupFakeUI(bool expect_started) {
244    scoped_ptr<MockMediaStreamUIProxy> stream_ui(new MockMediaStreamUIProxy());
245    if (expect_started) {
246      EXPECT_CALL(*stream_ui, OnStarted(_));
247    }
248    media_stream_manager_->UseFakeUI(
249        stream_ui.PassAs<FakeMediaStreamUIProxy>());
250  }
251
252  void GenerateStreamAndWaitForResult(int render_view_id,
253                                      int page_request_id,
254                                      const StreamOptions& options) {
255    base::RunLoop run_loop;
256    int expected_audio_array_size =
257        (options.audio_requested &&
258         physical_audio_devices_.size() > 0) ? 1 : 0;
259    int expected_video_array_size =
260        (options.video_requested &&
261         physical_video_devices_.size() > 0) ? 1 : 0;
262    EXPECT_CALL(*host_.get(), OnStreamGenerated(render_view_id, page_request_id,
263                                                expected_audio_array_size,
264                                                expected_video_array_size));
265    host_->OnGenerateStream(render_view_id, page_request_id, options, origin_,
266                            run_loop.QuitClosure());
267    run_loop.Run();
268    EXPECT_FALSE(DoesContainRawIds(host_->audio_devices_));
269    EXPECT_FALSE(DoesContainRawIds(host_->video_devices_));
270    EXPECT_TRUE(DoesEveryDeviceMapToRawId(host_->audio_devices_, origin_));
271    EXPECT_TRUE(DoesEveryDeviceMapToRawId(host_->video_devices_, origin_));
272  }
273
274  void GenerateStreamAndWaitForFailure(int render_view_id,
275                                       int page_request_id,
276                                       const StreamOptions& options) {
277      base::RunLoop run_loop;
278      EXPECT_CALL(*host_.get(),
279                  OnStreamGenerationFailed(render_view_id, page_request_id));
280      host_->OnGenerateStream(render_view_id, page_request_id, options, origin_,
281                              run_loop.QuitClosure());
282      run_loop.Run();
283  }
284
285  void OpenVideoDeviceAndWaitForResult(int render_view_id,
286                                       int page_request_id,
287                                       const std::string& device_id) {
288    base::RunLoop run_loop;
289    host_->OnOpenDevice(render_view_id, page_request_id, device_id,
290                        MEDIA_DEVICE_VIDEO_CAPTURE, origin_,
291                        run_loop.QuitClosure());
292    run_loop.Run();
293    EXPECT_FALSE(DoesContainRawIds(host_->video_devices_));
294    EXPECT_TRUE(DoesEveryDeviceMapToRawId(host_->video_devices_, origin_));
295  }
296
297  void EnumerateDevicesAndWaitForResult(int render_view_id,
298                                        int page_request_id,
299                                        MediaStreamType type) {
300    base::RunLoop run_loop;
301    host_->OnEnumerateDevices(render_view_id, page_request_id, type, origin_,
302                              run_loop.QuitClosure());
303    run_loop.Run();
304    ASSERT_FALSE(host_->enumerated_devices_.empty());
305    EXPECT_FALSE(DoesContainRawIds(host_->enumerated_devices_));
306    EXPECT_TRUE(DoesEveryDeviceMapToRawId(host_->enumerated_devices_, origin_));
307  }
308
309  bool DoesContainRawIds(const StreamDeviceInfoArray& devices) {
310    for (size_t i = 0; i < devices.size(); ++i) {
311      media::AudioDeviceNames::const_iterator audio_it =
312          physical_audio_devices_.begin();
313      for (; audio_it != physical_audio_devices_.end(); ++audio_it) {
314        if (audio_it->unique_id == devices[i].device.id)
315          return true;
316      }
317      media::VideoCaptureDevice::Names::const_iterator video_it =
318          physical_video_devices_.begin();
319      for (; video_it != physical_video_devices_.end(); ++video_it) {
320        if (video_it->id() == devices[i].device.id)
321          return true;
322      }
323    }
324    return false;
325  }
326
327  bool DoesEveryDeviceMapToRawId(const StreamDeviceInfoArray& devices,
328                                 const GURL& origin) {
329    for (size_t i = 0; i < devices.size(); ++i) {
330      bool found_match = false;
331      media::AudioDeviceNames::const_iterator audio_it =
332          physical_audio_devices_.begin();
333      for (; audio_it != physical_audio_devices_.end(); ++audio_it) {
334        if (content::DoesMediaDeviceIDMatchHMAC(
335                browser_context_.GetResourceContext()->GetMediaDeviceIDSalt(),
336                origin,
337                devices[i].device.id,
338                audio_it->unique_id)) {
339          EXPECT_FALSE(found_match);
340          found_match = true;
341        }
342      }
343      media::VideoCaptureDevice::Names::const_iterator video_it =
344          physical_video_devices_.begin();
345      for (; video_it != physical_video_devices_.end(); ++video_it) {
346        if (content::DoesMediaDeviceIDMatchHMAC(
347                browser_context_.GetResourceContext()->GetMediaDeviceIDSalt(),
348                origin,
349                devices[i].device.id,
350                video_it->id())) {
351          EXPECT_FALSE(found_match);
352          found_match = true;
353        }
354      }
355      if (!found_match)
356        return false;
357    }
358    return true;
359  }
360
361  void AddSourceIdConstraint(const std::string& source_id,
362                             StreamOptions::Constraints* constraints) {
363    constraints->push_back(StreamOptions::Constraint(kMediaStreamSourceInfoId,
364                                                     source_id));
365  }
366
367  scoped_refptr<MockMediaStreamDispatcherHost> host_;
368  scoped_ptr<media::AudioManager> audio_manager_;
369  scoped_ptr<MediaStreamManager> media_stream_manager_;
370  ContentBrowserClient* old_browser_client_;
371  scoped_ptr<ContentClient> content_client_;
372  content::TestBrowserThreadBundle thread_bundle_;
373  content::TestBrowserContext browser_context_;
374  media::AudioDeviceNames physical_audio_devices_;
375  media::VideoCaptureDevice::Names physical_video_devices_;
376  GURL origin_;
377};
378
379TEST_F(MediaStreamDispatcherHostTest, GenerateStreamWithVideoOnly) {
380  StreamOptions options(false, true);
381
382  SetupFakeUI(true);
383  GenerateStreamAndWaitForResult(kRenderId, kPageRequestId, options);
384
385  EXPECT_EQ(host_->audio_devices_.size(), 0u);
386  EXPECT_EQ(host_->video_devices_.size(), 1u);
387}
388
389TEST_F(MediaStreamDispatcherHostTest, GenerateStreamWithAudioOnly) {
390  StreamOptions options(true, false);
391
392  SetupFakeUI(true);
393  GenerateStreamAndWaitForResult(kRenderId, kPageRequestId, options);
394
395  EXPECT_EQ(host_->audio_devices_.size(), 1u);
396  EXPECT_EQ(host_->video_devices_.size(), 0u);
397}
398
399TEST_F(MediaStreamDispatcherHostTest, GenerateStreamWithNothing) {
400  StreamOptions options(false, false);
401
402  GenerateStreamAndWaitForFailure(kRenderId, kPageRequestId, options);
403}
404
405TEST_F(MediaStreamDispatcherHostTest, GenerateStreamWithAudioAndVideo) {
406  StreamOptions options(true, true);
407
408  SetupFakeUI(true);
409  GenerateStreamAndWaitForResult(kRenderId, kPageRequestId, options);
410
411  EXPECT_EQ(host_->audio_devices_.size(), 1u);
412  EXPECT_EQ(host_->video_devices_.size(), 1u);
413}
414
415// This test generates two streams with video only using the same render view
416// id. The same capture device  with the same device and session id is expected
417// to be used.
418TEST_F(MediaStreamDispatcherHostTest, GenerateStreamsFromSameRenderId) {
419  StreamOptions options(false, true);
420
421  // Generate first stream.
422  SetupFakeUI(true);
423  GenerateStreamAndWaitForResult(kRenderId, kPageRequestId, options);
424
425  // Check the latest generated stream.
426  EXPECT_EQ(host_->audio_devices_.size(), 0u);
427  EXPECT_EQ(host_->video_devices_.size(), 1u);
428  const std::string label1 = host_->label_;
429  const std::string device_id1 = host_->video_devices_.front().device.id;
430  const int session_id1 = host_->video_devices_.front().session_id;
431
432  // Generate second stream.
433  SetupFakeUI(true);
434  GenerateStreamAndWaitForResult(kRenderId, kPageRequestId + 1, options);
435
436  // Check the latest generated stream.
437  EXPECT_EQ(host_->audio_devices_.size(), 0u);
438  EXPECT_EQ(host_->video_devices_.size(), 1u);
439  const std::string label2 = host_->label_;
440  const std::string device_id2 = host_->video_devices_.front().device.id;
441  int session_id2 = host_->video_devices_.front().session_id;
442  EXPECT_EQ(device_id1, device_id2);
443  EXPECT_EQ(session_id1, session_id2);
444  EXPECT_NE(label1, label2);
445}
446
447TEST_F(MediaStreamDispatcherHostTest,
448       GenerateStreamAndOpenDeviceFromSameRenderId) {
449  StreamOptions options(false, true);
450
451  // Generate first stream.
452  SetupFakeUI(true);
453  GenerateStreamAndWaitForResult(kRenderId, kPageRequestId, options);
454
455  EXPECT_EQ(host_->audio_devices_.size(), 0u);
456  EXPECT_EQ(host_->video_devices_.size(), 1u);
457  const std::string label1 = host_->label_;
458  const std::string device_id1 = host_->video_devices_.front().device.id;
459  const int session_id1 = host_->video_devices_.front().session_id;
460
461  // Generate second stream.
462  OpenVideoDeviceAndWaitForResult(kRenderId, kPageRequestId, device_id1);
463
464  const std::string device_id2 = host_->opened_device_.device.id;
465  const int session_id2 = host_->opened_device_.session_id;
466  const std::string label2 = host_->label_;
467
468  EXPECT_EQ(device_id1, device_id2);
469  EXPECT_NE(session_id1, session_id2);
470  EXPECT_NE(label1, label2);
471}
472
473
474// This test generates two streams with video only using two separate render
475// view ids. The same device id but different session ids are expected.
476TEST_F(MediaStreamDispatcherHostTest, GenerateStreamsDifferentRenderId) {
477  StreamOptions options(false, true);
478
479  // Generate first stream.
480  SetupFakeUI(true);
481  GenerateStreamAndWaitForResult(kRenderId, kPageRequestId, options);
482
483  // Check the latest generated stream.
484  EXPECT_EQ(host_->audio_devices_.size(), 0u);
485  EXPECT_EQ(host_->video_devices_.size(), 1u);
486  const std::string label1 = host_->label_;
487  const std::string device_id1 = host_->video_devices_.front().device.id;
488  const int session_id1 = host_->video_devices_.front().session_id;
489
490  // Generate second stream from another render view.
491  SetupFakeUI(true);
492  GenerateStreamAndWaitForResult(kRenderId+1, kPageRequestId + 1, options);
493
494  // Check the latest generated stream.
495  EXPECT_EQ(host_->audio_devices_.size(), 0u);
496  EXPECT_EQ(host_->video_devices_.size(), 1u);
497  const std::string label2 = host_->label_;
498  const std::string device_id2 = host_->video_devices_.front().device.id;
499  const int session_id2 = host_->video_devices_.front().session_id;
500  EXPECT_EQ(device_id1, device_id2);
501  EXPECT_NE(session_id1, session_id2);
502  EXPECT_NE(label1, label2);
503}
504
505// This test request two streams with video only without waiting for the first
506// stream to be generated before requesting the second.
507// The same device id and session ids are expected.
508TEST_F(MediaStreamDispatcherHostTest, GenerateStreamsWithoutWaiting) {
509  StreamOptions options(false, true);
510
511  // Generate first stream.
512  SetupFakeUI(true);
513  EXPECT_CALL(*host_.get(), OnStreamGenerated(kRenderId, kPageRequestId, 0, 1));
514
515  // Generate second stream.
516  EXPECT_CALL(*host_.get(),
517              OnStreamGenerated(kRenderId, kPageRequestId + 1, 0, 1));
518
519  base::RunLoop run_loop1;
520  base::RunLoop run_loop2;
521  host_->OnGenerateStream(kRenderId, kPageRequestId, options, origin_,
522                          run_loop1.QuitClosure());
523  host_->OnGenerateStream(kRenderId, kPageRequestId + 1, options, origin_,
524                          run_loop2.QuitClosure());
525
526  run_loop1.Run();
527  run_loop2.Run();
528}
529
530// Test that we can generate streams where a mandatory sourceId is specified in
531// the request.
532TEST_F(MediaStreamDispatcherHostTest, GenerateStreamsWithMandatorySourceId) {
533  ASSERT_GE(physical_audio_devices_.size(), 1u);
534  ASSERT_GE(physical_video_devices_.size(), 1u);
535
536  media::AudioDeviceNames::const_iterator audio_it =
537      physical_audio_devices_.begin();
538  for (; audio_it != physical_audio_devices_.end(); ++audio_it) {
539    std::string source_id = content::GetHMACForMediaDeviceID(
540        browser_context_.GetResourceContext()->GetMediaDeviceIDSalt(),
541        origin_,
542        audio_it->unique_id);
543    ASSERT_FALSE(source_id.empty());
544    StreamOptions options(true, true);
545    AddSourceIdConstraint(source_id, &options.mandatory_audio);
546
547    SetupFakeUI(true);
548    GenerateStreamAndWaitForResult(kRenderId, kPageRequestId, options);
549    EXPECT_EQ(host_->audio_devices_[0].device.id, source_id);
550  }
551
552  media::VideoCaptureDevice::Names::const_iterator video_it =
553      physical_video_devices_.begin();
554  for (; video_it != physical_video_devices_.end(); ++video_it) {
555    std::string source_id = content::GetHMACForMediaDeviceID(
556        browser_context_.GetResourceContext()->GetMediaDeviceIDSalt(),
557        origin_,
558        video_it->id());
559    ASSERT_FALSE(source_id.empty());
560    StreamOptions options(true, true);
561    AddSourceIdConstraint(source_id, &options.mandatory_video);
562
563    SetupFakeUI(true);
564    GenerateStreamAndWaitForResult(kRenderId, kPageRequestId, options);
565    EXPECT_EQ(host_->video_devices_[0].device.id, source_id);
566  }
567}
568
569// Test that we can generate streams where a optional sourceId is specified in
570// the request.
571TEST_F(MediaStreamDispatcherHostTest, GenerateStreamsWithOptionalSourceId) {
572  ASSERT_GE(physical_audio_devices_.size(), 1u);
573  ASSERT_GE(physical_video_devices_.size(), 1u);
574
575  media::AudioDeviceNames::const_iterator audio_it =
576      physical_audio_devices_.begin();
577  for (; audio_it != physical_audio_devices_.end(); ++audio_it) {
578    std::string source_id = content::GetHMACForMediaDeviceID(
579        browser_context_.GetResourceContext()->GetMediaDeviceIDSalt(),
580        origin_,
581        audio_it->unique_id);
582    ASSERT_FALSE(source_id.empty());
583    StreamOptions options(true, true);
584    AddSourceIdConstraint(source_id, &options.optional_audio);
585
586    SetupFakeUI(true);
587    GenerateStreamAndWaitForResult(kRenderId, kPageRequestId, options);
588    EXPECT_EQ(host_->audio_devices_[0].device.id, source_id);
589  }
590
591  media::VideoCaptureDevice::Names::const_iterator video_it =
592      physical_video_devices_.begin();
593  for (; video_it != physical_video_devices_.end(); ++video_it) {
594    std::string source_id = content::GetHMACForMediaDeviceID(
595        browser_context_.GetResourceContext()->GetMediaDeviceIDSalt(),
596        origin_,
597        video_it->id());
598    ASSERT_FALSE(source_id.empty());
599    StreamOptions options(true, true);
600    AddSourceIdConstraint(source_id, &options.optional_video);
601
602    SetupFakeUI(true);
603    GenerateStreamAndWaitForResult(kRenderId, kPageRequestId, options);
604    EXPECT_EQ(host_->video_devices_[0].device.id, source_id);
605  }
606}
607
608// Test that generating a stream with an invalid mandatory video source id fail.
609TEST_F(MediaStreamDispatcherHostTest,
610       GenerateStreamsWithInvalidMandatoryVideoSourceId) {
611  StreamOptions options(true, true);
612  AddSourceIdConstraint("invalid source id", &options.mandatory_video);
613
614  GenerateStreamAndWaitForFailure(kRenderId, kPageRequestId, options);
615}
616
617// Test that generating a stream with an invalid mandatory audio source id fail.
618TEST_F(MediaStreamDispatcherHostTest,
619       GenerateStreamsWithInvalidMandatoryAudioSourceId) {
620  StreamOptions options(true, true);
621  AddSourceIdConstraint("invalid source id", &options.mandatory_audio);
622
623  GenerateStreamAndWaitForFailure(kRenderId, kPageRequestId, options);
624}
625
626// Test that generating a stream with an invalid optional video source id
627// succeed.
628TEST_F(MediaStreamDispatcherHostTest,
629       GenerateStreamsWithInvalidOptionalVideoSourceId) {
630  StreamOptions options(true, true);
631  AddSourceIdConstraint("invalid source id", &options.optional_video);
632
633  SetupFakeUI(true);
634  GenerateStreamAndWaitForResult(kRenderId, kPageRequestId, options);
635}
636
637// Test that generating a stream with an invalid optional audio source id
638// succeed.
639TEST_F(MediaStreamDispatcherHostTest,
640       GenerateStreamsWithInvalidOptionalAudioSourceId) {
641  StreamOptions options(true, true);
642  AddSourceIdConstraint("invalid source id", &options.optional_audio);
643
644  SetupFakeUI(true);
645  GenerateStreamAndWaitForResult(kRenderId, kPageRequestId, options);
646}
647
648TEST_F(MediaStreamDispatcherHostTest, GenerateStreamsNoAvailableVideoDevice) {
649  size_t number_of_fake_devices = physical_video_devices_.size();
650  media::FakeVideoCaptureDevice::SetNumberOfFakeDevices(0);
651  media::FakeVideoCaptureDevice::GetDeviceNames(&physical_video_devices_);
652  StreamOptions options(true, true);
653
654  SetupFakeUI(true);
655  GenerateStreamAndWaitForResult(kRenderId, kPageRequestId, options);
656  EXPECT_TRUE(host_->video_devices_.empty());
657
658  // Reset the number of fake devices for next test.
659  media::FakeVideoCaptureDevice::SetNumberOfFakeDevices(number_of_fake_devices);
660}
661
662// Test that if a OnStopStreamDevice message is received for a device that has
663// been opened in a MediaStream and by pepper, the device is only stopped for
664// the MediaStream.
665TEST_F(MediaStreamDispatcherHostTest, StopDeviceInStream) {
666  StreamOptions options(false, true);
667
668  SetupFakeUI(true);
669  GenerateStreamAndWaitForResult(kRenderId, kPageRequestId, options);
670
671  std::string stream_request_label = host_->label_;
672  StreamDeviceInfo video_device_info = host_->video_devices_.front();
673  ASSERT_EQ(1u, media_stream_manager_->GetDevicesOpenedByRequest(
674      stream_request_label).size());
675
676  // Open the same device by Pepper.
677  OpenVideoDeviceAndWaitForResult(kRenderId, kPageRequestId,
678                                  video_device_info.device.id);
679  std::string open_device_request_label = host_->label_;
680
681  // Stop the device in the MediaStream.
682  host_->OnStopStreamDevice(kRenderId, video_device_info.device.id);
683
684  EXPECT_EQ(0u, media_stream_manager_->GetDevicesOpenedByRequest(
685      stream_request_label).size());
686  EXPECT_EQ(1u, media_stream_manager_->GetDevicesOpenedByRequest(
687      open_device_request_label).size());
688}
689
690TEST_F(MediaStreamDispatcherHostTest, StopDeviceInStreamAndRestart) {
691  StreamOptions options(true, true);
692
693  SetupFakeUI(true);
694  GenerateStreamAndWaitForResult(kRenderId, kPageRequestId, options);
695
696  std::string request_label1 = host_->label_;
697  StreamDeviceInfo video_device_info = host_->video_devices_.front();
698  // Expect that 1 audio and 1 video device has been opened.
699  EXPECT_EQ(2u, media_stream_manager_->GetDevicesOpenedByRequest(
700      request_label1).size());
701
702  host_->OnStopStreamDevice(kRenderId, video_device_info.device.id);
703  EXPECT_EQ(1u, media_stream_manager_->GetDevicesOpenedByRequest(
704      request_label1).size());
705
706  GenerateStreamAndWaitForResult(kRenderId, kPageRequestId, options);
707  std::string request_label2 = host_->label_;
708
709  StreamDeviceInfoArray request1_devices =
710      media_stream_manager_->GetDevicesOpenedByRequest(request_label1);
711  StreamDeviceInfoArray request2_devices =
712      media_stream_manager_->GetDevicesOpenedByRequest(request_label2);
713
714  ASSERT_EQ(1u, request1_devices.size());
715  ASSERT_EQ(2u, request2_devices.size());
716
717  // Test that the same audio device has been opened in both streams.
718  EXPECT_TRUE(StreamDeviceInfo::IsEqual(request1_devices[0],
719                                        request2_devices[0]) ||
720              StreamDeviceInfo::IsEqual(request1_devices[0],
721                                        request2_devices[1]));
722}
723
724TEST_F(MediaStreamDispatcherHostTest, CancelPendingStreamsOnChannelClosing) {
725  StreamOptions options(false, true);
726
727  base::RunLoop run_loop;
728
729  // Create multiple GenerateStream requests.
730  size_t streams = 5;
731  for (size_t i = 1; i <= streams; ++i) {
732    host_->OnGenerateStream(kRenderId, kPageRequestId + i, options, origin_,
733                            run_loop.QuitClosure());
734  }
735
736  // Calling OnChannelClosing() to cancel all the pending requests.
737  host_->OnChannelClosing();
738  run_loop.RunUntilIdle();
739}
740
741TEST_F(MediaStreamDispatcherHostTest, StopGeneratedStreamsOnChannelClosing) {
742  StreamOptions options(false, true);
743
744  // Create first group of streams.
745  size_t generated_streams = 3;
746  for (size_t i = 0; i < generated_streams; ++i) {
747    SetupFakeUI(true);
748    GenerateStreamAndWaitForResult(kRenderId, kPageRequestId + i, options);
749  }
750
751  // Calling OnChannelClosing() to cancel all the pending/generated streams.
752  host_->OnChannelClosing();
753  base::RunLoop().RunUntilIdle();
754}
755
756TEST_F(MediaStreamDispatcherHostTest, CloseFromUI) {
757  StreamOptions options(false, true);
758
759  base::Closure close_callback;
760  scoped_ptr<MockMediaStreamUIProxy> stream_ui(new MockMediaStreamUIProxy());
761  EXPECT_CALL(*stream_ui, OnStarted(_))
762      .WillOnce(SaveArg<0>(&close_callback));
763  media_stream_manager_->UseFakeUI(stream_ui.PassAs<FakeMediaStreamUIProxy>());
764
765  GenerateStreamAndWaitForResult(kRenderId, kPageRequestId, options);
766
767  EXPECT_EQ(host_->audio_devices_.size(), 0u);
768  EXPECT_EQ(host_->video_devices_.size(), 1u);
769
770  ASSERT_FALSE(close_callback.is_null());
771  EXPECT_CALL(*host_.get(), OnDeviceStopped(kRenderId));
772  close_callback.Run();
773  base::RunLoop().RunUntilIdle();
774}
775
776// Test that the dispatcher is notified if a video device that is in use is
777// being unplugged.
778TEST_F(MediaStreamDispatcherHostTest, VideoDeviceUnplugged) {
779  size_t number_of_fake_devices = physical_video_devices_.size();
780  StreamOptions options(true, true);
781  SetupFakeUI(true);
782  GenerateStreamAndWaitForResult(kRenderId, kPageRequestId, options);
783  EXPECT_EQ(host_->audio_devices_.size(), 1u);
784  EXPECT_EQ(host_->video_devices_.size(), 1u);
785
786  media::FakeVideoCaptureDevice::SetNumberOfFakeDevices(0);
787
788  base::RunLoop run_loop;
789  EXPECT_CALL(*host_.get(), OnDeviceStopped(kRenderId))
790      .WillOnce(testing::InvokeWithoutArgs(&run_loop, &base::RunLoop::Quit));
791  media_stream_manager_->OnDevicesChanged(
792      base::SystemMonitor::DEVTYPE_VIDEO_CAPTURE);
793
794  run_loop.Run();
795
796  media::FakeVideoCaptureDevice::SetNumberOfFakeDevices(number_of_fake_devices);
797}
798
799TEST_F(MediaStreamDispatcherHostTest, EnumerateAudioDevices) {
800  EnumerateDevicesAndWaitForResult(kRenderId, kPageRequestId,
801                                   MEDIA_DEVICE_AUDIO_CAPTURE);
802}
803
804TEST_F(MediaStreamDispatcherHostTest, EnumerateVideoDevices) {
805  EnumerateDevicesAndWaitForResult(kRenderId, kPageRequestId,
806                                   MEDIA_DEVICE_VIDEO_CAPTURE);
807}
808
809};  // namespace content
810