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
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
)
46 return JNI_VERSION_1_2
;
49 static JNIEnv
* GetEnv()
52 if (javaVM
) (*javaVM
)->GetEnv(javaVM
, (void**)&env
, JNI_VERSION_1_2
);
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
69 static void* thread_function(void* arg
)
71 ALCdevice
* device
= (ALCdevice
*)arg
;
72 AndroidData
* data
= (AndroidData
*)device
->ExtraData
;
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
);
97 void* pBuffer
= (*env
)->GetPrimitiveArrayCritical(env
, buffer
, NULL
);
101 aluMixData(device
, pBuffer
, bufferSizeInSamples
);
102 (*env
)->ReleasePrimitiveArrayCritical(env
, buffer
, pBuffer
, 0);
104 (*env
)->CallNonvirtualIntMethod(env
, track
, cAudioTrack
, mWrite
, buffer
, 0, bufferSizeInBytes
);
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
);
121 static ALCboolean
android_open_playback(ALCdevice
*device
, const ALCchar
*deviceName
)
123 JNIEnv
* env
= GetEnv();
130 /* Cache AudioTrack class and it's method id's
131 * And do this only once!
134 cAudioTrack
= (*env
)->FindClass(env
, "android/media/AudioTrack");
137 AL_PRINT("android.media.AudioTrack class is not found. Are you running at least 1.5 version?");
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");
153 deviceName
= android_device
;
155 else if (strcmp(deviceName
, android_device
) != 0)
160 data
= (AndroidData
*)calloc(1, sizeof(*data
));
161 device
->szDeviceName
= strdup(deviceName
);
162 device
->ExtraData
= data
;
166 static void android_close_playback(ALCdevice
*device
)
168 AndroidData
* data
= (AndroidData
*)device
->ExtraData
;
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
;
186 device
->Format
= aluBytesFromFormat(device
->Format
) >= 2 ? AL_FORMAT_MONO16
: AL_FORMAT_MONO8
;
189 SetDefaultChannelOrder(device
);
192 pthread_create(&data
->thread
, NULL
, thread_function
, device
);
197 static void android_stop_playback(ALCdevice
*device
)
199 AndroidData
* data
= (AndroidData
*)device
->ExtraData
;
204 pthread_join(data
->thread
, NULL
);
208 static ALCboolean
android_open_capture(ALCdevice
*pDevice
, const ALCchar
*deviceName
)
215 static void android_close_capture(ALCdevice
*pDevice
)
220 static void android_start_capture(ALCdevice
*pDevice
)
225 static void android_stop_capture(ALCdevice
*pDevice
)
230 static void android_capture_samples(ALCdevice
*pDevice
, ALCvoid
*pBuffer
, ALCuint lSamples
)
237 static ALCuint
android_available_samples(ALCdevice
*pDevice
)
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
);