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 <asm/byteorder.h> 29 #include <sys/types.h> 30 #include <sys/stat.h> 31 #include <fcntl.h> 32 33 #include <tinyalsa/asoundlib.h> 34 35 #define DRIVER_NAME "/dev/usb_accessory" 36 37 #define USB_IN_JACK_SUFFIX "Input Jack" 38 #define USB_OUT_JACK_SUFFIX "Output Jack" 39 40 namespace android 41 { 42 43 static struct mixer_ctl* find_mixer_with_suffix(struct mixer* card_mixer, const char* suffix) { 44 int id = 0; 45 struct mixer_ctl* ctl; 46 while ((ctl = mixer_get_ctl(card_mixer, id++)) != NULL) { 47 const char* name = mixer_ctl_get_name(ctl); 48 if (android::base::EndsWith(name, suffix)) { 49 return ctl; 50 } 51 } 52 return NULL; 53 } 54 55 static jboolean is_jack_connected(jint card, const char* suffix) { 56 struct mixer* card_mixer = mixer_open(card); 57 if (card_mixer == NULL) { 58 return true; 59 } 60 struct mixer_ctl* ctl = find_mixer_with_suffix(card_mixer, suffix); 61 if (!ctl) { 62 return true; 63 } 64 mixer_ctl_update(ctl); 65 int val = mixer_ctl_get_value(ctl, 0); 66 ALOGI("%s - value %d\n", mixer_ctl_get_name(ctl), val); 67 mixer_close(card_mixer); 68 69 return val != 0; 70 } 71 72 static jboolean android_server_UsbAlsaJackDetector_hasJackDetect(JNIEnv* /* env */, 73 jobject /* thiz */, 74 jint card) 75 { 76 struct mixer* card_mixer = mixer_open(card); 77 if (card_mixer == NULL) { 78 return false; 79 } 80 81 jboolean has_jack = false; 82 if ((find_mixer_with_suffix(card_mixer, USB_IN_JACK_SUFFIX) != NULL) || 83 (find_mixer_with_suffix(card_mixer, USB_OUT_JACK_SUFFIX) != NULL)) { 84 has_jack = true; 85 } 86 mixer_close(card_mixer); 87 return has_jack; 88 } 89 90 static jboolean android_server_UsbAlsaJackDetector_inputJackConnected(JNIEnv* /* env */, 91 jobject /* thiz */, 92 jint card) 93 { 94 return is_jack_connected(card, USB_IN_JACK_SUFFIX); 95 } 96 97 static jboolean android_server_UsbAlsaJackDetector_outputJackConnected(JNIEnv* /* env */, 98 jobject /* thiz */, 99 jint card) 100 { 101 return is_jack_connected(card, USB_OUT_JACK_SUFFIX); 102 } 103 104 static void android_server_UsbAlsaJackDetector_jackDetect(JNIEnv* env, 105 jobject thiz, 106 jint card) { 107 jclass jdclass = env->GetObjectClass(thiz); 108 jmethodID method_jackDetectCallback = env->GetMethodID(jdclass, "jackDetectCallback", "()Z"); 109 if (method_jackDetectCallback == NULL) { 110 ALOGE("Can't find jackDetectCallback"); 111 return; 112 } 113 114 struct mixer* m = mixer_open(card); 115 if (!m) { 116 ALOGE("Jack detect unable to open mixer\n"); 117 return; 118 } 119 mixer_subscribe_events(m, 1); 120 do { 121 122 // Wait for a mixer event. Retry if interrupted, exit on error. 123 int retval; 124 do { 125 retval = mixer_wait_event(m, -1); 126 } while (retval == -EINTR); 127 if (retval < 0) { 128 break; 129 } 130 mixer_consume_event(m); 131 } while (env->CallBooleanMethod(thiz, method_jackDetectCallback)); 132 133 mixer_close(m); 134 return; 135 } 136 137 static const JNINativeMethod method_table[] = { 138 { "nativeHasJackDetect", "(I)Z", (void*)android_server_UsbAlsaJackDetector_hasJackDetect }, 139 { "nativeInputJackConnected", "(I)Z", 140 (void*)android_server_UsbAlsaJackDetector_inputJackConnected }, 141 { "nativeOutputJackConnected", "(I)Z", 142 (void*)android_server_UsbAlsaJackDetector_outputJackConnected }, 143 { "nativeJackDetect", "(I)Z", (void*)android_server_UsbAlsaJackDetector_jackDetect }, 144 }; 145 146 int register_android_server_UsbAlsaJackDetector(JNIEnv *env) 147 { 148 jclass clazz = env->FindClass("com/android/server/usb/UsbAlsaJackDetector"); 149 if (clazz == NULL) { 150 ALOGE("Can't find com/android/server/usb/UsbAlsaJackDetector"); 151 return -1; 152 } 153 154 if (!jniRegisterNativeMethods(env, "com/android/server/usb/UsbAlsaJackDetector", 155 method_table, NELEM(method_table))) { 156 ALOGE("Can't register UsbAlsaJackDetector native methods"); 157 return -1; 158 } 159 160 return 0; 161 } 162 163 } 164