src/audio/android/SDL_androidaudio.c
author Ryan C. Gordon
Tue, 24 Jan 2017 16:18:25 -0500
changeset 10850 c9dc0068b0e7
parent 10737 3406a0f8b041
child 11811 5d94cb6b24d3
permissions -rw-r--r--
configure: report libsamplerate support status.
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
     4 
     5   This software is provided 'as-is', without any express or implied
     6   warranty.  In no event will the authors be held liable for any damages
     7   arising from the use of this software.
     8 
     9   Permission is granted to anyone to use this software for any purpose,
    10   including commercial applications, and to alter it and redistribute it
    11   freely, subject to the following restrictions:
    12 
    13   1. The origin of this software must not be misrepresented; you must not
    14      claim that you wrote the original software. If you use this software
    15      in a product, an acknowledgment in the product documentation would be
    16      appreciated but is not required.
    17   2. Altered source versions must be plainly marked as such, and must not be
    18      misrepresented as being the original software.
    19   3. This notice may not be removed or altered from any source distribution.
    20 */
    21 #include "../../SDL_internal.h"
    22 
    23 #if SDL_AUDIO_DRIVER_ANDROID
    24 
    25 /* Output audio to Android */
    26 
    27 #include "SDL_assert.h"
    28 #include "SDL_audio.h"
    29 #include "../SDL_audio_c.h"
    30 #include "SDL_androidaudio.h"
    31 
    32 #include "../../core/android/SDL_android.h"
    33 
    34 #include <android/log.h>
    35 
    36 static SDL_AudioDevice* audioDevice = NULL;
    37 static SDL_AudioDevice* captureDevice = NULL;
    38 
    39 static int
    40 ANDROIDAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
    41 {
    42     SDL_AudioFormat test_format;
    43 
    44     SDL_assert((captureDevice == NULL) || !iscapture);
    45     SDL_assert((audioDevice == NULL) || iscapture);
    46 
    47     if (iscapture) {
    48         captureDevice = this;
    49     } else {
    50         audioDevice = this;
    51     }
    52 
    53     this->hidden = (struct SDL_PrivateAudioData *) SDL_calloc(1, (sizeof *this->hidden));
    54     if (this->hidden == NULL) {
    55         return SDL_OutOfMemory();
    56     }
    57 
    58     test_format = SDL_FirstAudioFormat(this->spec.format);
    59     while (test_format != 0) { /* no "UNKNOWN" constant */
    60         if ((test_format == AUDIO_U8) || (test_format == AUDIO_S16LSB)) {
    61             this->spec.format = test_format;
    62             break;
    63         }
    64         test_format = SDL_NextAudioFormat();
    65     }
    66 
    67     if (test_format == 0) {
    68         /* Didn't find a compatible format :( */
    69         return SDL_SetError("No compatible audio format!");
    70     }
    71 
    72     if (this->spec.channels > 1) {
    73         this->spec.channels = 2;
    74     } else {
    75         this->spec.channels = 1;
    76     }
    77 
    78     if (this->spec.freq < 8000) {
    79         this->spec.freq = 8000;
    80     }
    81     if (this->spec.freq > 48000) {
    82         this->spec.freq = 48000;
    83     }
    84 
    85     /* TODO: pass in/return a (Java) device ID */
    86     this->spec.samples = Android_JNI_OpenAudioDevice(iscapture, this->spec.freq, this->spec.format == AUDIO_U8 ? 0 : 1, this->spec.channels, this->spec.samples);
    87 
    88     if (this->spec.samples == 0) {
    89         /* Init failed? */
    90         return SDL_SetError("Java-side initialization failed!");
    91     }
    92 
    93     SDL_CalculateAudioSpec(&this->spec);
    94 
    95     return 0;
    96 }
    97 
    98 static void
    99 ANDROIDAUDIO_PlayDevice(_THIS)
   100 {
   101     Android_JNI_WriteAudioBuffer();
   102 }
   103 
   104 static Uint8 *
   105 ANDROIDAUDIO_GetDeviceBuf(_THIS)
   106 {
   107     return Android_JNI_GetAudioBuffer();
   108 }
   109 
   110 static int
   111 ANDROIDAUDIO_CaptureFromDevice(_THIS, void *buffer, int buflen)
   112 {
   113     return Android_JNI_CaptureAudioBuffer(buffer, buflen);
   114 }
   115 
   116 static void
   117 ANDROIDAUDIO_FlushCapture(_THIS)
   118 {
   119     Android_JNI_FlushCapturedAudio();
   120 }
   121 
   122 static void
   123 ANDROIDAUDIO_CloseDevice(_THIS)
   124 {
   125     /* At this point SDL_CloseAudioDevice via close_audio_device took care of terminating the audio thread
   126        so it's safe to terminate the Java side buffer and AudioTrack
   127      */
   128     Android_JNI_CloseAudioDevice(this->iscapture);
   129     if (this->iscapture) {
   130         SDL_assert(captureDevice == this);
   131         captureDevice = NULL;
   132     } else {
   133         SDL_assert(audioDevice == this);
   134         audioDevice = NULL;
   135     }
   136     SDL_free(this->hidden);
   137 }
   138 
   139 static int
   140 ANDROIDAUDIO_Init(SDL_AudioDriverImpl * impl)
   141 {
   142     /* Set the function pointers */
   143     impl->OpenDevice = ANDROIDAUDIO_OpenDevice;
   144     impl->PlayDevice = ANDROIDAUDIO_PlayDevice;
   145     impl->GetDeviceBuf = ANDROIDAUDIO_GetDeviceBuf;
   146     impl->CloseDevice = ANDROIDAUDIO_CloseDevice;
   147     impl->CaptureFromDevice = ANDROIDAUDIO_CaptureFromDevice;
   148     impl->FlushCapture = ANDROIDAUDIO_FlushCapture;
   149 
   150     /* and the capabilities */
   151     impl->HasCaptureSupport = SDL_TRUE;
   152     impl->OnlyHasDefaultOutputDevice = 1;
   153     impl->OnlyHasDefaultCaptureDevice = 1;
   154 
   155     return 1;   /* this audio target is available. */
   156 }
   157 
   158 AudioBootStrap ANDROIDAUDIO_bootstrap = {
   159     "android", "SDL Android audio driver", ANDROIDAUDIO_Init, 0
   160 };
   161 
   162 /* Pause (block) all non already paused audio devices by taking their mixer lock */
   163 void ANDROIDAUDIO_PauseDevices(void)
   164 {
   165     /* TODO: Handle multiple devices? */
   166     struct SDL_PrivateAudioData *private;
   167     if(audioDevice != NULL && audioDevice->hidden != NULL) {
   168         private = (struct SDL_PrivateAudioData *) audioDevice->hidden;
   169         if (SDL_AtomicGet(&audioDevice->paused)) {
   170             /* The device is already paused, leave it alone */
   171             private->resume = SDL_FALSE;
   172         }
   173         else {
   174             SDL_LockMutex(audioDevice->mixer_lock);
   175             SDL_AtomicSet(&audioDevice->paused, 1);
   176             private->resume = SDL_TRUE;
   177         }
   178     }
   179 
   180     if(captureDevice != NULL && captureDevice->hidden != NULL) {
   181         private = (struct SDL_PrivateAudioData *) captureDevice->hidden;
   182         if (SDL_AtomicGet(&captureDevice->paused)) {
   183             /* The device is already paused, leave it alone */
   184             private->resume = SDL_FALSE;
   185         }
   186         else {
   187             SDL_LockMutex(captureDevice->mixer_lock);
   188             SDL_AtomicSet(&captureDevice->paused, 1);
   189             private->resume = SDL_TRUE;
   190         }
   191     }
   192 }
   193 
   194 /* Resume (unblock) all non already paused audio devices by releasing their mixer lock */
   195 void ANDROIDAUDIO_ResumeDevices(void)
   196 {
   197     /* TODO: Handle multiple devices? */
   198     struct SDL_PrivateAudioData *private;
   199     if(audioDevice != NULL && audioDevice->hidden != NULL) {
   200         private = (struct SDL_PrivateAudioData *) audioDevice->hidden;
   201         if (private->resume) {
   202             SDL_AtomicSet(&audioDevice->paused, 0);
   203             private->resume = SDL_FALSE;
   204             SDL_UnlockMutex(audioDevice->mixer_lock);
   205         }
   206     }
   207 
   208     if(captureDevice != NULL && captureDevice->hidden != NULL) {
   209         private = (struct SDL_PrivateAudioData *) captureDevice->hidden;
   210         if (private->resume) {
   211             SDL_AtomicSet(&captureDevice->paused, 0);
   212             private->resume = SDL_FALSE;
   213             SDL_UnlockMutex(captureDevice->mixer_lock);
   214         }
   215     }
   216 }
   217 
   218 #else 
   219 
   220 void ANDROIDAUDIO_ResumeDevices(void) {}
   221 void ANDROIDAUDIO_PauseDevices(void) {}
   222 
   223 #endif /* SDL_AUDIO_DRIVER_ANDROID */
   224 
   225 /* vi: set ts=4 sw=4 expandtab: */
   226