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%08"PRIxPTR
", 0x%08"PRIxPTR
")\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%08"PRIxPTR
")\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
;
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
;
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%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
;
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
,
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
))
291 "NaClBotSysVideo_Init: video not originally requested\n");
293 nacl_multimedia
.have_video
= 1;
294 nacl_multimedia
.video
.screen
= SDL_SetVideoMode(width
, height
,
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
;
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");
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
)
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
)
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
;
349 nacl_multimedia
.have_video
= 0;
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
,
375 retval
= -NACL_ABI_EINVAL
;
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
,
388 if (kNaClBadAddress
== sysaddr
) {
389 NaClLog(LOG_ERROR
, "NaClBotSysVideo_Update: width, height: %d, %d\n",
390 nacl_multimedia
.video
.width
, nacl_multimedia
.video
.height
);
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);
406 "NaClBotSysVideo_Update: SDL_CreateRGBSurfaceFrom failed\n");
407 retval
= -NACL_ABI_EPERM
;
411 retval
= SDL_SetAlpha(image
, 0, 255);
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
);
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
);
429 NaClLog(LOG_ERROR
, "NaClBotSysVideo_Update: SDL_Flip failed\n");
430 retval
= -NACL_ABI_EPERM
;
431 goto done_free_image
;
435 /* fall through to free image and closure */
438 SDL_FreeSurface(image
);
440 NaClClosureResultDone(&natp
->result
, (void *) retval
);
444 void NaClBotSysVideo_Poll_Event(struct NaClAppThread
*natp
,
445 union NaClMultimediaEvent
*event
) {
451 if (0 == nacl_multimedia
.initialized
)
453 "NaClBotSysVideo_Poll_Event: multmedia not initialized!\n");
454 if (0 == nacl_multimedia
.have_video
)
456 "NaClBotSysVideo_Poll_Event: video subsystem not initialized!\n");
459 sdl_r
= SDL_PollEvent(&sdl_event
);
462 retval
= -NACL_ABI_ENODATA
;
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
;
472 case SDL_VIDEOEXPOSE
:
473 event
->type
= NACL_EVENT_EXPOSE
;
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
;
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
;
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
;
507 event
->type
= NACL_EVENT_QUIT
;
510 // an sdl event happened, but we don't support it
511 // so move along and try polling again
516 } while (0 != repoll
);
518 NaClClosureResultDone(&natp
->result
, (void *) retval
);
522 void __NaCl_InternalAudioCallback(void *unused
, Uint8
*stream
, int size
) {
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
)
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
) {
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
,
555 int *obtained_samples
)
557 SDL_AudioSpec desired
;
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)) {
580 "NaClSysAudio_Init: desired sample value out of range\n");
581 retval
= -NACL_ABI_ERANGE
;
585 memset(&nacl_multimedia
.audio
, 0, sizeof(nacl_multimedia
.audio
));
586 memset(&desired
, 0, sizeof(desired
));
588 r
= NaClMutexCtor(&nacl_multimedia
.audio
.mutex
);
590 NaClLog(LOG_FATAL
, "NaClBotSysAudio_Init: mutex ctor failed\n");
591 r
= NaClCondVarCtor(&nacl_multimedia
.audio
.condvar
);
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;
611 /* we only support two simple high quality stereo formats */
612 NaClLog(LOG_ERROR
, "NaClSysAudio_Init: unsupported format\n");
613 retval
= -NACL_ABI_EINVAL
;
617 if (SDL_OpenAudio(&desired
, &nacl_multimedia
.audio
.obtained
) < 0) {
618 NaClLog(LOG_ERROR
, "NaClSysAudio_Init: Couldn't open SDL audio: %s\n",
620 retval
= -NACL_ABI_EIO
;
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
;
630 *obtained_samples
= nacl_multimedia
.audio
.obtained
.samples
;
632 nacl_multimedia
.have_audio
= 1;
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
) {
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 */
673 /* no more callbacks at this point */
674 nacl_multimedia
.have_audio
= 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
,
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
711 sysaddr
= NaClUserToSysAddrRange(natp
->nap
,
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
;
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
) {
727 "NaClSliceSysAudio_Stream: called from different thread\n");
730 /* validate data buffer based on last size */
731 sysaddr
= NaClUserToSysAddrRange(natp
->nap
,
733 nacl_multimedia
.audio
.size
);
734 if (kNaClBadAddress
== sysaddr
) {
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
) {
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
)
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
) {
774 "__NaCl_InternalAudioCallback: cond var wait failed\n");
778 if (0 != nacl_multimedia
.audio
.shutdown
) {
779 nacl_multimedia
.audio
.size
= 0;
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
)
787 "NaClSliceSysAudio_Stream: audio mutex unlock failed\n");
790 r
= NaClMutexUnlock(&nacl_multimedia_mutex
);
791 if (NACL_SYNC_OK
!= r
)
793 "NaClSliceSysAudio_Stream: global mutex unlock failed\n");
798 #endif /* HAVE_SDL */