198 lines
6.1 KiB
Kotlin
198 lines
6.1 KiB
Kotlin
package com.yzx.kiosk.audio
|
|
|
|
import android.content.Context
|
|
import android.net.Uri
|
|
import androidx.media3.common.MediaItem
|
|
import androidx.media3.common.Player
|
|
import androidx.media3.exoplayer.ExoPlayer
|
|
import com.yzx.kiosk.utils.LogUtils
|
|
import kotlinx.coroutines.flow.MutableStateFlow
|
|
import kotlinx.coroutines.flow.StateFlow
|
|
import kotlinx.coroutines.flow.asStateFlow
|
|
import javax.inject.Inject
|
|
import javax.inject.Singleton
|
|
|
|
/**
|
|
* 音频播放服务
|
|
* 用于播放在线音频,支持切换音频时及时播放新的音频
|
|
*/
|
|
@Singleton
|
|
class AudioPlayService @Inject constructor(
|
|
private val context: Context
|
|
) {
|
|
private var exoPlayer: ExoPlayer? = null
|
|
private var currentAudioUrl: String? = null
|
|
|
|
// 播放状态
|
|
private val _isPlaying = MutableStateFlow(false)
|
|
val isPlaying: StateFlow<Boolean> = _isPlaying.asStateFlow()
|
|
|
|
// 当前播放的音频URL
|
|
private val _currentUrl = MutableStateFlow<String?>(null)
|
|
val currentUrl: StateFlow<String?> = _currentUrl.asStateFlow()
|
|
|
|
companion object {
|
|
private const val TAG = "AudioPlayService"
|
|
}
|
|
|
|
init {
|
|
initializePlayer()
|
|
}
|
|
|
|
/**
|
|
* 初始化播放器
|
|
*/
|
|
private fun initializePlayer() {
|
|
if (exoPlayer == null) {
|
|
exoPlayer = ExoPlayer.Builder(context).build().apply {
|
|
repeatMode = Player.REPEAT_MODE_OFF // 默认单次播放,不循环
|
|
addListener(object : Player.Listener {
|
|
override fun onPlaybackStateChanged(playbackState: Int) {
|
|
when (playbackState) {
|
|
Player.STATE_READY -> {
|
|
LogUtils.d(TAG, "音频准备就绪")
|
|
}
|
|
Player.STATE_ENDED -> {
|
|
LogUtils.d(TAG, "音频播放结束")
|
|
_isPlaying.value = false
|
|
}
|
|
Player.STATE_BUFFERING -> {
|
|
LogUtils.d(TAG, "音频缓冲中")
|
|
}
|
|
Player.STATE_IDLE -> {
|
|
LogUtils.d(TAG, "音频空闲")
|
|
}
|
|
}
|
|
}
|
|
|
|
override fun onIsPlayingChanged(isPlaying: Boolean) {
|
|
_isPlaying.value = isPlaying
|
|
LogUtils.d(TAG, "播放状态变化: $isPlaying")
|
|
}
|
|
|
|
override fun onPlayerError(error: androidx.media3.common.PlaybackException) {
|
|
LogUtils.e(TAG, "音频播放错误: ${error.message}")
|
|
_isPlaying.value = false
|
|
}
|
|
})
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 播放音频
|
|
* @param audioUrl 音频URL
|
|
* @param forceRestart 是否强制重新开始(即使URL相同)
|
|
*/
|
|
fun play(audioUrl: String?, forceRestart: Boolean = false) {
|
|
if (audioUrl.isNullOrEmpty()) {
|
|
LogUtils.i(TAG, "音频URL为空,停止播放")
|
|
stop()
|
|
return
|
|
}
|
|
|
|
val player = exoPlayer ?: run {
|
|
initializePlayer()
|
|
exoPlayer
|
|
} ?: return
|
|
|
|
// 如果URL相同且不强制重启,则继续播放或恢复播放
|
|
if (audioUrl == currentAudioUrl && !forceRestart) {
|
|
if (!player.isPlaying) {
|
|
player.play()
|
|
LogUtils.d(TAG, "恢复播放音频: $audioUrl")
|
|
} else {
|
|
LogUtils.d(TAG, "音频已在播放: $audioUrl")
|
|
}
|
|
return
|
|
}
|
|
|
|
// URL不同或强制重启,切换音频
|
|
LogUtils.d(TAG, "切换音频: $currentAudioUrl -> $audioUrl")
|
|
|
|
try {
|
|
// 停止当前播放
|
|
if (player.isPlaying) {
|
|
player.stop()
|
|
}
|
|
|
|
// 设置新的音频
|
|
val mediaItem = MediaItem.fromUri(Uri.parse(audioUrl))
|
|
player.setMediaItem(mediaItem)
|
|
player.prepare()
|
|
|
|
// 开始播放
|
|
player.play()
|
|
|
|
// 更新当前URL
|
|
currentAudioUrl = audioUrl
|
|
_currentUrl.value = audioUrl
|
|
|
|
LogUtils.d(TAG, "开始播放音频: $audioUrl")
|
|
} catch (e: Exception) {
|
|
LogUtils.e(TAG, "播放音频失败: ${e.message}")
|
|
_isPlaying.value = false
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 暂停播放
|
|
*/
|
|
fun pause() {
|
|
exoPlayer?.pause()
|
|
LogUtils.d(TAG, "暂停播放")
|
|
}
|
|
|
|
/**
|
|
* 恢复播放
|
|
*/
|
|
fun resume() {
|
|
exoPlayer?.play()
|
|
LogUtils.d(TAG, "恢复播放")
|
|
}
|
|
|
|
/**
|
|
* 停止播放
|
|
*/
|
|
fun stop() {
|
|
exoPlayer?.stop()
|
|
currentAudioUrl = null
|
|
_currentUrl.value = null
|
|
_isPlaying.value = false
|
|
LogUtils.d(TAG, "停止播放")
|
|
}
|
|
|
|
/**
|
|
* 释放播放器资源
|
|
*/
|
|
fun release() {
|
|
exoPlayer?.release()
|
|
exoPlayer = null
|
|
currentAudioUrl = null
|
|
_currentUrl.value = null
|
|
_isPlaying.value = false
|
|
LogUtils.d(TAG, "释放播放器资源")
|
|
}
|
|
|
|
/**
|
|
* 设置音量
|
|
* @param volume 音量值,范围 0.0f - 1.0f
|
|
*/
|
|
fun setVolume(volume: Float) {
|
|
exoPlayer?.volume = volume.coerceIn(0f, 1f)
|
|
}
|
|
|
|
/**
|
|
* 设置循环播放模式
|
|
* @param repeatMode 循环模式:
|
|
* - Player.REPEAT_MODE_OFF: 不循环(单次播放)
|
|
* - Player.REPEAT_MODE_ONE: 循环播放当前音频
|
|
* - Player.REPEAT_MODE_ALL: 循环播放播放列表中的所有音频
|
|
*/
|
|
fun setRepeatMode(repeatMode: Int) {
|
|
exoPlayer?.repeatMode = repeatMode
|
|
LogUtils.d(TAG, "设置循环模式: $repeatMode")
|
|
}
|
|
}
|
|
|