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