Add ncval-stubout tool
[nativeclient.git] / tests / tone / tone.cc
blobdc6096b6bc0b40fdd8a09719eaa25d113298e986
1 /*
2 * Copyright 2008, Google Inc.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met:
8 *
9 * * Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * * Redistributions in binary form must reproduce the above
12 * copyright notice, this list of conditions and the following disclaimer
13 * in the documentation and/or other materials provided with the
14 * distribution.
15 * * Neither the name of Google Inc. nor the names of its
16 * contributors may be used to endorse or promote products derived from
17 * this software without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 // NaCl audio tone demo
33 // render a simple tone to the audio device for a couple seconds
35 #include <errno.h>
36 #include <math.h>
37 #include <pthread.h>
38 #include <stdint.h>
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <string.h>
42 #include <time.h>
43 #include <unistd.h>
44 #include <sys/time.h>
45 #if !defined(STANDALONE)
46 #include <nacl/nacl_av.h>
47 #endif
48 #if defined(STANDALONE)
49 #include "native_client/common/standalone.h"
50 #endif
52 const int kMaxDuration = 60;
53 const int kMaxFrequency = 24000;
54 const int kMaxAmplitude = 32000;
55 const int kSampling = 48000;
56 const int kDesiredSampleRate = 4096;
57 const int kMaxDemoLoop = 500;
58 const int kMinAmplitudeCutoff = 200;
59 const float kRampTime = 0.25f;
60 const float kPI = 3.14159265f;
61 int g_duration = 3;
62 int g_frequency = 1000;
63 int g_amplitude = 16000;
64 int g_loopcount = 1;
66 struct AudioControl {
67 int uid;
68 volatile bool running;
69 volatile bool enable_output;
70 pthread_t thread_id;
71 int sample_rate;
72 pthread_mutex_t start_barrier;
75 int global_audio_thread_exit = 0;
78 double gettimed() {
79 timeval tv;
80 double sec, usec;
81 const float kUSec = 1.e6f;
82 gettimeofday(&tv, NULL);
83 sec = static_cast<double>(tv.tv_sec);
84 usec = static_cast<double>(tv.tv_usec);
85 return (sec * kUSec + usec) / kUSec;
89 // pumps the audio via nacl_audio_update
90 // this is a very simple sine wave generator, with no mixing
91 void* AudioThread(void *userdata) {
92 AudioControl *ac = reinterpret_cast<AudioControl *>(userdata);
93 int16_t sbuffer[kNaClAudioBufferLength];
94 size_t count = 0;
95 float delta = static_cast<float>(g_frequency) * (2.0f * kPI / kSampling);
96 bool to_silence = false;
97 bool from_silence = false;
98 float grad = 0.0f, fclock = 0.0f, amplitude = 0.0f;
100 printf("Audio thread: Starting up...\n");
101 printf("Audio thread: uid = 0x%0X\n", ac->uid);
102 printf("Audio thread: running = %s\n", ac->running ? "yes" : "no");
103 // This lock/unlock will stall until main thread releases lock.
104 // We do this because we can't call nacl_audio_update until
105 // after the audio system has been successfully initialized.
106 pthread_mutex_lock(&ac->start_barrier);
107 pthread_mutex_unlock(&ac->start_barrier);
108 printf("Audio thread: Entering output loop\n");
109 while (ac->running) {
110 bool last_enable = ac->enable_output;
111 if (0 != nacl_audio_stream(sbuffer, &count))
112 break;
113 bool now_enable = ac->enable_output;
114 // eliminate audio pops at post-startup and pre-shutdown
115 if ((last_enable) && (!now_enable)) {
116 // shutting down to silence
117 to_silence = true;
118 from_silence = false;
119 grad = 1.0f;
120 } else if ((!last_enable) && (now_enable)) {
121 // starting up, reset sine wave clock
122 fclock = 0.0f;
123 from_silence = true;
124 to_silence = false;
125 grad = 1.0f;
127 // output to buffer
128 count = count / 2;
129 for (size_t i = 0; i < count; i += 2) {
130 // sine wave
131 int16_t wave = static_cast<int16_t>(sinf(fclock) * amplitude);
132 // left channel
133 sbuffer[i+0] = wave;
134 // right channel
135 sbuffer[i+1] = wave;
136 // increment fclock by delta
137 fclock += delta;
138 // keep fclock within -2PI..2PI
139 if (fclock > 2.0f * kPI)
140 fclock = fclock - (2.0f * kPI);
141 // ramp up / ramp down amplitude in transitions
142 if (to_silence) {
143 grad *= 0.99f;
144 // ramp down amplitude
145 amplitude = grad * g_amplitude;
146 // if the wave gets close to 0, cut it
147 if (abs(wave) < kMinAmplitudeCutoff)
148 grad = 0.0f;
149 } else if (from_silence) {
150 grad *= 0.99f;
151 // ramp up amplitude
152 amplitude = (1.0f - grad) * g_amplitude;
156 printf("Audio thread: Shutting down...\n");
157 global_audio_thread_exit++;
158 return NULL;
162 // Initializes the audio system with the desired sample rate.
163 // (The audio system might choose a different sample rate.)
164 int InitAudioDemo(AudioControl *ac, int desired_samples) {
165 int r;
166 void *thread_result;
168 // init basic audio controller
169 ac->uid = 0xC0DE5EED;
170 ac->running = true;
171 ac->enable_output = false;
172 pthread_mutex_init(&ac->start_barrier, NULL);
173 pthread_mutex_lock(&ac->start_barrier);
175 // create audio thread
176 printf("Main thread: Spawning audio thread...\n");
177 int p = pthread_create(&ac->thread_id, NULL, AudioThread, ac);
178 if (0 != p) {
179 printf("Main thread: Unable to create audio thread!\n");
180 pthread_mutex_unlock(&ac->start_barrier);
181 nacl_audio_shutdown();
182 nacl_multimedia_shutdown();
183 return -1;
186 // initialize multimedia
187 r = nacl_multimedia_init(NACL_SUBSYSTEM_AUDIO);
188 if (r != 0) {
189 printf("Main thread: Couldn't init multimedia w/ audio\n");
190 ac->running = false;
191 pthread_mutex_unlock(&ac->start_barrier);
192 pthread_join(ac->thread_id, &thread_result);
193 return -1;
196 // Open the audio device
197 printf("Main thread: Desired samples: %d\n", desired_samples);
198 r = nacl_audio_init(NACL_AUDIO_FORMAT_STEREO_48K,
199 desired_samples, &ac->sample_rate);
200 if (r != 0) {
201 printf("Main thread: Couldn't init nacl audio\n");
202 nacl_multimedia_shutdown();
203 pthread_mutex_unlock(&ac->start_barrier);
204 ac->running = false;
205 pthread_join(ac->thread_id, &thread_result);
206 return -1;
208 printf("Main thread: Obtained samples: %d\n", ac->sample_rate);
210 // Audio thread can go ahead and start now
211 pthread_mutex_unlock(&ac->start_barrier);
213 return 0;
217 void Sleep(double x) {
218 double start, current;
219 start = gettimed();
220 while (true) {
221 current = gettimed();
222 if ((current - start) > x) break;
227 // Runs the demo loop for a few seconds...
228 void RunAudioDemo(AudioControl *ac) {
229 // the audio is being continuously output by the AudioThread.
230 // So we can just wait g_duration seconds here and do nothing...
231 // (we'll be rude and ask for timeofday over and over
232 // to exercise the cpu and memory while audio is playing.)
233 printf("Main thread: Doing something for a few seconds\n");
234 Sleep(0.2f);
235 ac->enable_output = true;
236 Sleep(static_cast<float>(g_duration));
237 ac->enable_output = false;
238 Sleep(0.2f);
242 void ShutdownAudioDemo(AudioControl *ac) {
243 void *thread_result;
244 // tell audio thread to exit
245 ac->running = false;
246 pthread_join(ac->thread_id, &thread_result);
247 nacl_audio_shutdown();
248 nacl_multimedia_shutdown();
249 printf("Main thread: Exited gracefully\n");
253 int ToneTest() {
254 AudioControl ac;
255 if (0 == InitAudioDemo(&ac, kDesiredSampleRate)) {
256 RunAudioDemo(&ac);
257 ShutdownAudioDemo(&ac);
258 printf("TEST PASSED\n");
259 return 0;
260 } else {
261 printf("Main thread: Unable to init audio\n");
262 return -1;
267 // If user specifies options on cmd line, parse them
268 // here and update global settings as needed.
269 void ParseCmdLineArgs(int argc, char **argv) {
270 // look for cmd line args
271 if (argc > 1) {
272 for (int i = 1; i < argc; ++i) {
273 if (argv[i] == strstr(argv[i], "-d")) {
274 int d = atoi(&argv[i][2]);
275 if ((d > 0) && (d < kMaxDuration)) {
276 g_duration = d;
278 } else if (argv[i] == strstr(argv[i], "-a")) {
279 int a = atoi(&argv[i][2]);
280 if ((a > 0) && (a < kMaxAmplitude)) {
281 g_amplitude = a;
283 } else if (argv[i] == strstr(argv[i], "-f")) {
284 int f = atoi(&argv[i][2]);
285 if ((f > 0) && (f < kMaxFrequency)) {
286 g_frequency = f;
288 } else if (argv[i] == strstr(argv[i], "-c")) {
289 int c = atoi(&argv[i][2]);
290 if ((c > 0) && (c < kMaxDemoLoop)) {
291 g_loopcount = c;
293 } else {
294 printf("Tone SDL Demo\n");
295 printf("usage: -f<n> output tone at frequency n.\n");
296 printf(" -a<n> amplitude\n");
297 printf(" -d<n> duration of n seconds.\n");
298 printf(" -c<n> demo loop count.\n");
299 printf(" --help show this screen.\n");
300 exit(0);
307 // Parses cmd line options, initializes surface, runs the demo & shuts down.
308 int main(int argc, char **argv) {
309 ParseCmdLineArgs(argc, argv);
310 for (int i = 0; i < g_loopcount; ++i) {
311 printf("Test %d, %d:\n", i, global_audio_thread_exit);
312 ToneTest();
314 return 0;