android_media_AudioSystem.cpp revision 6824a143c90a2cd05c5f4f05830fa53527e856b8
1/*
2**
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"
19#include <utils/Log.h>
20
21#include <jni.h>
22#include <JNIHelp.h>
23#include <android_runtime/AndroidRuntime.h>
24
25#include <media/AudioSystem.h>
26
27#include <system/audio.h>
28#include <system/audio_policy.h>
29
30// ----------------------------------------------------------------------------
31
32using namespace android;
33
34static const char* const kClassPathName = "android/media/AudioSystem";
35
36enum AudioError {
37    kAudioStatusOk = 0,
38    kAudioStatusError = 1,
39    kAudioStatusMediaServerDied = 100
40};
41
42static int check_AudioSystem_Command(status_t status)
43{
44    if (status == NO_ERROR) {
45        return kAudioStatusOk;
46    } else {
47        return kAudioStatusError;
48    }
49}
50
51static int
52android_media_AudioSystem_muteMicrophone(JNIEnv *env, jobject thiz, jboolean on)
53{
54    return check_AudioSystem_Command(AudioSystem::muteMicrophone(on));
55}
56
57static jboolean
58android_media_AudioSystem_isMicrophoneMuted(JNIEnv *env, jobject thiz)
59{
60    bool state = false;
61    AudioSystem::isMicrophoneMuted(&state);
62    return state;
63}
64
65static jboolean
66android_media_AudioSystem_isStreamActive(JNIEnv *env, jobject thiz, jint stream, jint inPastMs)
67{
68    bool state = false;
69    AudioSystem::isStreamActive((audio_stream_type_t) stream, &state, inPastMs);
70    return state;
71}
72
73static jboolean
74android_media_AudioSystem_isStreamActiveRemotely(JNIEnv *env, jobject thiz, jint stream,
75        jint inPastMs)
76{
77    bool state = false;
78    AudioSystem::isStreamActiveRemotely((audio_stream_type_t) stream, &state, inPastMs);
79    return state;
80}
81
82static jboolean
83android_media_AudioSystem_isSourceActive(JNIEnv *env, jobject thiz, jint source)
84{
85    bool state = false;
86    AudioSystem::isSourceActive((audio_source_t) source, &state);
87    return state;
88}
89
90static int
91android_media_AudioSystem_setParameters(JNIEnv *env, jobject thiz, jstring keyValuePairs)
92{
93    const jchar* c_keyValuePairs = env->GetStringCritical(keyValuePairs, 0);
94    String8 c_keyValuePairs8;
95    if (keyValuePairs) {
96        c_keyValuePairs8 = String8(c_keyValuePairs, env->GetStringLength(keyValuePairs));
97        env->ReleaseStringCritical(keyValuePairs, c_keyValuePairs);
98    }
99    int status = check_AudioSystem_Command(AudioSystem::setParameters(0, c_keyValuePairs8));
100    return status;
101}
102
103static jstring
104android_media_AudioSystem_getParameters(JNIEnv *env, jobject thiz, jstring keys)
105{
106    const jchar* c_keys = env->GetStringCritical(keys, 0);
107    String8 c_keys8;
108    if (keys) {
109        c_keys8 = String8(c_keys, env->GetStringLength(keys));
110        env->ReleaseStringCritical(keys, c_keys);
111    }
112    return env->NewStringUTF(AudioSystem::getParameters(0, c_keys8).string());
113}
114
115static JNIEnv* AudioSystem_getJNIEnv(bool* needsDetach) {
116    *needsDetach = false;
117    JNIEnv* env = AndroidRuntime::getJNIEnv();
118    if (env == NULL) {
119        JavaVMAttachArgs args = {JNI_VERSION_1_4, NULL, NULL};
120        JavaVM* vm = AndroidRuntime::getJavaVM();
121        int result = vm->AttachCurrentThread(&env, (void*) &args);
122        if (result != JNI_OK) {
123            ALOGE("thread attach failed: %#x", result);
124            return NULL;
125        }
126        *needsDetach = true;
127    }
128    return env;
129}
130
131static void AudioSystem_detachJNI() {
132    JavaVM* vm = AndroidRuntime::getJavaVM();
133    int result = vm->DetachCurrentThread();
134    if (result != JNI_OK) {
135        ALOGE("thread detach failed: %#x", result);
136    }
137}
138
139static void
140android_media_AudioSystem_error_callback(status_t err)
141{
142    bool needsDetach = false;
143    JNIEnv *env = AudioSystem_getJNIEnv(&needsDetach);
144
145    if (env == NULL) {
146        return;
147    }
148
149    jclass clazz = env->FindClass(kClassPathName);
150
151    int error;
152
153    switch (err) {
154    case DEAD_OBJECT:
155        error = kAudioStatusMediaServerDied;
156        break;
157    case NO_ERROR:
158        error = kAudioStatusOk;
159        break;
160    default:
161        error = kAudioStatusError;
162        break;
163    }
164
165    env->CallStaticVoidMethod(clazz, env->GetStaticMethodID(clazz, "errorCallbackFromNative","(I)V"), error);
166
167    if (needsDetach) {
168        AudioSystem_detachJNI();
169    }
170}
171
172static int
173android_media_AudioSystem_setDeviceConnectionState(JNIEnv *env, jobject thiz, jint device, jint state, jstring device_address)
174{
175    const char *c_address = env->GetStringUTFChars(device_address, NULL);
176    int status = check_AudioSystem_Command(AudioSystem::setDeviceConnectionState(static_cast <audio_devices_t>(device),
177                                          static_cast <audio_policy_dev_state_t>(state),
178                                          c_address));
179    env->ReleaseStringUTFChars(device_address, c_address);
180    return status;
181}
182
183static int
184android_media_AudioSystem_getDeviceConnectionState(JNIEnv *env, jobject thiz, jint device, jstring device_address)
185{
186    const char *c_address = env->GetStringUTFChars(device_address, NULL);
187    int state = static_cast <int>(AudioSystem::getDeviceConnectionState(static_cast <audio_devices_t>(device),
188                                          c_address));
189    env->ReleaseStringUTFChars(device_address, c_address);
190    return state;
191}
192
193static int
194android_media_AudioSystem_setPhoneState(JNIEnv *env, jobject thiz, jint state)
195{
196    return check_AudioSystem_Command(AudioSystem::setPhoneState((audio_mode_t) state));
197}
198
199static int
200android_media_AudioSystem_setForceUse(JNIEnv *env, jobject thiz, jint usage, jint config)
201{
202    return check_AudioSystem_Command(AudioSystem::setForceUse(static_cast <audio_policy_force_use_t>(usage),
203                                                           static_cast <audio_policy_forced_cfg_t>(config)));
204}
205
206static int
207android_media_AudioSystem_getForceUse(JNIEnv *env, jobject thiz, jint usage)
208{
209    return static_cast <int>(AudioSystem::getForceUse(static_cast <audio_policy_force_use_t>(usage)));
210}
211
212static int
213android_media_AudioSystem_initStreamVolume(JNIEnv *env, jobject thiz, jint stream, jint indexMin, jint indexMax)
214{
215    return check_AudioSystem_Command(AudioSystem::initStreamVolume(static_cast <audio_stream_type_t>(stream),
216                                                                   indexMin,
217                                                                   indexMax));
218}
219
220static int
221android_media_AudioSystem_setStreamVolumeIndex(JNIEnv *env,
222                                               jobject thiz,
223                                               jint stream,
224                                               jint index,
225                                               jint device)
226{
227    return check_AudioSystem_Command(
228            AudioSystem::setStreamVolumeIndex(static_cast <audio_stream_type_t>(stream),
229                                              index,
230                                              (audio_devices_t)device));
231}
232
233static int
234android_media_AudioSystem_getStreamVolumeIndex(JNIEnv *env,
235                                               jobject thiz,
236                                               jint stream,
237                                               jint device)
238{
239    int index;
240    if (AudioSystem::getStreamVolumeIndex(static_cast <audio_stream_type_t>(stream),
241                                          &index,
242                                          (audio_devices_t)device)
243            != NO_ERROR) {
244        index = -1;
245    }
246    return index;
247}
248
249static int
250android_media_AudioSystem_setMasterVolume(JNIEnv *env, jobject thiz, jfloat value)
251{
252    return check_AudioSystem_Command(AudioSystem::setMasterVolume(value));
253}
254
255static jfloat
256android_media_AudioSystem_getMasterVolume(JNIEnv *env, jobject thiz)
257{
258    float value;
259    if (AudioSystem::getMasterVolume(&value) != NO_ERROR) {
260        value = -1.0;
261    }
262    return value;
263}
264
265static int
266android_media_AudioSystem_setMasterMute(JNIEnv *env, jobject thiz, jboolean mute)
267{
268    return check_AudioSystem_Command(AudioSystem::setMasterMute(mute));
269}
270
271static jfloat
272android_media_AudioSystem_getMasterMute(JNIEnv *env, jobject thiz)
273{
274    bool mute;
275    if (AudioSystem::getMasterMute(&mute) != NO_ERROR) {
276        mute = false;
277    }
278    return mute;
279}
280
281static jint
282android_media_AudioSystem_getDevicesForStream(JNIEnv *env, jobject thiz, jint stream)
283{
284    return (jint) AudioSystem::getDevicesForStream(static_cast <audio_stream_type_t>(stream));
285}
286
287static jint
288android_media_AudioSystem_getPrimaryOutputSamplingRate(JNIEnv *env, jobject clazz)
289{
290    return (jint) AudioSystem::getPrimaryOutputSamplingRate();
291}
292
293static jint
294android_media_AudioSystem_getPrimaryOutputFrameCount(JNIEnv *env, jobject clazz)
295{
296    return (jint) AudioSystem::getPrimaryOutputFrameCount();
297}
298
299static jint
300android_media_AudioSystem_getOutputLatency(JNIEnv *env, jobject clazz, jint stream)
301{
302    uint32_t afLatency;
303    if (AudioSystem::getOutputLatency(&afLatency, static_cast <audio_stream_type_t>(stream))
304            != NO_ERROR) {
305        afLatency = -1;
306    }
307    return (jint) afLatency;
308}
309
310static jint
311android_media_AudioSystem_setLowRamDevice(JNIEnv *env, jobject clazz, jboolean isLowRamDevice)
312{
313    return (jint) AudioSystem::setLowRamDevice((bool) isLowRamDevice);
314}
315
316// ----------------------------------------------------------------------------
317
318static JNINativeMethod gMethods[] = {
319    {"setParameters",        "(Ljava/lang/String;)I", (void *)android_media_AudioSystem_setParameters},
320    {"getParameters",        "(Ljava/lang/String;)Ljava/lang/String;", (void *)android_media_AudioSystem_getParameters},
321    {"muteMicrophone",      "(Z)I",     (void *)android_media_AudioSystem_muteMicrophone},
322    {"isMicrophoneMuted",   "()Z",      (void *)android_media_AudioSystem_isMicrophoneMuted},
323    {"isStreamActive",      "(II)Z",    (void *)android_media_AudioSystem_isStreamActive},
324    {"isStreamActiveRemotely","(II)Z",  (void *)android_media_AudioSystem_isStreamActiveRemotely},
325    {"isSourceActive",      "(I)Z",     (void *)android_media_AudioSystem_isSourceActive},
326    {"setDeviceConnectionState", "(IILjava/lang/String;)I", (void *)android_media_AudioSystem_setDeviceConnectionState},
327    {"getDeviceConnectionState", "(ILjava/lang/String;)I",  (void *)android_media_AudioSystem_getDeviceConnectionState},
328    {"setPhoneState",       "(I)I",     (void *)android_media_AudioSystem_setPhoneState},
329    {"setForceUse",         "(II)I",    (void *)android_media_AudioSystem_setForceUse},
330    {"getForceUse",         "(I)I",     (void *)android_media_AudioSystem_getForceUse},
331    {"initStreamVolume",    "(III)I",   (void *)android_media_AudioSystem_initStreamVolume},
332    {"setStreamVolumeIndex","(III)I",   (void *)android_media_AudioSystem_setStreamVolumeIndex},
333    {"getStreamVolumeIndex","(II)I",    (void *)android_media_AudioSystem_getStreamVolumeIndex},
334    {"setMasterVolume",     "(F)I",     (void *)android_media_AudioSystem_setMasterVolume},
335    {"getMasterVolume",     "()F",      (void *)android_media_AudioSystem_getMasterVolume},
336    {"setMasterMute",       "(Z)I",     (void *)android_media_AudioSystem_setMasterMute},
337    {"getMasterMute",       "()Z",      (void *)android_media_AudioSystem_getMasterMute},
338    {"getDevicesForStream", "(I)I",     (void *)android_media_AudioSystem_getDevicesForStream},
339    {"getPrimaryOutputSamplingRate", "()I", (void *)android_media_AudioSystem_getPrimaryOutputSamplingRate},
340    {"getPrimaryOutputFrameCount",   "()I", (void *)android_media_AudioSystem_getPrimaryOutputFrameCount},
341    {"getOutputLatency",    "(I)I",     (void *)android_media_AudioSystem_getOutputLatency},
342    {"setLowRamDevice",     "(Z)I",     (void *)android_media_AudioSystem_setLowRamDevice},
343};
344
345int register_android_media_AudioSystem(JNIEnv *env)
346{
347    AudioSystem::setErrorCallback(android_media_AudioSystem_error_callback);
348
349    return AndroidRuntime::registerNativeMethods(env,
350                kClassPathName, gMethods, NELEM(gMethods));
351}
352