• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# AVSession Controller (ArkTS)
2
3Media Controller preset in OpenHarmony functions as the controller to interact with audio and video applications, for example, obtaining and displaying media information and delivering playback control commands.
4
5You can develop a system application (for example, a new playback control center or voice assistant) as the controller to interact with audio and video applications in the system.
6
7## Basic Concepts
8
9- AVSessionDescriptor: session information, including the session ID, session type (audio/video), custom session name (**sessionTag**), information about the corresponding application (**elementName**), and whether the session is pined on top (isTopSession).
10
11- Top session: session with the highest priority in the system, for example, a session that is being played. Generally, the controller must hold an **AVSessionController** object to communicate with a session. However, the controller can directly communicate with the top session, for example, directly sending a playback control command or key event, without holding an **AVSessionController** object.
12
13## Available APIs
14
15The key APIs used by the controller are classified into the following types:
16
171. APIs called by the **AVSessionManager** object, which is obtained by means of import. An example API is **AVSessionManager.createController(sessionId)**.
182. APIs called by the **AVSessionController** object. An example API is **controller.getAVPlaybackState()**.
19
20Asynchronous JavaScript APIs use either a callback or promise to return the result. The APIs listed below use a callback. They provide the same functions as their counterparts that use a promise.
21
22For details, see [AVSession Management](../reference/apis-avsession-kit/js-apis-avsession.md).
23
24### APIs Called by the AVSessionManager Object
25
26| API| Description|
27| -------- | -------- |
28| getAllSessionDescriptors(callback: AsyncCallback<Array<Readonly<AVSessionDescriptor>>>): void | Obtains the descriptors of all AVSessions in the system.|
29| createController(sessionId: string, callback: AsyncCallback<AVSessionController>): void | Creates an AVSessionController.|
30| sendSystemAVKeyEvent(event: KeyEvent, callback: AsyncCallback<void>): void | Sends a key event to the top session.|
31| sendSystemControlCommand(command: AVControlCommand, callback: AsyncCallback<void>): void | Sends a playback control command to the top session.|
32| getHistoricalSessionDescriptors(maxSize: number, callback: AsyncCallback\<Array\<Readonly\<AVSessionDescriptor>>>): void<sup>10+<sup> | Obtains the descriptors of historical sessions.|
33
34### APIs Called by the AVSessionController Object
35
36| API| Description|
37| -------- | -------- |
38| getAVPlaybackState(callback: AsyncCallback&lt;AVPlaybackState&gt;): void<sup>10+<sup> | Obtains the information related to the playback state.|
39| getAVMetadata(callback: AsyncCallback&lt;AVMetadata&gt;): void<sup>10+<sup> | Obtains the session metadata.|
40| getOutputDevice(callback: AsyncCallback&lt;OutputDeviceInfo&gt;): void<sup>10+<sup> | Obtains the output device information.|
41| sendAVKeyEvent(event: KeyEvent, callback: AsyncCallback&lt;void&gt;): void<sup>10+<sup> | Sends a key event to the session corresponding to this controller.|
42| getLaunchAbility(callback: AsyncCallback&lt;WantAgent&gt;): void<sup>10+<sup> | Obtains the **WantAgent** object saved by the application in the session.|
43| isActive(callback: AsyncCallback&lt;boolean&gt;): void<sup>10+<sup> | Checks whether the session is activated.|
44| destroy(callback: AsyncCallback&lt;void&gt;): void<sup>10+<sup> | Destroys this controller. A controller can no longer be used after being destroyed.|
45| getValidCommands(callback: AsyncCallback&lt;Array&lt;AVControlCommandType&gt;&gt;): void<sup>10+<sup> | Obtains valid commands supported by the session.|
46| sendControlCommand(command: AVControlCommand, callback: AsyncCallback&lt;void&gt;): void<sup>10+<sup> | Sends a playback control command to the session through the controller.|
47| sendCommonCommand(command: string, args: {[key: string]: Object}, callback: AsyncCallback&lt;void&gt;): void<sup>10+<sup> | Sends a custom playback control command to the session through the controller.|
48| getAVQueueItems(callback: AsyncCallback&lt;Array&lt;AVQueueItem&gt;&gt;): void<sup>10+<sup> | Obtains the information related to the items in the playlist.|
49| getAVQueueTitle(callback: AsyncCallback&lt;string&gt;): void<sup>10+<sup> | Obtains the name of the playlist.|
50| skipToQueueItem(itemId: number, callback: AsyncCallback&lt;void&gt;): void<sup>10+<sup> | Sends the ID of an item in the playlist to the session for processing. The session can play the song.|
51| getExtras(callback: AsyncCallback&lt;{[key: string]: Object}&gt;): void<sup>10+<sup> | Obtains the custom media packet set by the provider.|
52| getOutputDeviceSync(): OutputDeviceInfo<sup>10+<sup> | Obtains the output device information. This API is a synchronous API.|
53| getAVPlaybackStateSync(): AVPlaybackState<sup>10+<sup> | Obtains the information related to the playback state. This API is a synchronous API.|
54| getAVMetadataSync(): AVMetadata<sup>10+<sup> | Obtains the session metadata. This API is a synchronous API.|
55| getAVQueueTitleSync(): string<sup>10+<sup> | Obtains the name of the playlist. This API is a synchronous API.|
56| getAVQueueItemsSync(): Array&lt;AVQueueItem&gt;<sup>10+<sup> | Obtains the information related to the items in the playlist. This API is a synchronous API.|
57| isActiveSync(): boolean<sup>10+<sup> | Checks whether the session is activated. This API is a synchronous API.|
58| getValidCommandsSync(): Array&lt;AVControlCommandType&gt;<sup>10+<sup> | Obtains valid commands supported by the session. This API is a synchronous API.|
59
60## How to Develop
61
62To enable a system application to access the AVSession service as a controller, proceed as follows:
63
641. Obtain **AVSessionDescriptor** through AVSessionManager and create an **AVSessionController** object.
65   The controller may obtain all **AVSessionDescriptor**s in the current system, and create an **AVSessionController** object for each session, so as to perform unified playback control on all the audio and video applications.
66
67   ```ts
68   // Import the AVSessionManager module.
69   import AVSessionManager from '@ohos.multimedia.avsession';
70   import { BusinessError } from '@ohos.base';
71
72   // Define global variables.
73   let g_controller = new Array<AVSessionManager.AVSessionController>();
74   let g_centerSupportCmd:Set<AVSessionManager.AVControlCommandType> = new Set(['play', 'pause', 'playNext', 'playPrevious', 'fastForward', 'rewind', 'seek','setSpeed', 'setLoopMode', 'toggleFavorite']);
75   let g_validCmd:Set<AVSessionManager.AVControlCommandType>;
76   // Obtain the session descriptors and create an AVSessionController object.
77   AVSessionManager.getAllSessionDescriptors().then((descriptors) => {
78     descriptors.forEach((descriptor) => {
79       AVSessionManager.createController(descriptor.sessionId).then((controller) => {
80         g_controller.push(controller);
81       }).catch((err: BusinessError) => {
82         console.error(`Failed to create controller. Code: ${err.code}, message: ${err.message}`);
83       });
84     });
85   }).catch((err: BusinessError) => {
86     console.error(`Failed to get all session descriptors. Code: ${err.code}, message: ${err.message}`);
87   });
88
89   // Obtain the descriptors of historical sessions.
90   AVSessionManager.getHistoricalSessionDescriptors().then((descriptors) => {
91     console.info(`getHistoricalSessionDescriptors : SUCCESS : descriptors.length : ${descriptors.length}`);
92     if (descriptors.length > 0){
93       console.info(`getHistoricalSessionDescriptors : SUCCESS : descriptors[0].isActive : ${descriptors[0].isActive}`);
94       console.info(`getHistoricalSessionDescriptors : SUCCESS : descriptors[0].type : ${descriptors[0].type}`);
95       console.info(`getHistoricalSessionDescriptors : SUCCESS : descriptors[0].sessionTag : ${descriptors[0].sessionTag}`);
96       console.info(`getHistoricalSessionDescriptors : SUCCESS : descriptors[0].sessionId : ${descriptors[0].sessionId}`);
97       console.info(`getHistoricalSessionDescriptors : SUCCESS : descriptors[0].elementName.bundleName : ${descriptors[0].elementName.bundleName}`);
98     }
99   }).catch((err: BusinessError) => {
100     console.error(`Failed to get historical session descriptors, error code: ${err.code}, error message: ${err.message}`);
101   });
102   ```
103
1042. Listen for the session state and service state events.
105
106   The following session state events are available:
107
108   - **sessionCreate**: triggered when a session is created.
109   - **sessionDestroy**: triggered when a session is destroyed.
110   - **topSessionChange**: triggered when the top session is changed.
111
112   The service state event **sessionServiceDie** is reported when the AVSession service is abnormal.
113
114   ```ts
115   import AVSessionManager from '@ohos.multimedia.avsession';
116   import { BusinessError } from '@ohos.base';
117
118   let g_controller = new Array<AVSessionManager.AVSessionController>();
119   // Subscribe to the 'sessionCreate' event and create an AVSessionController object.
120   AVSessionManager.on('sessionCreate', (session) => {
121     // After an AVSession is added, you must create an AVSessionController object.
122     AVSessionManager.createController(session.sessionId).then((controller) => {
123       g_controller.push(controller);
124     }).catch((err: BusinessError) => {
125       console.error(`Failed to create controller. Code: ${err.code}, message: ${err.message}`);
126     });
127   });
128
129   // Subscribe to the 'sessionDestroy' event to enable the application to get notified when the session dies.
130   AVSessionManager.on('sessionDestroy', (session) => {
131     let index = g_controller.findIndex((controller) => {
132       return controller.sessionId === session.sessionId;
133     });
134     if (index !== 0) {
135       g_controller[index].destroy();
136       g_controller.splice(index, 1);
137     }
138   });
139   // Subscribe to the 'topSessionChange' event.
140   AVSessionManager.on('topSessionChange', (session) => {
141     let index = g_controller.findIndex((controller) => {
142       return controller.sessionId === session.sessionId;
143     });
144     // Place the session on the top.
145     if (index !== 0) {
146       g_controller.sort((a, b) => {
147         return a.sessionId === session.sessionId ? -1 : 0;
148       });
149     }
150   });
151   // Subscribe to the 'sessionServiceDie' event.
152   AVSessionManager.on('sessionServiceDie', () => {
153     // The server is abnormal, and the application clears resources.
154     console.info(`Server exception.`);
155   })
156   ```
157
1583. Subscribe to media information changes and other session events.
159
160   The following media information change events are available:
161
162   - **metadataChange**: triggered when the session metadata changes.
163   - **playbackStateChange**: triggered when the playback state changes.
164   - **activeStateChange**: triggered when the activation state of the session changes.
165   - **validCommandChange**: triggered when the valid commands supported by the session changes.
166   - **outputDeviceChange**: triggered when the output device changes.
167   - **sessionDestroy**: triggered when a session is destroyed.
168   - **sessionEvent**: triggered when the custom session event changes.
169   - **extrasChange**: triggered when the custom media packet of the session changes.
170   - **queueItemsChange**: triggered when one or more items in the custom playlist of the session changes.
171   - **queueTitleChange**: triggered when the custom playlist name of the session changes.
172
173   The controller can listen for events as required.
174
175   ```ts
176   import AVSessionManager from '@ohos.multimedia.avsession';
177   import { BusinessError } from '@ohos.base';
178
179   let g_controller = new Array<AVSessionManager.AVSessionController>();
180   let controller = g_controller[0];
181   let g_validCmd:Set<AVSessionManager.AVControlCommandType>;
182   let g_centerSupportCmd:Set<AVSessionManager.AVControlCommandType> = new Set(['play', 'pause', 'playNext', 'playPrevious', 'fastForward', 'rewind', 'seek','setSpeed', 'setLoopMode', 'toggleFavorite']);
183   // Subscribe to the 'activeStateChange' event.
184   controller.on('activeStateChange', (isActive) => {
185     if (isActive) {
186       console.info(`The widget corresponding to the controller is highlighted.`);
187     } else {
188       console.info(`The widget corresponding to the controller is invalid.`);
189     }
190   });
191   // Subscribe to the 'sessionDestroy' event to enable the controller to get notified when the session dies.
192   controller.on('sessionDestroy', () => {
193     console.info(`on sessionDestroy : SUCCESS `);
194     controller.destroy().then(() => {
195       console.info(`destroy : SUCCESS`);
196     }).catch((err: BusinessError) => {
197       console.error(`Failed to destroy session. Code: ${err.code}, message: ${err.message}`);
198     });
199   });
200
201   // Subscribe to metadata changes.
202   controller.on('metadataChange', ['assetId', 'title', 'description'], (metadata: AVSessionManager.AVMetadata) => {
203     console.info(`on metadataChange assetId : ${metadata.assetId}`);
204   });
205   // Subscribe to playback state changes.
206   controller.on('playbackStateChange', ['state', 'speed', 'loopMode'], (playbackState: AVSessionManager.AVPlaybackState) => {
207     console.info(`on playbackStateChange state : ${playbackState.state}`);
208   });
209   // Subscribe to supported command changes.
210   controller.on('validCommandChange', (cmds) => {
211     console.info(`validCommandChange : SUCCESS : size : ${cmds.length}`);
212     console.info(`validCommandChange : SUCCESS : cmds : ${cmds.values()}`);
213     g_validCmd.clear();
214     let centerSupportCmd = Array.from(g_centerSupportCmd.values())
215     for (let c of centerSupportCmd) {
216       if (cmds.concat(c)) {
217         g_validCmd.add(c);
218       }
219     }
220   });
221   // Subscribe to output device changes.
222   controller.on('outputDeviceChange', (state, device) => {
223     console.info(`outputDeviceChange device are : ${JSON.stringify(device)}`);
224   });
225   // Subscribe to custom session event changes.
226   controller.on('sessionEvent', (eventName, eventArgs) => {
227     console.info(`Received new session event, event name is ${eventName}, args are ${JSON.stringify(eventArgs)}`);
228   });
229   // Subscribe to custom media packet changes.
230   controller.on('extrasChange', (extras) => {
231     console.info(`Received custom media packet, packet data is ${JSON.stringify(extras)}`);
232   });
233   // Subscribe to custom playlist item changes.
234   controller.on('queueItemsChange', (items) => {
235     console.info(`Caught queue items change, items length is ${items.length}`);
236   });
237   // Subscribe to custom playback name changes.
238   controller.on('queueTitleChange', (title) => {
239     console.info(`Caught queue title change, title is ${title}`);
240   });
241   ```
242
2434. Obtain the media information transferred by the provider for display on the UI, for example, displaying the track being played and the playback state in Media Controller.
244
245   ```ts
246   import AVSessionManager from '@ohos.multimedia.avsession';
247   async function getInfoFromSessionByController() {
248     // It is assumed that an AVSessionController object corresponding to the session already exists. For details about how to create an AVSessionController object, see the code snippet above.
249     let controller = await AVSessionManager.createController("")
250     // Obtain the session ID.
251     let sessionId = controller.sessionId;
252     console.info(`get sessionId by controller : isActive : ${sessionId}`);
253     // Obtain the activation state of the session.
254     let isActive = await controller.isActive();
255     console.info(`get activeState by controller : ${isActive}`);
256     // Obtain the media information of the session.
257     let metadata = await controller.getAVMetadata();
258     console.info(`get media title by controller : ${metadata.title}`);
259     console.info(`get media artist by controller : ${metadata.artist}`);
260     // Obtain the playback information of the session.
261     let avPlaybackState = await controller.getAVPlaybackState();
262     console.info(`get playbackState by controller : ${avPlaybackState.state}`);
263     console.info(`get favoriteState by controller : ${avPlaybackState.isFavorite}`);
264     // Obtain the playlist items of the session.
265     let queueItems = await controller.getAVQueueItems();
266     console.info(`get queueItems length by controller : ${queueItems.length}`);
267     // Obtain the playlist name of the session.
268     let queueTitle = await controller.getAVQueueTitle();
269     console.info(`get queueTitle by controller : ${queueTitle}`);
270     // Obtain the custom media packet of the session.
271     let extras = await controller.getExtras();
272     console.info(`get custom media packets by controller : ${JSON.stringify(extras)}`);
273     // Obtain the ability information provided by the application corresponding to the session.
274     let agent = await controller.getLaunchAbility();
275     console.info(`get want agent info by controller : ${JSON.stringify(agent)}`);
276     // Obtain the current playback position of the session.
277     let currentTime = controller.getRealPlaybackPositionSync();
278     console.info(`get current playback time by controller : ${currentTime}`);
279     // Obtain valid commands supported by the session.
280     let validCommands = await controller.getValidCommands();
281     console.info(`get valid commands by controller : ${JSON.stringify(validCommands)}`);
282   }
283   ```
284
2855. Control the playback behavior, for example, sending a command to operate (play/pause/previous/next) the item being played in Media Controller.
286
287   After listening for the playback control command event, the audio and video application serving as the provider needs to implement the corresponding operation.
288
289   ```ts
290   import AVSessionManager from '@ohos.multimedia.avsession';
291   import { BusinessError } from '@ohos.base';
292
293   async function  sendCommandToSessionByController() {
294     // It is assumed that an AVSessionController object corresponding to the session already exists. For details about how to create an AVSessionController object, see the code snippet above.
295     let controller = await AVSessionManager.createController("")
296     // Obtain valid commands supported by the session.
297     let validCommandTypeArray = await controller.getValidCommands();
298     console.info(`get validCommandArray by controller : length : ${validCommandTypeArray.length}`);
299     // Deliver the 'play' command.
300     // If the 'play' command is valid, deliver it. Normal sessions should provide and implement the playback.
301     if (validCommandTypeArray.indexOf('play') >= 0) {
302       let avCommand: AVSessionManager.AVControlCommand = {command:'play'};
303       controller.sendControlCommand(avCommand);
304     }
305     // Deliver the 'pause' command.
306     if (validCommandTypeArray.indexOf('pause') >= 0) {
307       let avCommand: AVSessionManager.AVControlCommand = {command:'pause'};
308       controller.sendControlCommand(avCommand);
309     }
310     // Deliver the 'playPrevious' command.
311     if (validCommandTypeArray.indexOf('playPrevious') >= 0) {
312       let avCommand: AVSessionManager.AVControlCommand = {command:'playPrevious'};
313       controller.sendControlCommand(avCommand);
314     }
315     // Deliver the 'playNext' command.
316     if (validCommandTypeArray.indexOf('playNext') >= 0) {
317       let avCommand: AVSessionManager.AVControlCommand = {command:'playNext'};
318       controller.sendControlCommand(avCommand);
319     }
320     // Deliver a custom playback control command.
321     let commandName = 'custom command';
322     await controller.sendCommonCommand(commandName, {command : 'This is my custom command'}).then(() => {
323       console.info(`SendCommonCommand successfully`);
324     }).catch((err: BusinessError) => {
325       console.error(`Failed to send common command. Code: ${err.code}, message: ${err.message}`);
326     })
327     // Set the ID of an item in the specified playlist for the session to play.
328     let queueItemId = 0;
329     await controller.skipToQueueItem(queueItemId).then(() => {
330       console.info(`SkipToQueueItem successfully`);
331     }).catch((err: BusinessError) => {
332       console.error(`Failed to skip to queue item. Code: ${err.code}, message: ${err.message}`);
333     });
334   }
335   ```
336
3376. When the audio and video application exits, cancel the listener and release the resources.
338
339   ```ts
340   import AVSessionManager from '@ohos.multimedia.avsession';
341   import { BusinessError } from '@ohos.base';
342
343   async function destroyController() {
344     // It is assumed that an AVSessionController object corresponding to the session already exists. For details about how to create an AVSessionController object, see the code snippet above.
345     let controller = await AVSessionManager.createController("")
346
347     // Destroy the AVSessionController object. After being destroyed, it is no longer available.
348     controller.destroy((err: BusinessError) => {
349       if (err) {
350         console.error(`Failed to destroy controller. Code: ${err.code}, message: ${err.message}`);
351       } else {
352         console.info(`Destroy controller SUCCESS`);
353       }
354     });
355   }
356   ```
357