Fix file permissions: set executable bit
[nativeclient.git] / service_runtime / nacl_bottom_half.c
blob82d9e8cceeaf2ea2eb79187ba3824697bac2b5d7
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%08x, 0x%08x)\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%08x)\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 int32_t ready;
140 size_t size;
141 unsigned char *stream;
142 int32_t first;
143 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%08x, %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 enum NaClVideoFormat format,
267 int width,
268 int height)
270 int32_t r;
271 int32_t retval;
272 uint32_t sdl_video_flags = SDL_DOUBLEBUF | SDL_HWSURFACE;
274 r = NaClMutexLock(&nacl_multimedia_mutex);
275 if (NACL_SYNC_OK != r)
276 NaClLog(LOG_FATAL, "NaClBotSysVideo_Init: mutex lock failed\n");
278 NaClLog(3, "Entered NaClBotSysVideo_Init(0x%08x, %d, %d)\n",
279 (uintptr_t) natp, width, height);
281 retval = -NACL_ABI_EINVAL;
283 if (0 == nacl_multimedia.initialized)
284 NaClLog(LOG_FATAL, "NaClBotSysVideo_Init: multimedia not initialized\n");
286 /* for now don't allow app to have more than one SDL window or resize */
287 if (0 != nacl_multimedia.have_video)
288 NaClLog(LOG_FATAL, "NaClBotSysVideo_Init: already initialized!\n");
290 if (SDL_INIT_VIDEO != (nacl_multimedia.sdl_init_flags & SDL_INIT_VIDEO))
291 NaClLog(LOG_FATAL,
292 "NaClBotSysVideo_Init: video not originally requested\n");
294 nacl_multimedia.have_video = 1;
295 nacl_multimedia.video.screen = SDL_SetVideoMode(width, height,
296 0, sdl_video_flags);
297 if (!nacl_multimedia.video.screen) {
298 NaClLog(LOG_ERROR, "NaClSysVideo_Init: SDL_SetVideoMode failed\n");
299 nacl_multimedia.have_video = 0;
300 retval = -NACL_ABI_EIO;
301 goto done;
304 /* width, height and format validated in top half */
305 nacl_multimedia.video.format = format;
306 nacl_multimedia.video.width = width;
307 nacl_multimedia.video.height = height;
308 if (NACL_VIDEO_FORMAT_RGB == format) {
309 nacl_multimedia.video.rmask = 0x000000FF;
310 nacl_multimedia.video.gmask = 0x0000FF00;
311 nacl_multimedia.video.bmask = 0x00FF0000;
312 nacl_multimedia.video.bits_per_pixel = 24;
313 nacl_multimedia.video.bytes_per_pixel = 3;
314 } else if (NACL_VIDEO_FORMAT_RGBA == format) {
315 nacl_multimedia.video.rmask = 0x000000FF;
316 nacl_multimedia.video.gmask = 0x0000FF00;
317 nacl_multimedia.video.bmask = 0x00FF0000;
318 nacl_multimedia.video.bits_per_pixel = 32;
319 nacl_multimedia.video.bytes_per_pixel = 4;
320 } else if (NACL_VIDEO_FORMAT_BGRA == format) {
321 nacl_multimedia.video.rmask = 0x00FF0000;
322 nacl_multimedia.video.gmask = 0x0000FF00;
323 nacl_multimedia.video.bmask = 0x000000FF;
324 nacl_multimedia.video.bits_per_pixel = 32;
325 nacl_multimedia.video.bytes_per_pixel = 4;
326 } else {
327 NaClLog(LOG_FATAL, "NaClBotSysVideo_Init: Panic, unrecognized format!\n");
330 /* set the window caption */
331 /* todo: as parameter to nacl_video_init? */
332 SDL_WM_SetCaption("NaCl Application", "NaCl Application");
333 retval = 0;
335 done:
336 r = NaClMutexUnlock(&nacl_multimedia_mutex);
337 if (NACL_SYNC_OK != r)
338 NaClLog(LOG_FATAL, "NaClBotSysVideo_Init: mutex unlock failed\n");
339 NaClClosureResultDone(&natp->result, (void *) retval);
344 * NaClBotSysVideo_Shutdown -- shuts down the Video interface. This
345 * doesn't have to be a bottom half function per se, except that it
346 * references nacl_multimedia, and if we were to make that accessible
347 * to top-half code, we'd have to ensure memory barriers are in place
348 * around accesses to it.
350 void NaClBotSysVideo_Shutdown(struct NaClAppThread *natp)
352 int32_t r;
353 int32_t retval;
355 r = NaClMutexLock(&nacl_multimedia_mutex);
356 if (NACL_SYNC_OK != r)
357 NaClLog(LOG_FATAL, "NaClBotSysVideo_Shutdown: mutex lock failed\n");
358 if (0 == nacl_multimedia.initialized)
359 NaClLog(LOG_FATAL,
360 "NaClBotSysVideo_Shutdown: multimedia not initialized!\n");
361 if (0 == nacl_multimedia.have_video) {
362 NaClLog(LOG_ERROR, "NaClBotSysVideo_Shutdown: video already shutdown!\n");
363 retval = -NACL_ABI_EPERM;
364 goto done;
366 nacl_multimedia.have_video = 0;
367 retval = 0;
368 done:
369 r = NaClMutexUnlock(&nacl_multimedia_mutex);
370 if (NACL_SYNC_OK != r)
371 NaClLog(LOG_FATAL, "NaClBotSysVideo_Shutdown: mutex unlock failed\n");
372 NaClClosureResultDone(&natp->result, (void *) retval);
377 * Update the "frame buffer" with user-supplied video data.
379 * Note that "data" is a user address that must be validated in the
380 * bottom half code because the top half does not record the
381 * width/height/video format info, and the global static variable
382 * nacl_multimedia is inaccessible to top-half threads.
384 void NaClBotSysVideo_Update(struct NaClAppThread *natp,
385 const void *data)
387 int retval;
388 SDL_Surface *image;
389 uintptr_t sysaddr;
390 int32_t size;
392 retval = -NACL_ABI_EINVAL;
393 image = NULL;
395 if (0 == nacl_multimedia.have_video)
396 NaClLog(LOG_FATAL, "NaClBotVideo_Update: video not initialized\n");
398 /* verify data ptr range */
399 size = nacl_multimedia.video.bytes_per_pixel *
400 nacl_multimedia.video.width *
401 nacl_multimedia.video.height;
402 sysaddr = NaClUserToSysAddrRange(natp->nap,
403 (uintptr_t) data,
404 size);
405 if (kNaClBadAddress == sysaddr) {
406 NaClLog(LOG_ERROR, "NaClBotSysVideo_Update: width, height: %d, %d\n",
407 nacl_multimedia.video.width, nacl_multimedia.video.height);
408 NaClLog(LOG_FATAL,
409 "NaClBotSysVideo_Update: input data address range invalid\n");
412 image = SDL_CreateRGBSurfaceFrom((unsigned char*) sysaddr,
413 nacl_multimedia.video.width,
414 nacl_multimedia.video.height,
415 nacl_multimedia.video.bits_per_pixel,
416 nacl_multimedia.video.width *
417 nacl_multimedia.video.bytes_per_pixel,
418 nacl_multimedia.video.rmask,
419 nacl_multimedia.video.gmask,
420 nacl_multimedia.video.bmask, 0);
421 if (NULL == image) {
422 NaClLog(LOG_ERROR,
423 "NaClBotSysVideo_Update: SDL_CreateRGBSurfaceFrom failed\n");
424 retval = -NACL_ABI_EPERM;
425 goto done;
428 retval = SDL_SetAlpha(image, 0, 255);
429 if (0 != retval) {
430 NaClLog(LOG_ERROR,
431 "NaClBotSysVideo_Update SDL_SetAlpha failed (%d)\n", retval);
432 retval = -NACL_ABI_EPERM;
433 goto done_free_image;
436 retval = SDL_BlitSurface(image, NULL, nacl_multimedia.video.screen, NULL);
437 if (0 != retval) {
438 NaClLog(LOG_ERROR,
439 "NaClBotSysVideo_Update: SDL_BlitSurface failed\n");
440 retval = -NACL_ABI_EPERM;
441 goto done_free_image;
444 retval = SDL_Flip(nacl_multimedia.video.screen);
445 if (0 != retval) {
446 NaClLog(LOG_ERROR, "NaClBotSysVideo_Update: SDL_Flip failed\n");
447 retval = -NACL_ABI_EPERM;
448 goto done_free_image;
451 retval = 0;
452 /* fall through to free image and closure */
454 done_free_image:
455 SDL_FreeSurface(image);
456 done:
457 NaClClosureResultDone(&natp->result, (void *) retval);
461 void NaClBotSysVideo_Poll_Event(struct NaClAppThread *natp,
462 union NaClMultimediaEvent *event) {
463 int32_t sdl_r;
464 int32_t retval;
465 int32_t repoll;
466 SDL_Event sdl_event;
468 if (0 == nacl_multimedia.initialized)
469 NaClLog(LOG_FATAL,
470 "NaClBotSysVideo_Poll_Event: multmedia not initialized!\n");
471 if (0 == nacl_multimedia.have_video)
472 NaClLog(LOG_FATAL,
473 "NaClBotSysVideo_Poll_Event: video subsystem not initialized!\n");
475 do {
476 sdl_r = SDL_PollEvent(&sdl_event);
477 repoll = 0;
478 if (sdl_r == 0) {
479 retval = -NACL_ABI_ENODATA;
480 break;
481 } else {
482 retval = 0;
483 switch(sdl_event.type) {
484 case SDL_ACTIVEEVENT:
485 event->type = NACL_EVENT_ACTIVE;
486 event->active.gain = sdl_event.active.gain;
487 event->active.state = sdl_event.active.state;
488 break;
489 case SDL_VIDEOEXPOSE:
490 event->type = NACL_EVENT_EXPOSE;
491 break;
492 case SDL_KEYDOWN:
493 case SDL_KEYUP:
494 event->type = (SDL_KEYUP == sdl_event.type) ?
495 NACL_EVENT_KEY_UP : NACL_EVENT_KEY_DOWN;
496 event->key.which = sdl_event.key.which;
497 event->key.state = sdl_event.key.state;
498 event->key.keysym.scancode = sdl_event.key.keysym.scancode;
499 event->key.keysym.sym = sdl_event.key.keysym.sym;
500 event->key.keysym.mod = sdl_event.key.keysym.mod;
501 event->key.keysym.unicode = sdl_event.key.keysym.unicode;
502 break;
503 case SDL_MOUSEMOTION:
504 event->type = NACL_EVENT_MOUSE_MOTION;
505 event->motion.which = sdl_event.motion.which;
506 event->motion.state = sdl_event.motion.state;
507 event->motion.x = sdl_event.motion.x;
508 event->motion.y = sdl_event.motion.y;
509 event->motion.xrel = sdl_event.motion.xrel;
510 event->motion.yrel = sdl_event.motion.yrel;
511 break;
512 case SDL_MOUSEBUTTONDOWN:
513 case SDL_MOUSEBUTTONUP:
514 event->type = (SDL_MOUSEBUTTONUP == sdl_event.type) ?
515 NACL_EVENT_MOUSE_BUTTON_UP :
516 NACL_EVENT_MOUSE_BUTTON_DOWN;
517 event->button.which = sdl_event.button.which;
518 event->button.button = sdl_event.button.button;
519 event->button.state = sdl_event.button.state;
520 event->button.x = sdl_event.button.x;
521 event->button.y = sdl_event.button.y;
522 break;
523 case SDL_QUIT:
524 event->type = NACL_EVENT_QUIT;
525 break;
526 default:
527 // an sdl event happened, but we don't support it
528 // so move along and try polling again
529 repoll = 1;
530 break;
533 } while (0 != repoll);
535 NaClClosureResultDone(&natp->result, (void *) retval);
539 void __NaCl_InternalAudioCallback(void *unused, Uint8 *stream, int size) {
540 int32_t r;
541 r = NaClMutexLock(&nacl_multimedia.audio.mutex);
542 if (NACL_SYNC_OK != r)
543 NaClLog(LOG_FATAL, "__NaCl_InternalAudioCallback: mutex lock failed\n");
544 if (0 == nacl_multimedia.audio.ready) {
545 nacl_multimedia.audio.stream = stream;
546 nacl_multimedia.audio.size = size;
547 nacl_multimedia.audio.ready = 1;
548 r = NaClCondVarSignal(&nacl_multimedia.audio.condvar);
549 if (NACL_SYNC_OK != r)
550 NaClLog(LOG_FATAL,
551 "__NaCl_InternalAudioCallback: cond var signal failed\n");
552 /* wait for return signal */
553 while ((1 == nacl_multimedia.audio.ready) &&
554 (0 == nacl_multimedia.audio.shutdown)) {
555 r = NaClCondVarWait(&nacl_multimedia.audio.condvar,
556 &nacl_multimedia.audio.mutex);
557 if (NACL_SYNC_OK != r)
558 NaClLog(LOG_FATAL,
559 "__NaCl_InternalAudioCallback: cond var wait failed\n");
562 r = NaClMutexUnlock(&nacl_multimedia.audio.mutex);
563 if (NACL_SYNC_OK != r)
564 NaClLog(LOG_FATAL, "__NaCl_InternalAudioCallback: mutex unlock failed\n");
568 void NaClBotSysAudio_Init(struct NaClAppThread *natp,
569 enum NaClAudioFormat format,
570 int desired_samples,
571 int *obtained_samples)
573 SDL_AudioSpec desired;
574 int32_t r;
575 int32_t retval;
577 r = NaClMutexLock(&nacl_multimedia_mutex);
578 if (NACL_SYNC_OK != r)
579 NaClLog(LOG_FATAL, "NaClBotSysAudio_Init: mutex lock failed\n");
581 NaClLog(3, "Entered NaClBotSysAudio_Init(0x%08x, %d)\n",
582 (uintptr_t) natp, format);
584 retval = -NACL_ABI_EINVAL;
586 if (0 == nacl_multimedia.initialized)
587 NaClLog(LOG_FATAL, "NaClSysAudio_Init: multimedia not initialized!\n");
589 /* for now, don't allow an app to open more than one SDL audio device */
590 if (0 != nacl_multimedia.have_audio) {
591 NaClLog(LOG_FATAL, "NaClSysAudio_Init: already initialized!\n");
594 if ((desired_samples < 128) || (desired_samples > 8192)) {
595 NaClLog(LOG_ERROR,
596 "NaClSysAudio_Init: desired sample value out of range\n");
597 retval = -NACL_ABI_ERANGE;
598 goto done;
601 memset(&nacl_multimedia.audio, 0, sizeof(nacl_multimedia.audio));
602 memset(&desired, 0, sizeof(desired));
604 r = NaClMutexCtor(&nacl_multimedia.audio.mutex);
605 if (1 != r)
606 NaClLog(LOG_FATAL, "NaClBotSysAudio_Init: mutex ctor failed\n");
607 r = NaClCondVarCtor(&nacl_multimedia.audio.condvar);
608 if (1 != r)
609 NaClLog(LOG_FATAL, "NaClBotSysAudio_Init: cond var ctor failed\n");
611 nacl_multimedia.audio.thread_ptr = 0;
612 nacl_multimedia.audio.size = 0;
613 nacl_multimedia.audio.ready = 0;
614 nacl_multimedia.audio.first = 1;
615 nacl_multimedia.audio.shutdown = 0;
617 desired.format = AUDIO_S16LSB;
618 desired.channels = 2;
619 desired.samples = desired_samples;
620 desired.callback = __NaCl_InternalAudioCallback;
622 if (NACL_AUDIO_FORMAT_STEREO_44K == format) {
623 desired.freq = 44100;
624 } else if (NACL_AUDIO_FORMAT_STEREO_48K == format) {
625 desired.freq = 48000;
626 } else {
627 /* we only support two simple high quality stereo formats */
628 NaClLog(LOG_ERROR, "NaClSysAudio_Init: unsupported format\n");
629 retval = -NACL_ABI_EINVAL;
630 goto done;
633 if (SDL_OpenAudio(&desired, &nacl_multimedia.audio.obtained) < 0) {
634 NaClLog(LOG_ERROR, "NaClSysAudio_Init: Couldn't open SDL audio: %s\n",
635 SDL_GetError());
636 retval = -NACL_ABI_EIO;
637 goto done;
640 if (nacl_multimedia.audio.obtained.format != desired.format) {
641 NaClLog(LOG_ERROR, "NaClSysAudio_Init: Couldn't get desired format\n");
642 retval = -NACL_ABI_EIO;
643 goto done_close;
646 *obtained_samples = nacl_multimedia.audio.obtained.samples;
648 nacl_multimedia.have_audio = 1;
649 retval = 0;
650 goto done;
652 done_close:
653 SDL_CloseAudio();
655 done:
656 r = NaClMutexUnlock(&nacl_multimedia_mutex);
657 if (NACL_SYNC_OK != r)
658 NaClLog(LOG_FATAL, "NaClBotSysAudio_Init: mutex unlock failed\n");
660 NaClClosureResultDone(&natp->result, (void *) retval);
664 void NaClBotSysAudio_Shutdown(struct NaClAppThread *natp) {
665 int32_t r;
666 int32_t retval = -NACL_ABI_EINVAL;
668 r = NaClMutexLock(&nacl_multimedia_mutex);
669 if (NACL_SYNC_OK != r)
670 NaClLog(LOG_FATAL, "NaClBotSysAudio_Shutdown: mutex lock failed\n");
671 if (0 == nacl_multimedia.initialized)
672 NaClLog(LOG_FATAL, "NaClSysAudio_Shutdown: multimedia not initialized\n");
673 if (0 == nacl_multimedia.have_audio)
674 NaClLog(LOG_FATAL, "NaClSysAudio_Shutdown: audio not initialized!\n");
675 /* tell audio thread we're shutting down */
676 r = NaClMutexLock(&nacl_multimedia.audio.mutex);
677 if (NACL_SYNC_OK != r)
678 NaClLog(LOG_FATAL, "NaClSysAudio_Shutdown: mutex lock failed\n");
679 nacl_multimedia.audio.shutdown = 1;
680 r = NaClCondVarBroadcast(&nacl_multimedia.audio.condvar);
681 if (NACL_SYNC_OK != r)
682 NaClLog(LOG_FATAL, "NaClSysAudio_Shutdown: cond var broadcast failed\n");
683 r = NaClMutexUnlock(&nacl_multimedia.audio.mutex);
684 if (NACL_SYNC_OK != r)
685 NaClLog(LOG_FATAL, "NaClSysAudio_Shutdown: mutex unlock failed\n");
686 /* close out audio */
687 SDL_CloseAudio();
688 /* no more callbacks at this point */
689 nacl_multimedia.have_audio = 0;
690 retval = 0;
691 r = NaClMutexUnlock(&nacl_multimedia_mutex);
692 if (NACL_SYNC_OK != r)
693 NaClLog(LOG_FATAL, "NaClBotSysAudio_Shutdown: mutex unlock failed\n");
694 NaClClosureResultDone(&natp->result, (void *) retval);
699 * returns 0 during normal operation.
700 * returns -1 indicating that it is time to exit the audio thread
702 int32_t NaClSliceSysAudio_Stream(struct NaClAppThread *natp,
703 const void *data,
704 size_t *size)
706 int32_t r;
707 int32_t retval = 0;
708 uintptr_t sysaddr;
709 size_t *syssize;
711 r = NaClMutexLock(&nacl_multimedia_mutex);
712 if (NACL_SYNC_OK != r)
713 NaClLog(LOG_FATAL, "NaClSliceSysAudio_Stream: global mutex lock failed\n");
715 if (0 == nacl_multimedia.have_audio) {
717 * hmm... if we don't have audio, one reason could be that shutdown was
718 * just called in another thread. So we silently fail, telling the app
719 * it is time to leave the audio thread. The alternative is to treat
720 * this situation as fatal, but that makes shutdown that much harder
722 retval = -1;
723 goto done;
726 sysaddr = NaClUserToSysAddrRange(natp->nap,
727 (uintptr_t) size,
728 sizeof(size));
729 if (kNaClBadAddress == sysaddr) {
730 NaClLog(LOG_FATAL, "NaClSliceSysAudio_Stream: size address invalid\n");
732 syssize = (size_t *)sysaddr;
734 if (nacl_multimedia.audio.first) {
735 /* don't copy data on first call... */
736 nacl_multimedia.audio.thread_ptr = natp;
737 } else {
738 /* verify we're being called from same thread as before */
739 /* TODO: need to use a stronger thread uid mechanism */
740 if (natp != nacl_multimedia.audio.thread_ptr) {
741 NaClLog(LOG_FATAL,
742 "NaClSliceSysAudio_Stream: called from different thread\n");
745 /* validate data buffer based on last size */
746 sysaddr = NaClUserToSysAddrRange(natp->nap,
747 (uintptr_t) data,
748 nacl_multimedia.audio.size);
749 if (kNaClBadAddress == sysaddr) {
750 NaClLog(LOG_ERROR,
751 "NaClSliceSysAudio_Stream: size: %d\n", nacl_multimedia.audio.size);
752 NaClLog(LOG_FATAL, "NaClSliceSysAudio_Stream: data address invalid\n");
755 /* copy the audio data into the sdl audio buffer */
756 memcpy(nacl_multimedia.audio.stream,
757 (void *)sysaddr, nacl_multimedia.audio.size);
760 /* callback synchronization */
761 r = NaClMutexLock(&nacl_multimedia.audio.mutex);
762 if (NACL_SYNC_OK != r)
763 NaClLog(LOG_FATAL, "NaClSliceSysAudio_Stream: audio mutex lock failed\n");
764 /* unpause audio on first, start callbacks */
765 if (nacl_multimedia.audio.first) {
766 SDL_PauseAudio(0);
767 nacl_multimedia.audio.first = 0;
770 /* signal callback (if it is waiting) */
771 if (nacl_multimedia.audio.ready != 0) {
772 nacl_multimedia.audio.ready = 0;
773 r = NaClCondVarSignal(&nacl_multimedia.audio.condvar);
774 if (NACL_SYNC_OK != r)
775 NaClLog(LOG_FATAL,
776 "NaClSliceSysAudio_Stream: cond var signal failed\n");
779 nacl_multimedia.audio.size = 0;
781 /* wait for next callback */
782 while ((0 == nacl_multimedia.audio.ready) &&
783 (0 == nacl_multimedia.audio.shutdown)) {
784 r = NaClCondVarWait(&nacl_multimedia.audio.condvar,
785 &nacl_multimedia.audio.mutex);
786 if (NACL_SYNC_OK != r)
787 NaClLog(LOG_FATAL, "NaClSliceSysAudio_Stream: cond var wait failed\n");
790 if (0 != nacl_multimedia.audio.shutdown) {
791 nacl_multimedia.audio.size = 0;
792 retval = -1;
794 /* return size of next audio block */
795 *syssize = (size_t)nacl_multimedia.audio.size;
796 r = NaClMutexUnlock(&nacl_multimedia.audio.mutex);
797 if (NACL_SYNC_OK != r)
798 NaClLog(LOG_FATAL,
799 "NaClSliceSysAudio_Stream: audio mutex unlock failed\n");
801 done:
802 r = NaClMutexUnlock(&nacl_multimedia_mutex);
803 if (NACL_SYNC_OK != r)
804 NaClLog(LOG_FATAL,
805 "NaClSliceSysAudio_Stream: global mutex unlock failed\n");
806 return retval;
810 #endif /* HAVE_SDL */