赞
踩
音视频应用在实现音视频功能的同时,需要接入媒体会话即AVSession Kit,下文将提供一些典型的接入AVSession的展示和控制场景,方便开发者根据场景进行适配。
对于不同的场景,将会在系统的播控中心看到不同的UI呈现。同时,在不同的场景下,应用的接入处理也需要遵循不同的规范约束。
AVSession会对后台的音频播放、VOIP通话做约束,所以通常来说,长音频应用、听书类应用、长视频应用、VOIP类应用等都需要接入AVSession。当应用在没有创建接入AVSession的情况下进行了上述业务,那么系统会在检测到应用后台时,停止对应的音频播放,静音通话声音,以达到约束应用行为的目的。这种约束,应用上架前在本地就可以验证。
对于其他使用到音频播放的应用,比如游戏,直播等场景,接入AVSession不是必选项,只是可选,取决于应用是否有后台播放的使用诉求。若应用需要后台播放,那么接入AVSession仍然是必须的,否则业务的正常功能会受到限制。
当应用需要实现后台播放等功能时,需要使用[BackgroundTasks Kit](后台任务管理)的能力,申请对应的长时任务,避免进入挂起(Suspend)状态。
应用接入AVSession流程分为如下几个步骤:
AVSession在构造方法中支持不同的类型参数,由 [AVSessionType] 定义,不同的类型代表了不同场景的控制能力,对于播控中心来说,会展示不同的控制模版。
使用代码示例:
import { avSession as AVSessionManager } from '@kit.AVSessionKit';
// 开始创建并激活媒体会话
// 创建session
let context: Context = getContext(this);
async function createSession() {
let type: AVSessionManager.AVSessionType = 'audio';
let session = await AVSessionManager.createAVSession(context,'SESSION_NAME', type);
// 激活接口要在元数据、控制命令注册完成之后再执行
await session.activate();
console.info(`session create done : sessionId : ${session.sessionId}`);
}
当应用需要实现后台播放等功能时,需要使用[BackgroundTasks Kit](后台任务管理)的能力,申请对应的长时任务,避免进入挂起(Suspend)状态。
对媒体类播放来说,需要申请[AUDIO_PLAYBACK BackgroundMode]的长时任务。
应用可以通过setAVMetadata把会话的一些元数据信息设置给系统,从而在播控中心界面进行展示,包括不限制:当前媒体的ID(assetId),上一首媒体的ID(previousAssetId),下一首媒体的ID(nextAssetId),标题(title),专辑作者(author),专辑名称(album),词作者(writer),媒体时长(duration)等。
import { avSession as AVSessionManager } from '@kit.AVSessionKit'; import { BusinessError } from '@kit.BasicServicesKit'; let context: Context = getContext(this); async function setSessionInfo() { // 假设已经创建了一个session,如何创建session可以参考之前的案例 let session = await AVSessionManager.createAVSession(context, 'SESSION_NAME', 'audio'); // 设置必要的媒体信息 let metadata: AVSessionManager.AVMetadata = { assetId: '0', // 由应用指定,用于标识应用媒体库里的媒体 title: 'TITLE', mediaImage: 'IMAGE', artist: 'ARTIST', }; session.setAVMetadata(metadata).then(() => { console.info(`SetAVMetadata successfully`); }).catch((err: BusinessError) => { console.error(`Failed to set AVMetadata. Code: ${err.code}, message: ${err.message}`); }); }
对于长音频来说,播控中心提供了歌词的展示页面,对于应用来说,接入也比较简单,只需要把歌词内容设置给系统。播控中心会解析歌词内容,并根据播放进度进行同步的刷新。
import { avSession as AVSessionManager } from '@kit.AVSessionKit'; import { BusinessError } from '@kit.BasicServicesKit'; let context: Context = getContext(this); async function setListener() { // 假设已经创建了一个session,如何创建session可以参考之前的案例 let type: AVSessionManager.AVSessionType = 'audio'; let session = await AVSessionManager.createAVSession(context, 'SESSION_NAME', type); // 把歌词信息设置给AVSession let metadata: AVSessionManager.AVMetadata = { assetId: '0', title: 'TITLE', mediaImage: 'IMAGE', lyric: 'http://www.test.lyric', }; session.setAVMetadata(metadata).then(() => { console.info(`SetAVMetadata successfully`); }).catch((err: BusinessError) => { console.error(`Failed to set AVMetadata. Code: ${err.code}, message: ${err.message}`); }); }
历史歌单(历史播放列表)的接入,需要应用只需要先注册支持后台启动模式(executeMode为background)的播放歌单(PlayMusicList)意图,再实现相应的意图调用接口即可的意图注册及意图调用。
设置歌单:
音乐类应用在播放内容时,可以通过[setAVMetadata]接口设置当前播放内容的歌单信息,歌单信息由下面几个字段组成:
系统媒体信息根据应用上报实时刷新,若应用接入歌单,则确保一直上报歌单数据。
歌单播放:
当应用向系统设置歌单后,用户在播控中心界面可以对歌单进行播放控制,系统会将歌单的唯一标识id传回应用,应用会在意图调用接口中获取到歌单的id,如后台模式需要实现方法[onExecuteInUIAbilityBackgroundMode],歌单会包装在参数param中传递回应用。
歌单启动播放后,应用仍然通过[AVSessionController]来接收控制命令。
需要注意的是:
import { avSession as AVSessionManager } from '@kit.AVSessionKit'; import { BusinessError } from '@kit.BasicServicesKit'; let context: Context = getContext(this); async function setListener() { // 假设已经创建了一个session,如何创建session可以参考之前的案例 let type: AVSessionManager.AVSessionType = 'audio'; let session = await AVSessionManager.createAVSession(context, 'SESSION_NAME', type); // 把歌单信息设置给AVSession let metadata: AVSessionManager.AVMetadata = { // 下面内容均由应用指定 assetId: '0', avQueueName: 'myQueue', avQueueId: 'myQueue123', avQueueImage: "PIXELMAP_OBJECT", }; session.setAVMetadata(metadata).then(() => { console.info(`SetAVMetadata successfully`); }).catch((err: BusinessError) => { console.error(`Failed to set AVMetadata. Code: ${err.code}, message: ${err.message}`); }); // 上报播放状态,参考播放状态 }
对于长音频,播控中心提供了媒体资源金标的展示,媒体资源金标又可称为应用媒体音频音源的标识,目前暂时只支持展示AudioVivid标识。
对于应用来说,接入只需要在AVMetadata中通知系统,当前播放音频的音源标识,播控就会同步展示。
import { avSession as AVSessionManager } from '@kit.AVSessionKit'; import { BusinessError } from '@kit.BasicServicesKit'; let context: Context = getContext(this); async function setListener() { // 假设已经创建了一个session,如何创建session可以参考之前的案例 let type: AVSessionManager.AVSessionType = 'audio'; let session = await AVSessionManager.createAVSession(context, 'SESSION_NAME', type); // 把媒体音源信息设置给AVSession let metadata: AVSessionManager.AVMetadata = { assetId: '0', title: 'TITLE', mediaImage: 'IMAGE', // 标识该媒体音源是AudioVivid displayTags: AVSessionManager.DisplayTag.TAG_AUDIO_VIVID, }; session.setAVMetadata(metadata).then(() => { console.info(`SetAVMetadata successfully`); }).catch((err: BusinessError) => { console.error(`Failed to set AVMetadata. Code: ${err.code}, message: ${err.message}`); }); }
应用可以通过[setAVPlaybackState]。把当前的播放状态设置给系统,以在播控中心界面进行展示。
播放状态一般是在资源播放后会进行变化的内容,包括:当前媒体的播放状态(state)、播放位置(position)、播放倍速(speed)、缓冲时间(bufferedTime)、循环模式(loopMode)、是否收藏(isFavorite)、正在播放的媒体Id(activeItemId)、自定义媒体数据(extras)等。
import { avSession as AVSessionManager } from '@kit.AVSessionKit'; import { BusinessError } from '@kit.BasicServicesKit'; let context: Context = getContext(this); async function setSessionInfo() { // 假设已经创建了一个session,如何创建session可以参考之前的案例 let session = await AVSessionManager.createAVSession(context, 'SESSION_NAME', 'audio'); // 播放器逻辑··· 引发媒体信息与播放状态的变更 // 简单设置一个播放状态 - 暂停 未收藏 let playbackState: AVSessionManager.AVPlaybackState = { state:AVSessionManager.PlaybackState.PLAYBACK_STATE_PAUSE, isFavorite:false }; session.setAVPlaybackState(playbackState, (err: BusinessError) => { if (err) { console.error(`Failed to set AVPlaybackState. Code: ${err.code}, message: ${err.message}`); } else { console.info(`SetAVPlaybackState successfully`); } }); }
应用如果支持在播控中心展示进度,那么在媒体资源播放中,需要设置资源的时长、播放状态(暂停、播放)、播放位置、倍速,播控中心会使用这些信息进行进度的展示:
import { avSession as AVSessionManager } from '@kit.AVSessionKit'; import { BusinessError } from '@kit.BasicServicesKit'; let context: Context = getContext(this); async function setListener() { // 假设已经创建了一个session,如何创建session可以参考之前的案例 let type: AVSessionManager.AVSessionType = 'audio'; let session = await AVSessionManager.createAVSession(context, 'SESSION_NAME', type); // 设置媒体资源时长 let metadata: AVSessionManager.AVMetadata = { assetId: '0', title: 'TITLE', mediaImage: 'IMAGE', duration: 23000, // 资源的时长,以ms为单位 }; session.setAVMetadata(metadata).then(() => { console.info(`SetAVMetadata successfully`); }).catch((err: BusinessError) => { console.error(`Failed to set AVMetadata. Code: ${err.code}, message: ${err.message}`); }); // 设置状态: 播放状态,进度位置,播放倍速,缓存的时间 let playbackState: AVSessionManager.AVPlaybackState = { state: AVSessionManager.PlaybackState.PLAYBACK_STATE_PLAY, // 播放状态 position: { elapsedTime: 1000, // 已经播放的位置,以ms为单位 updateTime: new Date().getTime(), // 应用更新当前位置时的时间戳,以ms为单位 }, speed: 1.0, // 可选,默认是1.0,播放的倍速,按照应用内支持的speed进行设置,系统不做校验 bufferedTime: 14000, // 可选,资源缓存的时间,以ms为单位 }; session.setAVPlaybackState(playbackState, (err) => { if (err) { console.error(`Failed to set AVPlaybackState. Code: ${err.code}, message: ${err.message}`); } else { console.info(`SetAVPlaybackState successfully`); } }); }
系统的播控中心会根据应用设置的信息自行进行播放进度的计算,而不需要应用实时更新播放进度;
但是应用需要如下状态发生变化的时候,再更新AVPlaybackState,否则系统会发生计算错误:
应用在真实播放开始时,再上报进度起始position;若播放存在buffer状态,可以先上报播放状态为AVSessionManager.PlaybackState.PLAYBACK_STATE_BUFFERING,来通知系统不刷新进度。
关于进度条有一些特殊情况需要处理:
歌曲支持试听
(1)应用不需要设置完整的歌曲时长,则只需要设置歌曲的试听时长。当应用仅设置歌曲的试听时长而不是完整时长,用户在播控中心触发进度控制时,应用收到的时长也是VIP试听时长内的相对时间戳位置,而不是完整歌曲的绝对时间戳位置,应用需要重新计算歌曲从零开始的绝对时间戳进行实际响应处理。
(2)如果应用设置完整歌曲时长,但需要系统支持试听片段,也可以在播放时上报起始进度position,当收到的seek指令超过试听片段时,上报试听截止position,系统播控的进度会跟随回弹。
歌曲不支持试听
如果歌曲不支持试听,那么理论上应用内也不支持播放,这时可以把 duration 设置为 -1,以通知系统不显示实际的时长。
广告等内容的时长设置
对于有前贴广告、后贴广告的资源来说,建议这么处理:
应用接入AVSession,可以通过注册不同的控制命令来实现播控中心界面上的控制操作,即通过on接口注册不同的控制命令参数,即可实现对应的功能。
说明
创建AVSession后,请先注册应用支持的控制命令,再激活 Session
媒体资源支持的控制命令列表:
控制命令 | 功能说明 |
---|---|
play | 播放命令。 |
pause | 暂停命令。 |
stop | 停止命令。 |
playNext | 播放下一首命令。 |
playPrevious | 播放上一首命令。 |
fastForward | 快进命令。 |
rewind | 快退命令。 |
playFromAssetId | 根据某个资源id进行播放命令。 |
seek | 跳转命令。 |
setSpeed | 设置播放速率命令。 |
setLoopMode | 设置循环模式命令。 |
toggleFavorite | 设置是否收藏命令。 |
skipToQueueItem | 设置播放列表其中某项被选中播放的命令。 |
handleKeyEvent | 设置按键事件的命令。 |
commonCommand | 设置自定义控制命令。 |
通话类应用支持的控制:
控制命令 | 功能说明 |
---|---|
answer | 接听电话的命令。 |
hangUp | 通话挂断的命令。 |
toggleCallMute | 通话静音或解除静音的命令。 |
系统支持的控制命令对于不支持的控制,比如应用不支持“上一首”的命令处理,只需要使用off 接口注销对应的控制命令,系统的播控中心会相应的对该控制界面进行置灰处理,以明确告知用户此控制命令不支持。
import { avSession as AVSessionManager } from '@kit.AVSessionKit';
let context: Context = getContext(this);
async function unregisterSessionListener() {
// 假设已经创建了一个session,如何创建session可以参考之前的案例
let type: AVSessionManager.AVSessionType = 'audio';
let session = await AVSessionManager.createAVSession(context, 'SESSION_NAME', type);
// 取消指定session下的相关监听
session.off('play');
session.off('pause');
session.off('stop');
session.off('playNext');
session.off('playPrevious');
}
系统支持三种快进快退的时长,应用可以通过接口进行设置;同时注册快进快退的回调命令,以响应控制。
import { avSession as AVSessionManager } from '@kit.AVSessionKit'; import { BusinessError } from '@kit.BasicServicesKit'; let context: Context = getContext(this); async function unregisterSessionListener() { // 假设已经创建了一个session,如何创建session可以参考之前的案例 let type: AVSessionManager.AVSessionType = 'audio'; let session = await AVSessionManager.createAVSession(context, 'SESSION_NAME', type); // 设置支持的快进快退的时长设置给AVSession let metadata: AVSessionManager.AVMetadata = { assetId: '0', // 由应用指定,用于标识应用媒体库里的媒体 title: 'TITLE', mediaImage: 'IMAGE', skipIntervals: AVSessionManager.SkipIntervals.SECONDS_10, }; session.setAVMetadata(metadata).then(() => { console.info(`SetAVMetadata successfully`); }).catch((err: BusinessError) => { console.error(`Failed to set AVMetadata. Code: ${err.code}, message: ${err.message}`); }); session.on('fastForward', (time ?: number) => { console.info(`on fastForward , do fastForward task`); // do some tasks ··· }); session.on('rewind', (time ?: number) => { console.info(`on rewind , do rewind task`); // do some tasks ··· }); }
音乐类应用实现收藏功能,那么需要注册收藏的控制响应[on(‘toggleFavorite’)]。
import { avSession as AVSessionManager } from '@kit.AVSessionKit'; import { BusinessError } from '@kit.BasicServicesKit'; let context: Context = getContext(this); async function setListener() { // 假设已经创建了一个session,如何创建session可以参考之前的案例 let type: AVSessionManager.AVSessionType = 'audio'; let session = await AVSessionManager.createAVSession(context, 'SESSION_NAME', type); session.on('toggleFavorite', (assetId) => { console.info(`on toggleFavorite `); // 应用收到收藏命令,进行收藏处理 // 应用内完成或者取消收藏,把新的收藏状态设置给AVSession let playbackState: AVSessionManager.AVPlaybackState = { isFavorite:true, }; session.setAVPlaybackState(playbackState).then(() => { console.info(`SetAVPlaybackState successfully`); }).catch((err: BusinessError) => { console.info(`SetAVPlaybackState BusinessError: code: ${err.code}, message: ${err.message}`); }); }); }
针对音乐类应用,系统的播控中心界面会默认展示循环模式的控制操作,目前系统支持四种固定的循环模式控制。
播控中心支持固定的四种循环模式的切换,即: 随机播放、顺序播放、单曲循环、列表循环。应用收到循环模式切换的指令并切换后,需要向系统上报切换后的LoopMode。
若应用内支持的LoopMode不在系统固定的四个循环模式内,需要选择四个固定循环模式其一向系统上报,由应用自定。
实现参考:
import { avSession as AVSessionManager } from '@kit.AVSessionKit'; import { BusinessError } from '@kit.BasicServicesKit'; let context: Context = getContext(this); async function setListener() { // 假设已经创建了一个session,如何创建session可以参考之前的案例 let type: AVSessionManager.AVSessionType = 'audio'; let session = await AVSessionManager.createAVSession(context, 'SESSION_NAME', type); // 应用启动时/内部切换循环模式,需要把应用内的当前的循环模式设置给AVSession let playBackState: AVSessionManager.AVPlaybackState = { loopMode: AVSessionManager.LoopMode.LOOP_MODE_SINGLE, }; session.setAVPlaybackState(playBackState).then(() => { console.info(`set AVPlaybackState successfully`); }).catch((err: BusinessError) => { console.error(`Failed to set AVPlaybackState. Code: ${err.code}, message: ${err.message}`); }); // 应用注册循环模式的控制监听 session.on('setLoopMode', (mode) => { console.info(`on setLoopMode ${mode}`); // 应用收到设置循环模式的指令后,应用自定下一个模式,切换完毕后通过AVPlaybackState上报切换后的LoopMode let playBackState: AVSessionManager.AVPlaybackState = { loopMode: AVSessionManager.LoopMode.LOOP_MODE_SINGLE, }; session.setAVPlaybackState(playBackState).then(() => { console.info(`set AVPlaybackState successfully`); }).catch((err: BusinessError) => { console.error(`Failed to set AVPlaybackState. Code: ${err.code}, message: ${err.message}`); }); }); }
应用如果支持进度显示,进一步也可以支持进度控制。应用需要响应seek的控制命令,那么当用户在播控中心的界面上进行拖动操作时,应用就会收到对应的回调。参考实现:
import { avSession as AVSessionManager } from '@kit.AVSessionKit'; let context: Context = getContext(this); async function setListener() { // 假设已经创建了一个session,如何创建session可以参考之前的案例 let type: AVSessionManager.AVSessionType = 'audio'; let session = await AVSessionManager.createAVSession(context, 'SESSION_NAME', type); session.on('seek', (position: number) => { console.info(`on seek , the time is ${JSON.stringify(position)}`); // 由于应用内seek可能会触发较长的缓冲等待,可以先把状态设置为 Buffering let playbackState: AVSessionManager.AVPlaybackState = { state: AVSessionManager.PlaybackState.PLAYBACK_STATE_BUFFERING, // 缓冲状态 }; session.setAVPlaybackState(playbackState, (err) => { if (err) { console.error(`Failed to set AVPlaybackState. Code: ${err.code}, message: ${err.message}`); } else { console.info(`SetAVPlaybackState successfully`); } }); // 应用响应seek命令,使用应用内播放器完成seek实现 // 应用内更新新的位置后,也需要同步更新状态给系统 playbackState.state = AVSessionManager.PlaybackState.PLAYBACK_STATE_PLAY; // 播放状态 playbackState.position = { elapsedTime: position, // 已经播放的位置,以ms为单位 updateTime: new Date().getTime(), // 应用更新当前位置的时间戳,以ms为单位 } session.setAVPlaybackState(playbackState, (err) => { if (err) { console.error(`Failed to set AVPlaybackState. Code: ${err.code}, message: ${err.message}`); } else { console.info(`SetAVPlaybackState successfully`); } }); }); }
当前系统不直接向应用提供主动发送媒体控制通知的接口,那么当应用进入播放状态时,系统会自动发送通知,同时在通知和锁屏界面进行展示。
说明
很多开发朋友不知道需要学习那些鸿蒙技术?鸿蒙开发岗位需要掌握那些核心技术点?为此鸿蒙的开发学习必须要系统性的进行。
而网上有关鸿蒙的开发资料非常的少,假如你想学好鸿蒙的应用开发与系统底层开发。你可以参考这份资料,少走很多弯路,节省没必要的麻烦。由两位前阿里高级研发工程师联合打造的《鸿蒙NEXT星河版OpenHarmony开发文档》里面内容包含了(ArkTS、ArkUI开发组件、Stage模型、多端部署、分布式应用开发、音频、视频、WebGL、OpenHarmony多媒体技术、Napi组件、OpenHarmony内核、Harmony南向开发、鸿蒙项目实战等等)鸿蒙(Harmony NEXT)技术知识点
如果你是一名Android、Java、前端等等开发人员,想要转入鸿蒙方向发展。可以直接领取这份资料辅助你的学习。下面是鸿蒙开发的学习路线图。
针对鸿蒙成长路线打造的鸿蒙学习文档。话不多说,我们直接看详细鸿蒙(OpenHarmony )手册(共计1236页)与鸿蒙(OpenHarmony )开发入门视频,帮助大家在技术的道路上更进一步。
鸿蒙—作为国家主力推送的国产操作系统。部分的高校已经取消了安卓课程,从而开设鸿蒙课程;企业纷纷跟进启动了鸿蒙研发。
并且鸿蒙是完全具备无与伦比的机遇和潜力的;预计到年底将有 5,000 款的应用完成原生鸿蒙开发,未来将会支持 50 万款的应用。那么这么多的应用需要开发,也就意味着需要有更多的鸿蒙人才。鸿蒙开发工程师也将会迎来爆发式的增长,学习鸿蒙势在必行! 自↓↓↓拿
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。