playback: add audioeffect integration [#211]
Add support for external AudioEffect implementers, like Wavelet. Doing this involves doing a weird broadcast dance with AudioEffect Intents at special points to indicate a valid audio session that can be manipulated. Still has some issues, such as a null name showing up in wavelet. As far as I am aware, this is the best possible system I can do, and allows me to delegate an equalizer implementation to other apps instead of making my own. Resolves #211.
This commit is contained in:
parent
deffe065d5
commit
ce2e950a9b
2 changed files with 32 additions and 0 deletions
|
@ -3,6 +3,7 @@
|
||||||
## dev
|
## dev
|
||||||
|
|
||||||
#### What's New
|
#### What's New
|
||||||
|
- Added basic equalizer support in external apps like Wavelet
|
||||||
- Detail UI now displays the type of item shown (ex. the release type)
|
- Detail UI now displays the type of item shown (ex. the release type)
|
||||||
|
|
||||||
#### What's Fixed
|
#### What's Fixed
|
||||||
|
|
|
@ -23,6 +23,7 @@ import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.content.IntentFilter
|
import android.content.IntentFilter
|
||||||
import android.media.AudioManager
|
import android.media.AudioManager
|
||||||
|
import android.media.audiofx.AudioEffect
|
||||||
import android.os.IBinder
|
import android.os.IBinder
|
||||||
import com.google.android.exoplayer2.C
|
import com.google.android.exoplayer2.C
|
||||||
import com.google.android.exoplayer2.ExoPlayer
|
import com.google.android.exoplayer2.ExoPlayer
|
||||||
|
@ -93,6 +94,7 @@ class PlaybackService :
|
||||||
// State
|
// State
|
||||||
private lateinit var foregroundManager: ForegroundManager
|
private lateinit var foregroundManager: ForegroundManager
|
||||||
private var hasPlayed = false
|
private var hasPlayed = false
|
||||||
|
private var openAudioEffectSession = false
|
||||||
|
|
||||||
// Coroutines
|
// Coroutines
|
||||||
private val serviceJob = Job()
|
private val serviceJob = Job()
|
||||||
|
@ -175,7 +177,13 @@ class PlaybackService :
|
||||||
|
|
||||||
widgetComponent.release()
|
widgetComponent.release()
|
||||||
mediaSessionComponent.release()
|
mediaSessionComponent.release()
|
||||||
|
|
||||||
player.release()
|
player.release()
|
||||||
|
if (openAudioEffectSession) {
|
||||||
|
// Make sure to close the audio session when we release the player.
|
||||||
|
broadcastAudioEffectAction(AudioEffect.ACTION_CLOSE_AUDIO_EFFECT_CONTROL_SESSION)
|
||||||
|
openAudioEffectSession = false
|
||||||
|
}
|
||||||
|
|
||||||
logD("Service destroyed")
|
logD("Service destroyed")
|
||||||
}
|
}
|
||||||
|
@ -197,6 +205,7 @@ class PlaybackService :
|
||||||
override fun onPlaybackStateChanged(state: Int) {
|
override fun onPlaybackStateChanged(state: Int) {
|
||||||
when (state) {
|
when (state) {
|
||||||
Player.STATE_ENDED -> {
|
Player.STATE_ENDED -> {
|
||||||
|
logD("State ended")
|
||||||
if (playbackManager.repeatMode == RepeatMode.TRACK) {
|
if (playbackManager.repeatMode == RepeatMode.TRACK) {
|
||||||
playbackManager.rewind()
|
playbackManager.rewind()
|
||||||
if (settings.pauseOnRepeat) {
|
if (settings.pauseOnRepeat) {
|
||||||
|
@ -250,6 +259,12 @@ class PlaybackService :
|
||||||
// Stop the foreground state if there's nothing to play.
|
// Stop the foreground state if there's nothing to play.
|
||||||
logD("Nothing playing, stopping playback")
|
logD("Nothing playing, stopping playback")
|
||||||
player.stop()
|
player.stop()
|
||||||
|
if (openAudioEffectSession) {
|
||||||
|
// Make sure to close the audio session when we stop playback.
|
||||||
|
broadcastAudioEffectAction(AudioEffect.ACTION_CLOSE_AUDIO_EFFECT_CONTROL_SESSION)
|
||||||
|
openAudioEffectSession = false
|
||||||
|
}
|
||||||
|
|
||||||
stopAndSave()
|
stopAndSave()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -257,6 +272,14 @@ class PlaybackService :
|
||||||
logD("Loading ${song.rawName}")
|
logD("Loading ${song.rawName}")
|
||||||
player.setMediaItem(MediaItem.fromUri(song.uri))
|
player.setMediaItem(MediaItem.fromUri(song.uri))
|
||||||
player.prepare()
|
player.prepare()
|
||||||
|
|
||||||
|
if (!openAudioEffectSession) {
|
||||||
|
// Wavelet does not like it if you start an audio effect session without having
|
||||||
|
// something within your player buffer. Make sure we only start one when we load
|
||||||
|
// a song.
|
||||||
|
broadcastAudioEffectAction(AudioEffect.ACTION_OPEN_AUDIO_EFFECT_CONTROL_SESSION)
|
||||||
|
openAudioEffectSession = true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun seekTo(positionMs: Long) {
|
override fun seekTo(positionMs: Long) {
|
||||||
|
@ -330,6 +353,14 @@ class PlaybackService :
|
||||||
.build()
|
.build()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun broadcastAudioEffectAction(event: String) {
|
||||||
|
sendBroadcast(
|
||||||
|
Intent(event)
|
||||||
|
.putExtra(AudioEffect.EXTRA_PACKAGE_NAME, packageName)
|
||||||
|
.putExtra(AudioEffect.EXTRA_AUDIO_SESSION, player.audioSessionId)
|
||||||
|
.putExtra(AudioEffect.EXTRA_CONTENT_TYPE, AudioEffect.CONTENT_TYPE_MUSIC))
|
||||||
|
}
|
||||||
|
|
||||||
/** Stop the foreground state and hide the notification */
|
/** Stop the foreground state and hide the notification */
|
||||||
private fun stopAndSave() {
|
private fun stopAndSave() {
|
||||||
if (foregroundManager.tryStopForeground()) {
|
if (foregroundManager.tryStopForeground()) {
|
||||||
|
|
Loading…
Reference in a new issue