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