blob: 56922d8e85162e50334c4f9c7538ab85a709915b [file] [log] [blame]
/*
* Copyright (c) 2012 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 <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#if defined(_WIN32)
#include <conio.h>
#endif
#include "webrtc/voice_engine/test/auto_test/voe_stress_test.h"
#include "webrtc/system_wrappers/include/sleep.h"
#include "webrtc/voice_engine/test/channel_transport/channel_transport.h"
#include "webrtc/voice_engine/test/auto_test/voe_standard_test.h"
#include "webrtc/voice_engine/test/auto_test/voe_test_defines.h"
#include "webrtc/voice_engine/voice_engine_defines.h" // defines build macros
using namespace webrtc;
using namespace test;
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) SleepMs(x);
#endif
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();
VoENetwork* voe_network = _mgr.NetworkPtr();
// 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);
std::unique_ptr<VoiceChannelTransport> voice_channel_transport(
new VoiceChannelTransport(voe_network, 0));
for (i = 0; i < numberOfLoops; ++i) {
voice_channel_transport->SetSendDestination("127.0.0.1", 4800);
voice_channel_transport->SetLocalReceiver(4800);
VALIDATE_STRESS(base->StartReceive(0));
VALIDATE_STRESS(base->StartPlayout(0));
VALIDATE_STRESS(base->StartSend(0));
if (!(i % markInterval))
MARK();
SleepMs(loopSleep);
VALIDATE_STRESS(base->StopSend(0));
VALIDATE_STRESS(base->StopPlayout(0));
VALIDATE_STRESS(base->StopReceive(0));
}
ANL();
VALIDATE_STRESS(voice_channel_transport->SetSendDestination("127.0.0.1",
4800));
VALIDATE_STRESS(voice_channel_transport->SetLocalReceiver(4800));
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 = 100;
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();
SleepMs(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
_ptrExtraApiThread.reset(
new rtc::PlatformThread(RunExtraApi, this, "StressTestExtraApiThread"));
_ptrExtraApiThread->Start();
// 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();
SleepMs(loopSleep);
}
ANL();
// Stop extra thread
_ptrExtraApiThread->Stop();
///////////// 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