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)