/*
|
* 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;
|
}
|
|
}
|