improve media control logic

This commit is contained in:
Kavish Devar
2025-01-03 02:05:20 +05:30
parent 9fea483d51
commit 66eaa985c8
4 changed files with 62 additions and 10 deletions

View File

@@ -459,6 +459,7 @@ class AirPodsService: Service() {
) )
var justEnabledA2dp = false var justEnabledA2dp = false
earReceiver = object : BroadcastReceiver() { earReceiver = object : BroadcastReceiver() {
@SuppressLint("NewApi")
override fun onReceive(context: Context, intent: Intent) { override fun onReceive(context: Context, intent: Intent) {
val data = intent.getByteArrayExtra("data") val data = intent.getByteArrayExtra("data")
if (data != null && earDetectionEnabled) { if (data != null && earDetectionEnabled) {
@@ -516,15 +517,41 @@ class AirPodsService: Service() {
disconnectAudio(this@AirPodsService, device) disconnectAudio(this@AirPodsService, device)
} }
if (inEarData.contains(false) && newInEarData == listOf(
true,
true
)
) {
Log.d("AirPods Parser", "User put in both AirPods from just one.")
MediaController.userPlayedTheMedia = false
}
if (newInEarData.contains(false) && inEarData == listOf(
true,
true
)
) {
Log.d("AirPods Parser", "User took one of two out.")
MediaController.userPlayedTheMedia = false
}
if (newInEarData.sorted() == inEarData.sorted()) {
return
}
inEarData = newInEarData inEarData = newInEarData
if (inEar == true) { if (inEar == true) {
if (!justEnabledA2dp) { if (!justEnabledA2dp) {
justEnabledA2dp = false justEnabledA2dp = false
// if (audioManager.activePlaybackConfigurations.any { it.audioDeviceInfo?.address == device.address }) {
MediaController.sendPlay() MediaController.sendPlay()
MediaController.iPausedTheMedia = false
// }
} }
} else { } else {
MediaController.sendPause() // if (audioManager.activePlaybackConfigurations.any { it.audioDeviceInfo?.address == device.address }) {
MediaController.sendPause()
// }
} }
} }
} }

View File

@@ -20,21 +20,43 @@
package me.kavishdevar.aln.utils package me.kavishdevar.aln.utils
import android.media.AudioManager import android.media.AudioManager
import android.media.AudioPlaybackConfiguration
import android.os.Handler
import android.os.Looper
import android.util.Log import android.util.Log
import android.view.KeyEvent import android.view.KeyEvent
object MediaController { object MediaController {
private var initialVolume: Int? = null // Nullable to track the unset state private var initialVolume: Int? = null
private lateinit var audioManager: AudioManager // Declare AudioManager private lateinit var audioManager: AudioManager
var iPausedTheMedia = false
var userPlayedTheMedia = false
// Initialize the singleton with the AudioManager instance
fun initialize(audioManager: AudioManager) { fun initialize(audioManager: AudioManager) {
this.audioManager = audioManager this.audioManager = audioManager
audioManager.registerAudioPlaybackCallback(cb, null)
}
val cb = object : AudioManager.AudioPlaybackCallback() {
override fun onPlaybackConfigChanged(configs: MutableList<AudioPlaybackConfiguration>?) {
super.onPlaybackConfigChanged(configs)
Log.d("MediaController", "Playback config changed, iPausedTheMedia: $iPausedTheMedia")
if (configs != null && !iPausedTheMedia) {
Log.d("MediaController", "Seems like the user changed the state of media themselves, now I won't `play` until the ear detection pauses it.")
Handler(Looper.getMainLooper()).postDelayed({
iPausedTheMedia = !audioManager.isMusicActive
userPlayedTheMedia = audioManager.isMusicActive
}, 7) // i have no idea why, but android sends a pause event a hundred times after the user does something.
}
}
} }
@Synchronized @Synchronized
fun sendPause() { fun sendPause() {
if (audioManager.isMusicActive) { Log.d("MediaController", "Sending pause with iPausedTheMedia: $iPausedTheMedia, userPlayedTheMedia: $userPlayedTheMedia")
if (audioManager.isMusicActive && !userPlayedTheMedia) {
iPausedTheMedia = true
userPlayedTheMedia = false
audioManager.dispatchMediaKeyEvent( audioManager.dispatchMediaKeyEvent(
KeyEvent( KeyEvent(
KeyEvent.ACTION_DOWN, KeyEvent.ACTION_DOWN,
@@ -52,7 +74,10 @@ object MediaController {
@Synchronized @Synchronized
fun sendPlay() { fun sendPlay() {
if (!audioManager.isMusicActive) { Log.d("MediaController", "Sending play with iPausedTheMedia: $iPausedTheMedia")
if (iPausedTheMedia) {
Log.d("MediaController", "Sending play and setting userPlayedTheMedia to false")
userPlayedTheMedia = false
audioManager.dispatchMediaKeyEvent( audioManager.dispatchMediaKeyEvent(
KeyEvent( KeyEvent(
KeyEvent.ACTION_DOWN, KeyEvent.ACTION_DOWN,
@@ -76,8 +101,7 @@ object MediaController {
Log.d("MediaController", "Initial Volume Set: $initialVolume") Log.d("MediaController", "Initial Volume Set: $initialVolume")
audioManager.setStreamVolume( audioManager.setStreamVolume(
AudioManager.STREAM_MUSIC, AudioManager.STREAM_MUSIC,
audioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC) * 1 / 12, // Set to a lower volume when speaking starts audioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC) * 1 / 12, 0
0
) )
} }
Log.d("MediaController", "Initial Volume: $initialVolume") Log.d("MediaController", "Initial Volume: $initialVolume")
@@ -91,4 +115,5 @@ object MediaController {
initialVolume = null // Reset to null after restoring the volume initialVolume = null // Reset to null after restoring the volume
} }
} }
} }

View File

@@ -1,6 +1,6 @@
[versions] [versions]
accompanistPermissions = "0.36.0" accompanistPermissions = "0.36.0"
agp = "8.7.2" agp = "8.7.3"
hiddenapibypass = "4.3" hiddenapibypass = "4.3"
kotlin = "2.0.0" kotlin = "2.0.0"
coreKtx = "1.15.0" coreKtx = "1.15.0"

View File

@@ -1,6 +1,6 @@
#Mon Oct 07 22:30:36 IST 2024 #Mon Oct 07 22:30:36 IST 2024
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-bin.zip distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-bin.zip
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists