1 /*
2 * snd_android.c
3 * Android-specific sound interface
4 *
5 */
6
7 #include "quakedef.h"
8
9 #include <pthread.h>
10 #include <time.h>
11 #include <math.h>
12 #include <stdlib.h>
13 #include <unistd.h>
14
15 #include <android/log.h>
16 #include <SLES/OpenSLES.h>
17
18 #define LOG_TAG "Quake snd_android"
19 #define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
20 #define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)
21
22 const size_t SAMPLE_RATE = 11025;
23
24
25 const size_t BYTES_PER_SAMPLE = 2;
26 const size_t CHANNEL_COUNT = 2;
27 const size_t BITS_PER_SAMPLE = 8 * BYTES_PER_SAMPLE;
28
29 const size_t TOTAL_BUFFER_SIZE = 4 * 1024;
30
31 #define MAX_NUMBER_INTERFACES 3
32
33 /* Local storage for Audio data in 16 bit words */
34 #define AUDIO_DATA_STORAGE_SIZE (TOTAL_BUFFER_SIZE / 2)
35 /* Audio data buffer size in 16 bit words. 8 data segments are used in
36 this simple example */
37 #define AUDIO_DATA_BUFFER_SIZE (4096/8)
38
39 const size_t NUMBER_OF_BUFFERS = AUDIO_DATA_STORAGE_SIZE / AUDIO_DATA_BUFFER_SIZE;
40
41 /* Checks for error. If any errors exit the application! */
CheckErr(SLresult res)42 void CheckErr( SLresult res )
43 {
44 if ( res != SL_RESULT_SUCCESS )
45 {
46 fprintf(stdout, "%u SL failure, exiting\n", res);
47 exit(EXIT_FAILURE);
48 }
49 else {
50 //fprintf(stdout, "%d SL success, proceeding...\n", res);
51 }
52 }
53
54 /* Structure for passing information to callback function */
55 typedef struct CallbackCntxt_ {
56 SLPlayItf playItf;
57 SLint16* pDataBase; // Base adress of local audio data storage
58 SLint16* pData; // Current adress of local audio data storage
59 SLuint32 size;
60 } CallbackCntxt;
61
62 /* Local storage for Audio data */
63 SLint16 pcmData[AUDIO_DATA_STORAGE_SIZE];
64
65 /* Callback for Buffer Queue events */
BufferQueueCallback(SLBufferQueueItf queueItf,void * pContext)66 void BufferQueueCallback(
67 SLBufferQueueItf queueItf,
68 void *pContext)
69 {
70 //fprintf(stdout, "BufferQueueCallback called\n");
71 SLresult res;
72 //fprintf(stdout, " pContext=%p\n", pContext);
73 CallbackCntxt *pCntxt = (CallbackCntxt*)pContext;
74
75 if (pCntxt->pData >= (pCntxt->pDataBase + pCntxt->size)) {
76 pCntxt->pData = pCntxt->pDataBase;
77 }
78 {
79 //fprintf(stdout, "callback: before enqueue\n");
80 res = (*queueItf)->Enqueue(queueItf, (void*) pCntxt->pData,
81 2 * AUDIO_DATA_BUFFER_SIZE); /* Size given in bytes. */
82 CheckErr(res);
83 /* Increase data pointer by buffer size */
84 pCntxt->pData += AUDIO_DATA_BUFFER_SIZE;
85 }
86 //fprintf(stdout, "end of BufferQueueCallback()\n");
87 }
88
89 SLEngineItf EngineItf;
90
91 SLint32 numOutputs = 0;
92 SLuint32 deviceID = 0;
93
94
95 SLDataSource audioSource;
96 SLDataLocator_BufferQueue bufferQueue;
97 SLDataFormat_PCM pcm;
98
99 SLDataSink audioSink;
100 SLDataLocator_OutputMix locator_outputmix;
101
102
103 SLVolumeItf volumeItf;
104
105
106 SLboolean required[MAX_NUMBER_INTERFACES];
107 SLInterfaceID iidArray[MAX_NUMBER_INTERFACES];
108
109 /* Callback context for the buffer queue callback function */
110 CallbackCntxt cntxt;
111
112 static SLObjectItf OutputMix;
113 static SLPlayItf playItf;
114 static SLObjectItf player;
115 static SLBufferQueueItf bufferQueueItf;
116 static SLBufferQueueState state;
117
118 /* Play some audio from a buffer queue */
TestPlaySawtoothBufferQueue(SLObjectItf sl)119 void TestPlaySawtoothBufferQueue( SLObjectItf sl )
120 {
121 SLresult res;
122 int i;
123
124 /* Get the SL Engine Interface which is implicit */
125 res = (*sl)->GetInterface(sl, SL_IID_ENGINE, (void*)&EngineItf);
126 CheckErr(res);
127
128 /* Initialize arrays required[] and iidArray[] */
129 for (i=0;i<MAX_NUMBER_INTERFACES;i++)
130 {
131 required[i] = SL_BOOLEAN_FALSE;
132 iidArray[i] = SL_IID_NULL;
133 }
134
135 // Set arrays required[] and iidArray[] for VOLUME interface
136 required[0] = SL_BOOLEAN_TRUE;
137 iidArray[0] = SL_IID_VOLUME;
138 // Create Output Mix object to be used by player
139 res = (*EngineItf)->CreateOutputMix(EngineItf, &OutputMix, 0,
140 iidArray, required); CheckErr(res);
141
142 // Realizing the Output Mix object in synchronous mode.
143 res = (*OutputMix)->Realize(OutputMix, SL_BOOLEAN_FALSE);
144 CheckErr(res);
145
146 #if 0
147 res = (*OutputMix)->GetInterface(OutputMix, SL_IID_VOLUME,
148 (void*)&volumeItf); CheckErr(res);
149 #endif
150
151 /* Setup the data source structure for the buffer queue */
152 bufferQueue.locatorType = SL_DATALOCATOR_BUFFERQUEUE;
153 bufferQueue.numBuffers = 4; /* Four buffers in our buffer queue */
154
155 /* Setup the format of the content in the buffer queue */
156 pcm.formatType = SL_DATAFORMAT_PCM;
157 pcm.numChannels = 2;
158 pcm.samplesPerSec = SL_SAMPLINGRATE_11_025;
159 pcm.bitsPerSample = SL_PCMSAMPLEFORMAT_FIXED_16;
160 pcm.containerSize = 16;
161 pcm.channelMask = SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT;
162 pcm.endianness = SL_BYTEORDER_LITTLEENDIAN;
163
164 audioSource.pFormat = (void *)&pcm;
165 audioSource.pLocator = (void *)&bufferQueue;
166
167 /* Setup the data sink structure */
168 locator_outputmix.locatorType = SL_DATALOCATOR_OUTPUTMIX;
169 locator_outputmix.outputMix = OutputMix;
170 audioSink.pLocator = (void *)&locator_outputmix;
171 audioSink.pFormat = NULL;
172
173 /* Initialize the audio data to silence */
174 memset(pcmData, 0, sizeof(pcmData));
175
176 /* Initialize the context for Buffer queue callbacks */
177 cntxt.pDataBase = /*(void*)&*/pcmData;
178 cntxt.pData = cntxt.pDataBase;
179 cntxt.size = sizeof(pcmData) / 2;
180
181 /* Set arrays required[] and iidArray[] for SEEK interface
182 (PlayItf is implicit) */
183 required[0] = SL_BOOLEAN_TRUE;
184 iidArray[0] = SL_IID_BUFFERQUEUE;
185
186 /* Create the music player */
187 res = (*EngineItf)->CreateAudioPlayer(EngineItf, &player,
188 &audioSource, &audioSink, 1, iidArray, required); CheckErr(res);
189 fprintf(stdout, "bufferQueue example: after CreateAudioPlayer\n");
190
191 /* Realizing the player in synchronous mode. */
192 res = (*player)->Realize(player, SL_BOOLEAN_FALSE); CheckErr(res);
193 fprintf(stdout, "bufferQueue example: after Realize\n");
194
195 /* Get seek and play interfaces */
196 res = (*player)->GetInterface(player, SL_IID_PLAY, (void*)&playItf);
197 CheckErr(res);
198 fprintf(stdout, "bufferQueue example: after GetInterface(PLAY)\n");
199
200 res = (*player)->GetInterface(player, SL_IID_BUFFERQUEUE,
201 (void*)&bufferQueueItf); CheckErr(res);
202
203 /* Setup to receive buffer queue event callbacks */
204 res = (*bufferQueueItf)->RegisterCallback(bufferQueueItf,
205 BufferQueueCallback, &cntxt); CheckErr(res);
206
207 #if 0
208 /* Before we start set volume to -3dB (-300mB) */
209 res = (*volumeItf)->SetVolumeLevel(volumeItf, -300); CheckErr(res);
210 #endif
211
212 /* Enqueue a few buffers to get the ball rolling */
213 res = (*bufferQueueItf)->Enqueue(bufferQueueItf, cntxt.pData,
214 2 * AUDIO_DATA_BUFFER_SIZE); /* Size given in bytes. */
215 CheckErr(res);
216 cntxt.pData += AUDIO_DATA_BUFFER_SIZE;
217
218 res = (*bufferQueueItf)->Enqueue(bufferQueueItf, cntxt.pData,
219 2 * AUDIO_DATA_BUFFER_SIZE); /* Size given in bytes. */
220 CheckErr(res);
221 cntxt.pData += AUDIO_DATA_BUFFER_SIZE;
222
223 res = (*bufferQueueItf)->Enqueue(bufferQueueItf, cntxt.pData,
224 2 * AUDIO_DATA_BUFFER_SIZE); /* Size given in bytes. */
225 CheckErr(res);
226 cntxt.pData += AUDIO_DATA_BUFFER_SIZE;
227
228 /* Play the PCM samples using a buffer queue */
229 fprintf(stdout, "bufferQueue example: starting to play\n");
230 res = (*playItf)->SetPlayState( playItf, SL_PLAYSTATE_PLAYING );
231 CheckErr(res);
232
233 /* Wait until the PCM data is done playing, the buffer queue callback
234 will continue to queue buffers until the entire PCM data has been
235 played. This is indicated by waiting for the count member of the
236 SLBufferQueueState to go to zero.
237 */
238 res = (*bufferQueueItf)->GetState(bufferQueueItf, &state);
239 CheckErr(res);
240
241 #if 0
242 // while (state.playIndex < 100) {
243 while (state.count) {
244 usleep(10000);
245 (*bufferQueueItf)->GetState(bufferQueueItf, &state);
246 }
247
248 #endif
249 }
250
251 SLObjectItf gSoundEngine;
252
startAndroidSound()253 int startAndroidSound()
254 {
255 SLresult res;
256
257 SLEngineOption EngineOption[] = {
258 {(SLuint32) SL_ENGINEOPTION_THREADSAFE,
259 (SLuint32) SL_BOOLEAN_TRUE}};
260
261 res = slCreateEngine( &gSoundEngine, 1, EngineOption, 0, NULL, NULL);
262 CheckErr(res);
263 /* Realizing the SL Engine in synchronous mode. */
264 res = (*gSoundEngine)->Realize(gSoundEngine, SL_BOOLEAN_FALSE); CheckErr(res);
265
266 /* Run the test */
267 TestPlaySawtoothBufferQueue(gSoundEngine);
268 return EXIT_SUCCESS;
269 }
270
finishAndroidSound()271 void finishAndroidSound()
272 {
273 SLresult res;
274
275 if (gSoundEngine == NULL) {
276 return;
277 }
278
279 /* Make sure player is stopped */
280 if (playItf != NULL) {
281 res = (*playItf)->SetPlayState(playItf, SL_PLAYSTATE_STOPPED);
282 CheckErr(res);
283 playItf = NULL;
284 }
285
286 if (player != NULL) {
287 /* Destroy the player */
288 (*player)->Destroy(player);
289 player = NULL;
290 }
291
292 if (OutputMix != NULL) {
293 /* Destroy Output Mix object */
294 (*OutputMix)->Destroy(OutputMix);
295 OutputMix = NULL;
296 }
297
298 /* Shutdown OpenSL ES */
299 (*gSoundEngine)->Destroy(gSoundEngine);
300 gSoundEngine = NULL;
301 }
302
303 #if 1
304
305 /*
306 ==================
307 SNDDMA_Init
308
309 Try to find a sound device to mix for.
310 Returns false if nothing is found.
311 ==================
312 */
SNDDMA_Init(void)313 qboolean SNDDMA_Init(void)
314 {
315 // Initialize Quake's idea of a DMA buffer.
316
317 shm = &sn;
318 memset((void*)&sn, 0, sizeof(sn));
319
320 shm->splitbuffer = false; // Not used.
321 shm->samplebits = 16;
322 shm->speed = 11025;
323 shm->channels = 2;
324 shm->samples = TOTAL_BUFFER_SIZE / BYTES_PER_SAMPLE;
325 shm->samplepos = 0; // Not used.
326 shm->buffer = (unsigned char*) pcmData;
327 shm->submission_chunk = 1; // Not used.
328
329 shm->soundalive = true;
330
331 if ( (shm->samples & 0x1ff) != 0 ) {
332 LOGE("SNDDDMA_Init: samples must be power of two.");
333 return false;
334 }
335
336 if ( shm->buffer == 0 ) {
337 LOGE("SNDDDMA_Init: Could not allocate sound buffer.");
338 return false;
339 }
340
341 int result = startAndroidSound();
342 return result == EXIT_SUCCESS;
343 }
344
345 /*
346 ==============
347 SNDDMA_GetDMAPos
348
349 return the current sample position (in mono samples read)
350 inside the recirculating dma buffer, so the mixing code will know
351 how many sample are required to fill it up.
352 ===============
353 */
SNDDMA_GetDMAPos(void)354 int SNDDMA_GetDMAPos(void)
355 {
356 SLresult res;
357 if (bufferQueueItf != NULL) {
358 res = (*bufferQueueItf)->GetState(bufferQueueItf, &state);
359 CheckErr(res);
360 // Index of the currently playing or filling buffer.
361 SLuint32 playIndex = state.playIndex;
362 int ringIndex = playIndex % NUMBER_OF_BUFFERS;
363 return ringIndex * AUDIO_DATA_BUFFER_SIZE;
364 }
365 return 0;
366 }
367
368 /*
369 ===============
370 SNDDMA_ReportWrite
371
372 Report valid data being written into the DMA buffer by the sound mixing code.
373 This is an Android specific API.
374 ================
375 */
SNDDMA_ReportWrite(size_t lengthBytes)376 void SNDDMA_ReportWrite(size_t lengthBytes) {
377 // TODO: keep track of how much of the sound ring buffer has sound in it,
378 // detect starvation, and mix silence when we are starving.
379 }
380
381 /*
382 ==============
383 SNDDMA_Submit
384
385 Send sound to device if buffer isn't really the dma buffer
386 ===============
387 */
SNDDMA_Submit(void)388 void SNDDMA_Submit(void)
389 {
390 }
391
392 /*
393 ==============
394 SNDDMA_Shutdown
395
396 Reset the sound device for exiting
397 ===============
398 */
SNDDMA_Shutdown(void)399 void SNDDMA_Shutdown(void)
400 {
401 finishAndroidSound();
402 }
403
404
405 #else
406
407 // Written by the callback function running in an audio thread.
408 // index in bytes of where we last read.
409
410 static volatile size_t gDMAByteIndex;
411
412
413 // Written by main thread
414 static size_t gAvailableBytes;
415 static bool gSoundMixingStarted;
416
417 // The condition is "new data is now available"
418
419 static pthread_mutex_t condition_mutex = PTHREAD_MUTEX_INITIALIZER;
420 static pthread_cond_t condition_cond = PTHREAD_COND_INITIALIZER;
421
422 /*
423 ==================
424 SNDDMA_Init
425
426 Try to find a sound device to mix for.
427 Returns false if nothing is found.
428 ==================
429 */
430
431
432 const size_t SAMPLE_RATE = 11025;
433
434
435 const size_t BYTES_PER_SAMPLE = 2;
436 const size_t CHANNEL_COUNT = 2;
437 const size_t BITS_PER_SAMPLE = 8 * BYTES_PER_SAMPLE;
438
439 const size_t TOTAL_BUFFER_SIZE = 16 * 1024;
440
min(size_t a,size_t b)441 static size_t min(size_t a, size_t b) {
442 return a < b ? a : b;
443 }
444
mod(size_t value,size_t mod)445 static size_t mod(size_t value, size_t mod) {
446 return value % mod;
447 }
448
next(size_t value,size_t mod)449 static size_t next(size_t value, size_t mod) {
450 value = value + 1;
451 if ( value >= mod ) {
452 value = 0;
453 }
454 return value;
455 }
456
prev(size_t value,size_t mod)457 static size_t prev(size_t value, size_t mod) {
458 if ( value <= 0 ) {
459 value = mod;
460 }
461 return value - 1;
462 }
463
464
enableSound()465 static bool enableSound() {
466
467 if (COM_CheckParm("-nosound"))
468 return false;
469
470 return true;
471 }
472
473 // Choose one:
474
475 // #define GENERATE_SINE_WAVE
476 #define NORMAL_SOUND
477
478 #ifdef GENERATE_SINE_WAVE
479
480 static const float p = 2 * M_PI * 440.0f / SAMPLE_RATE;
481 static float left = 0.0f;
482 static float right = 0.0f;
483
sinef(float x)484 static float sinef(float x)
485 {
486 const float A = 1.0f / (2.0f*M_PI);
487 const float B = -16.0f;
488 const float C = 8.0f;
489
490 // scale angle for easy argument reduction
491 x *= A;
492
493 if (fabsf(x) >= 0.5f) {
494 // Argument reduction
495 x = x - ceilf(x + 0.5f) + 1.0f;
496 }
497
498 const float y = B*x*fabsf(x) + C*x;
499 return 0.2215f * (y*fabsf(y) - y) + y;
500 }
501
502 static
AndroidQuakeSoundCallback(int event,void * user,void * info)503 void AndroidQuakeSoundCallback(int event, void* user, void *info) {
504
505 if (event != AudioTrack::EVENT_MORE_DATA) return;
506
507 const AudioTrack::Buffer *buffer = static_cast<const AudioTrack::Buffer *>(info);
508 size_t bytesToCopy = buffer->size;
509 size_t framesToCopy = buffer->size / (BYTES_PER_SAMPLE * CHANNEL_COUNT);
510 short* pData = buffer->i16;
511
512 for(size_t frame = 0; frame < framesToCopy; frame++) {
513 short leftSample = (short) (32767.0f * sinef(left));
514 left += p;
515 if (left > 2*M_PI) {
516 left -= 2*M_PI;
517 }
518 pData[frame * CHANNEL_COUNT] = leftSample;
519
520 short rightSample = (short) (32767.0f * sinef(right));
521 right += 2 * p;
522 if (right > 2*M_PI) {
523 right -= 2*M_PI;
524 }
525 pData[1 + frame * CHANNEL_COUNT] = rightSample;
526 }
527
528 gDMAByteIndex = mod(gDMAByteIndex + bytesToCopy, TOTAL_BUFFER_SIZE);
529 asm volatile ("":::"memory");
530 }
531
532 #endif
533
534 #ifdef NORMAL_SOUND
535
536 static bool gWaitingForMixerToRestart;
537
538 // Assumes the mutex is acquired.
539 // Waits until audio is available or a time period has elapsed.
shouldMixSilence()540 static bool shouldMixSilence() {
541 if (!gSoundMixingStarted) {
542 return true;
543 }
544 while (gAvailableBytes == 0) {
545 if (gWaitingForMixerToRestart) {
546 return true;
547 }
548 timeval tp;
549 if (gettimeofday(&tp, NULL)) {
550 return true;
551 }
552 const long WAIT_NS = 40 * 1000 * 1000;
553 const long NS_PER_SECOND = 1000 * 1000 * 1000;
554 timespec ts;
555 ts.tv_sec = tp.tv_sec;
556 ts.tv_nsec = tp.tv_usec * 1000 + WAIT_NS;
557 if (ts.tv_nsec >= NS_PER_SECOND) {
558 ts.tv_nsec -= NS_PER_SECOND;
559 ts.tv_sec += 1;
560 }
561 if (ETIMEDOUT == pthread_cond_timedwait( &condition_cond, &condition_mutex, &ts)) {
562 gWaitingForMixerToRestart = true;
563 return true;
564 }
565 }
566 gWaitingForMixerToRestart = false;
567 return false;
568 }
569
570 static
AndroidQuakeSoundCallback(int event,void * user,void * info)571 void AndroidQuakeSoundCallback(int event, void* user, void *info) {
572
573 if (event != AudioTrack::EVENT_MORE_DATA) return;
574
575 const AudioTrack::Buffer *buffer = static_cast<const AudioTrack::Buffer *>(info);
576 size_t dmaByteIndex = gDMAByteIndex;
577 size_t size = buffer->size;
578 unsigned char* pDestBuffer = (unsigned char*) buffer->raw;
579
580 if (size == 0) return;
581
582 if ( ! shm ) {
583 memset(pDestBuffer, 0, size);
584 return;
585 }
586
587 const unsigned char* pSrcBuffer = shm->buffer;
588
589 while(size > 0) {
590 pthread_mutex_lock( &condition_mutex );
591
592 if (shouldMixSilence()) {
593 memset(pDestBuffer, 0, size);
594 pthread_mutex_unlock( &condition_mutex );
595 return;
596 }
597
598 size_t chunkSize = min(gAvailableBytes, min(TOTAL_BUFFER_SIZE-dmaByteIndex, size));
599 gAvailableBytes -= chunkSize;
600
601 pthread_mutex_unlock( &condition_mutex );
602
603 memcpy(pDestBuffer, pSrcBuffer + dmaByteIndex, chunkSize);
604 size -= chunkSize;
605 pDestBuffer += chunkSize;
606 dmaByteIndex += chunkSize;
607 if (dmaByteIndex >= TOTAL_BUFFER_SIZE) {
608 dmaByteIndex = 0;
609 }
610 }
611
612 gDMAByteIndex = dmaByteIndex;
613 asm volatile ("":::"memory");
614 }
615
616 #endif
617
SNDDMA_Init(void)618 qboolean SNDDMA_Init(void)
619 {
620 if ( ! enableSound() ) {
621 return false;
622 }
623
624 gDMAByteIndex = 0;
625
626 // Initialize the AudioTrack.
627
628 status_t result = gAudioTrack.set(
629 AUDIO_STREAM_DEFAULT, // stream type
630 SAMPLE_RATE, // sample rate
631 BITS_PER_SAMPLE == 16 ? AUDIO_FORMAT_PCM_16_BIT : AUDIO_FORMAT_PCM_8_BIT, // format (8 or 16)
632 (CHANNEL_COUNT > 1) ? AUDIO_CHANNEL_OUT_STEREO : AUDIO_CHANNEL_OUT_MONO, // channel mask
633 0, // default buffer size
634 0, // flags
635 AndroidQuakeSoundCallback, // callback
636 0, // user
637 0); // default notification size
638
639 LOGI("AudioTrack status = %d (%s)\n", result, result == NO_ERROR ? "success" : "error");
640
641 if ( result == NO_ERROR ) {
642 LOGI("AudioTrack latency = %u ms\n", gAudioTrack.latency());
643 LOGI("AudioTrack format = %u bits\n", gAudioTrack.format() == AUDIO_FORMAT_PCM_16_BIT ? 16 : 8);
644 LOGI("AudioTrack sample rate = %u Hz\n", gAudioTrack.getSampleRate());
645 LOGI("AudioTrack frame count = %d\n", int(gAudioTrack.frameCount()));
646 LOGI("AudioTrack channel count = %d\n", gAudioTrack.channelCount());
647
648 // Initialize Quake's idea of a DMA buffer.
649
650 shm = &sn;
651 memset((void*)&sn, 0, sizeof(sn));
652
653 shm->splitbuffer = false; // Not used.
654 shm->samplebits = gAudioTrack.format() == AUDIO_FORMAT_PCM_16_BIT ? 16 : 8;
655 shm->speed = gAudioTrack.getSampleRate();
656 shm->channels = gAudioTrack.channelCount();
657 shm->samples = TOTAL_BUFFER_SIZE / BYTES_PER_SAMPLE;
658 shm->samplepos = 0; // Not used.
659 shm->buffer = (unsigned char*) Hunk_AllocName(TOTAL_BUFFER_SIZE, (char*) "shmbuf");
660 shm->submission_chunk = 1; // Not used.
661
662 shm->soundalive = true;
663
664 if ( (shm->samples & 0x1ff) != 0 ) {
665 LOGE("SNDDDMA_Init: samples must be power of two.");
666 return false;
667 }
668
669 if ( shm->buffer == 0 ) {
670 LOGE("SNDDDMA_Init: Could not allocate sound buffer.");
671 return false;
672 }
673
674 gAudioTrack.setVolume(1.0f, 1.0f);
675 gAudioTrack.start();
676 }
677
678 return result == NO_ERROR;
679 }
680
681 /*
682 ==============
683 SNDDMA_GetDMAPos
684
685 return the current sample position (in mono samples read)
686 inside the recirculating dma buffer, so the mixing code will know
687 how many sample are required to fill it up.
688 ===============
689 */
SNDDMA_GetDMAPos(void)690 int SNDDMA_GetDMAPos(void)
691 {
692 int dmaPos = gDMAByteIndex / BYTES_PER_SAMPLE;
693 asm volatile ("":::"memory");
694 return dmaPos;
695 }
696
697 /*
698 ===============
699 SNDDMA_ReportWrite
700
701 Report valid data being written into the DMA buffer by the sound mixing code.
702 This is an Android specific API.
703 ================
704 */
SNDDMA_ReportWrite(size_t lengthBytes)705 void SNDDMA_ReportWrite(size_t lengthBytes) {
706 pthread_mutex_lock( &condition_mutex );
707 gSoundMixingStarted = true;
708 if (gAvailableBytes == 0) {
709 pthread_cond_signal( &condition_cond );
710 }
711 gAvailableBytes += lengthBytes;
712 pthread_mutex_unlock( &condition_mutex );
713 }
714
715 /*
716 ==============
717 SNDDMA_Submit
718
719 Send sound to device if buffer isn't really the dma buffer
720 ===============
721 */
SNDDMA_Submit(void)722 void SNDDMA_Submit(void)
723 {
724 }
725
726 /*
727 ==============
728 SNDDMA_Shutdown
729
730 Reset the sound device for exiting
731 ===============
732 */
SNDDMA_Shutdown(void)733 void SNDDMA_Shutdown(void)
734 {
735 gAudioTrack.stop();
736 }
737
738 #endif
739