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.
33 * NaCl service runtime, bottom half routines for video.
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"
49 # include "native_client/service_runtime/include/sys/audio_video.h"
52 int NaClClosureResultCtor(struct NaClClosureResult
*self
)
54 self
->result_valid
= 0;
56 if (!NaClMutexCtor(&self
->mu
)) {
59 if (!NaClCondVarCtor(&self
->cv
)) {
60 NaClMutexDtor(&self
->mu
);
66 void NaClClosureResultDtor(struct NaClClosureResult
*self
)
68 NaClMutexDtor(&self
->mu
);
69 NaClCondVarDtor(&self
->cv
);
72 void *NaClClosureResultWait(struct NaClClosureResult
*self
)
76 NaClXMutexLock(&self
->mu
);
77 while (!self
->result_valid
) {
78 NaClXCondVarWait(&self
->cv
, &self
->mu
);
81 self
->result_valid
= 0;
82 NaClXMutexUnlock(&self
->mu
);
87 void NaClClosureResultDone(struct NaClClosureResult
*self
,
90 NaClXMutexLock(&self
->mu
);
91 if (self
->result_valid
) {
92 NaClLog(LOG_FATAL
, "NaClClosureResultDone: result already present?!?\n");
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",
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",
115 return (uint32_t) NaClClosureResultWait(&natp
->result
);
119 #if defined(HAVE_SDL)
122 typedef struct InfoVideo
{
126 int32_t bits_per_pixel
;
127 int32_t bytes_per_pixel
;
135 typedef struct InfoAudio
{
136 SDL_AudioSpec
*audio_spec
;
137 struct NaClMutex mutex
;
138 struct NaClCondVar condvar
;
141 unsigned char *stream
;
144 SDL_AudioSpec obtained
;
145 struct NaClAppThread
*thread_ptr
;
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 */
160 static struct InfoMultimedia nacl_multimedia
;
161 static struct NaClMutex nacl_multimedia_mutex
;
164 void NaClMultimediaModuleInit() {
166 /* clear all values in nacl_multimedia to 0 */
167 memset(&nacl_multimedia
, 0, sizeof(nacl_multimedia
));
168 r
= NaClMutexCtor(&nacl_multimedia_mutex
);
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
) {
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
;
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
;
222 nacl_multimedia
.initialized
= 1;
226 r
= NaClMutexUnlock(&nacl_multimedia_mutex
);
227 if (NACL_SYNC_OK
!= r
)
229 "NaClBotSysMultimedia_Init: mutex unlock failed\n");
231 NaClClosureResultDone(&natp
->result
, (void *) retval
);
235 void NaClBotSysMultimedia_Shutdown(struct NaClAppThread
*natp
) {
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
)
246 "NaClBotSysMultimedia_Shutdown: video subsystem not shutdown!\n");
247 if (0 != nacl_multimedia
.have_audio
)
249 "NaClBotSysMultimedia_Shutdown: audio subsystem not shutdown!\n");
253 nacl_multimedia
.sdl_init_flags
= 0;
254 nacl_multimedia
.initialized
= 0;
256 r
= NaClMutexUnlock(&nacl_multimedia_mutex
);
257 if (NACL_SYNC_OK
!= r
)
259 "NaClBotSysMultimedia_Shutdown: mutex unlock failed\n");
261 NaClClosureResultDone(&natp
->result
, (void *) retval
);
265 void NaClBotSysVideo_Init(struct NaClAppThread
*natp
,
266 enum NaClVideoFormat format
,
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
))
292 "NaClBotSysVideo_Init: video not originally requested\n");
294 nacl_multimedia
.have_video
= 1;
295 nacl_multimedia
.video
.screen
= SDL_SetVideoMode(width
, height
,
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
;
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;
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");
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
)
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
)
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
;
366 nacl_multimedia
.have_video
= 0;
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
,
392 retval
= -NACL_ABI_EINVAL
;
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
,
405 if (kNaClBadAddress
== sysaddr
) {
406 NaClLog(LOG_ERROR
, "NaClBotSysVideo_Update: width, height: %d, %d\n",
407 nacl_multimedia
.video
.width
, nacl_multimedia
.video
.height
);
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);
423 "NaClBotSysVideo_Update: SDL_CreateRGBSurfaceFrom failed\n");
424 retval
= -NACL_ABI_EPERM
;
428 retval
= SDL_SetAlpha(image
, 0, 255);
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
);
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
);
446 NaClLog(LOG_ERROR
, "NaClBotSysVideo_Update: SDL_Flip failed\n");
447 retval
= -NACL_ABI_EPERM
;
448 goto done_free_image
;
452 /* fall through to free image and closure */
455 SDL_FreeSurface(image
);
457 NaClClosureResultDone(&natp
->result
, (void *) retval
);
461 void NaClBotSysVideo_Poll_Event(struct NaClAppThread
*natp
,
462 union NaClMultimediaEvent
*event
) {
468 if (0 == nacl_multimedia
.initialized
)
470 "NaClBotSysVideo_Poll_Event: multmedia not initialized!\n");
471 if (0 == nacl_multimedia
.have_video
)
473 "NaClBotSysVideo_Poll_Event: video subsystem not initialized!\n");
476 sdl_r
= SDL_PollEvent(&sdl_event
);
479 retval
= -NACL_ABI_ENODATA
;
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
;
489 case SDL_VIDEOEXPOSE
:
490 event
->type
= NACL_EVENT_EXPOSE
;
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
;
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
;
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
;
524 event
->type
= NACL_EVENT_QUIT
;
527 // an sdl event happened, but we don't support it
528 // so move along and try polling again
533 } while (0 != repoll
);
535 NaClClosureResultDone(&natp
->result
, (void *) retval
);
539 void __NaCl_InternalAudioCallback(void *unused
, Uint8
*stream
, int size
) {
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
)
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
)
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
,
571 int *obtained_samples
)
573 SDL_AudioSpec desired
;
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)) {
596 "NaClSysAudio_Init: desired sample value out of range\n");
597 retval
= -NACL_ABI_ERANGE
;
601 memset(&nacl_multimedia
.audio
, 0, sizeof(nacl_multimedia
.audio
));
602 memset(&desired
, 0, sizeof(desired
));
604 r
= NaClMutexCtor(&nacl_multimedia
.audio
.mutex
);
606 NaClLog(LOG_FATAL
, "NaClBotSysAudio_Init: mutex ctor failed\n");
607 r
= NaClCondVarCtor(&nacl_multimedia
.audio
.condvar
);
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;
627 /* we only support two simple high quality stereo formats */
628 NaClLog(LOG_ERROR
, "NaClSysAudio_Init: unsupported format\n");
629 retval
= -NACL_ABI_EINVAL
;
633 if (SDL_OpenAudio(&desired
, &nacl_multimedia
.audio
.obtained
) < 0) {
634 NaClLog(LOG_ERROR
, "NaClSysAudio_Init: Couldn't open SDL audio: %s\n",
636 retval
= -NACL_ABI_EIO
;
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
;
646 *obtained_samples
= nacl_multimedia
.audio
.obtained
.samples
;
648 nacl_multimedia
.have_audio
= 1;
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
) {
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 */
688 /* no more callbacks at this point */
689 nacl_multimedia
.have_audio
= 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
,
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
726 sysaddr
= NaClUserToSysAddrRange(natp
->nap
,
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
;
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
) {
742 "NaClSliceSysAudio_Stream: called from different thread\n");
745 /* validate data buffer based on last size */
746 sysaddr
= NaClUserToSysAddrRange(natp
->nap
,
748 nacl_multimedia
.audio
.size
);
749 if (kNaClBadAddress
== sysaddr
) {
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
) {
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
)
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;
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
)
799 "NaClSliceSysAudio_Stream: audio mutex unlock failed\n");
802 r
= NaClMutexUnlock(&nacl_multimedia_mutex
);
803 if (NACL_SYNC_OK
!= r
)
805 "NaClSliceSysAudio_Stream: global mutex unlock failed\n");
810 #endif /* HAVE_SDL */