Changed how device format is selected in restart_playback, and other small changes...
[openal-soft/android.git] / Alc / android.c
blob66c1f52600c3b5f014f34bd50f551d15b063c1b6
1 /**
2 * OpenAL cross platform audio library
3 * Copyright (C) 2010 by Chris Robinson
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
18 * Or go to http://www.gnu.org/copyleft/lgpl.html
21 #include "config.h"
23 #include <stdlib.h>
24 #include <jni.h>
25 #include <pthread.h>
26 #include "alMain.h"
27 #include "AL/al.h"
28 #include "AL/alc.h"
30 static const ALCchar android_device[] = "Android Default";
32 static JavaVM* javaVM = NULL;
34 static jclass cAudioTrack = NULL;
36 static jmethodID mAudioTrack;
37 static jmethodID mGetMinBufferSize;
38 static jmethodID mPlay;
39 static jmethodID mStop;
40 static jmethodID mRelease;
41 static jmethodID mWrite;
43 jint JNI_OnLoad(JavaVM* vm, void* reserved)
45 javaVM = vm;
46 return JNI_VERSION_1_2;
49 static JNIEnv* GetEnv()
51 JNIEnv* env = NULL;
52 if (javaVM) (*javaVM)->GetEnv(javaVM, (void**)&env, JNI_VERSION_1_2);
53 return env;
56 typedef struct
58 pthread_t thread;
59 volatile int running;
60 } AndroidData;
62 #define STREAM_MUSIC 3
63 #define CHANNEL_CONFIGURATION_MONO 2
64 #define CHANNEL_CONFIGURATION_STEREO 3
65 #define ENCODING_PCM_8BIT 3
66 #define ENCODING_PCM_16BIT 2
67 #define MODE_STREAM 1
69 static void* thread_function(void* arg)
71 ALCdevice* device = (ALCdevice*)arg;
72 AndroidData* data = (AndroidData*)device->ExtraData;
74 JNIEnv* env;
75 (*javaVM)->AttachCurrentThread(javaVM, &env, NULL);
77 (*env)->PushLocalFrame(env, 2);
79 int sampleRateInHz = device->Frequency;
80 int channelConfig = aluChannelsFromFormat(device->Format) == 1 ? CHANNEL_CONFIGURATION_MONO : CHANNEL_CONFIGURATION_STEREO;
81 int audioFormat = aluBytesFromFormat(device->Format) == 1 ? ENCODING_PCM_8BIT : ENCODING_PCM_16BIT;
83 int bufferSizeInBytes = (*env)->CallStaticIntMethod(env, cAudioTrack,
84 mGetMinBufferSize, sampleRateInHz, channelConfig, audioFormat);
86 int bufferSizeInSamples = bufferSizeInBytes / aluFrameSizeFromFormat(device->Format);
88 jobject track = (*env)->NewObject(env, cAudioTrack, mAudioTrack,
89 STREAM_MUSIC, sampleRateInHz, channelConfig, audioFormat, device->NumUpdates * bufferSizeInBytes, MODE_STREAM);
91 (*env)->CallNonvirtualVoidMethod(env, track, cAudioTrack, mPlay);
93 jarray buffer = (*env)->NewByteArray(env, bufferSizeInBytes);
95 while (data->running)
97 void* pBuffer = (*env)->GetPrimitiveArrayCritical(env, buffer, NULL);
99 if (pBuffer)
101 aluMixData(device, pBuffer, bufferSizeInSamples);
102 (*env)->ReleasePrimitiveArrayCritical(env, buffer, pBuffer, 0);
104 (*env)->CallNonvirtualIntMethod(env, track, cAudioTrack, mWrite, buffer, 0, bufferSizeInBytes);
106 else
108 AL_PRINT("Failed to get pointer to array bytes");
112 (*env)->CallNonvirtualVoidMethod(env, track, cAudioTrack, mStop);
113 (*env)->CallNonvirtualVoidMethod(env, track, cAudioTrack, mRelease);
115 (*env)->PopLocalFrame(env, NULL);
117 (*javaVM)->DetachCurrentThread(javaVM);
118 return NULL;
121 static ALCboolean android_open_playback(ALCdevice *device, const ALCchar *deviceName)
123 JNIEnv* env = GetEnv();
124 AndroidData* data;
125 int channels;
126 int bytes;
128 if (!cAudioTrack)
130 /* Cache AudioTrack class and it's method id's
131 * And do this only once!
134 cAudioTrack = (*env)->FindClass(env, "android/media/AudioTrack");
135 if (!cAudioTrack)
137 AL_PRINT("android.media.AudioTrack class is not found. Are you running at least 1.5 version?");
138 return ALC_FALSE;
141 cAudioTrack = (*env)->NewGlobalRef(env, cAudioTrack);
143 mAudioTrack = (*env)->GetMethodID(env, cAudioTrack, "<init>", "(IIIIII)V");
144 mGetMinBufferSize = (*env)->GetStaticMethodID(env, cAudioTrack, "getMinBufferSize", "(III)I");
145 mPlay = (*env)->GetMethodID(env, cAudioTrack, "play", "()V");
146 mStop = (*env)->GetMethodID(env, cAudioTrack, "stop", "()V");
147 mRelease = (*env)->GetMethodID(env, cAudioTrack, "release", "()V");
148 mWrite = (*env)->GetMethodID(env, cAudioTrack, "write", "([BII)I");
151 if (!deviceName)
153 deviceName = android_device;
155 else if (strcmp(deviceName, android_device) != 0)
157 return ALC_FALSE;
160 data = (AndroidData*)calloc(1, sizeof(*data));
161 device->szDeviceName = strdup(deviceName);
162 device->ExtraData = data;
163 return ALC_TRUE;
166 static void android_close_playback(ALCdevice *device)
168 AndroidData* data = (AndroidData*)device->ExtraData;
169 if (data != NULL)
171 free(data);
172 device->ExtraData = NULL;
176 static ALCboolean android_reset_playback(ALCdevice *device)
178 AndroidData* data = (AndroidData*)device->ExtraData;
180 if (aluChannelsFromFormat(device->Format) >= 2)
182 device->Format = aluBytesFromFormat(device->Format) >= 2 ? AL_FORMAT_STEREO16 : AL_FORMAT_STEREO8;
184 else
186 device->Format = aluBytesFromFormat(device->Format) >= 2 ? AL_FORMAT_MONO16 : AL_FORMAT_MONO8;
189 SetDefaultChannelOrder(device);
191 data->running = 1;
192 pthread_create(&data->thread, NULL, thread_function, device);
194 return ALC_TRUE;
197 static void android_stop_playback(ALCdevice *device)
199 AndroidData* data = (AndroidData*)device->ExtraData;
201 if (data->running)
203 data->running = 0;
204 pthread_join(data->thread, NULL);
208 static ALCboolean android_open_capture(ALCdevice *pDevice, const ALCchar *deviceName)
210 (void)pDevice;
211 (void)deviceName;
212 return ALC_FALSE;
215 static void android_close_capture(ALCdevice *pDevice)
217 (void)pDevice;
220 static void android_start_capture(ALCdevice *pDevice)
222 (void)pDevice;
225 static void android_stop_capture(ALCdevice *pDevice)
227 (void)pDevice;
230 static void android_capture_samples(ALCdevice *pDevice, ALCvoid *pBuffer, ALCuint lSamples)
232 (void)pDevice;
233 (void)pBuffer;
234 (void)lSamples;
237 static ALCuint android_available_samples(ALCdevice *pDevice)
239 (void)pDevice;
240 return 0;
243 static const BackendFuncs android_funcs = {
244 android_open_playback,
245 android_close_playback,
246 android_reset_playback,
247 android_stop_playback,
248 android_open_capture,
249 android_close_capture,
250 android_start_capture,
251 android_stop_capture,
252 android_capture_samples,
253 android_available_samples
256 void alc_android_init(BackendFuncs *func_list)
258 *func_list = android_funcs;
261 void alc_android_deinit(void)
263 JNIEnv* env = GetEnv();
265 /* release cached AudioTrack class */
266 (*env)->DeleteGlobalRef(env, cAudioTrack);
269 void alc_android_probe(int type)
271 if (type == DEVICE_PROBE)
273 AppendDeviceList(android_device);
275 else if (type == ALL_DEVICE_PROBE)
277 AppendAllDeviceList(android_device);