From 4bfb6af2271d9238afd029141344052181510c65 Mon Sep 17 00:00:00 2001 From: bengris32 Date: Sat, 16 Jul 2022 12:48:37 +0100 Subject: [PATCH 1/3] 2e: Introduce MtkInCallService * My attempt at fixing in call gain control on MediaTek devices. * It attempts to replicate what the stock MediaTek framework does when controlling the volume of the earpiece speaker, since MTK's audio HAL is not able to set the gain of the speaker from the values sent by AOSP framework. Signed-off-by: bengris32 --- InCallService/Android.bp | 30 +++++++++++ InCallService/AndroidManifest.xml | 25 ++++++++++ InCallService/res/values/strings.xml | 4 ++ .../OnLockedBootCompleteReceiver.java | 19 +++++++ .../incallservice/VolumeChangeReceiver.java | 50 +++++++++++++++++++ .../incallservice/VolumeChangeService.java | 39 +++++++++++++++ device.mk | 4 ++ 7 files changed, 171 insertions(+) create mode 100644 InCallService/Android.bp create mode 100644 InCallService/AndroidManifest.xml create mode 100644 InCallService/res/values/strings.xml create mode 100644 InCallService/src/org/lineageos/mediatek/incallservice/OnLockedBootCompleteReceiver.java create mode 100644 InCallService/src/org/lineageos/mediatek/incallservice/VolumeChangeReceiver.java create mode 100644 InCallService/src/org/lineageos/mediatek/incallservice/VolumeChangeService.java diff --git a/InCallService/Android.bp b/InCallService/Android.bp new file mode 100644 index 0000000..bf5143e --- /dev/null +++ b/InCallService/Android.bp @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2022 bengris32 + * + * 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: "MtkInCallService", + + srcs: ["src/**/*.java"], + resource_dirs: ["res"], + + certificate: "platform", + platform_apis: true, + privileged: true, + + optimize: { + enabled: false, + } +} diff --git a/InCallService/AndroidManifest.xml b/InCallService/AndroidManifest.xml new file mode 100644 index 0000000..cb5c2bc --- /dev/null +++ b/InCallService/AndroidManifest.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + diff --git a/InCallService/res/values/strings.xml b/InCallService/res/values/strings.xml new file mode 100644 index 0000000..d71b129 --- /dev/null +++ b/InCallService/res/values/strings.xml @@ -0,0 +1,4 @@ + + + MTK In-call service + diff --git a/InCallService/src/org/lineageos/mediatek/incallservice/OnLockedBootCompleteReceiver.java b/InCallService/src/org/lineageos/mediatek/incallservice/OnLockedBootCompleteReceiver.java new file mode 100644 index 0000000..80d7f7d --- /dev/null +++ b/InCallService/src/org/lineageos/mediatek/incallservice/OnLockedBootCompleteReceiver.java @@ -0,0 +1,19 @@ +package org.lineageos.mediatek.incallservice; + +import android.content.BroadcastReceiver; +import android.content.Intent; +import android.content.Context; + +import android.util.Log; + +public class OnLockedBootCompleteReceiver extends BroadcastReceiver { + private static final String LOG_TAG = "MtkInCallService"; + + @Override + public void onReceive(final Context context, Intent intent) { + Log.i(LOG_TAG, "onBoot"); + + Intent sIntent = new Intent(context, VolumeChangeService.class); + context.startService(sIntent); + } +} diff --git a/InCallService/src/org/lineageos/mediatek/incallservice/VolumeChangeReceiver.java b/InCallService/src/org/lineageos/mediatek/incallservice/VolumeChangeReceiver.java new file mode 100644 index 0000000..49a127d --- /dev/null +++ b/InCallService/src/org/lineageos/mediatek/incallservice/VolumeChangeReceiver.java @@ -0,0 +1,50 @@ +package org.lineageos.mediatek.incallservice; + +import android.content.Intent; +import android.content.Context; +import android.content.BroadcastReceiver; + +import android.media.AudioManager; +import android.media.AudioSystem; +import android.media.AudioDeviceInfo; + +import android.util.Log; + +public class VolumeChangeReceiver extends BroadcastReceiver { + public static final String LOG_TAG = "MtkInCallService"; + + private AudioManager mAudioManager; + + public VolumeChangeReceiver(Context context) { + mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); + } + + @Override + public void onReceive(Context context, Intent intent) { + int streamType = intent.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, -1); + if (streamType == AudioSystem.STREAM_VOICE_CALL) { + AudioDeviceInfo callDevice = mAudioManager.getCommunicationDevice(); + if (callDevice.getInternalType() != AudioDeviceInfo.TYPE_BUILTIN_EARPIECE) { + // Device is not the built in earpiece, we don't need to do anything. + return; + } + + // Start building parameters + String parameters = "volumeDevice=" + (callDevice.getId() - 1) + ";"; + int volumeIndex = intent.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_VALUE, -1); + if (volumeIndex < 0) { + Log.w(LOG_TAG, "Could not get volumeIndex!"); + return; + } + + // Limit volumeIndex to a max of 7 since that's the size of + // MediaTek's gain table. + parameters += "volumeIndex=" + Math.min(7, volumeIndex) + ";"; + parameters += "volumeStreamType=" + streamType; + + // Set gain parameters + Log.d(LOG_TAG, "Setting audio parameters: " + parameters); + AudioSystem.setParameters(parameters); + } + } +} diff --git a/InCallService/src/org/lineageos/mediatek/incallservice/VolumeChangeService.java b/InCallService/src/org/lineageos/mediatek/incallservice/VolumeChangeService.java new file mode 100644 index 0000000..a7f0203 --- /dev/null +++ b/InCallService/src/org/lineageos/mediatek/incallservice/VolumeChangeService.java @@ -0,0 +1,39 @@ +package org.lineageos.mediatek.incallservice; + +import android.media.AudioManager; + +import android.content.Intent; +import android.content.IntentFilter; +import android.content.Context; +import android.app.Service; +import android.os.IBinder; + +import android.util.Log; + +public class VolumeChangeService extends Service { + public static final String LOG_TAG = "MtkInCallService"; + + private Context mContext; + private VolumeChangeReceiver mVolumeChangeReceiver; + + @Override + public IBinder onBind(Intent intent) { + return null; + } + + @Override + public void onDestroy() { + super.onDestroy(); + } + + @Override + public int onStartCommand(Intent intent, int flags, int startid) { + mContext = this; + mVolumeChangeReceiver = new VolumeChangeReceiver(mContext); + + Log.i(LOG_TAG, "Service is starting..."); + this.registerReceiver(mVolumeChangeReceiver, + new IntentFilter(AudioManager.VOLUME_CHANGED_ACTION)); + return START_STICKY; + } +} diff --git a/device.mk b/device.mk index 08e4638..79f5e4a 100644 --- a/device.mk +++ b/device.mk @@ -188,6 +188,10 @@ PRODUCT_PACKAGES += \ com.android.media.swcodec \ libsfplugin_ccodec +# MtkInCallService +PRODUCT_PACKAGES += \ + MtkInCallService + # NFC PRODUCT_COPY_FILES += \ frameworks/native/data/etc/android.hardware.nfc.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/sku_nfc-st/android.hardware.nfc.xml \ -- GitLab From f182674d944609a3b0c1045bbc79293b9874b6a0 Mon Sep 17 00:00:00 2001 From: bengris32 Date: Mon, 8 Aug 2022 18:22:41 +0100 Subject: [PATCH 2/3] 2e: InCallService: Bugfixes and refactor * Refactor and cleanup code * Use proper way of getting audioDevice with getPort().type() * Stop mixing up values between AudioSystem and AudioManager, as values between AudioManager (java) and AudioSystem (native) could change and become different from eachother. Signed-off-by: bengris32 --- .../mediatek/incallservice/GainUtils.java | 16 ++++++++++ .../incallservice/VolumeChangeReceiver.java | 29 ++++++++----------- .../incallservice/VolumeChangeService.java | 5 +++- 3 files changed, 32 insertions(+), 18 deletions(-) create mode 100644 InCallService/src/org/lineageos/mediatek/incallservice/GainUtils.java diff --git a/InCallService/src/org/lineageos/mediatek/incallservice/GainUtils.java b/InCallService/src/org/lineageos/mediatek/incallservice/GainUtils.java new file mode 100644 index 0000000..9e778fe --- /dev/null +++ b/InCallService/src/org/lineageos/mediatek/incallservice/GainUtils.java @@ -0,0 +1,16 @@ +package org.lineageos.mediatek.incallservice; + +import android.media.AudioSystem; + +import android.util.Log; + +public class GainUtils { + public static final String LOG_TAG = "MtkInCallService"; + + public static void setGainLevel(int audioDevice, int gainIndex, int streamType) { + String parameters = String.format("volumeDevice=%d;volumeIndex=%d;volumeStreamType=%d", + audioDevice, Math.min(7, gainIndex), streamType); + Log.d(LOG_TAG, "Setting audio parameters to: " + parameters); + AudioSystem.setParameters(parameters); + } +} diff --git a/InCallService/src/org/lineageos/mediatek/incallservice/VolumeChangeReceiver.java b/InCallService/src/org/lineageos/mediatek/incallservice/VolumeChangeReceiver.java index 49a127d..3e73491 100644 --- a/InCallService/src/org/lineageos/mediatek/incallservice/VolumeChangeReceiver.java +++ b/InCallService/src/org/lineageos/mediatek/incallservice/VolumeChangeReceiver.java @@ -15,36 +15,31 @@ public class VolumeChangeReceiver extends BroadcastReceiver { private AudioManager mAudioManager; - public VolumeChangeReceiver(Context context) { - mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); + public VolumeChangeReceiver(AudioManager audioManager) { + mAudioManager = audioManager; } - @Override - public void onReceive(Context context, Intent intent) { - int streamType = intent.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, -1); - if (streamType == AudioSystem.STREAM_VOICE_CALL) { + private void handleVolumeStateChange(Intent intent) { + if (intent.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, -1) == AudioManager.STREAM_VOICE_CALL) { AudioDeviceInfo callDevice = mAudioManager.getCommunicationDevice(); - if (callDevice.getInternalType() != AudioDeviceInfo.TYPE_BUILTIN_EARPIECE) { + if (callDevice.getType() != AudioDeviceInfo.TYPE_BUILTIN_EARPIECE) { // Device is not the built in earpiece, we don't need to do anything. return; } - // Start building parameters - String parameters = "volumeDevice=" + (callDevice.getId() - 1) + ";"; + // Try to get volumeIndex int volumeIndex = intent.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_VALUE, -1); if (volumeIndex < 0) { Log.w(LOG_TAG, "Could not get volumeIndex!"); return; } - // Limit volumeIndex to a max of 7 since that's the size of - // MediaTek's gain table. - parameters += "volumeIndex=" + Math.min(7, volumeIndex) + ";"; - parameters += "volumeStreamType=" + streamType; - - // Set gain parameters - Log.d(LOG_TAG, "Setting audio parameters: " + parameters); - AudioSystem.setParameters(parameters); + GainUtils.setGainLevel(callDevice.getPort().type(), volumeIndex, AudioSystem.STREAM_VOICE_CALL); } } + + @Override + public void onReceive(Context context, Intent intent) { + handleVolumeStateChange(intent); + } } diff --git a/InCallService/src/org/lineageos/mediatek/incallservice/VolumeChangeService.java b/InCallService/src/org/lineageos/mediatek/incallservice/VolumeChangeService.java index a7f0203..e1cc8db 100644 --- a/InCallService/src/org/lineageos/mediatek/incallservice/VolumeChangeService.java +++ b/InCallService/src/org/lineageos/mediatek/incallservice/VolumeChangeService.java @@ -29,9 +29,12 @@ public class VolumeChangeService extends Service { @Override public int onStartCommand(Intent intent, int flags, int startid) { mContext = this; - mVolumeChangeReceiver = new VolumeChangeReceiver(mContext); + + AudioManager audioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE); + mVolumeChangeReceiver = new VolumeChangeReceiver(audioManager); Log.i(LOG_TAG, "Service is starting..."); + this.registerReceiver(mVolumeChangeReceiver, new IntentFilter(AudioManager.VOLUME_CHANGED_ACTION)); return START_STICKY; -- GitLab From 4c9b7811756f93beb92eb992cbbf91252ab9d415 Mon Sep 17 00:00:00 2001 From: Daniel Jacob Chittoor Date: Wed, 16 Nov 2022 13:24:26 +0000 Subject: [PATCH 3/3] 2e: InCallService: Backport to Android 10 The getCommunicationDevice() was exposed post-Android 10. So, retrieve the device outputs via the getDevices() API and then find the earpiece output device. Test: check if volume gains work in-call while on earpiece device --- .../incallservice/VolumeChangeReceiver.java | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/InCallService/src/org/lineageos/mediatek/incallservice/VolumeChangeReceiver.java b/InCallService/src/org/lineageos/mediatek/incallservice/VolumeChangeReceiver.java index 3e73491..b80533d 100644 --- a/InCallService/src/org/lineageos/mediatek/incallservice/VolumeChangeReceiver.java +++ b/InCallService/src/org/lineageos/mediatek/incallservice/VolumeChangeReceiver.java @@ -21,12 +21,21 @@ public class VolumeChangeReceiver extends BroadcastReceiver { private void handleVolumeStateChange(Intent intent) { if (intent.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, -1) == AudioManager.STREAM_VOICE_CALL) { - AudioDeviceInfo callDevice = mAudioManager.getCommunicationDevice(); - if (callDevice.getType() != AudioDeviceInfo.TYPE_BUILTIN_EARPIECE) { + + if (!mAudioManager.isSpeakerphoneOn() && !mAudioManager.isBluetoothScoOn()) { // Device is not the built in earpiece, we don't need to do anything. return; } + AudioDeviceInfo[] allDevices = mAudioManager.getDevices(AudioManager.GET_DEVICES_OUTPUTS); + AudioDeviceInfo callDevice = null; + for (AudioDeviceInfo device: allDevices) { + if (device.getType() == AudioDeviceInfo.TYPE_BUILTIN_EARPIECE) { + callDevice = device; + break; + } + } + // Try to get volumeIndex int volumeIndex = intent.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_VALUE, -1); if (volumeIndex < 0) { -- GitLab