1 /*
2 Simple DirectMedia Layer
3 Copyright (C) 1997-2016 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) || (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
ANDROIDAUDIO_PlayDevice(_THIS)99 ANDROIDAUDIO_PlayDevice(_THIS)
100 {
101 Android_JNI_WriteAudioBuffer();
102 }
103
104 static Uint8 *
ANDROIDAUDIO_GetDeviceBuf(_THIS)105 ANDROIDAUDIO_GetDeviceBuf(_THIS)
106 {
107 return Android_JNI_GetAudioBuffer();
108 }
109
110 static int
ANDROIDAUDIO_CaptureFromDevice(_THIS,void * buffer,int buflen)111 ANDROIDAUDIO_CaptureFromDevice(_THIS, void *buffer, int buflen)
112 {
113 return Android_JNI_CaptureAudioBuffer(buffer, buflen);
114 }
115
116 static void
ANDROIDAUDIO_FlushCapture(_THIS)117 ANDROIDAUDIO_FlushCapture(_THIS)
118 {
119 Android_JNI_FlushCapturedAudio();
120 }
121
122 static void
ANDROIDAUDIO_CloseDevice(_THIS)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
ANDROIDAUDIO_Init(SDL_AudioDriverImpl * impl)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 */
ANDROIDAUDIO_PauseDevices(void)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 */
ANDROIDAUDIO_ResumeDevices(void)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
219 #endif /* SDL_AUDIO_DRIVER_ANDROID */
220
221 /* vi: set ts=4 sw=4 expandtab: */
222
223