blob: b7098ecdfbffa07c8767958762a6c32f61a75aac [file] [log] [blame]
/*
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
// Some ideas of improvements:
// Break out common init and maybe terminate to separate function(s).
// How much trace should we have enabled?
// API error counter, to print info and return -1 if any error.
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <cassert>
#if defined(_WIN32)
#include <conio.h>
#endif
#include "voe_stress_test.h"
#include "voe_standard_test.h"
#include "../../source/voice_engine_defines.h" // defines build macros
#include "thread_wrapper.h"
using namespace webrtc;
namespace voetest {
#define VALIDATE_STRESS(expr) \
if (expr) \
{ \
printf("Error at line: %i, %s \n", __LINE__, #expr); \
printf("Error code: %i \n", base->LastError()); \
}
#ifdef _WIN32
// Pause if supported
#define PAUSE_OR_SLEEP(x) PAUSE;
#else
// Sleep a bit instead if pause not supported
#define PAUSE_OR_SLEEP(x) SLEEP(x);
#endif
extern char* GetFilename(char* filename);
extern const char* GetFilename(const char* filename);
extern int GetResource(char* resource, char* dest, int destLen);
extern char* GetResource(char* resource);
extern const char* GetResource(const char* resource);
const char* VoEStressTest::_key = "====YUtFWRAAAAADBtIHgAAAAAEAAAAcAAAAAQBHU0ds"
"b2JhbCBJUCBTb3VuZAAC\nAAAAIwAAAExpY2Vuc2VkIHRvIE5vcnRlbCBOZXR3cm9rcwAAAAA"
"xAAAAZxZ7/u0M\niFYyTwSwko5Uutf7mh8S0O4rYZYTFidbzQeuGonuL17F/2oD/2pfDp3jL4"
"Rf3z/A\nnlJsEJgEtASkDNFuwLILjGY0pzjjAYQp3pCl6z6k2MtE06AirdjGLYCjENpq/opX"
"\nOrs3sIuwdYK5va/aFcsjBDmlsGCUM48RDYG9s23bIHYafXUC4ofOaubbZPWiPTmL\nEVJ8WH"
"4F9pgNjALc14oJXfON7r/3\n=EsLx";
int VoEStressTest::DoTest() {
int test(-1);
while (test != 0) {
test = MenuSelection();
switch (test) {
case 0:
// Quit stress test
break;
case 1:
// All tests
StartStopTest();
CreateDeleteChannelsTest();
MultipleThreadsTest();
break;
case 2:
StartStopTest();
break;
case 3:
CreateDeleteChannelsTest();
break;
case 4:
MultipleThreadsTest();
break;
default:
// Should not be possible
printf("Invalid selection! (Test code error)\n");
assert(false);
} // switch
} // while
return 0;
}
int VoEStressTest::MenuSelection() {
printf("------------------------------------------------\n");
printf("Select stress test\n\n");
printf(" (0) Quit\n");
printf(" (1) All\n");
printf("- - - - - - - - - - - - - - - - - - - - - - - - \n");
printf(" (2) Start/stop\n");
printf(" (3) Create/delete channels\n");
printf(" (4) Multiple threads\n");
const int maxMenuSelection = 4;
int selection(-1);
while ((selection < 0) || (selection > maxMenuSelection)) {
printf("\n: ");
int retval = scanf("%d", &selection);
if ((retval != 1) || (selection < 0) || (selection > maxMenuSelection)) {
printf("Invalid selection!\n");
}
}
return selection;
}
int VoEStressTest::StartStopTest() {
printf("------------------------------------------------\n");
printf("Running start/stop test\n");
printf("------------------------------------------------\n");
printf("\nNOTE: this thest will fail after a while if Core audio is used\n");
printf("because MS returns AUDCLNT_E_CPUUSAGE_EXCEEDED (VoE Error 10013).\n");
// Get sub-API pointers
VoEBase* base = _mgr.BasePtr();
// Set trace
// VALIDATE_STRESS(base->SetTraceFileName(
// GetFilename("VoEStressTest_StartStop_trace.txt")));
// VALIDATE_STRESS(base->SetDebugTraceFileName(
// GetFilename("VoEStressTest_StartStop_trace_debug.txt")));
// VALIDATE_STRESS(base->SetTraceFilter(kTraceStateInfo |
// kTraceWarning | kTraceError |
// kTraceCritical | kTraceApiCall |
// kTraceMemory | kTraceInfo));
VALIDATE_STRESS(base->Init());
VALIDATE_STRESS(base->CreateChannel());
///////////// Start test /////////////
int numberOfLoops(2000);
int loopSleep(200);
int i(0);
int markInterval(20);
printf("Running %d loops with %d ms sleep. Mark every %d loop. \n",
numberOfLoops, loopSleep, markInterval);
printf("Test will take approximately %d minutes. \n",
numberOfLoops * loopSleep / 1000 / 60 + 1);
for (i = 0; i < numberOfLoops; ++i) {
VALIDATE_STRESS(base->SetLocalReceiver(0, 4800));
VALIDATE_STRESS(base->SetSendDestination(0, 4800, "127.0.0.1"));
VALIDATE_STRESS(base->StartReceive(0));
VALIDATE_STRESS(base->StartPlayout(0));
VALIDATE_STRESS(base->StartSend(0));
if (!(i % markInterval))
MARK();
SLEEP(loopSleep);
VALIDATE_STRESS(base->StopSend(0));
VALIDATE_STRESS(base->StopPlayout(0));
VALIDATE_STRESS(base->StopReceive(0));
}
ANL();
VALIDATE_STRESS(base->SetLocalReceiver(0, 4800));
VALIDATE_STRESS(base->SetSendDestination(0, 4800, "127.0.0.1"));
VALIDATE_STRESS(base->StartReceive(0));
VALIDATE_STRESS(base->StartPlayout(0));
VALIDATE_STRESS(base->StartSend(0));
printf("Verify that audio is good. \n");
PAUSE_OR_SLEEP(20000);
VALIDATE_STRESS(base->StopSend(0));
VALIDATE_STRESS(base->StopPlayout(0));
VALIDATE_STRESS(base->StopReceive(0));
///////////// End test /////////////
// Terminate
VALIDATE_STRESS(base->DeleteChannel(0));
VALIDATE_STRESS(base->Terminate());
printf("Test finished \n");
return 0;
}
int VoEStressTest::CreateDeleteChannelsTest() {
printf("------------------------------------------------\n");
printf("Running create/delete channels test\n");
printf("------------------------------------------------\n");
// Get sub-API pointers
VoEBase* base = _mgr.BasePtr();
// Set trace
// VALIDATE_STRESS(base->SetTraceFileName(
// GetFilename("VoEStressTest_CreateChannels_trace.txt")));
// VALIDATE_STRESS(base->SetDebugTraceFileName(
// GetFilename("VoEStressTest_CreateChannels_trace_debug.txt")));
// VALIDATE_STRESS(base->SetTraceFilter(kTraceStateInfo |
// kTraceWarning | kTraceError |
// kTraceCritical | kTraceApiCall |
// kTraceMemory | kTraceInfo));
VALIDATE_STRESS(base->Init());
///////////// Start test /////////////
int numberOfLoops(10000);
int loopSleep(10);
int i(0);
int markInterval(200);
printf("Running %d loops with %d ms sleep. Mark every %d loop. \n",
numberOfLoops, loopSleep, markInterval);
printf("Test will take approximately %d minutes. \n",
numberOfLoops * loopSleep / 1000 / 60 + 1);
// Some possible extensions include:
// Different sleep times (fixed or random) or zero.
// Start call on all or some channels.
// Two parts: first have a slight overweight to creating channels,
// then to deleting. (To ensure we hit max channels and go to zero.)
// Make sure audio is OK after test has finished.
// Set up, start with maxChannels/2 channels
const int maxChannels = base->MaxNumOfChannels();
VALIDATE_STRESS(maxChannels < 1); // Should always have at least one channel
bool* channelState = new bool[maxChannels];
memset(channelState, 0, maxChannels * sizeof(bool));
int channel(0);
int noOfActiveChannels(0);
for (i = 0; i < (maxChannels / 2); ++i) {
channel = base->CreateChannel();
VALIDATE_STRESS(channel < 0);
if (channel >= 0) {
channelState[channel] = true;
++noOfActiveChannels;
}
}
srand((unsigned int) time(NULL));
bool action(false);
double rnd(0.0);
int res(0);
// Create/delete channels with slight
for (i = 0; i < numberOfLoops; ++i) {
// Randomize action (create or delete channel)
action = rand() <= (RAND_MAX / 2);
if (action) {
if (noOfActiveChannels < maxChannels) {
// Create new channel
channel = base->CreateChannel();
VALIDATE_STRESS(channel < 0);
if (channel >= 0) {
channelState[channel] = true;
++noOfActiveChannels;
}
}
} else {
if (noOfActiveChannels > 0) {
// Delete random channel that's created [0, maxChannels - 1]
do {
rnd = static_cast<double> (rand());
channel = static_cast<int> (rnd /
(static_cast<double> (RAND_MAX) + 1.0f) *
maxChannels);
} while (!channelState[channel]); // Must find a created channel
res = base->DeleteChannel(channel);
VALIDATE_STRESS(0 != res);
if (0 == res) {
channelState[channel] = false;
--noOfActiveChannels;
}
}
}
if (!(i % markInterval))
MARK();
SLEEP(loopSleep);
}
ANL();
delete[] channelState;
///////////// End test /////////////
// Terminate
VALIDATE_STRESS(base->Terminate()); // Deletes all channels
printf("Test finished \n");
return 0;
}
int VoEStressTest::MultipleThreadsTest() {
printf("------------------------------------------------\n");
printf("Running multiple threads test\n");
printf("------------------------------------------------\n");
// Get sub-API pointers
VoEBase* base = _mgr.BasePtr();
// Set trace
// VALIDATE_STRESS(base->SetTraceFileName(
// GetFilename("VoEStressTest_MultipleThreads_trace.txt")));
// VALIDATE_STRESS(base->SetDebugTraceFileName(
// GetFilename("VoEStressTest_MultipleThreads_trace_debug.txt")));
// VALIDATE_STRESS(base->SetTraceFilter(kTraceStateInfo |
// kTraceWarning | kTraceError |
// kTraceCritical | kTraceApiCall |
// kTraceMemory | kTraceInfo));
// Init
VALIDATE_STRESS(base->Init());
VALIDATE_STRESS(base->CreateChannel());
///////////// Start test /////////////
int numberOfLoops(10000);
int loopSleep(0);
int i(0);
int markInterval(1000);
printf("Running %d loops with %d ms sleep. Mark every %d loop. \n",
numberOfLoops, loopSleep, markInterval);
printf("Test will take approximately %d minutes. \n",
numberOfLoops * loopSleep / 1000 / 60 + 1);
srand((unsigned int) time(NULL));
int rnd(0);
// Start extra thread
const char* threadName = "StressTest Extra API Thread";
_ptrExtraApiThread = ThreadWrapper::CreateThread(RunExtraApi, this,
kNormalPriority, threadName);
unsigned int id(0);
VALIDATE_STRESS(!_ptrExtraApiThread->Start(id));
// Some possible extensions include:
// Add more API calls to randomize
// More threads
// Different sleep times (fixed or random).
// Make sure audio is OK after test has finished.
// Call random API functions here and in extra thread, ignore any error
for (i = 0; i < numberOfLoops; ++i) {
// This part should be equal to the marked part in the extra thread
// --- BEGIN ---
rnd = rand();
if (rnd < (RAND_MAX / 2)) {
// Start playout
base->StartPlayout(0);
} else {
// Stop playout
base->StopPlayout(0);
}
// --- END ---
if (!(i % markInterval))
MARK();
SLEEP(loopSleep);
}
ANL();
// Stop extra thread
VALIDATE_STRESS(!_ptrExtraApiThread->Stop());
delete _ptrExtraApiThread;
///////////// End test /////////////
// Terminate
VALIDATE_STRESS(base->Terminate()); // Deletes all channels
printf("Test finished \n");
return 0;
}
// Thread functions
bool VoEStressTest::RunExtraApi(void* ptr) {
return static_cast<VoEStressTest*> (ptr)->ProcessExtraApi();
}
bool VoEStressTest::ProcessExtraApi() {
// Prepare
VoEBase* base = _mgr.BasePtr();
int rnd(0);
// Call random API function, ignore any error
// This part should be equal to the marked part in the main thread
// --- BEGIN ---
rnd = rand();
if (rnd < (RAND_MAX / 2)) {
// Start playout
base->StartPlayout(0);
} else {
// Stop playout
base->StopPlayout(0);
}
// --- END ---
return true;
}
} // namespace voetest