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/base/gunit.h" 29 #include "talk/base/thread.h" 30 #include "talk/session/media/call.h" 31 #include "talk/session/media/currentspeakermonitor.h" 32 33 namespace cricket { 34 35 static const uint32 kSsrc1 = 1001; 36 static const uint32 kSsrc2 = 1002; 37 static const uint32 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 kSleepTimeBetweenSwitches = 100; 44 45 class MockCall : public Call { 46 public: 47 MockCall() : Call(NULL) {} 48 49 void EmitAudioMonitor(const AudioInfo& info) { 50 SignalAudioMonitor(this, info); 51 } 52 }; 53 54 class CurrentSpeakerMonitorTest : public testing::Test, 55 public sigslot::has_slots<> { 56 public: 57 CurrentSpeakerMonitorTest() { 58 call_ = new MockCall(); 59 monitor_ = new CurrentSpeakerMonitor(call_, NULL); 60 // Shrink the minimum time betweeen switches to 10 ms so we don't have to 61 // slow down our tests. 62 monitor_->set_min_time_between_switches(kMinTimeBetweenSwitches); 63 monitor_->SignalUpdate.connect(this, &CurrentSpeakerMonitorTest::OnUpdate); 64 current_speaker_ = 0; 65 num_changes_ = 0; 66 monitor_->Start(); 67 } 68 69 ~CurrentSpeakerMonitorTest() { 70 delete monitor_; 71 delete call_; 72 } 73 74 protected: 75 MockCall* call_; 76 CurrentSpeakerMonitor* monitor_; 77 int num_changes_; 78 uint32 current_speaker_; 79 80 void OnUpdate(CurrentSpeakerMonitor* monitor, uint32 current_speaker) { 81 current_speaker_ = current_speaker; 82 num_changes_++; 83 } 84 }; 85 86 static void InitAudioInfo(AudioInfo* info, int input_level, int output_level) { 87 info->input_level = input_level; 88 info->output_level = output_level; 89 } 90 91 TEST_F(CurrentSpeakerMonitorTest, NoActiveStreams) { 92 AudioInfo info; 93 InitAudioInfo(&info, 0, 0); 94 call_->EmitAudioMonitor(info); 95 96 EXPECT_EQ(current_speaker_, 0U); 97 EXPECT_EQ(num_changes_, 0); 98 } 99 100 TEST_F(CurrentSpeakerMonitorTest, MultipleActiveStreams) { 101 AudioInfo info; 102 InitAudioInfo(&info, 0, 0); 103 104 info.active_streams.push_back(std::make_pair(kSsrc1, 3)); 105 info.active_streams.push_back(std::make_pair(kSsrc2, 7)); 106 call_->EmitAudioMonitor(info); 107 108 // No speaker recognized because the initial sample is treated as possibly 109 // just noise and disregarded. 110 EXPECT_EQ(current_speaker_, 0U); 111 EXPECT_EQ(num_changes_, 0); 112 113 info.active_streams.push_back(std::make_pair(kSsrc1, 3)); 114 info.active_streams.push_back(std::make_pair(kSsrc2, 7)); 115 call_->EmitAudioMonitor(info); 116 117 EXPECT_EQ(current_speaker_, kSsrc2); 118 EXPECT_EQ(num_changes_, 1); 119 } 120 121 TEST_F(CurrentSpeakerMonitorTest, RapidSpeakerChange) { 122 AudioInfo info; 123 InitAudioInfo(&info, 0, 0); 124 125 info.active_streams.push_back(std::make_pair(kSsrc1, 3)); 126 info.active_streams.push_back(std::make_pair(kSsrc2, 7)); 127 call_->EmitAudioMonitor(info); 128 129 EXPECT_EQ(current_speaker_, 0U); 130 EXPECT_EQ(num_changes_, 0); 131 132 info.active_streams.push_back(std::make_pair(kSsrc1, 3)); 133 info.active_streams.push_back(std::make_pair(kSsrc2, 7)); 134 call_->EmitAudioMonitor(info); 135 136 EXPECT_EQ(current_speaker_, kSsrc2); 137 EXPECT_EQ(num_changes_, 1); 138 139 info.active_streams.push_back(std::make_pair(kSsrc1, 9)); 140 info.active_streams.push_back(std::make_pair(kSsrc2, 1)); 141 call_->EmitAudioMonitor(info); 142 143 // We expect no speaker change because of the rapid change. 144 EXPECT_EQ(current_speaker_, kSsrc2); 145 EXPECT_EQ(num_changes_, 1); 146 } 147 148 TEST_F(CurrentSpeakerMonitorTest, SpeakerChange) { 149 AudioInfo info; 150 InitAudioInfo(&info, 0, 0); 151 152 info.active_streams.push_back(std::make_pair(kSsrc1, 3)); 153 info.active_streams.push_back(std::make_pair(kSsrc2, 7)); 154 call_->EmitAudioMonitor(info); 155 156 EXPECT_EQ(current_speaker_, 0U); 157 EXPECT_EQ(num_changes_, 0); 158 159 info.active_streams.push_back(std::make_pair(kSsrc1, 3)); 160 info.active_streams.push_back(std::make_pair(kSsrc2, 7)); 161 call_->EmitAudioMonitor(info); 162 163 EXPECT_EQ(current_speaker_, kSsrc2); 164 EXPECT_EQ(num_changes_, 1); 165 166 // Wait so the changes don't come so rapidly. 167 talk_base::Thread::SleepMs(kSleepTimeBetweenSwitches); 168 169 info.active_streams.push_back(std::make_pair(kSsrc1, 9)); 170 info.active_streams.push_back(std::make_pair(kSsrc2, 1)); 171 call_->EmitAudioMonitor(info); 172 173 EXPECT_EQ(current_speaker_, kSsrc1); 174 EXPECT_EQ(num_changes_, 2); 175 } 176 177 TEST_F(CurrentSpeakerMonitorTest, InterwordSilence) { 178 AudioInfo info; 179 InitAudioInfo(&info, 0, 0); 180 181 info.active_streams.push_back(std::make_pair(kSsrc1, 3)); 182 info.active_streams.push_back(std::make_pair(kSsrc2, 7)); 183 call_->EmitAudioMonitor(info); 184 185 EXPECT_EQ(current_speaker_, 0U); 186 EXPECT_EQ(num_changes_, 0); 187 188 info.active_streams.push_back(std::make_pair(kSsrc1, 3)); 189 info.active_streams.push_back(std::make_pair(kSsrc2, 7)); 190 call_->EmitAudioMonitor(info); 191 192 EXPECT_EQ(current_speaker_, kSsrc2); 193 EXPECT_EQ(num_changes_, 1); 194 195 info.active_streams.push_back(std::make_pair(kSsrc1, 3)); 196 info.active_streams.push_back(std::make_pair(kSsrc2, 7)); 197 call_->EmitAudioMonitor(info); 198 199 EXPECT_EQ(current_speaker_, kSsrc2); 200 EXPECT_EQ(num_changes_, 1); 201 202 // Wait so the changes don't come so rapidly. 203 talk_base::Thread::SleepMs(kSleepTimeBetweenSwitches); 204 205 info.active_streams.push_back(std::make_pair(kSsrc1, 3)); 206 info.active_streams.push_back(std::make_pair(kSsrc2, 0)); 207 call_->EmitAudioMonitor(info); 208 209 // Current speaker shouldn't have changed because we treat this as an inter- 210 // word silence. 211 EXPECT_EQ(current_speaker_, kSsrc2); 212 EXPECT_EQ(num_changes_, 1); 213 214 info.active_streams.push_back(std::make_pair(kSsrc1, 3)); 215 info.active_streams.push_back(std::make_pair(kSsrc2, 0)); 216 call_->EmitAudioMonitor(info); 217 218 // Current speaker shouldn't have changed because we treat this as an inter- 219 // word silence. 220 EXPECT_EQ(current_speaker_, kSsrc2); 221 EXPECT_EQ(num_changes_, 1); 222 223 info.active_streams.push_back(std::make_pair(kSsrc1, 3)); 224 info.active_streams.push_back(std::make_pair(kSsrc2, 0)); 225 call_->EmitAudioMonitor(info); 226 227 // At this point, we should have concluded that SSRC2 stopped speaking. 228 EXPECT_EQ(current_speaker_, kSsrc1); 229 EXPECT_EQ(num_changes_, 2); 230 } 231 232 } // namespace cricket 233