diff --git a/audio/SamsungAudio/Android.bp b/audio/SamsungAudio/Android.bp
new file mode 100644
index 0000000..449e01e
--- /dev/null
+++ b/audio/SamsungAudio/Android.bp
@@ -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,
+}
diff --git a/audio/SamsungAudio/AndroidManifest.xml b/audio/SamsungAudio/AndroidManifest.xml
new file mode 100644
index 0000000..1e1d3d3
--- /dev/null
+++ b/audio/SamsungAudio/AndroidManifest.xml
@@ -0,0 +1,28 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/audio/SamsungAudio/src/android/hardware/media/BootCompletedReceiver.java b/audio/SamsungAudio/src/android/hardware/media/BootCompletedReceiver.java
new file mode 100644
index 0000000..3149c48
--- /dev/null
+++ b/audio/SamsungAudio/src/android/hardware/media/BootCompletedReceiver.java
@@ -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);
+ }
+}
diff --git a/audio/SamsungAudio/src/android/hardware/media/SamsungAudioService.java b/audio/SamsungAudio/src/android/hardware/media/SamsungAudioService.java
new file mode 100644
index 0000000..b13737b
--- /dev/null
+++ b/audio/SamsungAudio/src/android/hardware/media/SamsungAudioService.java
@@ -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;
+ }
+}
diff --git a/audio/SamsungAudio/src/android/hardware/media/Utils.java b/audio/SamsungAudio/src/android/hardware/media/Utils.java
new file mode 100644
index 0000000..a07af01
--- /dev/null
+++ b/audio/SamsungAudio/src/android/hardware/media/Utils.java
@@ -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);
+ }
+}
diff --git a/audio/impl/Android.bp b/audio/impl/Android.bp
index 297c747..538cbb2 100644
--- a/audio/impl/Android.bp
+++ b/audio/impl/Android.bp
@@ -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",
diff --git a/audio/impl/ParametersUtil.cpp b/audio/impl/ParametersUtil.cpp
index 2844d03..6c6a938 100644
--- a/audio/impl/ParametersUtil.cpp
+++ b/audio/impl/ParametersUtil.cpp
@@ -21,6 +21,9 @@
#include
+#include
+#include
+
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& context,
const hidl_vec& parameters) {
AudioParameter params;
@@ -150,6 +489,26 @@ Result ParametersUtil::setParametersImpl(const hidl_vec& 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);
diff --git a/common.mk b/common.mk
index a2277b3..6313d09 100644
--- a/common.mk
+++ b/common.mk
@@ -77,7 +77,8 @@ PRODUCT_PACKAGES += \
libqcomvoiceprocessing \
libqcompostprocbundle \
libvolumelistener \
- SamsungDAP
+ SamsungDAP \
+ SamsungAudio
TARGET_EXCLUDES_AUDIOFX := true
diff --git a/sepolicy/public/property.te b/sepolicy/public/property.te
index 7de6666..9d4a034 100644
--- a/sepolicy/public/property.te
+++ b/sepolicy/public/property.te
@@ -1,2 +1,5 @@
+# Audio
+system_public_prop(vendor_samsung_audio_prop)
+
# Fingerprint
system_public_prop(vendor_fingerprint_prop)
diff --git a/sepolicy/vendor/hal_audio_default.te b/sepolicy/vendor/hal_audio_default.te
index a819e93..c94724a 100644
--- a/sepolicy/vendor/hal_audio_default.te
+++ b/sepolicy/vendor/hal_audio_default.te
@@ -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)
diff --git a/sepolicy/vendor/property_contexts b/sepolicy/vendor/property_contexts
index e6528cd..959153f 100644
--- a/sepolicy/vendor/property_contexts
+++ b/sepolicy/vendor/property_contexts
@@ -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
diff --git a/sepolicy/vendor/system_app.te b/sepolicy/vendor/system_app.te
index a8fe735..7a43bdd 100644
--- a/sepolicy/vendor/system_app.te
+++ b/sepolicy/vendor/system_app.te
@@ -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)