• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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