You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android Media3 MediaSessionService如何指定HLS流源并传URL与Token

Android Media3 MediaSessionService 传递HLS参数与切换源方案

问题描述

在Android Media3的MediaSessionService中,只能在服务内为ExoPlayer配置HLS媒体源,无法直接在Activity/Composable的MediaController中完成设置。需解决两个核心问题:

  1. 如何向PlaybackService传递HLS流URL和Authorization Token,以正确初始化HLSMediaSource?
  2. 后续如何通过MediaController切换播放不同的HLS源?

一、向服务传递URL和Token的实现方案

1. 启动Intent传递(首次初始化场景)

在Composable/Activity中启动服务时,将URL和Token放入Intent的Extra字段,服务在onStartCommand中读取并初始化播放源。

修改后的Composable代码:

val context = LocalContext.current
// 启动服务并传递HLS参数
val startHlsPlayback = { url: String, token: String ->
    val intent = Intent(context, PlaybackService::class.java).apply {
        putExtra("HLS_STREAM_URL", url)
        putExtra("AUTHORIZATION_TOKEN", token)
    }
    ContextCompat.startForegroundService(context, intent)
}

修改后的PlaybackService核心代码:

class PlaybackService : MediaSessionService() {
    private var mediaSession: MediaSession? = null
    private lateinit var player: ExoPlayer

    override fun onCreate() {
        super.onCreate()
        // 先初始化基础Player实例
        player = ExoPlayer.Builder(this).build()
        mediaSession = MediaSession.Builder(this, player).build()
        // 注意:需调用startForeground()并设置通知,避免服务被系统回收
    }

    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
        intent?.let {
            val hlsUrl = it.getStringExtra("HLS_STREAM_URL")
            val authToken = it.getStringExtra("AUTHORIZATION_TOKEN")
            if (!hlsUrl.isNullOrEmpty() && !authToken.isNullOrEmpty()) {
                setupHlsPlayback(hlsUrl, authToken)
                player.playWhenReady = true
            }
        }
        return START_STICKY
    }

    // 封装HLS源初始化逻辑
    private fun setupHlsPlayback(url: String, token: String) {
        // 创建带Token的Http数据源工厂
        val authDataSourceFactory = DataSource.Factory {
            DefaultHttpDataSource.Factory().createDataSource().apply {
                setRequestProperty("Authorization", token)
            }
        }
        // 创建HLS媒体源
        val hlsMediaSource = HlsMediaSource.Factory(authDataSourceFactory)
            .createMediaSource(MediaItem.fromUri(url))
        // 替换当前播放源并准备播放
        player.setMediaSource(hlsMediaSource)
        player.prepare()
    }

    // 原有生命周期方法...
    override fun onGetSession(controllerInfo: MediaSession.ControllerInfo): MediaSession? {
        return mediaSession
    }
}

2. 自定义命令传递(动态切换场景)

如果需要在服务运行中动态更新播放源,可通过MediaController发送自定义命令,服务端接收后处理参数并切换源。

Composable中发送自定义命令:

val sessionToken = SessionToken(context, ComponentName(context, PlaybackService::class.java))
val controllerFuture = MediaController.Builder(context, sessionToken).buildAsync()
val mediaController = remember { mutableStateOf<MediaController?>(null) }

LaunchedEffect(controllerFuture) {
    controllerFuture.addListener({
        mediaController.value = controllerFuture.get()
    }, ContextCompat.getMainExecutor(context))
}

// 切换HLS流的方法
val switchHlsStream = { newUrl: String, newToken: String ->
    mediaController.value?.sendCustomCommand(
        SessionCommand(
            "com.your.app.COMMAND_SWITCH_HLS",
            Bundle().apply {
                putString("NEW_HLS_URL", newUrl)
                putString("NEW_AUTH_TOKEN", newToken)
            }
        ),
        null,
        ContextCompat.getMainExecutor(context)
    )
}

PlaybackService中注册命令回调:

override fun onCreate() {
    super.onCreate()
    player = ExoPlayer.Builder(this).build()
    mediaSession = MediaSession.Builder(this, player)
        .setCustomCommandReceiver { _, command, executor, callback ->
            when (command.customAction) {
                "com.your.app.COMMAND_SWITCH_HLS" -> {
                    val newUrl = command.extras.getString("NEW_HLS_URL")
                    val newToken = command.extras.getString("NEW_AUTH_TOKEN")
                    if (!newUrl.isNullOrEmpty() && !newToken.isNullOrEmpty()) {
                        executor.execute {
                            setupHlsPlayback(newUrl, newToken)
                            callback.onResult(SessionResult(SessionResult.RESULT_SUCCESS))
                        }
                    } else {
                        callback.onResult(SessionResult(SessionResult.RESULT_ERROR_BAD_VALUE))
                    }
                }
            }
        }
        .build()
}

二、切换不同HLS源的核心逻辑

不管是首次初始化还是后续切换,核心都是调用player.setMediaSource()替换当前媒体源,再调用player.prepare()完成准备工作:

  • 首次启动:通过Intent传递参数,触发setupHlsPlayback初始化播放
  • 动态切换:通过自定义命令传递新参数,重新调用setupHlsPlayback替换源

注意事项

  • 必须将服务设置为前台服务(调用startForeground()并配置通知),否则系统可能在后台回收服务
  • 需添加空值判断,避免URL或Token为空导致播放异常
  • 若需播放多段流,可使用player.addMediaItem()或player.setMediaItems()批量添加媒体项

内容的提问来源于stack exchange,提问作者rysv

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 13:43:19