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