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
34 using namespace webrtc;
35 using namespace test;
36
37 namespace 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
DoTest()54 int 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
MenuSelection()87 int 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
StartStopTest()111 int 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
CreateDeleteChannelsTest()189 int 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
MultipleThreadsTest()299 int 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
RunExtraApi(void * ptr)382 bool VoEStressTest::RunExtraApi(void* ptr) {
383 return static_cast<VoEStressTest*> (ptr)->ProcessExtraApi();
384 }
385
ProcessExtraApi()386 bool 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