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

如何在ExoPlayer DAI中动态添加/移除自定义请求头?

实现ExoPlayer DAI动态请求头切换方案

针对你用ExoPlayer androidx v1.0.1实现DAI时的请求头动态切换需求,核心思路是放弃全局固定请求头,通过自定义DataSourceFactory配合广告/播放状态监听,动态控制请求头的添加与移除,具体实现步骤如下:

1. 自定义动态请求头的HttpDataSourceFactory

不要全局预设自定义头,而是在创建DataSource实例时,根据当前播放状态(内容/广告)决定是否添加自定义头:

class DynamicHeaderHttpDataSourceFactory(
    private val context: Context,
    private val customHeaders: Map<String, String>,
    private var isPlayingAd: Boolean = false
) : DefaultHttpDataSource.Factory() {

    init {
        setAllowCrossProtocolRedirects(true)
        setUserAgent(context.getString(R.string.player_name))
        setTransferListener(
            DefaultBandwidthMeter.Builder(context)
                .setResetOnNetworkTypeChange(false)
                .build()
        )
    }

    // 对外暴露状态切换方法
    fun updateAdState(isPlayingAd: Boolean) {
        this.isPlayingAd = isPlayingAd
    }

    override fun createDataSource(): DefaultHttpDataSource {
        val dataSource = super.createDataSource()
        // 每次创建数据源时清空原有请求头,避免残留
        dataSource.defaultRequestProperties.clear()
        
        if (!isPlayingAd) {
            // 播放直播内容时添加自定义头
            customHeaders.forEach { (key, value) ->
                dataSource.defaultRequestProperties.set(key, value)
            }
        }
        // 播放广告时仅保留UserAgent等基础配置,不添加自定义头
        return dataSource
    }
}

2. 监听广告状态切换,同步请求头配置

通过DAI的ImaAdsLoader监听广告的加载、播放、结束事件,实时切换请求头状态:

// 初始化DAI广告加载器
val adsLoader = ImaAdsLoader.Builder(context).build()
adsLoader.setAdEventListener(object : ImaAdsLoader.AdEventListener {
    override fun onAdPlaybackStateChanged(adPlaybackState: AdPlaybackState) {
        // 判断当前是否处于广告播放状态
        val isAdActive = adPlaybackState.adCount > 0 && adPlaybackState.currentAdIndex != C.INDEX_UNSET
        dynamicHeaderFactory.updateAdState(isAdActive)
    }

    override fun onAdFailedToLoad(adError: AdError) {
        // 广告加载失败时,切回内容请求头状态
        dynamicHeaderFactory.updateAdState(false)
    }
})

3. 监听Player播放状态,确保状态同步

配合Player的监听事件,在媒体切换、播放状态变化时修正请求头状态,避免异常:

player.addListener(object : Player.Listener {
    override fun onMediaItemTransition(mediaItem: MediaItem?, reason: Int) {
        // 切换到直播内容时,强制切回内容请求头状态
        if (mediaItem?.mediaId == YOUR_LIVE_CONTENT_MEDIA_ID) {
            dynamicHeaderFactory.updateAdState(false)
        }
    }

    override fun onPlaybackStateChanged(playbackState: Int) {
        // 播放就绪且未在播放广告时,确保请求头为内容模式
        if (playbackState == Player.STATE_READY && !player.isPlayingAd) {
            dynamicHeaderFactory.updateAdState(false)
        }
    }
})

4. 预取场景处理

预取直播内容时,需要强制切换到内容请求头状态,预取完成后恢复当前播放状态:

// 触发预取操作前
val currentAdState = player.isPlayingAd
dynamicHeaderFactory.updateAdState(false)

// 执行预取逻辑(比如用ExoPlayer的预加载API或自定义缓存逻辑)
// ...

// 预取完成后恢复原有状态
dynamicHeaderFactory.updateAdState(currentAdState)

5. 替换原有全局DataSourceFactory

将自定义的DynamicHeaderHttpDataSourceFactory传入MediaSourceFactory,替换原来的全局配置:

// 初始化动态请求头工厂
val dynamicHeaderFactory = DynamicHeaderHttpDataSourceFactory(
    context,
    mCustomHeaders
)

// 配置MediaSourceFactory,关联广告加载器
val mediaSourceFactory = DefaultMediaSourceFactory(dynamicHeaderFactory)
    .setAdsLoaderProvider { adsLoader }
    .setAdViewProvider(yourAdViewProvider)

// 初始化Player
player = ExoPlayer.Builder(context)
    .setMediaSourceFactory(mediaSourceFactory)
    .build()

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 10:42:25