Skip to content

Commit

Permalink
Duck the system music while playing notification sound
Browse files Browse the repository at this point in the history
  • Loading branch information
hufman committed Sep 23, 2024
1 parent ae37e4a commit b4dda91
Show file tree
Hide file tree
Showing 3 changed files with 44 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -381,12 +381,14 @@ class PhoneNotifications(val iDriveConnectionStatus: IDriveConnectionStatus, val
}

val played = if (notificationSettings.shouldPlaySound()) {
audioPlayer.requestDuck()
audioPlayer.playRingtone(sbn.soundUri)
} else false

if (notificationSettings.shouldReadoutNotificationPopup(passengerSeated) && played) {
if (played) {
Thread.sleep(3000)
}
audioPlayer.releaseDuck()
readoutInteractions.triggerPopupReadout(sbn)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ package me.hufman.androidautoidrive.notifications

import android.content.Context
import android.media.AudioAttributes
import android.media.AudioFocusRequest
import android.media.AudioManager
import android.media.RingtoneManager
import android.net.Uri
import android.os.Build
Expand All @@ -18,6 +20,9 @@ class AudioPlayer(val context: Context) {
val timeSinceLastPlayed: Long
get() = SystemClock.elapsedRealtime() - timeLastPlayed

private val audioManager = context.getSystemService(AudioManager::class.java)
private var duckRequest: AudioFocusRequest? = null

fun playRingtone(uri: Uri?): Boolean {
if (timeSinceLastPlayed < PLAYBACK_DEBOUNCE) return false
uri ?: return false
Expand All @@ -38,4 +43,36 @@ class AudioPlayer(val context: Context) {
}
return true
}

fun requestDuck() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val duckRequest = AudioFocusRequest.Builder(AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK).run {
setAudioAttributes(AudioAttributes.Builder().run {
setUsage(AudioAttributes.USAGE_MEDIA)
setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
build()
})
setAcceptsDelayedFocusGain(false)
build()
}
val success = audioManager.requestAudioFocus(duckRequest)
if (success == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
// Log.i(TAG, "Successfully ducked audio $success")
Thread.sleep(500) // wait for fadeout before playing notification sound
} else {
Log.i(TAG, "Error while ducking audio ($success)")
}
this.duckRequest = duckRequest
} else {
// Log.i(TAG, "Skipping audio duck on old phone")
}
}

fun releaseDuck() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val duckRequest = this.duckRequest ?: return
audioManager.abandonAudioFocusRequest(duckRequest)
}
this.duckRequest = null
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -483,6 +483,8 @@ class NotificationAppTest {

// plays the ringtone when showing statusbar icon
verify(audioPlayer).playRingtone(any())
verify(audioPlayer).requestDuck()
verify(audioPlayer).releaseDuck()

// reads out the new notification
verify(readoutController).readout(listOf("Chat: ", "Title: Text"))
Expand Down Expand Up @@ -513,6 +515,8 @@ class NotificationAppTest {

// plays the ringtone with the popup
verify(audioPlayer).playRingtone(any())
verify(audioPlayer).requestDuck()
verify(audioPlayer).releaseDuck()

// reads out the popup
verify(readoutController).readout(listOf("Chat: ", "Title: Text"))
Expand Down

0 comments on commit b4dda91

Please sign in to comment.