2 * Copyright 2008, Google Inc.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
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
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
45 #if !defined(STANDALONE)
46 #include <nacl/nacl_av.h>
48 #if defined(STANDALONE)
49 #include "native_client/common/standalone.h"
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
;
62 int g_frequency
= 1000;
63 int g_amplitude
= 16000;
68 volatile bool running
;
69 volatile bool enable_output
;
72 pthread_mutex_t start_barrier
;
75 int global_audio_thread_exit
= 0;
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
];
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
))
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
118 from_silence
= false;
120 } else if ((!last_enable
) && (now_enable
)) {
121 // starting up, reset sine wave clock
129 for (size_t i
= 0; i
< count
; i
+= 2) {
131 int16_t wave
= static_cast<int16_t>(sinf(fclock
) * amplitude
);
136 // increment fclock by 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
144 // ramp down amplitude
145 amplitude
= grad
* g_amplitude
;
146 // if the wave gets close to 0, cut it
147 if (abs(wave
) < kMinAmplitudeCutoff
)
149 } else if (from_silence
) {
152 amplitude
= (1.0f
- grad
) * g_amplitude
;
156 printf("Audio thread: Shutting down...\n");
157 global_audio_thread_exit
++;
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
) {
168 // init basic audio controller
169 ac
->uid
= 0xC0DE5EED;
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
);
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();
186 // initialize multimedia
187 r
= nacl_multimedia_init(NACL_SUBSYSTEM_AUDIO
);
189 printf("Main thread: Couldn't init multimedia w/ audio\n");
191 pthread_mutex_unlock(&ac
->start_barrier
);
192 pthread_join(ac
->thread_id
, &thread_result
);
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
);
201 printf("Main thread: Couldn't init nacl audio\n");
202 nacl_multimedia_shutdown();
203 pthread_mutex_unlock(&ac
->start_barrier
);
205 pthread_join(ac
->thread_id
, &thread_result
);
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
);
217 void Sleep(double x
) {
218 double start
, current
;
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");
235 ac
->enable_output
= true;
236 Sleep(static_cast<float>(g_duration
));
237 ac
->enable_output
= false;
242 void ShutdownAudioDemo(AudioControl
*ac
) {
244 // tell audio thread to exit
246 pthread_join(ac
->thread_id
, &thread_result
);
247 nacl_audio_shutdown();
248 nacl_multimedia_shutdown();
249 printf("Main thread: Exited gracefully\n");
255 if (0 == InitAudioDemo(&ac
, kDesiredSampleRate
)) {
257 ShutdownAudioDemo(&ac
);
258 printf("TEST PASSED\n");
261 printf("Main thread: Unable to init audio\n");
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
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
)) {
278 } else if (argv
[i
] == strstr(argv
[i
], "-a")) {
279 int a
= atoi(&argv
[i
][2]);
280 if ((a
> 0) && (a
< kMaxAmplitude
)) {
283 } else if (argv
[i
] == strstr(argv
[i
], "-f")) {
284 int f
= atoi(&argv
[i
][2]);
285 if ((f
> 0) && (f
< kMaxFrequency
)) {
288 } else if (argv
[i
] == strstr(argv
[i
], "-c")) {
289 int c
= atoi(&argv
[i
][2]);
290 if ((c
> 0) && (c
< kMaxDemoLoop
)) {
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");
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
);