| /* |
| * Copyright (C) 2018 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| #define LOG_TAG "UsbAlsaJackDetectorJNI" |
| #include "utils/Log.h" |
| |
| #include "jni.h" |
| #include <nativehelper/JNIHelp.h> |
| #include "android-base/strings.h" |
| #include "android_runtime/AndroidRuntime.h" |
| #include "android_runtime/Log.h" |
| |
| #include <stdio.h> |
| #include <string.h> |
| #include <asm/byteorder.h> |
| #include <sys/types.h> |
| #include <sys/stat.h> |
| #include <fcntl.h> |
| |
| #include <tinyalsa/asoundlib.h> |
| |
| #define DRIVER_NAME "/dev/usb_accessory" |
| |
| #define USB_IN_JACK_SUFFIX "Input Jack" |
| #define USB_OUT_JACK_SUFFIX "Output Jack" |
| |
| namespace android |
| { |
| |
| static struct mixer_ctl* find_mixer_with_suffix(struct mixer* card_mixer, const char* suffix) { |
| int id = 0; |
| struct mixer_ctl* ctl; |
| while ((ctl = mixer_get_ctl(card_mixer, id++)) != NULL) { |
| const char* name = mixer_ctl_get_name(ctl); |
| if (android::base::EndsWith(name, suffix)) { |
| return ctl; |
| } |
| } |
| return NULL; |
| } |
| |
| static jboolean is_jack_connected(jint card, const char* suffix) { |
| struct mixer* card_mixer = mixer_open(card); |
| if (card_mixer == NULL) { |
| return true; |
| } |
| struct mixer_ctl* ctl = find_mixer_with_suffix(card_mixer, suffix); |
| if (!ctl) { |
| return true; |
| } |
| mixer_ctl_update(ctl); |
| int val = mixer_ctl_get_value(ctl, 0); |
| ALOGI("%s - value %d\n", mixer_ctl_get_name(ctl), val); |
| mixer_close(card_mixer); |
| |
| return val != 0; |
| } |
| |
| static jboolean android_server_UsbAlsaJackDetector_hasJackDetect(JNIEnv* /* env */, |
| jobject /* thiz */, |
| jint card) |
| { |
| struct mixer* card_mixer = mixer_open(card); |
| if (card_mixer == NULL) { |
| return false; |
| } |
| |
| jboolean has_jack = false; |
| if ((find_mixer_with_suffix(card_mixer, USB_IN_JACK_SUFFIX) != NULL) || |
| (find_mixer_with_suffix(card_mixer, USB_OUT_JACK_SUFFIX) != NULL)) { |
| has_jack = true; |
| } |
| mixer_close(card_mixer); |
| return has_jack; |
| } |
| |
| static jboolean android_server_UsbAlsaJackDetector_inputJackConnected(JNIEnv* /* env */, |
| jobject /* thiz */, |
| jint card) |
| { |
| return is_jack_connected(card, USB_IN_JACK_SUFFIX); |
| } |
| |
| static jboolean android_server_UsbAlsaJackDetector_outputJackConnected(JNIEnv* /* env */, |
| jobject /* thiz */, |
| jint card) |
| { |
| return is_jack_connected(card, USB_OUT_JACK_SUFFIX); |
| } |
| |
| static void android_server_UsbAlsaJackDetector_jackDetect(JNIEnv* env, |
| jobject thiz, |
| jint card) { |
| jclass jdclass = env->GetObjectClass(thiz); |
| jmethodID method_jackDetectCallback = env->GetMethodID(jdclass, "jackDetectCallback", "()Z"); |
| if (method_jackDetectCallback == NULL) { |
| ALOGE("Can't find jackDetectCallback"); |
| return; |
| } |
| |
| struct mixer* m = mixer_open(card); |
| if (!m) { |
| ALOGE("Jack detect unable to open mixer\n"); |
| return; |
| } |
| mixer_subscribe_events(m, 1); |
| do { |
| |
| // Wait for a mixer event. Retry if interrupted, exit on error. |
| int retval; |
| do { |
| retval = mixer_wait_event(m, -1); |
| } while (retval == -EINTR); |
| if (retval < 0) { |
| break; |
| } |
| mixer_consume_event(m); |
| } while (env->CallBooleanMethod(thiz, method_jackDetectCallback)); |
| |
| mixer_close(m); |
| return; |
| } |
| |
| static const JNINativeMethod method_table[] = { |
| { "nativeHasJackDetect", "(I)Z", (void*)android_server_UsbAlsaJackDetector_hasJackDetect }, |
| { "nativeInputJackConnected", "(I)Z", |
| (void*)android_server_UsbAlsaJackDetector_inputJackConnected }, |
| { "nativeOutputJackConnected", "(I)Z", |
| (void*)android_server_UsbAlsaJackDetector_outputJackConnected }, |
| { "nativeJackDetect", "(I)Z", (void*)android_server_UsbAlsaJackDetector_jackDetect }, |
| }; |
| |
| int register_android_server_UsbAlsaJackDetector(JNIEnv *env) |
| { |
| jclass clazz = env->FindClass("com/android/server/usb/UsbAlsaJackDetector"); |
| if (clazz == NULL) { |
| ALOGE("Can't find com/android/server/usb/UsbAlsaJackDetector"); |
| return -1; |
| } |
| |
| if (!jniRegisterNativeMethods(env, "com/android/server/usb/UsbAlsaJackDetector", |
| method_table, NELEM(method_table))) { |
| ALOGE("Can't register UsbAlsaJackDetector native methods"); |
| return -1; |
| } |
| |
| return 0; |
| } |
| |
| } |