sm7125-common: Fix all of our audio issues

* Use a script to swap check if we are in an A2DP phone call
* Use an app to check if we are in a VoIP or A2DP call and pass parameters accordingly
* Correctly route A2DP phone calls to the actual bluetooth device instead of earpiece and un-swap speaker and earpiece in VoIP calls

Change-Id: I1de8b2ed57b265b65cf619000e78e290c98e3d5c
Co-Authored-By: Ruchit <ruchitmarathe@gmail.com>
urubino-microg
Simon1511 1 year ago committed by Ruchit
parent d8a92818ab
commit c1e2fc7ca1
  1. 7
      audio/Android.bp
  2. 367
      audio/ParametersUtil.cpp
  3. 23
      audio/SamsungAudio/Android.bp
  4. 28
      audio/SamsungAudio/AndroidManifest.xml
  5. 34
      audio/SamsungAudio/src/android/hardware/media/BootCompletedReceiver.java
  6. 122
      audio/SamsungAudio/src/android/hardware/media/SamsungAudioService.java
  7. 40
      audio/SamsungAudio/src/android/hardware/media/Utils.java
  8. 3
      common.mk
  9. 3
      sepolicy/public/property.te
  10. 2
      sepolicy/vendor/hal_audio_default.te
  11. 3
      sepolicy/vendor/property_contexts
  12. 3
      sepolicy/vendor/system_app.te

@ -43,6 +43,7 @@ cc_defaults {
"libmemunreachable",
"libutils",
"android.hardware.audio.common-util",
"libtinyalsa",
],
header_libs: [
@ -69,6 +70,7 @@ cc_library_shared {
"android.hardware.audio.common@2.0",
"android.hardware.audio.common@2.0-util",
"libcutils",
"libtinyalsa",
],
cflags: [
"-DMAJOR_VERSION=2",
@ -87,6 +89,7 @@ cc_library_shared {
"android.hardware.audio.common@4.0",
"android.hardware.audio.common@4.0-util",
"libcutils",
"libtinyalsa",
],
cflags: [
"-DMAJOR_VERSION=4",
@ -104,6 +107,7 @@ cc_library_shared {
"android.hardware.audio.common@5.0",
"android.hardware.audio.common@5.0-util",
"libcutils",
"libtinyalsa",
],
cflags: [
"-DMAJOR_VERSION=5",
@ -121,6 +125,7 @@ cc_library_shared {
"android.hardware.audio.common@6.0",
"android.hardware.audio.common@6.0-util",
"libcutils",
"libtinyalsa",
],
cflags: [
"-DMAJOR_VERSION=6",
@ -140,6 +145,7 @@ cc_library_shared {
"android.hardware.audio.common@7.0-util",
"libbase",
"libcutils",
"libtinyalsa",
],
cflags: [
"-DMAJOR_VERSION=7",
@ -160,6 +166,7 @@ cc_library_shared {
"android.hardware.audio.common@7.1-util",
"libbase",
"libcutils",
"libtinyalsa",
],
cflags: [
"-DMAJOR_VERSION=7",

@ -21,6 +21,9 @@
#include <util/CoreUtils.h>
#include <tinyalsa/asoundlib.h>
#include <cutils/properties.h>
namespace android {
namespace hardware {
namespace audio {
@ -139,6 +142,342 @@ Result ParametersUtil::setParam(const char* name, float value) {
return setParams(param);
}
int getMixerValueByName(const char *name) {
const auto mixer = mixer_open(0);
const auto ctl = mixer_get_ctl_by_name(mixer, name);
int value = 0;
if (mixer == nullptr) {
ALOGE("Failed to find mixer ctl for %s", name);
return 0;
}
if (ctl == nullptr) {
ALOGE("Failed to find mixer ctl for %s", name);
return 0;
}
value = mixer_ctl_get_value(ctl, 0);
mixer_close(mixer);
return value;
}
const char *getMixerValueString(const char *name) {
const auto mixer = mixer_open(0);
const auto ctl = mixer_get_ctl_by_name(mixer, name);
int control_value = mixer_ctl_get_value(ctl, 0);
const char *value;
if (mixer == nullptr) {
ALOGE("Failed to find mixer ctl for %s", name);
return "-1";
}
if (ctl == nullptr) {
ALOGE("Failed to find mixer ctl for %s", name);
return "-1";
}
value = mixer_ctl_get_enum_string(ctl, control_value);
mixer_close(mixer);
return value;
}
void setMixerValueByName(mixer *mixer, const char *name, int value) {
const auto ctl = mixer_get_ctl_by_name(mixer, name);
if (ctl == nullptr) {
ALOGE("Failed to find mixer ctl for %s", name);
return;
}
if (mixer_ctl_set_value(ctl, 0, value) < 0) {
ALOGE("Failed to find mixer ctl for %s", name);
return;
}
}
void setMixerValueByNameString(mixer *mixer, const char *name, const char *value) {
const auto ctl = mixer_get_ctl_by_name(mixer, name);
if (ctl == nullptr) {
ALOGE("Failed to find mixer ctl for %s", name);
return;
}
if (mixer_ctl_set_enum_by_string(ctl, value)) {
ALOGE("Failed to find mixer ctl for %s", name);
return;
}
}
void setBTincall(bool enabled, char *slot) {
const auto mixer = mixer_open(0);
if (mixer == nullptr) {
ALOGE("Failed to open mixer");
return;
}
if (enabled) {
ALOGD("Fixing BT in-call mixers");
setMixerValueByName(mixer, "QUIN_MI2S_RX_Voice Mixer VoiceMMode1", 0);
setMixerValueByName(mixer, "QUIN_MI2S_RX_Voice Mixer VoiceMMode2", 0);
setMixerValueByName(mixer, "VoiceMMode1_Tx Mixer TX_CDC_DMA_TX_3_MMode1", 0);
setMixerValueByName(mixer, "VoiceMMode2_Tx Mixer TX_CDC_DMA_TX_3_MMode2", 0);
setMixerValueByNameString(mixer, "SLIM7_RX ADM Channels", "Two");
setMixerValueByName(mixer, "TAS256X IVSENSE ENABLE", 0);
setMixerValueByName(mixer, "BT SOC status", 1);
setMixerValueByName(mixer, "Voip_Tx Mixer TX_CDC_DMA_TX_3_Voip", 0);
setMixerValueByName(mixer, "QUIN_MI2S_RX_Voice Mixer Voip", 0);
setMixerValueByName(mixer, "TAS256X RECEIVER ENABLE LEFT", 0);
setMixerValueByName(mixer, "SmartPA Mute", 1);
setMixerValueByNameString(mixer, "TX_CDC_DMA_TX_3 Channels", "One");
setMixerValueByName(mixer, "TAS256X ASI Left Switch", 0);
setMixerValueByNameString(mixer, "TAS256X ASI1 SEL LEFT", "I2C offset");
setMixerValueByName(mixer, "TAS256X AMP OUTPUT LVL LEFT", 20);
setMixerValueByName(mixer, "Compress Gapless Playback", 1);
setMixerValueByName(mixer, "TX_AIF1_CAP Mixer DEC0", 0);
setMixerValueByName(mixer, "TX_AIF1_CAP Mixer DEC1", 0);
setMixerValueByNameString(mixer, "TX SMIC MUX0", "ZERO");
setMixerValueByNameString(mixer, "TX SMIC MUX1", "ZERO");
setMixerValueByNameString(mixer, "TX DEC0 MUX", "MSM_DMIC");
setMixerValueByNameString(mixer, "TX DEC1 MUX", "MSM_DMIC");
setMixerValueByNameString(mixer, "EC Reference Bit Format", "S16_LE");
setMixerValueByName(mixer, "ADC1 Volume", 12);
setMixerValueByName(mixer, "ADC3 Volume", 12);
setMixerValueByNameString(mixer, "BT SampleRate", "KHZ_16");
setMixerValueByNameString(mixer, "BT SampleRate RX", "KHZ_16");
setMixerValueByNameString(mixer, "BT SampleRate TX", "KHZ_16");
setMixerValueByName(mixer, "ADC3_MIXER Switch", 0);
if (strcmp(slot, "0") == 0) {
setMixerValueByName(mixer, "SLIM_7_RX_Voice Mixer VoiceMMode1", 1);
setMixerValueByName(mixer, "VoiceMMode1_Tx Mixer SLIM_7_TX_MMode1", 1);
setMixerValueByName(mixer, "SLIM_7_RX_Voice Mixer VoiceMMode1", 0);
setMixerValueByName(mixer, "VoiceMMode1_Tx Mixer SLIM_7_TX_MMode1", 0);
setMixerValueByName(mixer, "SLIM_7_RX_Voice Mixer VoiceMMode1", 1);
setMixerValueByName(mixer, "VoiceMMode1_Tx Mixer SLIM_7_TX_MMode1", 1);
} else if (strcmp(slot, "1") == 0) {
setMixerValueByName(mixer, "SLIM_7_RX_Voice Mixer VoiceMMode2", 1);
setMixerValueByName(mixer, "VoiceMMode2_Tx Mixer SLIM_7_TX_MMode2", 1);
setMixerValueByName(mixer, "SLIM_7_RX_Voice Mixer VoiceMMode2", 0);
setMixerValueByName(mixer, "VoiceMMode2_Tx Mixer SLIM_7_TX_MMode2", 0);
setMixerValueByName(mixer, "SLIM_7_RX_Voice Mixer VoiceMMode2", 1);
setMixerValueByName(mixer, "VoiceMMode2_Tx Mixer SLIM_7_TX_MMode2", 1);
}
} else {
ALOGD("Resetting BT in-call mixers");
setMixerValueByNameString(mixer, "SLIM7_RX ADM Channels", "Zero");
setMixerValueByName(mixer, "TAS256X IVSENSE ENABLE", 1);
setMixerValueByName(mixer, "TAS256X RECEIVER ENABLE LEFT", 1);
setMixerValueByName(mixer, "SmartPA Mute", 0);
setMixerValueByNameString(mixer, "TX_CDC_DMA_TX_3 Channels", "Two");
setMixerValueByName(mixer, "TAS256X ASI Left Switch", 1);
setMixerValueByNameString(mixer, "TAS256X ASI1 SEL LEFT", "LeftRightDiv2");
setMixerValueByName(mixer, "TAS256X AMP OUTPUT LVL LEFT", 0);
setMixerValueByName(mixer, "TX_AIF1_CAP Mixer DEC0", 1);
setMixerValueByName(mixer, "TX_AIF1_CAP Mixer DEC1", 1);
setMixerValueByNameString(mixer, "TX SMIC MUX0", "ADC0");
setMixerValueByNameString(mixer, "TX SMIC MUX1", "ADC2");
setMixerValueByNameString(mixer, "TX DEC0 MUX", "SWR_MIC");
setMixerValueByNameString(mixer, "TX DEC1 MUX", "SWR_MIC");
setMixerValueByName(mixer, "EC Reference Bit Format", 0);
setMixerValueByName(mixer, "ADC1 Volume", 0);
setMixerValueByName(mixer, "ADC3 Volume", 0);
setMixerValueByName(mixer, "ADC3_MIXER Switch", 1);
setMixerValueByName(mixer, "SLIM_7_RX_Voice Mixer VoiceMMode1", 0);
setMixerValueByName(mixer, "VoiceMMode1_Tx Mixer SLIM_7_TX_MMode1", 0);
setMixerValueByName(mixer, "SLIM_7_RX_Voice Mixer VoiceMMode2", 0);
setMixerValueByName(mixer, "VoiceMMode2_Tx Mixer SLIM_7_TX_MMode2", 0);
if (strcmp(slot, "0") == 0) {
setMixerValueByName(mixer, "QUIN_MI2S_RX_Voice Mixer VoiceMMode1", 1);
setMixerValueByName(mixer, "VoiceMMode1_Tx Mixer TX_CDC_DMA_TX_3_MMode1", 1);
setMixerValueByName(mixer, "QUIN_MI2S_RX_Voice Mixer VoiceMMode1", 0);
setMixerValueByName(mixer, "VoiceMMode1_Tx Mixer TX_CDC_DMA_TX_3_MMode1", 0);
setMixerValueByName(mixer, "QUIN_MI2S_RX_Voice Mixer VoiceMMode1", 1);
setMixerValueByName(mixer, "VoiceMMode1_Tx Mixer TX_CDC_DMA_TX_3_MMode1", 1);
} else if (strcmp(slot, "1") == 0) {
setMixerValueByName(mixer, "QUIN_MI2S_RX_Voice Mixer VoiceMMode2", 1);
setMixerValueByName(mixer, "VoiceMMode2_Tx Mixer TX_CDC_DMA_TX_3_MMode2", 1);
setMixerValueByName(mixer, "QUIN_MI2S_RX_Voice Mixer VoiceMMode2", 0);
setMixerValueByName(mixer, "VoiceMMode2_Tx Mixer TX_CDC_DMA_TX_3_MMode2", 0);
setMixerValueByName(mixer, "QUIN_MI2S_RX_Voice Mixer VoiceMMode2", 1);
setMixerValueByName(mixer, "VoiceMMode2_Tx Mixer TX_CDC_DMA_TX_3_MMode2", 1);
}
}
mixer_close(mixer);
}
void setEarpieceVoipMixers(bool enabled) {
const auto mixer = mixer_open(0);
if (mixer == nullptr) {
ALOGE("Failed to open mixer");
return;
}
if (enabled) {
setMixerValueByNameString(mixer, "TX SMIC MUX0", "ADC0");
setMixerValueByNameString(mixer, "TX SMIC MUX1", "ADC2");
setMixerValueByName(mixer, "MultiMedia2 Mixer QUIN_MI2S_TX", 0);
setMixerValueByNameString(mixer, "TAS256X ASI1 SEL RIGHT", "I2C offset");
setMixerValueByName(mixer, "TAS256X ASI Right Switch", 0);
setMixerValueByNameString(mixer, "TAS256X ASI1 SEL LEFT", "LeftRightDiv2");
setMixerValueByName(mixer, "TAS256X RECEIVER ENABLE LEFT", 1);
setMixerValueByName(mixer, "TAS256X ASI Left Switch", 1);
setMixerValueByName(mixer, "TAS256X AMP OUTPUT LVL LEFT", 8);
setMixerValueByName(mixer, "TAS256X PLAYBACK VOLUME LEFT", 55);
setMixerValueByName(mixer, "TAS256X PLAYBACK VOLUME RIGHT", 55);
setMixerValueByName(mixer, "SmartPA Mute", 0);
setMixerValueByNameString(mixer, "EC Reference Channels", "One");
setMixerValueByNameString(mixer, "AUDIO_REF_EC_UL10 MUX", "QUIN_MI2S_RX");
setMixerValueByName(mixer, "Voip_Tx Mixer SLIM_7_TX_Voip", 0);
setMixerValueByName(mixer, "SLIM_7_RX_Voice Mixer Voip", 0);
setMixerValueByName(mixer, "QUIN_MI2S_RX_Voice Mixer Voip", 1);
setMixerValueByName(mixer, "Voip_Tx Mixer TX_CDC_DMA_TX_3_Voip", 1);
setMixerValueByName(mixer, "QUIN_MI2S_RX_Voice Mixer Voip", 0);
setMixerValueByName(mixer, "Voip_Tx Mixer TX_CDC_DMA_TX_3_Voip", 0);
}
mixer_close(mixer);
}
void setSpeakerVoipMixers(bool enabled) {
const auto mixer = mixer_open(0);
if (mixer == nullptr) {
ALOGE("Failed to open mixer");
return;
}
if (enabled) {
setMixerValueByNameString(mixer, "TX SMIC MUX0", "ADC2");
setMixerValueByNameString(mixer, "TX SMIC MUX1", "ADC0");
setMixerValueByName(mixer, "MultiMedia2 Mixer QUIN_MI2S_TX", 1);
setMixerValueByNameString(mixer, "TAS256X ASI1 SEL RIGHT", "Right");
setMixerValueByName(mixer, "TAS256X ASI Right Switch", 1);
setMixerValueByNameString(mixer, "TAS256X ASI1 SEL LEFT", "Left");
setMixerValueByName(mixer, "TAS256X RECEIVER ENABLE LEFT", 0);
setMixerValueByName(mixer, "TAS256X ASI Left Switch", 1);
setMixerValueByName(mixer, "TAS256X AMP OUTPUT LVL LEFT", 20);
setMixerValueByName(mixer, "TAS256X PLAYBACK VOLUME LEFT", 55);
setMixerValueByName(mixer, "TAS256X PLAYBACK VOLUME RIGHT", 55);
setMixerValueByName(mixer, "SmartPA Mute", 0);
setMixerValueByNameString(mixer, "EC Reference Channels", "Two");
setMixerValueByNameString(mixer, "AUDIO_REF_EC_UL10 MUX", "QUIN_MI2S_RX");
setMixerValueByName(mixer, "Voip_Tx Mixer SLIM_7_TX_Voip", 0);
setMixerValueByName(mixer, "SLIM_7_RX_Voice Mixer Voip", 0);
setMixerValueByName(mixer, "QUIN_MI2S_RX_Voice Mixer Voip", 1);
setMixerValueByName(mixer, "Voip_Tx Mixer TX_CDC_DMA_TX_3_Voip", 1);
setMixerValueByName(mixer, "QUIN_MI2S_RX_Voice Mixer Voip", 0);
setMixerValueByName(mixer, "Voip_Tx Mixer TX_CDC_DMA_TX_3_Voip", 0);
}
mixer_close(mixer);
}
void setBTVoipMixers(bool enabled) {
const auto mixer = mixer_open(0);
if (mixer == nullptr) {
ALOGE("Failed to open mixer");
return;
}
if (enabled) {
setMixerValueByName(mixer, "TX_AIF1_CAP Mixer DEC0", 0);
setMixerValueByName(mixer, "TX_AIF1_CAP Mixer DEC1", 0);
setMixerValueByNameString(mixer, "TX SMIC MUX0", "ZERO");
setMixerValueByNameString(mixer, "TX SMIC MUX1", "ZERO");
setMixerValueByNameString(mixer, "TX DEC0 MUX", "MSM_DMIC");
setMixerValueByNameString(mixer, "TX DEC1 MUX", "MSM_DMIC");
setMixerValueByName(mixer, "TX_DEC0 Volume", 102);
setMixerValueByName(mixer, "TX_DEC1 Volume", 102);
setMixerValueByName(mixer, "Voip_Tx Mixer SLIM_7_TX_Voip", 1);
setMixerValueByName(mixer, "Voip_Tx Mixer TX_CDC_DMA_TX_3_Voip", 0);
setMixerValueByName(mixer, "SLIM_7_RX_Voice Mixer Voip", 1);
setMixerValueByName(mixer, "QUIN_MI2S_RX_Voice Mixer Voip", 0);
setMixerValueByName(mixer, "TAS256X IVSENSE ENABLE", 0);
setMixerValueByName(mixer, "TAS256X PLAYBACK VOLUME LEFT", 55);
setMixerValueByName(mixer, "TAS256X RECEIVER ENABLE LEFT", 0);
setMixerValueByName(mixer, "TAS256X AMP OUTPUT LVL LEFT", 20);
setMixerValueByName(mixer, "SmartPA Mute", 1);
setMixerValueByName(mixer, "ADC1 Volume", 12);
setMixerValueByName(mixer, "ADC3 Volume", 12);
setMixerValueByNameString(mixer, "TX_CDC_DMA_TX_3 Channels", "One");
setMixerValueByName(mixer, "TAS256X ASI Left Switch", 0);
setMixerValueByNameString(mixer, "TAS256X ASI1 SEL LEFT", "I2C Offset");
setMixerValueByName(mixer, "ADC3_MIXER Switch", 0);
}
mixer_close(mixer);
}
void fixupMixers(int state) {
char a2dpcall[92];
char simslot[92];
char voipdevice[92];
char callswitched[92];
const char *ampstatus;
int voipstatus, btvoipstatus;
property_get("vendor.audio.a2dp.connected", a2dpcall, "false");
property_get("vendor.calls.slotid", simslot, "-1");
property_get("vendor.audio.voip.device", voipdevice, "none");
property_get("vendor.audio.call.switched", callswitched, "false");
voipstatus = getMixerValueByName("QUIN_MI2S_RX_Voice Mixer Voip");
ampstatus = getMixerValueString("TAS256X RECEIVER ENABLE LEFT");
btvoipstatus = getMixerValueByName("SLIM_7_RX_Voice Mixer Voip");
ALOGD("ampstatus is %s", ampstatus);
ALOGD("voipstatus is %d", voipstatus);
ALOGD("bluetooth VoIP status is %d", btvoipstatus);
// BT in-call
if (strcmp(simslot, "0") == 0 || strcmp(simslot, "1") == 0) {
ALOGD("In phone call");
if (strcmp(a2dpcall, "true") == 0 && state == 1) {
ALOGD("In BT phone call");
setBTincall(true, simslot);
} else if (strcmp(a2dpcall, "true") == 0 && state == 2 && strcmp(callswitched, "true") == 0) {
setBTincall(false, simslot);
}
} else if (state == 3) {
setBTincall(false, simslot);
}
// VoIP call
if (voipstatus == 1 || btvoipstatus == 1) {
ALOGD("In VoIP call");
if (strcmp(voipdevice, "bluetooth") == 0 && btvoipstatus == 0) {
ALOGD("Setting bluetooth mixers");
setBTVoipMixers(true);
}
if (strcmp(voipdevice, "earpiece") == 0) {
if (btvoipstatus == 1 || strcmp(ampstatus, "DISABLE") == 0) {
ALOGD("Setting earpiece mixers");
setEarpieceVoipMixers(true);
}
}
if (strcmp(voipdevice, "speaker") == 0) {
if (btvoipstatus == 1 || strcmp(ampstatus, "ENABLE") == 0) {
ALOGD("Setting speaker mixers");
setSpeakerVoipMixers(true);
}
}
}
}
Result ParametersUtil::setParametersImpl(const hidl_vec<ParameterValue>& context,
const hidl_vec<ParameterValue>& parameters) {
AudioParameter params;
@ -150,6 +489,26 @@ Result ParametersUtil::setParametersImpl(const hidl_vec<ParameterValue>& context
params.add(String8("g_sco_samplerate"),
String8(parameters[i].value == AudioParameter::valueOn ? "16000" : "8000"));
}
if (parameters[i].key == "a2dp_call" || parameters[i].key == "A2dpSuspended") {
if (parameters[i].value == "1" || parameters[i].value == "true") {
fixupMixers(1);
}
}
if (parameters[i].key == "voip_call") {
if (parameters[i].value == "1") {
fixupMixers(0);
}
}
if (parameters[i].key == "BT_SCO") {
if (parameters[i].value == "off") {
fixupMixers(2);
}
}
if (parameters[i].key == "reset_a2dp") {
if (parameters[i].value == "1") {
fixupMixers(3);
}
}
params.add(String8(parameters[i].key.c_str()), String8(parameters[i].value.c_str()));
}
return setParams(params);
@ -161,6 +520,14 @@ Result ParametersUtil::setParam(const char* name, const DeviceAddress& address)
if (CoreUtils::deviceAddressToHal(address, &halDeviceType, halDeviceAddress) != NO_ERROR) {
return Result::INVALID_ARGUMENTS;
}
if (halDeviceType == AUDIO_DEVICE_OUT_BLUETOOTH_A2DP || halDeviceType == AUDIO_DEVICE_OUT_BLUETOOTH_SCO
|| halDeviceType == AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET) {
if (strcmp(name, "connect") == 0) {
property_set("vendor.audio.a2dp.connected", "true");
} else if (strcmp(name, "disconnect") == 0) {
property_set("vendor.audio.a2dp.connected", "false");
}
}
AudioParameter params{String8(halDeviceAddress)};
params.addInt(String8(name), halDeviceType);
return setParams(params);

@ -0,0 +1,23 @@
//
// Copyright (C) 2023 The LineageOS 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.
//
android_app {
name: "SamsungAudio",
srcs: ["src/**/*.java"],
certificate: "platform",
platform_apis: true,
system_ext_specific: true,
}

@ -0,0 +1,28 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="android.hardware.media"
android:versionCode="1"
android:versionName="1.0"
android:sharedUserId="android.uid.system">
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
<uses-sdk
android:targetSdkVersion="30"/>
<application
android:label="SamsungAudio"
android:persistent="true">
<receiver android:name=".BootCompletedReceiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</receiver>
<service android:name=".SamsungAudioService"
android:permission="SamsungAudioService">
</service>
</application>
</manifest>

@ -0,0 +1,34 @@
/*
* Copyright (c) 2023 The LineageOS 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.
*/
package android.hardware.media;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
public class BootCompletedReceiver extends BroadcastReceiver {
private static final boolean DEBUG = false;
private static final String TAG = "SamsungAudio";
@Override
public void onReceive(final Context context, Intent intent) {
if (DEBUG) Log.d(TAG, "Received boot completed intent");
Utils.startService(context);
}
}

@ -0,0 +1,122 @@
/*
* Copyright (c) 2023 The LineageOS 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.
*/
package android.hardware.media;
import android.app.Service;
import android.content.Intent;
import android.content.Context;
import android.os.SystemProperties;
import android.os.IBinder;
import android.util.Log;
import android.os.Handler;
import android.media.AudioManager;
import android.media.AudioDeviceInfo;
import android.media.AudioSystem;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothManager;
public class SamsungAudioService extends Service {
private static final String TAG = "SamsungAudioService";
private static final boolean DEBUG = false;
private boolean hasBTcallSet = false;
private Handler mHandler;
private static Runnable mRunnable;
private AudioManager mAudioManager;
private BluetoothManager mBluetoothManager;
private BluetoothAdapter mBluetoothAdapter;
@Override
public void onCreate() {
if (DEBUG) Log.d(TAG, "SamsungAudioService Started");
mAudioManager = getSystemService(AudioManager.class);
mBluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
mBluetoothAdapter = mBluetoothManager.getAdapter();
mHandler = new Handler();
mRunnable = new Runnable() {
public void run() {
if (DEBUG) Log.d(TAG, "onCreate: " + TAG + " is running");
if (!mBluetoothAdapter.isEnabled()) {
if (DEBUG) Log.d(TAG, "Bluetooth is not enabled");
SystemProperties.set("vendor.audio.a2dp.connected", "false");
}
if (mAudioManager.getMode() != AudioManager.MODE_IN_CALL && mAudioManager.getMode() != AudioManager.MODE_IN_COMMUNICATION && hasBTcallSet) {
if (DEBUG) Log.d(TAG, "Call ended, reset everything");
hasBTcallSet = false;
SystemProperties.set("vendor.audio.call.switched", "false");
AudioSystem.setParameters("reset_a2dp=1");
}
if (SystemProperties.get("vendor.audio.a2dp.connected").equals("true") && mAudioManager.getMode() == AudioManager.MODE_IN_CALL
&& mBluetoothAdapter.isEnabled()) {
if (hasBTcallSet) {
SystemProperties.set("vendor.audio.call.switched", "true");
}
if (!hasBTcallSet) {
if (DEBUG) Log.d(TAG, "Setting A2DP parameter");
AudioSystem.setParameters("a2dp_call=1");
hasBTcallSet = true;
SystemProperties.set("vendor.audio.call.switched", "false");
}
}
if (mAudioManager.getMode() == AudioManager.MODE_IN_COMMUNICATION) {
if (mAudioManager.getCommunicationDevice().getType() == AudioDeviceInfo.TYPE_BLUETOOTH_SCO
|| mAudioManager.getCommunicationDevice().getType() == AudioDeviceInfo.TYPE_BLUETOOTH_A2DP
|| mAudioManager.getCommunicationDevice().getType() == AudioDeviceInfo.TYPE_BLE_SPEAKER
|| mAudioManager.getCommunicationDevice().getType() == AudioDeviceInfo.TYPE_BLE_HEADSET) {
if (DEBUG) Log.d(TAG, "Setting VoIP parameter for bluetooth");
SystemProperties.set("vendor.audio.voip.device", "bluetooth");
AudioSystem.setParameters("voip_call=1");
}
if (mAudioManager.getCommunicationDevice().getType() == AudioDeviceInfo.TYPE_BUILTIN_EARPIECE) {
if (DEBUG) Log.d(TAG, "Setting VoIP parameter for earpiece");
SystemProperties.set("vendor.audio.voip.device", "earpiece");
AudioSystem.setParameters("voip_call=1");
}
if (mAudioManager.getCommunicationDevice().getType() == AudioDeviceInfo.TYPE_BUILTIN_SPEAKER) {
if (DEBUG) Log.d(TAG, "Setting VoIP parameter for speaker");
SystemProperties.set("vendor.audio.voip.device", "speaker");
AudioSystem.setParameters("voip_call=1");
}
}
mHandler.postDelayed(mRunnable, 1000);
}
};
mHandler.postDelayed(mRunnable, 0);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (DEBUG) Log.d(TAG, "Starting service");
return START_STICKY;
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
}

@ -0,0 +1,40 @@
/*
* Copyright (C) 2023 The LineageOS 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.
*/
package android.hardware.media;
import android.content.Context;
import android.content.Intent;
import android.os.UserHandle;
import android.util.Log;
public final class Utils {
private static final String TAG = "SamsungAudioUtils";
private static final boolean DEBUG = false;
protected static void startService(Context context) {
if (DEBUG) Log.d(TAG, "Starting service");
context.startServiceAsUser(new Intent(context, SamsungAudioService.class),
UserHandle.CURRENT);
}
protected static void stopService(Context context) {
if (DEBUG) Log.d(TAG, "Stopping service");
context.stopServiceAsUser(new Intent(context, SamsungAudioService.class),
UserHandle.CURRENT);
}
}

@ -80,7 +80,8 @@ PRODUCT_PACKAGES += \
libqcomvisualizer \
libqcomvoiceprocessing \
libqcompostprocbundle \
libvolumelistener
libvolumelistener \
SamsungAudio
TARGET_EXCLUDES_AUDIOFX := true

@ -1,2 +1,5 @@
# Audio
system_public_prop(vendor_samsung_audio_prop)
# Fingerprint
system_public_prop(vendor_fingerprint_prop)

@ -7,3 +7,5 @@ allow hal_audio_default imei_efs_file:file { read open getattr };
allow hal_audio_default efs_file:dir search;
get_prop(hal_audio_default, vendor_radio_prop)
get_prop(hal_audio_default, vendor_samsung_audio_prop)
set_prop(hal_audio_default, vendor_samsung_audio_prop)

@ -1,5 +1,8 @@
# audio
vendor.audio_hal. u:object_r:vendor_audio_prop:s0
vendor.audio.voip.device u:object_r:vendor_samsung_audio_prop:s0
vendor.audio.a2dp.connected u:object_r:vendor_samsung_audio_prop:s0
vendor.audio.call.switched u:object_r:vendor_samsung_audio_prop:s0
# Bluetooth
vendor.bluetooth_fw_ver u:object_r:vendor_bluetooth_prop:s0

@ -14,3 +14,6 @@ allow system_app sysfs_mdnie_writable:file { open write getattr };
# UDFPS
set_prop(system_app, vendor_fingerprint_prop)
get_prop(system_app, vendor_fingerprint_prop)
set_prop(system_app, vendor_samsung_audio_prop)
get_prop(system_app, vendor_samsung_audio_prop)

Loading…
Cancel
Save