1 /* 2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. 3 * 4 * Use of this source code is governed by a BSD-style license 5 * that can be found in the LICENSE file in the root of the source 6 * tree. An additional intellectual property rights grant can be found 7 * in the file PATENTS. All contributing project authors may 8 * be found in the AUTHORS file in the root of the source tree. 9 */ 10 11 // Some ideas of improvements: 12 // Break out common init and maybe terminate to separate function(s). 13 // How much trace should we have enabled? 14 // API error counter, to print info and return -1 if any error. 15 16 #include <assert.h> 17 #include <stdio.h> 18 #include <stdlib.h> 19 #include <string.h> 20 #include <time.h> 21 #if defined(_WIN32) 22 #include <conio.h> 23 #endif 24 25 #include "webrtc/voice_engine/test/auto_test/voe_stress_test.h" 26 27 #include "webrtc/system_wrappers/interface/scoped_ptr.h" 28 #include "webrtc/system_wrappers/interface/sleep.h" 29 #include "webrtc/system_wrappers/interface/thread_wrapper.h" 30 #include "webrtc/test/channel_transport/include/channel_transport.h" 31 #include "webrtc/voice_engine/test/auto_test/voe_standard_test.h" 32 #include "webrtc/voice_engine/test/auto_test/voe_test_defines.h" 33 #include "webrtc/voice_engine/voice_engine_defines.h" // defines build macros 34 35 using namespace webrtc; 36 using namespace test; 37 38 namespace voetest { 39 40 #define VALIDATE_STRESS(expr) \ 41 if (expr) \ 42 { \ 43 printf("Error at line: %i, %s \n", __LINE__, #expr); \ 44 printf("Error code: %i \n", base->LastError()); \ 45 } 46 47 #ifdef _WIN32 48 // Pause if supported 49 #define PAUSE_OR_SLEEP(x) PAUSE; 50 #else 51 // Sleep a bit instead if pause not supported 52 #define PAUSE_OR_SLEEP(x) SleepMs(x); 53 #endif 54 55 int VoEStressTest::DoTest() { 56 int test(-1); 57 while (test != 0) { 58 test = MenuSelection(); 59 switch (test) { 60 case 0: 61 // Quit stress test 62 break; 63 case 1: 64 // All tests 65 StartStopTest(); 66 CreateDeleteChannelsTest(); 67 MultipleThreadsTest(); 68 break; 69 case 2: 70 StartStopTest(); 71 break; 72 case 3: 73 CreateDeleteChannelsTest(); 74 break; 75 case 4: 76 MultipleThreadsTest(); 77 break; 78 default: 79 // Should not be possible 80 printf("Invalid selection! (Test code error)\n"); 81 assert(false); 82 } // switch 83 } // while 84 85 return 0; 86 } 87 88 int VoEStressTest::MenuSelection() { 89 printf("------------------------------------------------\n"); 90 printf("Select stress test\n\n"); 91 printf(" (0) Quit\n"); 92 printf(" (1) All\n"); 93 printf("- - - - - - - - - - - - - - - - - - - - - - - - \n"); 94 printf(" (2) Start/stop\n"); 95 printf(" (3) Create/delete channels\n"); 96 printf(" (4) Multiple threads\n"); 97 98 const int maxMenuSelection = 4; 99 int selection(-1); 100 101 while ((selection < 0) || (selection > maxMenuSelection)) { 102 printf("\n: "); 103 int retval = scanf("%d", &selection); 104 if ((retval != 1) || (selection < 0) || (selection > maxMenuSelection)) { 105 printf("Invalid selection!\n"); 106 } 107 } 108 109 return selection; 110 } 111 112 int VoEStressTest::StartStopTest() { 113 printf("------------------------------------------------\n"); 114 printf("Running start/stop test\n"); 115 printf("------------------------------------------------\n"); 116 117 printf("\nNOTE: this thest will fail after a while if Core audio is used\n"); 118 printf("because MS returns AUDCLNT_E_CPUUSAGE_EXCEEDED (VoE Error 10013).\n"); 119 120 // Get sub-API pointers 121 VoEBase* base = _mgr.BasePtr(); 122 VoENetwork* voe_network = _mgr.NetworkPtr(); 123 124 // Set trace 125 // VALIDATE_STRESS(base->SetTraceFileName( 126 // GetFilename("VoEStressTest_StartStop_trace.txt"))); 127 // VALIDATE_STRESS(base->SetDebugTraceFileName( 128 // GetFilename("VoEStressTest_StartStop_trace_debug.txt"))); 129 // VALIDATE_STRESS(base->SetTraceFilter(kTraceStateInfo | 130 // kTraceWarning | kTraceError | 131 // kTraceCritical | kTraceApiCall | 132 // kTraceMemory | kTraceInfo)); 133 VALIDATE_STRESS(base->Init()); 134 VALIDATE_STRESS(base->CreateChannel()); 135 136 ///////////// Start test ///////////// 137 138 int numberOfLoops(2000); 139 int loopSleep(200); 140 int i(0); 141 int markInterval(20); 142 143 printf("Running %d loops with %d ms sleep. Mark every %d loop. \n", 144 numberOfLoops, loopSleep, markInterval); 145 printf("Test will take approximately %d minutes. \n", 146 numberOfLoops * loopSleep / 1000 / 60 + 1); 147 148 scoped_ptr<VoiceChannelTransport> voice_channel_transport( 149 new VoiceChannelTransport(voe_network, 0)); 150 151 for (i = 0; i < numberOfLoops; ++i) { 152 voice_channel_transport->SetSendDestination("127.0.0.1", 4800); 153 voice_channel_transport->SetLocalReceiver(4800); 154 VALIDATE_STRESS(base->StartReceive(0)); 155 VALIDATE_STRESS(base->StartPlayout(0)); 156 VALIDATE_STRESS(base->StartSend(0)); 157 if (!(i % markInterval)) 158 MARK(); 159 SleepMs(loopSleep); 160 VALIDATE_STRESS(base->StopSend(0)); 161 VALIDATE_STRESS(base->StopPlayout(0)); 162 VALIDATE_STRESS(base->StopReceive(0)); 163 } 164 ANL(); 165 166 VALIDATE_STRESS(voice_channel_transport->SetSendDestination("127.0.0.1", 167 4800)); 168 VALIDATE_STRESS(voice_channel_transport->SetLocalReceiver(4800)); 169 VALIDATE_STRESS(base->StartReceive(0)); 170 VALIDATE_STRESS(base->StartPlayout(0)); 171 VALIDATE_STRESS(base->StartSend(0)); 172 printf("Verify that audio is good. \n"); 173 PAUSE_OR_SLEEP(20000); 174 VALIDATE_STRESS(base->StopSend(0)); 175 VALIDATE_STRESS(base->StopPlayout(0)); 176 VALIDATE_STRESS(base->StopReceive(0)); 177 178 ///////////// End test ///////////// 179 180 181 // Terminate 182 VALIDATE_STRESS(base->DeleteChannel(0)); 183 VALIDATE_STRESS(base->Terminate()); 184 185 printf("Test finished \n"); 186 187 return 0; 188 } 189 190 int VoEStressTest::CreateDeleteChannelsTest() { 191 printf("------------------------------------------------\n"); 192 printf("Running create/delete channels test\n"); 193 printf("------------------------------------------------\n"); 194 195 // Get sub-API pointers 196 VoEBase* base = _mgr.BasePtr(); 197 198 // Set trace 199 // VALIDATE_STRESS(base->SetTraceFileName( 200 // GetFilename("VoEStressTest_CreateChannels_trace.txt"))); 201 // VALIDATE_STRESS(base->SetDebugTraceFileName( 202 // GetFilename("VoEStressTest_CreateChannels_trace_debug.txt"))); 203 // VALIDATE_STRESS(base->SetTraceFilter(kTraceStateInfo | 204 // kTraceWarning | kTraceError | 205 // kTraceCritical | kTraceApiCall | 206 // kTraceMemory | kTraceInfo)); 207 VALIDATE_STRESS(base->Init()); 208 209 ///////////// Start test ///////////// 210 211 int numberOfLoops(10000); 212 int loopSleep(10); 213 int i(0); 214 int markInterval(200); 215 216 printf("Running %d loops with %d ms sleep. Mark every %d loop. \n", 217 numberOfLoops, loopSleep, markInterval); 218 printf("Test will take approximately %d minutes. \n", 219 numberOfLoops * loopSleep / 1000 / 60 + 1); 220 221 // Some possible extensions include: 222 // Different sleep times (fixed or random) or zero. 223 // Start call on all or some channels. 224 // Two parts: first have a slight overweight to creating channels, 225 // then to deleting. (To ensure we hit max channels and go to zero.) 226 // Make sure audio is OK after test has finished. 227 228 // Set up, start with maxChannels/2 channels 229 const int maxChannels = 100; 230 VALIDATE_STRESS(maxChannels < 1); // Should always have at least one channel 231 bool* channelState = new bool[maxChannels]; 232 memset(channelState, 0, maxChannels * sizeof(bool)); 233 int channel(0); 234 int noOfActiveChannels(0); 235 for (i = 0; i < (maxChannels / 2); ++i) { 236 channel = base->CreateChannel(); 237 VALIDATE_STRESS(channel < 0); 238 if (channel >= 0) { 239 channelState[channel] = true; 240 ++noOfActiveChannels; 241 } 242 } 243 srand((unsigned int) time(NULL)); 244 bool action(false); 245 double rnd(0.0); 246 int res(0); 247 248 // Create/delete channels with slight 249 for (i = 0; i < numberOfLoops; ++i) { 250 // Randomize action (create or delete channel) 251 action = rand() <= (RAND_MAX / 2); 252 if (action) { 253 if (noOfActiveChannels < maxChannels) { 254 // Create new channel 255 channel = base->CreateChannel(); 256 VALIDATE_STRESS(channel < 0); 257 if (channel >= 0) { 258 channelState[channel] = true; 259 ++noOfActiveChannels; 260 } 261 } 262 } else { 263 if (noOfActiveChannels > 0) { 264 // Delete random channel that's created [0, maxChannels - 1] 265 do { 266 rnd = static_cast<double> (rand()); 267 channel = static_cast<int> (rnd / 268 (static_cast<double> (RAND_MAX) + 1.0f) * 269 maxChannels); 270 } while (!channelState[channel]); // Must find a created channel 271 272 res = base->DeleteChannel(channel); 273 VALIDATE_STRESS(0 != res); 274 if (0 == res) { 275 channelState[channel] = false; 276 --noOfActiveChannels; 277 } 278 } 279 } 280 281 if (!(i % markInterval)) 282 MARK(); 283 SleepMs(loopSleep); 284 } 285 ANL(); 286 287 delete[] channelState; 288 289 ///////////// End test ///////////// 290 291 292 // Terminate 293 VALIDATE_STRESS(base->Terminate()); // Deletes all channels 294 295 printf("Test finished \n"); 296 297 return 0; 298 } 299 300 int VoEStressTest::MultipleThreadsTest() { 301 printf("------------------------------------------------\n"); 302 printf("Running multiple threads test\n"); 303 printf("------------------------------------------------\n"); 304 305 // Get sub-API pointers 306 VoEBase* base = _mgr.BasePtr(); 307 308 // Set trace 309 // VALIDATE_STRESS(base->SetTraceFileName( 310 // GetFilename("VoEStressTest_MultipleThreads_trace.txt"))); 311 // VALIDATE_STRESS(base->SetDebugTraceFileName( 312 // GetFilename("VoEStressTest_MultipleThreads_trace_debug.txt"))); 313 // VALIDATE_STRESS(base->SetTraceFilter(kTraceStateInfo | 314 // kTraceWarning | kTraceError | 315 // kTraceCritical | kTraceApiCall | 316 // kTraceMemory | kTraceInfo)); 317 318 // Init 319 VALIDATE_STRESS(base->Init()); 320 VALIDATE_STRESS(base->CreateChannel()); 321 322 ///////////// Start test ///////////// 323 324 int numberOfLoops(10000); 325 int loopSleep(0); 326 int i(0); 327 int markInterval(1000); 328 329 printf("Running %d loops with %d ms sleep. Mark every %d loop. \n", 330 numberOfLoops, loopSleep, markInterval); 331 printf("Test will take approximately %d minutes. \n", 332 numberOfLoops * loopSleep / 1000 / 60 + 1); 333 334 srand((unsigned int) time(NULL)); 335 int rnd(0); 336 337 // Start extra thread 338 const char* threadName = "StressTest Extra API Thread"; 339 _ptrExtraApiThread = ThreadWrapper::CreateThread(RunExtraApi, this, 340 kNormalPriority, threadName); 341 unsigned int id(0); 342 VALIDATE_STRESS(!_ptrExtraApiThread->Start(id)); 343 344 // Some possible extensions include: 345 // Add more API calls to randomize 346 // More threads 347 // Different sleep times (fixed or random). 348 // Make sure audio is OK after test has finished. 349 350 // Call random API functions here and in extra thread, ignore any error 351 for (i = 0; i < numberOfLoops; ++i) { 352 // This part should be equal to the marked part in the extra thread 353 // --- BEGIN --- 354 rnd = rand(); 355 if (rnd < (RAND_MAX / 2)) { 356 // Start playout 357 base->StartPlayout(0); 358 } else { 359 // Stop playout 360 base->StopPlayout(0); 361 } 362 // --- END --- 363 364 if (!(i % markInterval)) 365 MARK(); 366 SleepMs(loopSleep); 367 } 368 ANL(); 369 370 // Stop extra thread 371 VALIDATE_STRESS(!_ptrExtraApiThread->Stop()); 372 delete _ptrExtraApiThread; 373 374 ///////////// End test ///////////// 375 376 // Terminate 377 VALIDATE_STRESS(base->Terminate()); // Deletes all channels 378 379 printf("Test finished \n"); 380 381 return 0; 382 } 383 384 // Thread functions 385 386 bool VoEStressTest::RunExtraApi(void* ptr) { 387 return static_cast<VoEStressTest*> (ptr)->ProcessExtraApi(); 388 } 389 390 bool VoEStressTest::ProcessExtraApi() { 391 // Prepare 392 VoEBase* base = _mgr.BasePtr(); 393 int rnd(0); 394 395 // Call random API function, ignore any error 396 397 // This part should be equal to the marked part in the main thread 398 // --- BEGIN --- 399 rnd = rand(); 400 if (rnd < (RAND_MAX / 2)) { 401 // Start playout 402 base->StartPlayout(0); 403 } else { 404 // Stop playout 405 base->StopPlayout(0); 406 } 407 // --- END --- 408 409 return true; 410 } 411 412 } // namespace voetest 413