1 /* 2 * libjingle 3 * Copyright 2004 Google Inc. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright notice, 9 * this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright notice, 11 * this list of conditions and the following disclaimer in the documentation 12 * and/or other materials provided with the distribution. 13 * 3. The name of the author may not be used to endorse or promote products 14 * derived from this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 19 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28 #include "talk/session/media/audiomonitor.h" 29 #include "talk/session/media/currentspeakermonitor.h" 30 #include "webrtc/base/gunit.h" 31 #include "webrtc/base/thread.h" 32 33 namespace cricket { 34 35 static const uint32_t kSsrc1 = 1001; 36 static const uint32_t kSsrc2 = 1002; 37 static const uint32_t kMinTimeBetweenSwitches = 10; 38 // Due to limited system clock resolution, the CurrentSpeakerMonitor may 39 // actually require more or less time between switches than that specified 40 // in the call to set_min_time_between_switches. To be safe, we sleep for 41 // 90 ms more than the min time between switches before checking for a switch. 42 // I am assuming system clocks do not have a coarser resolution than 90 ms. 43 static const uint32_t kSleepTimeBetweenSwitches = 100; 44 45 class CurrentSpeakerMonitorTest : public testing::Test, 46 public sigslot::has_slots<> { 47 public: 48 CurrentSpeakerMonitorTest() { 49 monitor_ = new CurrentSpeakerMonitor(&source_); 50 // Shrink the minimum time betweeen switches to 10 ms so we don't have to 51 // slow down our tests. 52 monitor_->set_min_time_between_switches(kMinTimeBetweenSwitches); 53 monitor_->SignalUpdate.connect(this, &CurrentSpeakerMonitorTest::OnUpdate); 54 current_speaker_ = 0; 55 num_changes_ = 0; 56 monitor_->Start(); 57 } 58 59 ~CurrentSpeakerMonitorTest() { 60 delete monitor_; 61 } 62 63 void SignalAudioMonitor(const AudioInfo& info) { 64 source_.SignalAudioMonitor(&source_, info); 65 } 66 67 protected: 68 AudioSourceContext source_; 69 CurrentSpeakerMonitor* monitor_; 70 int num_changes_; 71 uint32_t current_speaker_; 72 73 void OnUpdate(CurrentSpeakerMonitor* monitor, uint32_t current_speaker) { 74 current_speaker_ = current_speaker; 75 num_changes_++; 76 } 77 }; 78 79 static void InitAudioInfo(AudioInfo* info, int input_level, int output_level) { 80 info->input_level = input_level; 81 info->output_level = output_level; 82 } 83 84 TEST_F(CurrentSpeakerMonitorTest, NoActiveStreams) { 85 AudioInfo info; 86 InitAudioInfo(&info, 0, 0); 87 SignalAudioMonitor(info); 88 89 EXPECT_EQ(current_speaker_, 0U); 90 EXPECT_EQ(num_changes_, 0); 91 } 92 93 TEST_F(CurrentSpeakerMonitorTest, MultipleActiveStreams) { 94 AudioInfo info; 95 InitAudioInfo(&info, 0, 0); 96 97 info.active_streams.push_back(std::make_pair(kSsrc1, 3)); 98 info.active_streams.push_back(std::make_pair(kSsrc2, 7)); 99 SignalAudioMonitor(info); 100 101 // No speaker recognized because the initial sample is treated as possibly 102 // just noise and disregarded. 103 EXPECT_EQ(current_speaker_, 0U); 104 EXPECT_EQ(num_changes_, 0); 105 106 info.active_streams.push_back(std::make_pair(kSsrc1, 3)); 107 info.active_streams.push_back(std::make_pair(kSsrc2, 7)); 108 SignalAudioMonitor(info); 109 110 EXPECT_EQ(current_speaker_, kSsrc2); 111 EXPECT_EQ(num_changes_, 1); 112 } 113 114 // See: https://code.google.com/p/webrtc/issues/detail?id=2409 115 TEST_F(CurrentSpeakerMonitorTest, DISABLED_RapidSpeakerChange) { 116 AudioInfo info; 117 InitAudioInfo(&info, 0, 0); 118 119 info.active_streams.push_back(std::make_pair(kSsrc1, 3)); 120 info.active_streams.push_back(std::make_pair(kSsrc2, 7)); 121 SignalAudioMonitor(info); 122 123 EXPECT_EQ(current_speaker_, 0U); 124 EXPECT_EQ(num_changes_, 0); 125 126 info.active_streams.push_back(std::make_pair(kSsrc1, 3)); 127 info.active_streams.push_back(std::make_pair(kSsrc2, 7)); 128 SignalAudioMonitor(info); 129 130 EXPECT_EQ(current_speaker_, kSsrc2); 131 EXPECT_EQ(num_changes_, 1); 132 133 info.active_streams.push_back(std::make_pair(kSsrc1, 9)); 134 info.active_streams.push_back(std::make_pair(kSsrc2, 1)); 135 SignalAudioMonitor(info); 136 137 // We expect no speaker change because of the rapid change. 138 EXPECT_EQ(current_speaker_, kSsrc2); 139 EXPECT_EQ(num_changes_, 1); 140 } 141 142 TEST_F(CurrentSpeakerMonitorTest, SpeakerChange) { 143 AudioInfo info; 144 InitAudioInfo(&info, 0, 0); 145 146 info.active_streams.push_back(std::make_pair(kSsrc1, 3)); 147 info.active_streams.push_back(std::make_pair(kSsrc2, 7)); 148 SignalAudioMonitor(info); 149 150 EXPECT_EQ(current_speaker_, 0U); 151 EXPECT_EQ(num_changes_, 0); 152 153 info.active_streams.push_back(std::make_pair(kSsrc1, 3)); 154 info.active_streams.push_back(std::make_pair(kSsrc2, 7)); 155 SignalAudioMonitor(info); 156 157 EXPECT_EQ(current_speaker_, kSsrc2); 158 EXPECT_EQ(num_changes_, 1); 159 160 // Wait so the changes don't come so rapidly. 161 rtc::Thread::SleepMs(kSleepTimeBetweenSwitches); 162 163 info.active_streams.push_back(std::make_pair(kSsrc1, 9)); 164 info.active_streams.push_back(std::make_pair(kSsrc2, 1)); 165 SignalAudioMonitor(info); 166 167 EXPECT_EQ(current_speaker_, kSsrc1); 168 EXPECT_EQ(num_changes_, 2); 169 } 170 171 TEST_F(CurrentSpeakerMonitorTest, InterwordSilence) { 172 AudioInfo info; 173 InitAudioInfo(&info, 0, 0); 174 175 info.active_streams.push_back(std::make_pair(kSsrc1, 3)); 176 info.active_streams.push_back(std::make_pair(kSsrc2, 7)); 177 SignalAudioMonitor(info); 178 179 EXPECT_EQ(current_speaker_, 0U); 180 EXPECT_EQ(num_changes_, 0); 181 182 info.active_streams.push_back(std::make_pair(kSsrc1, 3)); 183 info.active_streams.push_back(std::make_pair(kSsrc2, 7)); 184 SignalAudioMonitor(info); 185 186 EXPECT_EQ(current_speaker_, kSsrc2); 187 EXPECT_EQ(num_changes_, 1); 188 189 info.active_streams.push_back(std::make_pair(kSsrc1, 3)); 190 info.active_streams.push_back(std::make_pair(kSsrc2, 7)); 191 SignalAudioMonitor(info); 192 193 EXPECT_EQ(current_speaker_, kSsrc2); 194 EXPECT_EQ(num_changes_, 1); 195 196 // Wait so the changes don't come so rapidly. 197 rtc::Thread::SleepMs(kSleepTimeBetweenSwitches); 198 199 info.active_streams.push_back(std::make_pair(kSsrc1, 3)); 200 info.active_streams.push_back(std::make_pair(kSsrc2, 0)); 201 SignalAudioMonitor(info); 202 203 // Current speaker shouldn't have changed because we treat this as an inter- 204 // word silence. 205 EXPECT_EQ(current_speaker_, kSsrc2); 206 EXPECT_EQ(num_changes_, 1); 207 208 info.active_streams.push_back(std::make_pair(kSsrc1, 3)); 209 info.active_streams.push_back(std::make_pair(kSsrc2, 0)); 210 SignalAudioMonitor(info); 211 212 // Current speaker shouldn't have changed because we treat this as an inter- 213 // word silence. 214 EXPECT_EQ(current_speaker_, kSsrc2); 215 EXPECT_EQ(num_changes_, 1); 216 217 info.active_streams.push_back(std::make_pair(kSsrc1, 3)); 218 info.active_streams.push_back(std::make_pair(kSsrc2, 0)); 219 SignalAudioMonitor(info); 220 221 // At this point, we should have concluded that SSRC2 stopped speaking. 222 EXPECT_EQ(current_speaker_, kSsrc1); 223 EXPECT_EQ(num_changes_, 2); 224 } 225 226 } // namespace cricket 227