Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit aef77326 authored by jiabin's avatar jiabin
Browse files

Maximize USB audio volume when connecting.

Some of the USB audio devices have low hardware volume by default. If
the audio system doesn't set the hardware volume, the user will not be
able to get the full range of volume that is supported by the device.

Bug: 245041322
Test: connect USB device with default low hw volume
Flag: com.android.server.usb.flags.maximize_usb_audio_volume_when_connecting
Change-Id: I86874254c31bfb009ad7c36add11f8ab6496fe96
parent d1d03a20
Loading
Loading
Loading
Loading
+1 −0
Original line number Original line Diff line number Diff line
@@ -61,6 +61,7 @@ cc_library_static {
        "com_android_server_SystemServer.cpp",
        "com_android_server_SystemServer.cpp",
        "com_android_server_tv_TvUinputBridge.cpp",
        "com_android_server_tv_TvUinputBridge.cpp",
        "com_android_server_tv_TvInputHal.cpp",
        "com_android_server_tv_TvInputHal.cpp",
        "com_android_server_UsbAlsaDevice.cpp",
        "com_android_server_UsbAlsaJackDetector.cpp",
        "com_android_server_UsbAlsaJackDetector.cpp",
        "com_android_server_UsbAlsaMidiDevice.cpp",
        "com_android_server_UsbAlsaMidiDevice.cpp",
        "com_android_server_UsbDeviceManager.cpp",
        "com_android_server_UsbDeviceManager.cpp",
+70 −0
Original line number Original line Diff line number Diff line
/*
 * Copyright (C) 2024 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 "UsbAlsaDeviceJNI"

#include <nativehelper/JNIPlatformHelp.h>
#include <tinyalsa/asoundlib.h>

#include <string>
#include <vector>

#include "jni.h"
#include "utils/Log.h"

static const std::vector<std::string> POSSIBLE_HARDWARE_VOLUME_MIXER_NAMES =
        {"Headphone Playback Volume", "Headset Playback Volume", "PCM Playback Volume"};

namespace android {

static void android_server_UsbAlsaDevice_setVolume(JNIEnv* /*env*/, jobject /*thiz*/, jint card,
                                                   float volume) {
    ALOGD("%s(%d, %f)", __func__, card, volume);
    struct mixer* alsaMixer = mixer_open(card);
    if (alsaMixer == nullptr) {
        ALOGW("%s(%d, %f) returned as no mixer is opened", __func__, card, volume);
        return;
    }
    struct mixer_ctl* ctl = nullptr;
    for (const auto& mixerName : POSSIBLE_HARDWARE_VOLUME_MIXER_NAMES) {
        ctl = mixer_get_ctl_by_name(alsaMixer, mixerName.c_str());
        if (ctl != nullptr) {
            break;
        }
    }
    if (ctl == nullptr) {
        ALOGW("%s(%d, %f) returned as no volume mixer is found", __func__, card, volume);
        return;
    }
    const unsigned int n = mixer_ctl_get_num_values(ctl);
    for (unsigned int id = 0; id < n; id++) {
        if (int error = mixer_ctl_set_percent(ctl, id, 100 * volume); error != 0) {
            ALOGE("%s(%d, %f) failed, error=%d", __func__, card, volume, error);
            return;
        }
    }
    ALOGD("%s(%d, %f) succeed", __func__, card, volume);
}

static JNINativeMethod method_table[] = {
        {"nativeSetVolume", "(IF)V", (void*)android_server_UsbAlsaDevice_setVolume},
};

int register_android_server_UsbAlsaDevice(JNIEnv* env) {
    return jniRegisterNativeMethods(env, "com/android/server/usb/UsbAlsaDevice", method_table,
                                    NELEM(method_table));
}
} // namespace android
+2 −0
Original line number Original line Diff line number Diff line
@@ -33,6 +33,7 @@ int register_android_server_power_stats_CpuPowerStatsCollector(JNIEnv* env);
int register_android_server_HintManagerService(JNIEnv* env);
int register_android_server_HintManagerService(JNIEnv* env);
int register_android_server_storage_AppFuse(JNIEnv* env);
int register_android_server_storage_AppFuse(JNIEnv* env);
int register_android_server_SystemServer(JNIEnv* env);
int register_android_server_SystemServer(JNIEnv* env);
int register_android_server_UsbAlsaDevice(JNIEnv* env);
int register_android_server_UsbAlsaJackDetector(JNIEnv* env);
int register_android_server_UsbAlsaJackDetector(JNIEnv* env);
int register_android_server_UsbAlsaMidiDevice(JNIEnv* env);
int register_android_server_UsbAlsaMidiDevice(JNIEnv* env);
int register_android_server_UsbDeviceManager(JavaVM* vm, JNIEnv* env);
int register_android_server_UsbDeviceManager(JavaVM* vm, JNIEnv* env);
@@ -98,6 +99,7 @@ extern "C" jint JNI_OnLoad(JavaVM* vm, void* /* reserved */)
    register_android_server_InputManager(env);
    register_android_server_InputManager(env);
    register_android_server_LightsService(env);
    register_android_server_LightsService(env);
    register_android_server_UsbDeviceManager(vm, env);
    register_android_server_UsbDeviceManager(vm, env);
    register_android_server_UsbAlsaDevice(env);
    register_android_server_UsbAlsaJackDetector(env);
    register_android_server_UsbAlsaJackDetector(env);
    register_android_server_UsbAlsaMidiDevice(env);
    register_android_server_UsbAlsaMidiDevice(env);
    register_android_server_UsbHostManager(env);
    register_android_server_UsbHostManager(env);
+6 −0
Original line number Original line Diff line number Diff line
@@ -26,6 +26,7 @@ import android.util.Slog;


import com.android.internal.util.dump.DualDumpOutputStream;
import com.android.internal.util.dump.DualDumpOutputStream;
import com.android.server.audio.AudioService;
import com.android.server.audio.AudioService;
import com.android.server.usb.flags.Flags;


import java.util.Arrays;
import java.util.Arrays;


@@ -211,6 +212,9 @@ public final class UsbAlsaDevice {
        mIsSelected[direction] = true;
        mIsSelected[direction] = true;
        mState[direction] = 0;
        mState[direction] = 0;
        startJackDetect();
        startJackDetect();
        if (direction == OUTPUT && Flags.maximizeUsbAudioVolumeWhenConnecting()) {
            nativeSetVolume(mCardNum, 1.0f /*volume*/);
        }
        updateWiredDeviceConnectionState(direction, true /*enable*/);
        updateWiredDeviceConnectionState(direction, true /*enable*/);
    }
    }


@@ -412,5 +416,7 @@ public final class UsbAlsaDevice {


        return result;
        return result;
    }
    }

    private native void nativeSetVolume(int card, float volume);
}
}