• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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&lt;Array&lt;AVControlCommandType&gt;&gt;): void | 获取媒体会话支持的有效命令。<br/>音视频应用在接入媒体会话时监听的播控命令,即为媒体会话支持的有效命令,相关信息请参见[媒体会话提供方监听播控命令事件](using-avsession-developer.md)。 |
24| getLaunchAbility(callback: AsyncCallback&lt;WantAgent&gt;): void | 获取媒体会话中配置的可被拉起的UIAbility。<br/>当用户在媒体会话控制方应用进行界面操作,例如点击了播控中心卡片后,可以拉起对应的应用。 |
25| sendAVKeyEvent(event: KeyEvent, callback: AsyncCallback&lt;void&gt;): void | 通过会话对应的AVSessionController向会话发送按键命令。 |
26| sendSystemAVKeyEvent(event: KeyEvent, callback: AsyncCallback&lt;void&gt;): void | 向置顶会话发送按键命令。 |
27| sendControlCommand(command: AVControlCommand, callback: AsyncCallback&lt;void&gt;): void | 通过会话对应的AVSessionController向会话发送播控命令。 |
28| sendSystemControlCommand(command: AVControlCommand, callback: AsyncCallback&lt;void&gt;): 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