imcplugin demo: Extend to support stat() call
[nativeclient.git] / service_runtime / nacl_bottom_half.c
blobebb3e48b477b1f07223c4293c994a05a7265307b
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.
33 * NaCl service runtime, bottom half routines for video.
36 #include <string.h>
37 #include "native_client/service_runtime/nacl_app_thread.h"
38 #include "native_client/service_runtime/nacl_closure.h"
39 #include "native_client/service_runtime/nacl_log.h"
40 #include "native_client/service_runtime/nacl_sync.h"
41 #include "native_client/service_runtime/nacl_sync_checked.h"
42 #include "native_client/service_runtime/nacl_sync_queue.h"
43 #include "native_client/service_runtime/sel_ldr.h"
45 #include "native_client/service_runtime/include/sys/errno.h"
47 #if defined(HAVE_SDL)
48 # include <SDL.h>
49 # include "native_client/service_runtime/include/sys/audio_video.h"
50 #endif
52 int NaClClosureResultCtor(struct NaClClosureResult *self)
54 self->result_valid = 0;
55 self->rv = NULL;
56 if (!NaClMutexCtor(&self->mu)) {
57 return 0;
59 if (!NaClCondVarCtor(&self->cv)) {
60 NaClMutexDtor(&self->mu);
61 return 0;
63 return 1;
66 void NaClClosureResultDtor(struct NaClClosureResult *self)
68 NaClMutexDtor(&self->mu);
69 NaClCondVarDtor(&self->cv);
72 void *NaClClosureResultWait(struct NaClClosureResult *self)
74 void *rv;
76 NaClXMutexLock(&self->mu);
77 while (!self->result_valid) {
78 NaClXCondVarWait(&self->cv, &self->mu);
80 rv = self->rv;
81 self->result_valid = 0;
82 NaClXMutexUnlock(&self->mu);
84 return rv;
87 void NaClClosureResultDone(struct NaClClosureResult *self,
88 void *rv)
90 NaClXMutexLock(&self->mu);
91 if (self->result_valid) {
92 NaClLog(LOG_FATAL, "NaClClosureResultDone: result already present?!?\n");
94 self->rv = rv;
95 self->result_valid = 1;
96 NaClXCondVarSignal(&self->cv);
97 NaClXMutexUnlock(&self->mu);
100 void NaClStartAsyncOp(struct NaClAppThread *natp,
101 struct NaClClosure *ncp)
103 NaClLog(4, "NaClStartAsyncOp(0x%08"PRIxPTR", 0x%08"PRIxPTR")\n",
104 (uintptr_t) natp,
105 (uintptr_t) ncp);
106 NaClSyncQueueInsert(&natp->nap->work_queue, ncp);
107 NaClLog(4, "Done\n");
110 int32_t NaClWaitForAsyncOp(struct NaClAppThread *natp)
112 NaClLog(4, "NaClWaitForAsyncOp(0x%08"PRIxPTR")\n",
113 (uintptr_t) natp);
115 return (uint32_t) NaClClosureResultWait(&natp->result);
119 #if defined(HAVE_SDL)
122 typedef struct InfoVideo {
123 int32_t width;
124 int32_t height;
125 int32_t format;
126 int32_t bits_per_pixel;
127 int32_t bytes_per_pixel;
128 int32_t rmask;
129 int32_t gmask;
130 int32_t bmask;
131 SDL_Surface *screen;
132 } InfoVideo;
135 typedef struct InfoAudio {
136 SDL_AudioSpec *audio_spec;
137 struct NaClMutex mutex;
138 struct NaClCondVar condvar;
139 volatile int32_t ready;
140 volatile size_t size;
141 unsigned char *stream;
142 volatile int32_t first;
143 volatile int32_t shutdown;
144 SDL_AudioSpec obtained;
145 struct NaClAppThread *thread_ptr;
146 } InfoAudio;
149 typedef struct InfoMultimedia {
150 /* do not move begin (initialization dep) */
151 volatile int32_t sdl_init_flags;
152 volatile int32_t initialized;
153 volatile int32_t have_video;
154 volatile int32_t have_audio;
155 /* do not move end */
156 InfoVideo video;
157 InfoAudio audio;
158 } InfoMultimedia;
160 static struct InfoMultimedia nacl_multimedia;
161 static struct NaClMutex nacl_multimedia_mutex;
164 void NaClMultimediaModuleInit() {
165 int r;
166 /* clear all values in nacl_multimedia to 0 */
167 memset(&nacl_multimedia, 0, sizeof(nacl_multimedia));
168 r = NaClMutexCtor(&nacl_multimedia_mutex);
169 if (1 != r)
170 NaClLog(LOG_FATAL, "NaClAudioVideoModuleInit: mutex ctor failed\n");
174 void NaClMultimediaModuleFini() {
175 NaClMutexDtor(&nacl_multimedia_mutex);
176 /* clear all values in nacl_multimedia to 0 */
177 memset(&nacl_multimedia, 0, sizeof(nacl_multimedia));
181 void NaClBotSysMultimedia_Init(struct NaClAppThread *natp, int subsys) {
182 int32_t r;
183 int32_t retval;
185 r = NaClMutexLock(&nacl_multimedia_mutex);
186 if (NACL_SYNC_OK != r)
187 NaClLog(LOG_FATAL, "NaClBotSysMultimedia_Init: mutex lock failed\n");
189 NaClLog(3, "Entered NaClBotSysMultimedia_Init(0x%08"PRIxPTR", %d)\n",
190 (uintptr_t) natp, subsys);
192 retval = -NACL_ABI_EINVAL;
194 if (!natp->is_privileged && natp->nap->restrict_to_main_thread) {
195 retval = -NACL_ABI_EIO;
196 goto done;
199 /* don't allow nested init */
200 if (0 != nacl_multimedia.initialized)
201 NaClLog(LOG_FATAL, "NaClSysMultimedia_Init: Already initialized!\n");
203 if (0 != nacl_multimedia.have_video)
204 NaClLog(LOG_FATAL, "NaClSysMultimedia_Init: video initialized?\n");
206 if (0 != nacl_multimedia.have_audio)
207 NaClLog(LOG_FATAL, "NaClSysMultimedia_Init: audio initialized?\n");
209 /* map nacl a/v to sdl subsystem init */
210 if (NACL_SUBSYSTEM_VIDEO == (subsys & NACL_SUBSYSTEM_VIDEO)) {
211 nacl_multimedia.sdl_init_flags |= SDL_INIT_VIDEO;
213 if (NACL_SUBSYSTEM_AUDIO == (subsys & NACL_SUBSYSTEM_AUDIO)) {
214 nacl_multimedia.sdl_init_flags |= SDL_INIT_AUDIO;
216 if (SDL_Init(nacl_multimedia.sdl_init_flags)) {
217 NaClLog(LOG_ERROR, "NaClSysMultimeida_Init: SDL_Init failed\n");
218 retval = -NACL_ABI_EIO;
219 goto done;
222 nacl_multimedia.initialized = 1;
223 retval = 0;
225 done:
226 r = NaClMutexUnlock(&nacl_multimedia_mutex);
227 if (NACL_SYNC_OK != r)
228 NaClLog(LOG_FATAL,
229 "NaClBotSysMultimedia_Init: mutex unlock failed\n");
231 NaClClosureResultDone(&natp->result, (void *) retval);
235 void NaClBotSysMultimedia_Shutdown(struct NaClAppThread *natp) {
236 int32_t r;
237 int32_t retval;
239 r = NaClMutexLock(&nacl_multimedia_mutex);
240 if (NACL_SYNC_OK != r)
241 NaClLog(LOG_FATAL, "NaClBotSysMultimedia_Shutdown: mutex lock failed\n");
242 if (0 == nacl_multimedia.initialized)
243 NaClLog(LOG_FATAL, "NaClBotSysMultimedia_Shutdown: not initialized!\n");
244 if (0 != nacl_multimedia.have_video)
245 NaClLog(LOG_FATAL,
246 "NaClBotSysMultimedia_Shutdown: video subsystem not shutdown!\n");
247 if (0 != nacl_multimedia.have_audio)
248 NaClLog(LOG_FATAL,
249 "NaClBotSysMultimedia_Shutdown: audio subsystem not shutdown!\n");
251 SDL_Quit();
252 retval = 0;
253 nacl_multimedia.sdl_init_flags = 0;
254 nacl_multimedia.initialized = 0;
256 r = NaClMutexUnlock(&nacl_multimedia_mutex);
257 if (NACL_SYNC_OK != r)
258 NaClLog(LOG_FATAL,
259 "NaClBotSysMultimedia_Shutdown: mutex unlock failed\n");
261 NaClClosureResultDone(&natp->result, (void *) retval);
265 void NaClBotSysVideo_Init(struct NaClAppThread *natp,
266 int width,
267 int height)
269 int32_t r;
270 int32_t retval;
271 uint32_t sdl_video_flags = SDL_DOUBLEBUF | SDL_HWSURFACE;
273 r = NaClMutexLock(&nacl_multimedia_mutex);
274 if (NACL_SYNC_OK != r)
275 NaClLog(LOG_FATAL, "NaClBotSysVideo_Init: mutex lock failed\n");
277 NaClLog(3, "Entered NaClBotSysVideo_Init(0x%08"PRIxPTR", %d, %d)\n",
278 (uintptr_t) natp, width, height);
280 retval = -NACL_ABI_EINVAL;
282 if (0 == nacl_multimedia.initialized)
283 NaClLog(LOG_FATAL, "NaClBotSysVideo_Init: multimedia not initialized\n");
285 /* for now don't allow app to have more than one SDL window or resize */
286 if (0 != nacl_multimedia.have_video)
287 NaClLog(LOG_FATAL, "NaClBotSysVideo_Init: already initialized!\n");
289 if (SDL_INIT_VIDEO != (nacl_multimedia.sdl_init_flags & SDL_INIT_VIDEO))
290 NaClLog(LOG_FATAL,
291 "NaClBotSysVideo_Init: video not originally requested\n");
293 nacl_multimedia.have_video = 1;
294 nacl_multimedia.video.screen = SDL_SetVideoMode(width, height,
295 0, sdl_video_flags);
296 if (!nacl_multimedia.video.screen) {
297 NaClLog(LOG_ERROR, "NaClSysVideo_Init: SDL_SetVideoMode failed\n");
298 nacl_multimedia.have_video = 0;
299 retval = -NACL_ABI_EIO;
300 goto done;
303 /* width, height and format validated in top half */
304 nacl_multimedia.video.width = width;
305 nacl_multimedia.video.height = height;
306 /* video format always BGRA */
307 nacl_multimedia.video.rmask = 0x00FF0000;
308 nacl_multimedia.video.gmask = 0x0000FF00;
309 nacl_multimedia.video.bmask = 0x000000FF;
310 nacl_multimedia.video.bits_per_pixel = 32;
311 nacl_multimedia.video.bytes_per_pixel = 4;
313 /* set the window caption */
314 /* todo: as parameter to nacl_video_init? */
315 SDL_WM_SetCaption("NaCl Application", "NaCl Application");
316 retval = 0;
318 done:
319 r = NaClMutexUnlock(&nacl_multimedia_mutex);
320 if (NACL_SYNC_OK != r)
321 NaClLog(LOG_FATAL, "NaClBotSysVideo_Init: mutex unlock failed\n");
322 NaClClosureResultDone(&natp->result, (void *) retval);
327 * NaClBotSysVideo_Shutdown -- shuts down the Video interface. This
328 * doesn't have to be a bottom half function per se, except that it
329 * references nacl_multimedia, and if we were to make that accessible
330 * to top-half code, we'd have to ensure memory barriers are in place
331 * around accesses to it.
333 void NaClBotSysVideo_Shutdown(struct NaClAppThread *natp)
335 int32_t r;
336 int32_t retval;
338 r = NaClMutexLock(&nacl_multimedia_mutex);
339 if (NACL_SYNC_OK != r)
340 NaClLog(LOG_FATAL, "NaClBotSysVideo_Shutdown: mutex lock failed\n");
341 if (0 == nacl_multimedia.initialized)
342 NaClLog(LOG_FATAL,
343 "NaClBotSysVideo_Shutdown: multimedia not initialized!\n");
344 if (0 == nacl_multimedia.have_video) {
345 NaClLog(LOG_ERROR, "NaClBotSysVideo_Shutdown: video already shutdown!\n");
346 retval = -NACL_ABI_EPERM;
347 goto done;
349 nacl_multimedia.have_video = 0;
350 retval = 0;
351 done:
352 r = NaClMutexUnlock(&nacl_multimedia_mutex);
353 if (NACL_SYNC_OK != r)
354 NaClLog(LOG_FATAL, "NaClBotSysVideo_Shutdown: mutex unlock failed\n");
355 NaClClosureResultDone(&natp->result, (void *) retval);
360 * Update the "frame buffer" with user-supplied video data.
362 * Note that "data" is a user address that must be validated in the
363 * bottom half code because the top half does not record the
364 * width/height/video format info, and the global static variable
365 * nacl_multimedia is inaccessible to top-half threads.
367 void NaClBotSysVideo_Update(struct NaClAppThread *natp,
368 const void *data)
370 int retval;
371 SDL_Surface *image;
372 uintptr_t sysaddr;
373 int32_t size;
375 retval = -NACL_ABI_EINVAL;
376 image = NULL;
378 if (0 == nacl_multimedia.have_video)
379 NaClLog(LOG_FATAL, "NaClBotVideo_Update: video not initialized\n");
381 /* verify data ptr range */
382 size = nacl_multimedia.video.bytes_per_pixel *
383 nacl_multimedia.video.width *
384 nacl_multimedia.video.height;
385 sysaddr = NaClUserToSysAddrRange(natp->nap,
386 (uintptr_t) data,
387 size);
388 if (kNaClBadAddress == sysaddr) {
389 NaClLog(LOG_ERROR, "NaClBotSysVideo_Update: width, height: %d, %d\n",
390 nacl_multimedia.video.width, nacl_multimedia.video.height);
391 NaClLog(LOG_FATAL,
392 "NaClBotSysVideo_Update: input data address range invalid\n");
395 image = SDL_CreateRGBSurfaceFrom((unsigned char*) sysaddr,
396 nacl_multimedia.video.width,
397 nacl_multimedia.video.height,
398 nacl_multimedia.video.bits_per_pixel,
399 nacl_multimedia.video.width *
400 nacl_multimedia.video.bytes_per_pixel,
401 nacl_multimedia.video.rmask,
402 nacl_multimedia.video.gmask,
403 nacl_multimedia.video.bmask, 0);
404 if (NULL == image) {
405 NaClLog(LOG_ERROR,
406 "NaClBotSysVideo_Update: SDL_CreateRGBSurfaceFrom failed\n");
407 retval = -NACL_ABI_EPERM;
408 goto done;
411 retval = SDL_SetAlpha(image, 0, 255);
412 if (0 != retval) {
413 NaClLog(LOG_ERROR,
414 "NaClBotSysVideo_Update SDL_SetAlpha failed (%d)\n", retval);
415 retval = -NACL_ABI_EPERM;
416 goto done_free_image;
419 retval = SDL_BlitSurface(image, NULL, nacl_multimedia.video.screen, NULL);
420 if (0 != retval) {
421 NaClLog(LOG_ERROR,
422 "NaClBotSysVideo_Update: SDL_BlitSurface failed\n");
423 retval = -NACL_ABI_EPERM;
424 goto done_free_image;
427 retval = SDL_Flip(nacl_multimedia.video.screen);
428 if (0 != retval) {
429 NaClLog(LOG_ERROR, "NaClBotSysVideo_Update: SDL_Flip failed\n");
430 retval = -NACL_ABI_EPERM;
431 goto done_free_image;
434 retval = 0;
435 /* fall through to free image and closure */
437 done_free_image:
438 SDL_FreeSurface(image);
439 done:
440 NaClClosureResultDone(&natp->result, (void *) retval);
444 void NaClBotSysVideo_Poll_Event(struct NaClAppThread *natp,
445 union NaClMultimediaEvent *event) {
446 int32_t sdl_r;
447 int32_t retval;
448 int32_t repoll;
449 SDL_Event sdl_event;
451 if (0 == nacl_multimedia.initialized)
452 NaClLog(LOG_FATAL,
453 "NaClBotSysVideo_Poll_Event: multmedia not initialized!\n");
454 if (0 == nacl_multimedia.have_video)
455 NaClLog(LOG_FATAL,
456 "NaClBotSysVideo_Poll_Event: video subsystem not initialized!\n");
458 do {
459 sdl_r = SDL_PollEvent(&sdl_event);
460 repoll = 0;
461 if (sdl_r == 0) {
462 retval = -NACL_ABI_ENODATA;
463 break;
464 } else {
465 retval = 0;
466 switch(sdl_event.type) {
467 case SDL_ACTIVEEVENT:
468 event->type = NACL_EVENT_ACTIVE;
469 event->active.gain = sdl_event.active.gain;
470 event->active.state = sdl_event.active.state;
471 break;
472 case SDL_VIDEOEXPOSE:
473 event->type = NACL_EVENT_EXPOSE;
474 break;
475 case SDL_KEYDOWN:
476 case SDL_KEYUP:
477 event->type = (SDL_KEYUP == sdl_event.type) ?
478 NACL_EVENT_KEY_UP : NACL_EVENT_KEY_DOWN;
479 event->key.which = sdl_event.key.which;
480 event->key.state = sdl_event.key.state;
481 event->key.keysym.scancode = sdl_event.key.keysym.scancode;
482 event->key.keysym.sym = sdl_event.key.keysym.sym;
483 event->key.keysym.mod = sdl_event.key.keysym.mod;
484 event->key.keysym.unicode = sdl_event.key.keysym.unicode;
485 break;
486 case SDL_MOUSEMOTION:
487 event->type = NACL_EVENT_MOUSE_MOTION;
488 event->motion.which = sdl_event.motion.which;
489 event->motion.state = sdl_event.motion.state;
490 event->motion.x = sdl_event.motion.x;
491 event->motion.y = sdl_event.motion.y;
492 event->motion.xrel = sdl_event.motion.xrel;
493 event->motion.yrel = sdl_event.motion.yrel;
494 break;
495 case SDL_MOUSEBUTTONDOWN:
496 case SDL_MOUSEBUTTONUP:
497 event->type = (SDL_MOUSEBUTTONUP == sdl_event.type) ?
498 NACL_EVENT_MOUSE_BUTTON_UP :
499 NACL_EVENT_MOUSE_BUTTON_DOWN;
500 event->button.which = sdl_event.button.which;
501 event->button.button = sdl_event.button.button;
502 event->button.state = sdl_event.button.state;
503 event->button.x = sdl_event.button.x;
504 event->button.y = sdl_event.button.y;
505 break;
506 case SDL_QUIT:
507 event->type = NACL_EVENT_QUIT;
508 break;
509 default:
510 // an sdl event happened, but we don't support it
511 // so move along and try polling again
512 repoll = 1;
513 break;
516 } while (0 != repoll);
518 NaClClosureResultDone(&natp->result, (void *) retval);
522 void __NaCl_InternalAudioCallback(void *unused, Uint8 *stream, int size) {
523 int32_t r;
524 r = NaClMutexLock(&nacl_multimedia.audio.mutex);
525 if (NACL_SYNC_OK != r)
526 NaClLog(LOG_FATAL, "__NaCl_InternalAudioCallback: mutex lock failed\n");
527 if (0 == nacl_multimedia.audio.ready) {
528 nacl_multimedia.audio.stream = stream;
529 nacl_multimedia.audio.size = size;
530 nacl_multimedia.audio.ready = 1;
531 r = NaClCondVarSignal(&nacl_multimedia.audio.condvar);
532 if (NACL_SYNC_OK != r)
533 NaClLog(LOG_FATAL,
534 "__NaCl_InternalAudioCallback: cond var signal failed\n");
535 /* wait for return signal */
536 while ((1 == nacl_multimedia.audio.ready) &&
537 (0 == nacl_multimedia.audio.shutdown)) {
538 r = NaClCondVarWait(&nacl_multimedia.audio.condvar,
539 &nacl_multimedia.audio.mutex);
540 if (NACL_SYNC_OK != r) {
541 NaClLog(LOG_FATAL,
542 "__NaCl_InternalAudioCallback: cond var wait failed\n");
546 r = NaClMutexUnlock(&nacl_multimedia.audio.mutex);
547 if (NACL_SYNC_OK != r)
548 NaClLog(LOG_FATAL, "__NaCl_InternalAudioCallback: mutex unlock failed\n");
552 void NaClBotSysAudio_Init(struct NaClAppThread *natp,
553 enum NaClAudioFormat format,
554 int desired_samples,
555 int *obtained_samples)
557 SDL_AudioSpec desired;
558 int32_t r;
559 int32_t retval;
561 r = NaClMutexLock(&nacl_multimedia_mutex);
562 if (NACL_SYNC_OK != r)
563 NaClLog(LOG_FATAL, "NaClBotSysAudio_Init: mutex lock failed\n");
565 NaClLog(3, "Entered NaClBotSysAudio_Init(0x%08"PRIxPTR", %d)\n",
566 (uintptr_t) natp, format);
568 retval = -NACL_ABI_EINVAL;
570 if (0 == nacl_multimedia.initialized)
571 NaClLog(LOG_FATAL, "NaClSysAudio_Init: multimedia not initialized!\n");
573 /* for now, don't allow an app to open more than one SDL audio device */
574 if (0 != nacl_multimedia.have_audio) {
575 NaClLog(LOG_FATAL, "NaClSysAudio_Init: already initialized!\n");
578 if ((desired_samples < 128) || (desired_samples > 8192)) {
579 NaClLog(LOG_ERROR,
580 "NaClSysAudio_Init: desired sample value out of range\n");
581 retval = -NACL_ABI_ERANGE;
582 goto done;
585 memset(&nacl_multimedia.audio, 0, sizeof(nacl_multimedia.audio));
586 memset(&desired, 0, sizeof(desired));
588 r = NaClMutexCtor(&nacl_multimedia.audio.mutex);
589 if (1 != r)
590 NaClLog(LOG_FATAL, "NaClBotSysAudio_Init: mutex ctor failed\n");
591 r = NaClCondVarCtor(&nacl_multimedia.audio.condvar);
592 if (1 != r)
593 NaClLog(LOG_FATAL, "NaClBotSysAudio_Init: cond var ctor failed\n");
595 nacl_multimedia.audio.thread_ptr = 0;
596 nacl_multimedia.audio.size = 0;
597 nacl_multimedia.audio.ready = 0;
598 nacl_multimedia.audio.first = 1;
599 nacl_multimedia.audio.shutdown = 0;
601 desired.format = AUDIO_S16LSB;
602 desired.channels = 2;
603 desired.samples = desired_samples;
604 desired.callback = __NaCl_InternalAudioCallback;
606 if (NACL_AUDIO_FORMAT_STEREO_44K == format) {
607 desired.freq = 44100;
608 } else if (NACL_AUDIO_FORMAT_STEREO_48K == format) {
609 desired.freq = 48000;
610 } else {
611 /* we only support two simple high quality stereo formats */
612 NaClLog(LOG_ERROR, "NaClSysAudio_Init: unsupported format\n");
613 retval = -NACL_ABI_EINVAL;
614 goto done;
617 if (SDL_OpenAudio(&desired, &nacl_multimedia.audio.obtained) < 0) {
618 NaClLog(LOG_ERROR, "NaClSysAudio_Init: Couldn't open SDL audio: %s\n",
619 SDL_GetError());
620 retval = -NACL_ABI_EIO;
621 goto done;
624 if (nacl_multimedia.audio.obtained.format != desired.format) {
625 NaClLog(LOG_ERROR, "NaClSysAudio_Init: Couldn't get desired format\n");
626 retval = -NACL_ABI_EIO;
627 goto done_close;
630 *obtained_samples = nacl_multimedia.audio.obtained.samples;
632 nacl_multimedia.have_audio = 1;
633 retval = 0;
634 goto done;
636 done_close:
637 SDL_CloseAudio();
639 done:
640 r = NaClMutexUnlock(&nacl_multimedia_mutex);
641 if (NACL_SYNC_OK != r)
642 NaClLog(LOG_FATAL, "NaClBotSysAudio_Init: mutex unlock failed\n");
644 NaClClosureResultDone(&natp->result, (void *) retval);
648 void NaClBotSysAudio_Shutdown(struct NaClAppThread *natp) {
649 int32_t r;
650 int32_t retval = -NACL_ABI_EINVAL;
652 /* set volatile shutdown outside of mutexes to avoid deadlocking */
653 nacl_multimedia.audio.shutdown = 1;
654 r = NaClMutexLock(&nacl_multimedia_mutex);
655 if (NACL_SYNC_OK != r)
656 NaClLog(LOG_FATAL, "NaClBotSysAudio_Shutdown: mutex lock failed\n");
657 if (0 == nacl_multimedia.initialized)
658 NaClLog(LOG_FATAL, "NaClSysAudio_Shutdown: multimedia not initialized\n");
659 if (0 == nacl_multimedia.have_audio)
660 NaClLog(LOG_FATAL, "NaClSysAudio_Shutdown: audio not initialized!\n");
661 /* tell audio thread we're shutting down */
662 r = NaClMutexLock(&nacl_multimedia.audio.mutex);
663 if (NACL_SYNC_OK != r)
664 NaClLog(LOG_FATAL, "NaClSysAudio_Shutdown: mutex lock failed\n");
665 r = NaClCondVarBroadcast(&nacl_multimedia.audio.condvar);
666 if (NACL_SYNC_OK != r)
667 NaClLog(LOG_FATAL, "NaClSysAudio_Shutdown: cond var broadcast failed\n");
668 r = NaClMutexUnlock(&nacl_multimedia.audio.mutex);
669 if (NACL_SYNC_OK != r)
670 NaClLog(LOG_FATAL, "NaClSysAudio_Shutdown: mutex unlock failed\n");
671 /* close out audio */
672 SDL_CloseAudio();
673 /* no more callbacks at this point */
674 nacl_multimedia.have_audio = 0;
675 retval = 0;
676 r = NaClMutexUnlock(&nacl_multimedia_mutex);
677 if (NACL_SYNC_OK != r)
678 NaClLog(LOG_FATAL, "NaClBotSysAudio_Shutdown: mutex unlock failed\n");
679 NaClClosureResultDone(&natp->result, (void *) retval);
684 * returns 0 during normal operation.
685 * returns -1 indicating that it is time to exit the audio thread
687 int32_t NaClSliceSysAudio_Stream(struct NaClAppThread *natp,
688 const void *data,
689 size_t *size)
691 int32_t r;
692 int32_t retval = 0;
693 uintptr_t sysaddr;
694 size_t *syssize;
696 r = NaClMutexLock(&nacl_multimedia_mutex);
697 if (NACL_SYNC_OK != r)
698 NaClLog(LOG_FATAL, "NaClSliceSysAudio_Stream: global mutex lock failed\n");
700 if (0 == nacl_multimedia.have_audio) {
702 * hmm... if we don't have audio, one reason could be that shutdown was
703 * just called in another thread. So we silently fail, telling the app
704 * it is time to leave the audio thread. The alternative is to treat
705 * this situation as fatal, but that makes shutdown that much harder
707 retval = -1;
708 goto done;
711 sysaddr = NaClUserToSysAddrRange(natp->nap,
712 (uintptr_t) size,
713 sizeof(size));
714 if (kNaClBadAddress == sysaddr) {
715 NaClLog(LOG_FATAL, "NaClSliceSysAudio_Stream: size address invalid\n");
717 syssize = (size_t *)sysaddr;
719 if (nacl_multimedia.audio.first) {
720 /* don't copy data on first call... */
721 nacl_multimedia.audio.thread_ptr = natp;
722 } else {
723 /* verify we're being called from same thread as before */
724 /* TODO: need to use a stronger thread uid mechanism */
725 if (natp != nacl_multimedia.audio.thread_ptr) {
726 NaClLog(LOG_FATAL,
727 "NaClSliceSysAudio_Stream: called from different thread\n");
730 /* validate data buffer based on last size */
731 sysaddr = NaClUserToSysAddrRange(natp->nap,
732 (uintptr_t) data,
733 nacl_multimedia.audio.size);
734 if (kNaClBadAddress == sysaddr) {
735 NaClLog(LOG_ERROR,
736 "NaClSliceSysAudio_Stream: size: %"PRIdS"\n",
737 nacl_multimedia.audio.size);
738 NaClLog(LOG_FATAL, "NaClSliceSysAudio_Stream: data address invalid\n");
741 /* copy the audio data into the sdl audio buffer */
742 memcpy(nacl_multimedia.audio.stream,
743 (void *)sysaddr, nacl_multimedia.audio.size);
746 /* callback synchronization */
747 r = NaClMutexLock(&nacl_multimedia.audio.mutex);
748 if (NACL_SYNC_OK != r)
749 NaClLog(LOG_FATAL, "NaClSliceSysAudio_Stream: audio mutex lock failed\n");
750 /* unpause audio on first, start callbacks */
751 if (nacl_multimedia.audio.first) {
752 SDL_PauseAudio(0);
753 nacl_multimedia.audio.first = 0;
756 /* signal callback (if it is waiting) */
757 if (nacl_multimedia.audio.ready != 0) {
758 nacl_multimedia.audio.ready = 0;
759 r = NaClCondVarSignal(&nacl_multimedia.audio.condvar);
760 if (NACL_SYNC_OK != r)
761 NaClLog(LOG_FATAL,
762 "NaClSliceSysAudio_Stream: cond var signal failed\n");
765 nacl_multimedia.audio.size = 0;
767 /* wait for next callback */
768 while ((0 == nacl_multimedia.audio.ready) &&
769 (0 == nacl_multimedia.audio.shutdown)) {
770 r = NaClCondVarWait(&nacl_multimedia.audio.condvar,
771 &nacl_multimedia.audio.mutex);
772 if (NACL_SYNC_OK != r) {
773 NaClLog(LOG_FATAL,
774 "__NaCl_InternalAudioCallback: cond var wait failed\n");
778 if (0 != nacl_multimedia.audio.shutdown) {
779 nacl_multimedia.audio.size = 0;
780 retval = -1;
782 /* return size of next audio block */
783 *syssize = (size_t)nacl_multimedia.audio.size;
784 r = NaClMutexUnlock(&nacl_multimedia.audio.mutex);
785 if (NACL_SYNC_OK != r)
786 NaClLog(LOG_FATAL,
787 "NaClSliceSysAudio_Stream: audio mutex unlock failed\n");
789 done:
790 r = NaClMutexUnlock(&nacl_multimedia_mutex);
791 if (NACL_SYNC_OK != r)
792 NaClLog(LOG_FATAL,
793 "NaClSliceSysAudio_Stream: global mutex unlock failed\n");
794 return retval;
798 #endif /* HAVE_SDL */