Home | History | Annotate | Download | only in media
      1 // Copyright (c) 2014 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 "base/process/process_handle.h"
      6 #include "base/strings/string_number_conversions.h"
      7 #include "base/strings/stringprintf.h"
      8 #include "content/browser/media/webrtc_internals.h"
      9 #include "content/browser/web_contents/web_contents_impl.h"
     10 #include "content/public/test/browser_test_utils.h"
     11 #include "content/public/test/content_browser_test_utils.h"
     12 #include "content/shell/browser/shell.h"
     13 #include "content/test/webrtc_content_browsertest_base.h"
     14 #include "media/audio/audio_manager.h"
     15 #include "net/test/embedded_test_server/embedded_test_server.h"
     16 
     17 namespace {
     18 
     19 const int kExpectedConsumerId = 0;
     20 
     21 // Get the ID for the render process host when there should only be one.
     22 bool GetRenderProcessHostId(base::ProcessId* id) {
     23   content::RenderProcessHost::iterator it(
     24       content::RenderProcessHost::AllHostsIterator());
     25   *id = base::GetProcId(it.GetCurrentValue()->GetHandle());
     26   EXPECT_NE(base::kNullProcessId, *id);
     27   if (*id == base::kNullProcessId)
     28     return false;
     29   it.Advance();
     30   EXPECT_TRUE(it.IsAtEnd());
     31   return it.IsAtEnd();
     32 }
     33 
     34 }  // namespace
     35 
     36 namespace content {
     37 
     38 class WebRtcAecDumpBrowserTest : public WebRtcContentBrowserTest {
     39  public:
     40   WebRtcAecDumpBrowserTest() {}
     41   virtual ~WebRtcAecDumpBrowserTest() {}
     42 };
     43 
     44 #if defined(OS_WIN)
     45 #define IntToStringType base::IntToString16
     46 #else
     47 #define IntToStringType base::IntToString
     48 #endif
     49 
     50 #if defined(OS_LINUX) && !defined(OS_CHROMEOS) && defined(ARCH_CPU_ARM_FAMILY)
     51 // Timing out on ARM linux bot: http://crbug.com/238490
     52 #define MAYBE_CallWithAecDump DISABLED_CallWithAecDump
     53 #elif defined(OS_ANDROID) && defined(ADDRESS_SANITIZER)
     54 // Renderer crashes under Android ASAN: https://crbug.com/408496.
     55 #define MAYBE_CallWithAecDump DISABLED_CallWithAecDump
     56 #elif defined(OS_WIN) && !defined(NDEBUG)
     57 // Flaky on Webkit Win7 Debug bot: http://crbug.com/417756
     58 #define MAYBE_CallWithAecDump DISABLED_CallWithAecDump
     59 #else
     60 #define MAYBE_CallWithAecDump CallWithAecDump
     61 #endif
     62 
     63 // This tests will make a complete PeerConnection-based call, verify that
     64 // video is playing for the call, and verify that a non-empty AEC dump file
     65 // exists. The AEC dump is enabled through webrtc-internals. The HTML and
     66 // Javascript is bypassed since it would trigger a file picker dialog. Instead,
     67 // the dialog callback FileSelected() is invoked directly. In fact, there's
     68 // never a webrtc-internals page opened at all since that's not needed.
     69 IN_PROC_BROWSER_TEST_F(WebRtcAecDumpBrowserTest, MAYBE_CallWithAecDump) {
     70   if (!media::AudioManager::Get()->HasAudioOutputDevices()) {
     71     LOG(INFO) << "Missing output devices: skipping test...";
     72     return;
     73   }
     74 
     75   ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
     76 
     77   // We must navigate somewhere first so that the render process is created.
     78   NavigateToURL(shell(), GURL(""));
     79 
     80   base::FilePath dump_file;
     81   ASSERT_TRUE(CreateTemporaryFile(&dump_file));
     82   base::DeleteFile(dump_file, false);
     83 
     84   // This fakes the behavior of another open tab with webrtc-internals, and
     85   // enabling AEC dump in that tab.
     86   WebRTCInternals::GetInstance()->FileSelected(dump_file, -1, NULL);
     87 
     88   GURL url(embedded_test_server()->GetURL("/media/peerconnection-call.html"));
     89   NavigateToURL(shell(), url);
     90   DisableOpusIfOnAndroid();
     91   ExecuteJavascriptAndWaitForOk("call({video: true, audio: true});");
     92 
     93   EXPECT_FALSE(base::PathExists(dump_file));
     94 
     95   // Add file extensions that we expect to be added. The dump name will be
     96   // <temporary path>.<render process id>.<consumer id>, for example
     97   // "/tmp/.com.google.Chrome.Z6UC3P.12345.0".
     98   base::ProcessId render_process_id = base::kNullProcessId;
     99   EXPECT_TRUE(GetRenderProcessHostId(&render_process_id));
    100   dump_file = dump_file.AddExtension(IntToStringType(render_process_id))
    101                        .AddExtension(IntToStringType(kExpectedConsumerId));
    102 
    103   EXPECT_TRUE(base::PathExists(dump_file));
    104   int64 file_size = 0;
    105   EXPECT_TRUE(base::GetFileSize(dump_file, &file_size));
    106   EXPECT_GT(file_size, 0);
    107 
    108   base::DeleteFile(dump_file, false);
    109 }
    110 
    111 // TODO(grunell): Add test for multiple dumps when re-use of
    112 // MediaStreamAudioProcessor in AudioCapturer has been removed.
    113 
    114 #if defined(OS_LINUX) && !defined(OS_CHROMEOS) && defined(ARCH_CPU_ARM_FAMILY)
    115 // Timing out on ARM linux bot: http://crbug.com/238490
    116 #define MAYBE_CallWithAecDumpEnabledThenDisabled DISABLED_CallWithAecDumpEnabledThenDisabled
    117 #elif defined(OS_ANDROID) && defined(ADDRESS_SANITIZER)
    118 // Renderer crashes under Android ASAN: https://crbug.com/408496.
    119 #define MAYBE_CallWithAecDumpEnabledThenDisabled DISABLED_CallWithAecDumpEnabledThenDisabled
    120 #else
    121 #define MAYBE_CallWithAecDumpEnabledThenDisabled CallWithAecDumpEnabledThenDisabled
    122 #endif
    123 
    124 // As above, but enable and disable dump before starting a call. The file should
    125 // be created, but should be empty.
    126 IN_PROC_BROWSER_TEST_F(WebRtcAecDumpBrowserTest,
    127                        MAYBE_CallWithAecDumpEnabledThenDisabled) {
    128   if (!media::AudioManager::Get()->HasAudioOutputDevices()) {
    129     LOG(INFO) << "Missing output devices: skipping test...";
    130     return;
    131   }
    132 
    133   ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
    134 
    135   // We must navigate somewhere first so that the render process is created.
    136   NavigateToURL(shell(), GURL(""));
    137 
    138   base::FilePath dump_file;
    139   ASSERT_TRUE(CreateTemporaryFile(&dump_file));
    140   base::DeleteFile(dump_file, false);
    141 
    142   // This fakes the behavior of another open tab with webrtc-internals, and
    143   // enabling AEC dump in that tab, then disabling it.
    144   WebRTCInternals::GetInstance()->FileSelected(dump_file, -1, NULL);
    145   WebRTCInternals::GetInstance()->DisableAecDump();
    146 
    147   GURL url(embedded_test_server()->GetURL("/media/peerconnection-call.html"));
    148   NavigateToURL(shell(), url);
    149   DisableOpusIfOnAndroid();
    150   ExecuteJavascriptAndWaitForOk("call({video: true, audio: true});");
    151 
    152   // Add file extensions that we expect to be added.
    153   base::ProcessId render_process_id = base::kNullProcessId;
    154   EXPECT_TRUE(GetRenderProcessHostId(&render_process_id));
    155   dump_file = dump_file.AddExtension(IntToStringType(render_process_id))
    156                        .AddExtension(IntToStringType(kExpectedConsumerId));
    157 
    158   EXPECT_FALSE(base::PathExists(dump_file));
    159 
    160   base::DeleteFile(dump_file, false);
    161 }
    162 
    163 #if defined(OS_LINUX) && !defined(OS_CHROMEOS) && defined(ARCH_CPU_ARM_FAMILY)
    164 // Timing out on ARM linux bot: http://crbug.com/238490
    165 #define MAYBE_TwoCallsWithAecDump DISABLED_TwoCallsWithAecDump
    166 #elif defined(OS_ANDROID) && defined(ADDRESS_SANITIZER)
    167 // Renderer crashes under Android ASAN: https://crbug.com/408496.
    168 #define MAYBE_TwoCallsWithAecDump DISABLED_TwoCallsWithAecDump
    169 #else
    170 #define MAYBE_TwoCallsWithAecDump TwoCallsWithAecDump
    171 #endif
    172 
    173 IN_PROC_BROWSER_TEST_F(WebRtcAecDumpBrowserTest, MAYBE_TwoCallsWithAecDump) {
    174   if (!media::AudioManager::Get()->HasAudioOutputDevices()) {
    175     LOG(INFO) << "Missing output devices: skipping test...";
    176     return;
    177   }
    178 
    179   ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
    180 
    181   // We must navigate somewhere first so that the render process is created.
    182   NavigateToURL(shell(), GURL(""));
    183 
    184   // Create a second window.
    185   Shell* shell2 = CreateBrowser();
    186   NavigateToURL(shell2, GURL(""));
    187 
    188   base::FilePath dump_file;
    189   ASSERT_TRUE(CreateTemporaryFile(&dump_file));
    190   base::DeleteFile(dump_file, false);
    191 
    192   // This fakes the behavior of another open tab with webrtc-internals, and
    193   // enabling AEC dump in that tab.
    194   WebRTCInternals::GetInstance()->FileSelected(dump_file, -1, NULL);
    195 
    196   GURL url(embedded_test_server()->GetURL("/media/peerconnection-call.html"));
    197 
    198   NavigateToURL(shell(), url);
    199   NavigateToURL(shell2, url);
    200   ExecuteJavascriptAndWaitForOk("call({video: true, audio: true});");
    201   std::string result;
    202   EXPECT_TRUE(ExecuteScriptAndExtractString(
    203       shell2->web_contents(),
    204       "call({video: true, audio: true});",
    205       &result));
    206   ASSERT_STREQ("OK", result.c_str());
    207 
    208   EXPECT_FALSE(base::PathExists(dump_file));
    209 
    210   RenderProcessHost::iterator it =
    211       content::RenderProcessHost::AllHostsIterator();
    212   for (; !it.IsAtEnd(); it.Advance()) {
    213     base::ProcessId render_process_id =
    214         base::GetProcId(it.GetCurrentValue()->GetHandle());
    215     EXPECT_NE(base::kNullProcessId, render_process_id);
    216 
    217     // Add file extensions that we expect to be added.
    218     base::FilePath unique_dump_file =
    219         dump_file.AddExtension(IntToStringType(render_process_id))
    220                  .AddExtension(IntToStringType(kExpectedConsumerId));
    221 
    222     EXPECT_TRUE(base::PathExists(unique_dump_file));
    223     int64 file_size = 0;
    224     EXPECT_TRUE(base::GetFileSize(unique_dump_file, &file_size));
    225     EXPECT_GT(file_size, 0);
    226 
    227     base::DeleteFile(unique_dump_file, false);
    228   }
    229 }
    230 
    231 }  // namespace content
    232