• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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