1# 媒体会话控制方 2 3OpenHarmony系统预置的播控中心,作为媒体会话控制方与音视频应用进行交互,包括获取媒体信息进行展示以及下发播控命令等。 4 5系统应用开发者也可以根据需要,按照本章节的内容自行开发一款新的系统应用(例如新开发一款播控中心或语音助手),作为媒体会话控制方的角色,与系统中的音视频应用进行交互。 6 7## 基本概念 8 9- 媒体会话描述符(AVSessionDescriptor):描述媒体会话的相关信息,包含标识媒体会话的ID(sessionId),媒体会话的类型type(音频Audio/视频Video),媒体会话自定义名称(sessionTag),媒体会话所属应用的信息(elementName)、是否为置顶会话(isTopSession)等。 10 11- 置顶会话(TopSession):系统中优先级最高的媒体会话,例如当前处于正在播放状态的会话。一般来说,如果想与媒体会话通信,需要获取会话对应的控制器,而媒体会话控制方可以在不用获取对应控制器的情况下,直接与置顶会话通信,例如直接向置顶会话发送播控命令和按键事件。 12 13## 接口说明 14 15媒体会话控制方使用的关键接口如下表所示。接口返回值有两种返回形式:callback和promise,下表中为callback形式接口,promise和callback只是返回值方式不一样,功能相同。 16 17更多API说明请参见[API文档](../reference/apis/js-apis-avsession.md)。 18 19| 接口名 | 说明 | 20| -------- | -------- | 21| getAllSessionDescriptors(callback: AsyncCallback<Array<Readonly<AVSessionDescriptor>>>): void | 获取系统中所有媒体会话的描述符。 | 22| createController(sessionId: string, callback: AsyncCallback<AVSessionController>): void | 创建媒体会话控制器。 | 23| getValidCommands(callback: AsyncCallback<Array<AVControlCommandType>>): void | 获取媒体会话支持的有效命令。<br/>音视频应用在接入媒体会话时监听的播控命令,即为媒体会话支持的有效命令,相关信息请参见[媒体会话提供方监听播控命令事件](using-avsession-developer.md)。 | 24| getLaunchAbility(callback: AsyncCallback<WantAgent>): void | 获取媒体会话中配置的可被拉起的UIAbility。<br/>当用户在媒体会话控制方应用进行界面操作,例如点击了播控中心卡片后,可以拉起对应的应用。 | 25| sendAVKeyEvent(event: KeyEvent, callback: AsyncCallback<void>): void | 通过会话对应的AVSessionController向会话发送按键命令。 | 26| sendSystemAVKeyEvent(event: KeyEvent, callback: AsyncCallback<void>): void | 向置顶会话发送按键命令。 | 27| sendControlCommand(command: AVControlCommand, callback: AsyncCallback<void>): void | 通过会话对应的AVSessionController向会话发送播控命令。 | 28| sendSystemControlCommand(command: AVControlCommand, callback: AsyncCallback<void>): void | 向置顶会话发送播控命令。 | 29 30## 开发步骤 31 32系统应用作为媒体会话控制方接入媒体会话的基本步骤如下所示: 33 341. 通过AVSessionManager获取媒体会话描述符AVSessionDescriptor,创建媒体会话控制器AVSessionController。 35 媒体会话控制方可以获取当前系统中所有的AVSessionDescriptor,并创建每个会话对应的AVSessionController,从而对系统中的音视频应用进行统一的播放控制。 36 37 ```ts 38 //导入AVSessionManager模块 39 import AVSessionManager from '@ohos.multimedia.avsession'; 40 41 // 全局变量定义 42 let g_controller = new Array<AVSessionManager.AVSessionController>(); 43 let g_centerSupportCmd:Set<AVSessionManager.AVControlCommandType> = new Set(['play', 'pause', 'playNext', 'playPrevious', 'fastForward', 'rewind', 'seek','setSpeed', 'setLoopMode', 'toggleFavorite']); 44 let g_validCmd:Set<AVSessionManager.AVControlCommandType>; 45 // 获取会话描述符,创建控制器 46 AVSessionManager.getAllSessionDescriptors().then((descriptors) => { 47 descriptors.forEach((descriptor) => { 48 AVSessionManager.createController(descriptor.sessionId).then((controller) => { 49 g_controller.push(controller); 50 }).catch((err) => { 51 console.error(`createController : ERROR : ${err.message}`); 52 }); 53 }); 54 }).catch((err) => { 55 console.error(`getAllSessionDescriptors : ERROR : ${err.message}`); 56 }); 57 58 ``` 59 602. 监听AVSession会话状态及AVSession服务状态事件。 61 62 AVSession会话状态事件包括: 63 64 - sessionCreate:媒体会话创建事件。 65 - sessionDestroy:媒体会话销毁事件。 66 - topSessionChange:置顶会话发生变化事件。 67 68 AVSession服务状态事件指sessionServiceDie,在AVSession服务异常时产生该事件。 69 70 ```ts 71 // 注册会话创建监听,创建控制器 72 AVSessionManager.on('sessionCreate', (session) => { 73 // 新增会话,需要创建控制器 74 AVSessionManager.createController(session.sessionId).then((controller) => { 75 g_controller.push(controller); 76 }).catch((err) => { 77 console.info(`createController : ERROR : ${err.message}`); 78 }); 79 }); 80 81 // 注册系统会话销毁监听 82 AVSessionManager.on('sessionDestroy', (session) => { 83 let index = g_controller.findIndex((controller) => { 84 return controller.sessionId === session.sessionId; 85 }); 86 if (index !== 0) { 87 g_controller[index].destroy(); 88 g_controller.splice(index, 1); 89 } 90 }); 91 // 注册系统最高优先级会话变更监听 92 AVSessionManager.on('topSessionChange', (session) => { 93 let index = g_controller.findIndex((controller) => { 94 return controller.sessionId === session.sessionId; 95 }); 96 // 将该会话显示排到第一个 97 if (index !== 0) { 98 g_controller.sort((a, b) => { 99 return a.sessionId === session.sessionId ? -1 : 0; 100 }); 101 } 102 }); 103 // 注册服务异常监听 104 AVSessionManager.on('sessionServiceDie', () => { 105 // 服务端异常,应用清理资源 106 console.info("服务端异常"); 107 }) 108 ``` 109 1103. 监听媒体信息变化及会话其他事件。 111 112 AVSession媒体信息变化事件主要包括: 113 114 - metadataChange:媒体会话元数据变化事件。 115 - playbackStateChange:媒体播放状态变化事件。 116 - activeStateChange:媒体会话激活状态变化事件。 117 - validCommandChange:媒体会话支持的有效命令变化事件。 118 - outputDeviceChange:播放设备变化事件。 119 - sessionDestroy:媒体会话销毁事件。 120 121 媒体会话控制方可以根据实际需要监听对应的事件。 122 123 ```ts 124 // 注册会话激活状态变更监听 125 controller.on('activeStateChange', (isActive) => { 126 if (isActive) { 127 console.info("控制器卡片按键高亮"); 128 } else { 129 console.info("控制器卡片按键变更为无效"); 130 } 131 }); 132 // 注册会话销毁监听 133 controller.on('sessionDestroy', () => { 134 console.info('on sessionDestroy : SUCCESS '); 135 controller.destroy().then(() => { 136 console.info('destroy : SUCCESS '); 137 }).catch((err) => { 138 console.info(`destroy : ERROR :${err.message}`); 139 }); 140 }); 141 142 // 注册元数据更新监听 143 let metaFilter = ['assetId', 'title', 'description']; 144 controller.on('metadataChange', metaFilter, (metadata) => { 145 console.info(`on metadataChange assetId : ${metadata.assetId}`); 146 }); 147 // 注册播放状态更新监听 148 let playbackFilter = ['state', 'speed', 'loopMode']; 149 controller.on('playbackStateChange', playbackFilter, (playbackState) => { 150 console.info(`on playbackStateChange state : ${playbackState.state}`); 151 }); 152 // 注册会话支持的命令变更监听 153 controller.on('validCommandChange', (cmds) => { 154 console.info(`validCommandChange : SUCCESS : size : ${cmds.size}`); 155 console.info(`validCommandChange : SUCCESS : cmds : ${cmds.values()}`); 156 g_validCmd.clear(); 157 for (let c of g_centerSupportCmd) { 158 if (cmds.has(c)) { 159 g_validCmd.add(c); 160 } 161 } 162 }); 163 // 注册输出设备变更监听 164 controller.on('outputDeviceChange', (device) => { 165 console.info(`on outputDeviceChange device isRemote : ${device.isRemote}`); 166 }); 167 ``` 168 1694. 获取媒体会话提供方传递的媒体信息,可以用于界面展示,例如在播控中心展示当前播放的曲目及对应的播放状态。 170 171 ```ts 172 async getInfoFromSessionByController() { 173 // 假设我们已经有了一个对应session的controller,如何创建controller可以参考之前的案例 174 let controller: AVSessionManager.AVSessionController = ALLREADY_HAVE_A_CONTROLLER; 175 // 获取sessionId 176 let sessionId: string = controller.sessionId; 177 console.info(`get sessionId by controller : isActive : ${sessionId}`); 178 // 获取session激活状态 179 let isActive: boolean = await controller.isActive(); 180 console.info(`get activeState by controller : ${isActive}`); 181 // 获取session的媒体信息 182 let metadata: AVSessionManager.AVMetadata = await controller.getAVMetadata(); 183 console.info(`get media title by controller : ${metadata.title}`); 184 console.info(`get media artist by controller : ${metadata.artist}`); 185 // 获取session的播放信息 186 let avPlaybackState: AVSessionManager.AVPlaybackState = await controller.getAVPlaybackState(); 187 console.info(`get playbackState by controller : ${avPlaybackState.state}`); 188 console.info(`get favoriteState by controller : ${avPlaybackState.isFavorite}`); 189 } 190 ``` 191 1925. 控制媒体会话行为,例如发送用户在播控中心对当前曲目的操作(播放/暂停/上一首/下一首等)命令。 193 194 作为媒体会话提供方的音视频应用在监听到相关的播控命令事件后,在相应的逻辑中可以完成对应的操作动作。 195 196 197 ```ts 198 async sendCommandToSessionByController() { 199 // 假设我们已经有了一个对应session的controller,如何创建controller可以参考之前的案例 200 let controller: AVSessionManager.AVSessionController = ALLREADY_HAVE_A_CONTROLLER; 201 // 获取这个session支持的命令种类 202 let validCommandTypeArray: Array<AVSessionManager.AVControlCommandType> = await controller.getValidCommands(); 203 console.info(`get validCommandArray by controller : length : ${validCommandTypeArray.length}`); 204 // 下发播放命令 205 // 如果可用命令包含播放,则下发播放命令,正常session都应该提供并实现播放功能 206 if (validCommandTypeArray.indexOf('play') >= 0) { 207 let avCommand: AVSessionManager.AVControlCommand = {command:'play'}; 208 controller.sendControlCommand(avCommand); 209 } 210 // 下发暂停命令 211 if (validCommandTypeArray.indexOf('pause') >= 0) { 212 let avCommand: AVSessionManager.AVControlCommand = {command:'pause'}; 213 controller.sendControlCommand(avCommand); 214 } 215 // 下发上一首命令 216 if (validCommandTypeArray.indexOf('playPrevious') >= 0) { 217 let avCommand: AVSessionManager.AVControlCommand = {command:'playPrevious'}; 218 controller.sendControlCommand(avCommand); 219 } 220 // 下发下一首命令 221 if (validCommandTypeArray.indexOf('playNext') >= 0) { 222 let avCommand: AVSessionManager.AVControlCommand = {command:'playNext'}; 223 controller.sendControlCommand(avCommand); 224 } 225 } 226 ``` 227 2286. 在媒体会话控制方应用退出时及时取消事件监听,并释放资源。 229 230 ```ts 231 async destroyController() { 232 // 假设我们已经有了一个对应session的controller,如何创建controller可以参考之前的案例 233 let controller: AVSessionManager.AVSessionController = ALLREADY_HAVE_A_CONTROLLER; 234 235 // 销毁当前的controller,销毁后这个controller将不在可用 236 controller.destroy(function (err) { 237 if (err) { 238 console.info(`Destroy controller ERROR : code: ${err.code}, message: ${err.message}`); 239 } else { 240 console.info('Destroy controller SUCCESS'); 241 } 242 }); 243 } 244 ``` 245