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