blob: 45561d3e4ea784f8faa277e3e89fa448779c45ca [file] [log] [blame]
Glenn Kastenb3db2132012-01-19 08:59:58 -08001/*
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002**
3** Copyright 2006, The Android Open Source Project
4**
5** Licensed under the Apache License, Version 2.0 (the "License");
6** you may not use this file except in compliance with the License.
7** You may obtain a copy of the License at
8**
9** http://www.apache.org/licenses/LICENSE-2.0
10**
11** Unless required by applicable law or agreed to in writing, software
12** distributed under the License is distributed on an "AS IS" BASIS,
13** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14** See the License for the specific language governing permissions and
15** limitations under the License.
16*/
17
18#define LOG_TAG "AudioSystem"
Glenn Kastenc81d31c2012-03-13 14:46:23 -070019#include <utils/Log.h>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080020
21#include <stdio.h>
22#include <unistd.h>
23#include <fcntl.h>
24#include <math.h>
25
Glenn Kastenc81d31c2012-03-13 14:46:23 -070026#include <jni.h>
27#include <JNIHelp.h>
28#include <android_runtime/AndroidRuntime.h>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080029
30#include <media/AudioSystem.h>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080031
Dima Zavin34bb4192011-05-11 14:15:23 -070032#include <system/audio.h>
Dima Zavin290029d2011-06-13 18:16:26 -070033#include <system/audio_policy.h>
Dima Zavin24fc2fb2011-04-19 22:30:36 -070034
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080035// ----------------------------------------------------------------------------
36
37using namespace android;
38
Glenn Kastened0079d2011-04-04 10:50:50 -070039static const char* const kClassPathName = "android/media/AudioSystem";
40
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080041enum AudioError {
42 kAudioStatusOk = 0,
43 kAudioStatusError = 1,
44 kAudioStatusMediaServerDied = 100
45};
46
47static int check_AudioSystem_Command(status_t status)
48{
49 if (status == NO_ERROR) {
50 return kAudioStatusOk;
51 } else {
52 return kAudioStatusError;
53 }
54}
55
56static int
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080057android_media_AudioSystem_muteMicrophone(JNIEnv *env, jobject thiz, jboolean on)
58{
59 return check_AudioSystem_Command(AudioSystem::muteMicrophone(on));
60}
61
62static jboolean
63android_media_AudioSystem_isMicrophoneMuted(JNIEnv *env, jobject thiz)
64{
65 bool state = false;
66 AudioSystem::isMicrophoneMuted(&state);
67 return state;
68}
69
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080070static jboolean
Eric Laurent25101b02011-02-02 09:33:30 -080071android_media_AudioSystem_isStreamActive(JNIEnv *env, jobject thiz, jint stream, jint inPastMs)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080072{
73 bool state = false;
Glenn Kastenbc1d77b2012-01-12 16:38:12 -080074 AudioSystem::isStreamActive((audio_stream_type_t) stream, &state, inPastMs);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080075 return state;
76}
77
Jean-Michel Trivid6770542012-10-10 12:03:41 -070078static jboolean
Jean-Michel Trivi679d5042013-02-04 16:24:09 -080079android_media_AudioSystem_isStreamActiveRemotely(JNIEnv *env, jobject thiz, jint stream,
80 jint inPastMs)
81{
82 bool state = false;
83 AudioSystem::isStreamActiveRemotely((audio_stream_type_t) stream, &state, inPastMs);
84 return state;
85}
86
87static jboolean
Jean-Michel Trivid6770542012-10-10 12:03:41 -070088android_media_AudioSystem_isSourceActive(JNIEnv *env, jobject thiz, jint source)
89{
90 bool state = false;
91 AudioSystem::isSourceActive((audio_source_t) source, &state);
92 return state;
93}
94
Eric Laurenta553c252009-07-17 12:17:14 -070095static int
96android_media_AudioSystem_setParameters(JNIEnv *env, jobject thiz, jstring keyValuePairs)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080097{
Eric Laurenta553c252009-07-17 12:17:14 -070098 const jchar* c_keyValuePairs = env->GetStringCritical(keyValuePairs, 0);
99 String8 c_keyValuePairs8;
100 if (keyValuePairs) {
101 c_keyValuePairs8 = String8(c_keyValuePairs, env->GetStringLength(keyValuePairs));
102 env->ReleaseStringCritical(keyValuePairs, c_keyValuePairs);
103 }
104 int status = check_AudioSystem_Command(AudioSystem::setParameters(0, c_keyValuePairs8));
105 return status;
106}
107
108static jstring
109android_media_AudioSystem_getParameters(JNIEnv *env, jobject thiz, jstring keys)
110{
111 const jchar* c_keys = env->GetStringCritical(keys, 0);
112 String8 c_keys8;
113 if (keys) {
114 c_keys8 = String8(c_keys, env->GetStringLength(keys));
115 env->ReleaseStringCritical(keys, c_keys);
116 }
117 return env->NewStringUTF(AudioSystem::getParameters(0, c_keys8).string());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800118}
119
Eric Laurentca35e482013-07-17 17:26:41 -0700120static JNIEnv* AudioSystem_getJNIEnv(bool* needsDetach) {
121 *needsDetach = false;
122 JNIEnv* env = AndroidRuntime::getJNIEnv();
123 if (env == NULL) {
124 JavaVMAttachArgs args = {JNI_VERSION_1_4, NULL, NULL};
125 JavaVM* vm = AndroidRuntime::getJavaVM();
126 int result = vm->AttachCurrentThread(&env, (void*) &args);
127 if (result != JNI_OK) {
128 ALOGE("thread attach failed: %#x", result);
129 return NULL;
130 }
131 *needsDetach = true;
132 }
133 return env;
134}
135
136static void AudioSystem_detachJNI() {
137 JavaVM* vm = AndroidRuntime::getJavaVM();
138 int result = vm->DetachCurrentThread();
139 if (result != JNI_OK) {
140 ALOGE("thread detach failed: %#x", result);
141 }
142}
143
Glenn Kastened0079d2011-04-04 10:50:50 -0700144static void
145android_media_AudioSystem_error_callback(status_t err)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800146{
Eric Laurentca35e482013-07-17 17:26:41 -0700147 bool needsDetach = false;
148 JNIEnv *env = AudioSystem_getJNIEnv(&needsDetach);
149
Eric Laurent0e7a4d92010-10-15 12:33:16 -0700150 if (env == NULL) {
151 return;
152 }
153
Glenn Kastened0079d2011-04-04 10:50:50 -0700154 jclass clazz = env->FindClass(kClassPathName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800155
156 int error;
157
158 switch (err) {
159 case DEAD_OBJECT:
160 error = kAudioStatusMediaServerDied;
161 break;
162 case NO_ERROR:
163 error = kAudioStatusOk;
164 break;
165 default:
166 error = kAudioStatusError;
167 break;
168 }
169
170 env->CallStaticVoidMethod(clazz, env->GetStaticMethodID(clazz, "errorCallbackFromNative","(I)V"), error);
Eric Laurentca35e482013-07-17 17:26:41 -0700171
172 if (needsDetach) {
173 AudioSystem_detachJNI();
174 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800175}
176
Eric Laurenta553c252009-07-17 12:17:14 -0700177static int
178android_media_AudioSystem_setDeviceConnectionState(JNIEnv *env, jobject thiz, jint device, jint state, jstring device_address)
179{
180 const char *c_address = env->GetStringUTFChars(device_address, NULL);
Dima Zavin24fc2fb2011-04-19 22:30:36 -0700181 int status = check_AudioSystem_Command(AudioSystem::setDeviceConnectionState(static_cast <audio_devices_t>(device),
182 static_cast <audio_policy_dev_state_t>(state),
Eric Laurenta553c252009-07-17 12:17:14 -0700183 c_address));
184 env->ReleaseStringUTFChars(device_address, c_address);
185 return status;
186}
187
188static int
189android_media_AudioSystem_getDeviceConnectionState(JNIEnv *env, jobject thiz, jint device, jstring device_address)
190{
191 const char *c_address = env->GetStringUTFChars(device_address, NULL);
Dima Zavin24fc2fb2011-04-19 22:30:36 -0700192 int state = static_cast <int>(AudioSystem::getDeviceConnectionState(static_cast <audio_devices_t>(device),
Eric Laurenta553c252009-07-17 12:17:14 -0700193 c_address));
194 env->ReleaseStringUTFChars(device_address, c_address);
195 return state;
196}
197
198static int
199android_media_AudioSystem_setPhoneState(JNIEnv *env, jobject thiz, jint state)
200{
Glenn Kastenaccb1142012-01-04 11:00:47 -0800201 return check_AudioSystem_Command(AudioSystem::setPhoneState((audio_mode_t) state));
Eric Laurenta553c252009-07-17 12:17:14 -0700202}
203
204static int
Eric Laurenta553c252009-07-17 12:17:14 -0700205android_media_AudioSystem_setForceUse(JNIEnv *env, jobject thiz, jint usage, jint config)
206{
Dima Zavin24fc2fb2011-04-19 22:30:36 -0700207 return check_AudioSystem_Command(AudioSystem::setForceUse(static_cast <audio_policy_force_use_t>(usage),
208 static_cast <audio_policy_forced_cfg_t>(config)));
Eric Laurenta553c252009-07-17 12:17:14 -0700209}
210
211static int
212android_media_AudioSystem_getForceUse(JNIEnv *env, jobject thiz, jint usage)
213{
Dima Zavin24fc2fb2011-04-19 22:30:36 -0700214 return static_cast <int>(AudioSystem::getForceUse(static_cast <audio_policy_force_use_t>(usage)));
Eric Laurenta553c252009-07-17 12:17:14 -0700215}
216
217static int
218android_media_AudioSystem_initStreamVolume(JNIEnv *env, jobject thiz, jint stream, jint indexMin, jint indexMax)
219{
Dima Zavin24fc2fb2011-04-19 22:30:36 -0700220 return check_AudioSystem_Command(AudioSystem::initStreamVolume(static_cast <audio_stream_type_t>(stream),
Eric Laurenta553c252009-07-17 12:17:14 -0700221 indexMin,
222 indexMax));
223}
224
225static int
Eric Laurent9bc8358d2011-11-18 16:43:31 -0800226android_media_AudioSystem_setStreamVolumeIndex(JNIEnv *env,
227 jobject thiz,
228 jint stream,
229 jint index,
230 jint device)
Eric Laurenta553c252009-07-17 12:17:14 -0700231{
Eric Laurent9bc8358d2011-11-18 16:43:31 -0800232 return check_AudioSystem_Command(
233 AudioSystem::setStreamVolumeIndex(static_cast <audio_stream_type_t>(stream),
234 index,
235 (audio_devices_t)device));
Eric Laurenta553c252009-07-17 12:17:14 -0700236}
237
238static int
Eric Laurent9bc8358d2011-11-18 16:43:31 -0800239android_media_AudioSystem_getStreamVolumeIndex(JNIEnv *env,
240 jobject thiz,
241 jint stream,
242 jint device)
Eric Laurenta553c252009-07-17 12:17:14 -0700243{
244 int index;
Eric Laurent9bc8358d2011-11-18 16:43:31 -0800245 if (AudioSystem::getStreamVolumeIndex(static_cast <audio_stream_type_t>(stream),
246 &index,
247 (audio_devices_t)device)
248 != NO_ERROR) {
Eric Laurenta553c252009-07-17 12:17:14 -0700249 index = -1;
250 }
251 return index;
252}
253
Mike Lockwoodcbdb49d2011-10-20 12:54:05 -0400254static int
255android_media_AudioSystem_setMasterVolume(JNIEnv *env, jobject thiz, jfloat value)
256{
257 return check_AudioSystem_Command(AudioSystem::setMasterVolume(value));
258}
259
260static jfloat
261android_media_AudioSystem_getMasterVolume(JNIEnv *env, jobject thiz)
262{
263 float value;
264 if (AudioSystem::getMasterVolume(&value) != NO_ERROR) {
265 value = -1.0;
266 }
267 return value;
268}
269
270static int
271android_media_AudioSystem_setMasterMute(JNIEnv *env, jobject thiz, jboolean mute)
272{
273 return check_AudioSystem_Command(AudioSystem::setMasterMute(mute));
274}
275
276static jfloat
277android_media_AudioSystem_getMasterMute(JNIEnv *env, jobject thiz)
278{
279 bool mute;
280 if (AudioSystem::getMasterMute(&mute) != NO_ERROR) {
281 mute = false;
282 }
283 return mute;
284}
285
Glenn Kasten8b4b97a2011-02-04 13:54:26 -0800286static jint
287android_media_AudioSystem_getDevicesForStream(JNIEnv *env, jobject thiz, jint stream)
288{
Dima Zavin24fc2fb2011-04-19 22:30:36 -0700289 return (jint) AudioSystem::getDevicesForStream(static_cast <audio_stream_type_t>(stream));
Glenn Kasten8b4b97a2011-02-04 13:54:26 -0800290}
291
Glenn Kastenc6c43652012-09-24 17:32:30 -0700292static jint
293android_media_AudioSystem_getPrimaryOutputSamplingRate(JNIEnv *env, jobject clazz)
294{
295 return (jint) AudioSystem::getPrimaryOutputSamplingRate();
296}
297
298static jint
299android_media_AudioSystem_getPrimaryOutputFrameCount(JNIEnv *env, jobject clazz)
300{
301 return (jint) AudioSystem::getPrimaryOutputFrameCount();
302}
303
Oliver Woodman61dcdf32013-06-26 12:43:36 +0100304static jint
305android_media_AudioSystem_getOutputLatency(JNIEnv *env, jobject clazz, jint stream)
306{
307 uint32_t afLatency;
308 if (AudioSystem::getOutputLatency(&afLatency, static_cast <audio_stream_type_t>(stream))
309 != NO_ERROR) {
310 afLatency = -1;
311 }
312 return (jint) afLatency;
313}
314
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800315// ----------------------------------------------------------------------------
316
317static JNINativeMethod gMethods[] = {
Eric Laurenta553c252009-07-17 12:17:14 -0700318 {"setParameters", "(Ljava/lang/String;)I", (void *)android_media_AudioSystem_setParameters},
319 {"getParameters", "(Ljava/lang/String;)Ljava/lang/String;", (void *)android_media_AudioSystem_getParameters},
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800320 {"muteMicrophone", "(Z)I", (void *)android_media_AudioSystem_muteMicrophone},
321 {"isMicrophoneMuted", "()Z", (void *)android_media_AudioSystem_isMicrophoneMuted},
Jean-Michel Trivid6770542012-10-10 12:03:41 -0700322 {"isStreamActive", "(II)Z", (void *)android_media_AudioSystem_isStreamActive},
Jean-Michel Trivi679d5042013-02-04 16:24:09 -0800323 {"isStreamActiveRemotely","(II)Z", (void *)android_media_AudioSystem_isStreamActiveRemotely},
Jean-Michel Trivid6770542012-10-10 12:03:41 -0700324 {"isSourceActive", "(I)Z", (void *)android_media_AudioSystem_isSourceActive},
Eric Laurenta553c252009-07-17 12:17:14 -0700325 {"setDeviceConnectionState", "(IILjava/lang/String;)I", (void *)android_media_AudioSystem_setDeviceConnectionState},
326 {"getDeviceConnectionState", "(ILjava/lang/String;)I", (void *)android_media_AudioSystem_getDeviceConnectionState},
327 {"setPhoneState", "(I)I", (void *)android_media_AudioSystem_setPhoneState},
Eric Laurenta553c252009-07-17 12:17:14 -0700328 {"setForceUse", "(II)I", (void *)android_media_AudioSystem_setForceUse},
329 {"getForceUse", "(I)I", (void *)android_media_AudioSystem_getForceUse},
330 {"initStreamVolume", "(III)I", (void *)android_media_AudioSystem_initStreamVolume},
Eric Laurent9bc8358d2011-11-18 16:43:31 -0800331 {"setStreamVolumeIndex","(III)I", (void *)android_media_AudioSystem_setStreamVolumeIndex},
332 {"getStreamVolumeIndex","(II)I", (void *)android_media_AudioSystem_getStreamVolumeIndex},
Mike Lockwoodcbdb49d2011-10-20 12:54:05 -0400333 {"setMasterVolume", "(F)I", (void *)android_media_AudioSystem_setMasterVolume},
334 {"getMasterVolume", "()F", (void *)android_media_AudioSystem_getMasterVolume},
335 {"setMasterMute", "(Z)I", (void *)android_media_AudioSystem_setMasterMute},
336 {"getMasterMute", "()Z", (void *)android_media_AudioSystem_getMasterMute},
Glenn Kasten8b4b97a2011-02-04 13:54:26 -0800337 {"getDevicesForStream", "(I)I", (void *)android_media_AudioSystem_getDevicesForStream},
Glenn Kastenc6c43652012-09-24 17:32:30 -0700338 {"getPrimaryOutputSamplingRate", "()I", (void *)android_media_AudioSystem_getPrimaryOutputSamplingRate},
339 {"getPrimaryOutputFrameCount", "()I", (void *)android_media_AudioSystem_getPrimaryOutputFrameCount},
Oliver Woodman61dcdf32013-06-26 12:43:36 +0100340 {"getOutputLatency", "(I)I", (void *)android_media_AudioSystem_getOutputLatency},
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800341};
342
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800343int register_android_media_AudioSystem(JNIEnv *env)
344{
345 AudioSystem::setErrorCallback(android_media_AudioSystem_error_callback);
Glenn Kasten18db49a2012-03-12 16:29:55 -0700346
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800347 return AndroidRuntime::registerNativeMethods(env,
Glenn Kastened0079d2011-04-04 10:50:50 -0700348 kClassPathName, gMethods, NELEM(gMethods));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800349}