Home | History | Annotate | Download | only in auto_test
      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