src/audio/android/SDL_androidaudio.c
author Sam Lantinga
Thu, 21 Jan 2021 22:47:37 -0800
changeset 14759 a02964691d50
parent 14640 b2b3343a310d
permissions -rw-r--r--
Fixed build on Android and iOS
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2021 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_audio.h"
    28 #include "../SDL_audio_c.h"
    29 #include "SDL_androidaudio.h"
    30 
    31 #include "../../core/android/SDL_android.h"
    32 
    33 #include <android/log.h>
    34 
    35 static SDL_AudioDevice* audioDevice = NULL;
    36 static SDL_AudioDevice* captureDevice = NULL;
    37 
    38 static int
    39 ANDROIDAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
    40 {
    41     SDL_AudioFormat test_format;
    42 
    43     SDL_assert((captureDevice == NULL) || !iscapture);
    44     SDL_assert((audioDevice == NULL) || iscapture);
    45 
    46     if (iscapture) {
    47         captureDevice = this;
    48     } else {
    49         audioDevice = this;
    50     }
    51 
    52     this->hidden = (struct SDL_PrivateAudioData *) SDL_calloc(1, (sizeof *this->hidden));
    53     if (this->hidden == NULL) {
    54         return SDL_OutOfMemory();
    55     }
    56 
    57     test_format = SDL_FirstAudioFormat(this->spec.format);
    58     while (test_format != 0) { /* no "UNKNOWN" constant */
    59         if ((test_format == AUDIO_U8) ||
    60 			(test_format == AUDIO_S16) ||
    61 			(test_format == AUDIO_F32)) {
    62             this->spec.format = test_format;
    63             break;
    64         }
    65         test_format = SDL_NextAudioFormat();
    66     }
    67 
    68     if (test_format == 0) {
    69         /* Didn't find a compatible format :( */
    70         return SDL_SetError("No compatible audio format!");
    71     }
    72 
    73     if (Android_JNI_OpenAudioDevice(iscapture, &this->spec) < 0) {
    74         return -1;
    75     }
    76 
    77     SDL_CalculateAudioSpec(&this->spec);
    78 
    79     return 0;
    80 }
    81 
    82 static void
    83 ANDROIDAUDIO_PlayDevice(_THIS)
    84 {
    85     Android_JNI_WriteAudioBuffer();
    86 }
    87 
    88 static Uint8 *
    89 ANDROIDAUDIO_GetDeviceBuf(_THIS)
    90 {
    91     return Android_JNI_GetAudioBuffer();
    92 }
    93 
    94 static int
    95 ANDROIDAUDIO_CaptureFromDevice(_THIS, void *buffer, int buflen)
    96 {
    97     return Android_JNI_CaptureAudioBuffer(buffer, buflen);
    98 }
    99 
   100 static void
   101 ANDROIDAUDIO_FlushCapture(_THIS)
   102 {
   103     Android_JNI_FlushCapturedAudio();
   104 }
   105 
   106 static void
   107 ANDROIDAUDIO_CloseDevice(_THIS)
   108 {
   109     /* At this point SDL_CloseAudioDevice via close_audio_device took care of terminating the audio thread
   110        so it's safe to terminate the Java side buffer and AudioTrack
   111      */
   112     Android_JNI_CloseAudioDevice(this->iscapture);
   113     if (this->iscapture) {
   114         SDL_assert(captureDevice == this);
   115         captureDevice = NULL;
   116     } else {
   117         SDL_assert(audioDevice == this);
   118         audioDevice = NULL;
   119     }
   120     SDL_free(this->hidden);
   121 }
   122 
   123 static int
   124 ANDROIDAUDIO_Init(SDL_AudioDriverImpl * impl)
   125 {
   126     /* Set the function pointers */
   127     impl->OpenDevice = ANDROIDAUDIO_OpenDevice;
   128     impl->PlayDevice = ANDROIDAUDIO_PlayDevice;
   129     impl->GetDeviceBuf = ANDROIDAUDIO_GetDeviceBuf;
   130     impl->CloseDevice = ANDROIDAUDIO_CloseDevice;
   131     impl->CaptureFromDevice = ANDROIDAUDIO_CaptureFromDevice;
   132     impl->FlushCapture = ANDROIDAUDIO_FlushCapture;
   133 
   134     /* and the capabilities */
   135     impl->HasCaptureSupport = SDL_TRUE;
   136     impl->OnlyHasDefaultOutputDevice = 1;
   137     impl->OnlyHasDefaultCaptureDevice = 1;
   138 
   139     return 1;   /* this audio target is available. */
   140 }
   141 
   142 AudioBootStrap ANDROIDAUDIO_bootstrap = {
   143     "android", "SDL Android audio driver", ANDROIDAUDIO_Init, 0
   144 };
   145 
   146 /* Pause (block) all non already paused audio devices by taking their mixer lock */
   147 void ANDROIDAUDIO_PauseDevices(void)
   148 {
   149     /* TODO: Handle multiple devices? */
   150     struct SDL_PrivateAudioData *private;
   151     if(audioDevice != NULL && audioDevice->hidden != NULL) {
   152         private = (struct SDL_PrivateAudioData *) audioDevice->hidden;
   153         if (SDL_AtomicGet(&audioDevice->paused)) {
   154             /* The device is already paused, leave it alone */
   155             private->resume = SDL_FALSE;
   156         }
   157         else {
   158             SDL_LockMutex(audioDevice->mixer_lock);
   159             SDL_AtomicSet(&audioDevice->paused, 1);
   160             private->resume = SDL_TRUE;
   161         }
   162     }
   163 
   164     if(captureDevice != NULL && captureDevice->hidden != NULL) {
   165         private = (struct SDL_PrivateAudioData *) captureDevice->hidden;
   166         if (SDL_AtomicGet(&captureDevice->paused)) {
   167             /* The device is already paused, leave it alone */
   168             private->resume = SDL_FALSE;
   169         }
   170         else {
   171             SDL_LockMutex(captureDevice->mixer_lock);
   172             SDL_AtomicSet(&captureDevice->paused, 1);
   173             private->resume = SDL_TRUE;
   174         }
   175     }
   176 }
   177 
   178 /* Resume (unblock) all non already paused audio devices by releasing their mixer lock */
   179 void ANDROIDAUDIO_ResumeDevices(void)
   180 {
   181     /* TODO: Handle multiple devices? */
   182     struct SDL_PrivateAudioData *private;
   183     if(audioDevice != NULL && audioDevice->hidden != NULL) {
   184         private = (struct SDL_PrivateAudioData *) audioDevice->hidden;
   185         if (private->resume) {
   186             SDL_AtomicSet(&audioDevice->paused, 0);
   187             private->resume = SDL_FALSE;
   188             SDL_UnlockMutex(audioDevice->mixer_lock);
   189         }
   190     }
   191 
   192     if(captureDevice != NULL && captureDevice->hidden != NULL) {
   193         private = (struct SDL_PrivateAudioData *) captureDevice->hidden;
   194         if (private->resume) {
   195             SDL_AtomicSet(&captureDevice->paused, 0);
   196             private->resume = SDL_FALSE;
   197             SDL_UnlockMutex(captureDevice->mixer_lock);
   198         }
   199     }
   200 }
   201 
   202 #else 
   203 
   204 void ANDROIDAUDIO_ResumeDevices(void) {}
   205 void ANDROIDAUDIO_PauseDevices(void) {}
   206 
   207 #endif /* SDL_AUDIO_DRIVER_ANDROID */
   208 
   209 /* vi: set ts=4 sw=4 expandtab: */
   210