1 /*
2  * Copyright (C) 2018 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #define LOG_TAG "UsbAlsaJackDetectorJNI"
18 #include "utils/Log.h"
19 
20 #include "jni.h"
21 #include <nativehelper/JNIHelp.h>
22 #include "android-base/strings.h"
23 #include "android_runtime/AndroidRuntime.h"
24 #include "android_runtime/Log.h"
25 
26 #include <stdio.h>
27 #include <string.h>
28 #include <sys/types.h>
29 #include <sys/stat.h>
30 #include <fcntl.h>
31 
32 #include <tinyalsa/asoundlib.h>
33 
34 #define DRIVER_NAME "/dev/usb_accessory"
35 
36 #define USB_IN_JACK_SUFFIX "Input Jack"
37 #define USB_OUT_JACK_SUFFIX "Output Jack"
38 
39 namespace android
40 {
41 
find_mixer_with_suffix(struct mixer * card_mixer,const char * suffix)42 static struct mixer_ctl* find_mixer_with_suffix(struct mixer* card_mixer, const char* suffix) {
43     int id = 0;
44     struct mixer_ctl* ctl;
45     while ((ctl = mixer_get_ctl(card_mixer, id++)) != NULL) {
46         const char* name = mixer_ctl_get_name(ctl);
47         if (android::base::EndsWith(name, suffix)) {
48           return ctl;
49         }
50     }
51     return NULL;
52 }
53 
is_jack_connected(jint card,const char * suffix)54 static jboolean is_jack_connected(jint card, const char* suffix) {
55   struct mixer* card_mixer = mixer_open(card);
56   if (card_mixer == NULL) {
57     return true;
58   }
59   struct mixer_ctl* ctl = find_mixer_with_suffix(card_mixer, suffix);
60   if (!ctl) {
61     return true;
62   }
63   mixer_ctl_update(ctl);
64   int val = mixer_ctl_get_value(ctl, 0);
65   ALOGI("%s - value %d\n", mixer_ctl_get_name(ctl), val);
66   mixer_close(card_mixer);
67 
68   return val != 0;
69 }
70 
android_server_UsbAlsaJackDetector_hasJackDetect(JNIEnv *,jobject,jint card)71 static jboolean android_server_UsbAlsaJackDetector_hasJackDetect(JNIEnv* /* env */,
72                                                                  jobject /* thiz */,
73                                                                  jint card)
74 {
75     struct mixer* card_mixer = mixer_open(card);
76     if (card_mixer == NULL) {
77         return false;
78     }
79 
80     jboolean has_jack = false;
81     if ((find_mixer_with_suffix(card_mixer, USB_IN_JACK_SUFFIX) != NULL) ||
82             (find_mixer_with_suffix(card_mixer, USB_OUT_JACK_SUFFIX) != NULL)) {
83         has_jack = true;
84     }
85     mixer_close(card_mixer);
86     return has_jack;
87 }
88 
android_server_UsbAlsaJackDetector_inputJackConnected(JNIEnv *,jobject,jint card)89 static jboolean android_server_UsbAlsaJackDetector_inputJackConnected(JNIEnv* /* env */,
90                                                                       jobject /* thiz */,
91                                                                       jint card)
92 {
93     return is_jack_connected(card, USB_IN_JACK_SUFFIX);
94 }
95 
android_server_UsbAlsaJackDetector_outputJackConnected(JNIEnv *,jobject,jint card)96 static jboolean android_server_UsbAlsaJackDetector_outputJackConnected(JNIEnv* /* env */,
97                                                                        jobject /* thiz */,
98                                                                        jint card)
99 {
100     return is_jack_connected(card, USB_OUT_JACK_SUFFIX);
101 }
102 
android_server_UsbAlsaJackDetector_jackDetect(JNIEnv * env,jobject thiz,jint card)103 static void android_server_UsbAlsaJackDetector_jackDetect(JNIEnv* env,
104                                                           jobject thiz,
105                                                           jint card) {
106     jclass jdclass = env->GetObjectClass(thiz);
107     jmethodID method_jackDetectCallback = env->GetMethodID(jdclass, "jackDetectCallback", "()Z");
108     if (method_jackDetectCallback == NULL) {
109         ALOGE("Can't find jackDetectCallback");
110         return;
111     }
112 
113     struct mixer* m = mixer_open(card);
114     if (!m) {
115         ALOGE("Jack detect unable to open mixer\n");
116         return;
117     }
118     mixer_subscribe_events(m, 1);
119     do {
120 
121         // Wait for a mixer event.  Retry if interrupted, exit on error.
122         int retval;
123         do {
124             retval = mixer_wait_event(m, -1);
125         } while (retval == -EINTR);
126         if (retval < 0) {
127             break;
128         }
129         mixer_consume_event(m);
130     } while (env->CallBooleanMethod(thiz, method_jackDetectCallback));
131 
132     mixer_close(m);
133     return;
134 }
135 
136 static const JNINativeMethod method_table[] = {
137     { "nativeHasJackDetect", "(I)Z", (void*)android_server_UsbAlsaJackDetector_hasJackDetect },
138     { "nativeInputJackConnected",     "(I)Z",
139             (void*)android_server_UsbAlsaJackDetector_inputJackConnected },
140     { "nativeOutputJackConnected",    "(I)Z",
141             (void*)android_server_UsbAlsaJackDetector_outputJackConnected },
142     { "nativeJackDetect", "(I)Z", (void*)android_server_UsbAlsaJackDetector_jackDetect },
143 };
144 
register_android_server_UsbAlsaJackDetector(JNIEnv * env)145 int register_android_server_UsbAlsaJackDetector(JNIEnv *env)
146 {
147     jclass clazz = env->FindClass("com/android/server/usb/UsbAlsaJackDetector");
148     if (clazz == NULL) {
149         ALOGE("Can't find com/android/server/usb/UsbAlsaJackDetector");
150         return -1;
151     }
152 
153     return jniRegisterNativeMethods(env, "com/android/server/usb/UsbAlsaJackDetector",
154             method_table, NELEM(method_table));
155 }
156 
157 }
158