1# AVSession Provider
2
3An audio and video application needs to access the AVSession service as a provider in order to display media information in the controller (for example, Media Controller) and respond to playback control commands delivered by the controller.
4
5## Basic Concepts
6
7- AVMetadata: media data related attributes, including the IDs of the current media asset (assetId), previous media asset (previousAssetId), and next media asset (nextAssetId), title, author, album, writer, and duration.
8
9- AVPlaybackState: playback state attributes, including the playback state, position, speed, buffered time, loop mode, media item being played (activeItemId), custom media data (extras), and whether the media asset is favorited (isFavorite).
10
11## Available APIs
12
13The table below lists the key APIs used by the provider. The 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.
14
15For details, see [AVSession Management](../../reference/apis-avsession-kit/js-apis-avsession.md).
16
17| API | Description | 
18| -------- | -------- |
19| createAVSession(context: Context, tag: string, type: AVSessionType, callback: AsyncCallback&lt;AVSession&gt;): void<sup>10+<sup> | Creates an AVSession.<br>Only one AVSession can be created for a UIAbility. | 
20| setAVMetadata(data: AVMetadata, callback: AsyncCallback&lt;void&gt;): void<sup>10+<sup> | Sets AVSession metadata. | 
21| setAVPlaybackState(state: AVPlaybackState, callback: AsyncCallback&lt;void&gt;): void<sup>10+<sup> | Sets the AVSession playback state. | 
22| setLaunchAbility(ability: WantAgent, callback: AsyncCallback&lt;void&gt;): void<sup>10+<sup> | Starts a UIAbility. | 
23| getController(callback: AsyncCallback&lt;AVSessionController&gt;): void<sup>10+<sup> | Obtains the controller of the AVSession. | 
24| getOutputDevice(callback: AsyncCallback&lt;OutputDeviceInfo&gt;): void<sup>10+<sup> | Obtains the output device information. |
25| activate(callback: AsyncCallback&lt;void&gt;): void<sup>10+<sup> | Activates the AVSession. | 
26| deactivate(callback: AsyncCallback&lt;void&gt;): void<sup>10+<sup> | Deactivates this session. |
27| destroy(callback: AsyncCallback&lt;void&gt;): void<sup>10+<sup> | Destroys the AVSession. | 
28| setAVQueueItems(items: Array&lt;AVQueueItem&gt;, callback: AsyncCallback&lt;void&gt;): void <sup>10+<sup> | Sets a playlist. |
29| setAVQueueTitle(title: string, callback: AsyncCallback&lt;void&gt;): void<sup>10+<sup> | Sets a name for the playlist. |
30| dispatchSessionEvent(event: string, args: {[key: string]: Object}, callback: AsyncCallback&lt;void&gt;): void<sup>10+<sup> | Dispatches a custom session event. |
31| setExtras(extras: {[key: string]: Object}, callback: AsyncCallback&lt;void&gt;): void<sup>10+<sup> | Sets a custom media packet in the form of a key-value pair.|
32| getOutputDeviceSync(): OutputDeviceInfo<sup>10+<sup> | Obtains the output device information. This API is a synchronous API. |
33
34## How to Develop
35
36To enable an audio and video application to access the AVSession service as a provider, proceed as follows:
37
381. Call an API in the **AVSessionManager** class to create and activate an **AVSession** object.
39     
40   ```ts
41   import { avSession as AVSessionManager } from '@kit.AVSessionKit';
42
43   // Start to create and activate an AVSession object.
44   // Create an AVSession object.
45   let context: Context = getContext(this);
46   async function createSession() {
47     let type: AVSessionManager.AVSessionType = 'audio';
48     let session = await AVSessionManager.createAVSession(context, 'SESSION_NAME', type);
49     await session.activate();
50     console.info(`session create done : sessionId : ${session.sessionId}`);
51   }
52   ```
53
542. Set AVSession information, which includes:
55   - AVMetadata
56   - AVPlaybackState
57
58   The controller will call an API in the **AVSessionController** class to obtain the information and display or process the information.
59     
60   ```ts
61   import { avSession as AVSessionManager } from '@kit.AVSessionKit';
62   import { BusinessError } from '@kit.BasicServicesKit';
63
64   let context: Context = getContext(this);
65   async function setSessionInfo() {
66     // It is assumed that an AVSession object has been created. For details about how to create an AVSession object, see the node snippet in step 1.
67     let session = await AVSessionManager.createAVSession(context, 'SESSION_NAME', 'audio');
68     // The player logic that triggers changes in the session metadata and playback state is omitted here.
69     // Set necessary session metadata.
70     let metadata: AVSessionManager.AVMetadata = {
71       assetId: '0', // Specified by the application, used to identify the media asset in the application media library.
72       title: 'TITLE',
73       mediaImage: 'IMAGE',
74       artist: 'ARTIST'
75     };
76     session.setAVMetadata(metadata).then(() => {
77       console.info(`SetAVMetadata successfully`);
78     }).catch((err: BusinessError) => {
79       console.error(`Failed to set AVMetadata. Code: ${err.code}, message: ${err.message}`);
80     });
81     // Set the playback state to paused and set isFavorite to false.
82     let playbackState: AVSessionManager.AVPlaybackState = {
83       state:AVSessionManager.PlaybackState.PLAYBACK_STATE_PAUSE,
84       isFavorite:false
85     };
86     session.setAVPlaybackState(playbackState, (err) => {
87       if (err) {
88         console.error(`Failed to set AVPlaybackState. Code: ${err.code}, message: ${err.message}`);
89       } else {
90         console.info(`SetAVPlaybackState successfully`);
91       }
92     });
93     // Set a playlist.
94     let queueItemDescription_1: AVSessionManager.AVMediaDescription = {
95       assetId: '001',
96       title: 'music_name',
97       subtitle: 'music_sub_name',
98       description: 'music_description',
99       mediaImage: "PIXELMAP_OBJECT",
100       extras: {'extras':'any'}
101     };
102     let queueItem_1: AVSessionManager.AVQueueItem = {
103       itemId: 1,
104       description: queueItemDescription_1
105     };
106     let queueItemDescription_2: AVSessionManager.AVMediaDescription = {
107       assetId: '002',
108       title: 'music_name',
109       subtitle: 'music_sub_name',
110       description: 'music_description',
111       mediaImage: "PIXELMAP_OBJECT",
112       extras: {'extras':'any'}
113     };
114     let queueItem_2: AVSessionManager.AVQueueItem = {
115       itemId: 2,
116       description: queueItemDescription_2
117     };
118     let queueItemsArray = [queueItem_1, queueItem_2];
119     session.setAVQueueItems(queueItemsArray).then(() => {
120       console.info(`SetAVQueueItems successfully`);
121     }).catch((err: BusinessError) => {
122       console.error(`Failed to set AVQueueItem, error code: ${err.code}, error message: ${err.message}`);
123     });
124     // Set a name for the playlist.
125     let queueTitle = 'QUEUE_TITLE';
126     session.setAVQueueTitle(queueTitle).then(() => {
127       console.info(`SetAVQueueTitle successfully`);
128     }).catch((err: BusinessError) => {
129       console.info(`Failed to set AVQueueTitle, error code: ${err.code}, error message: ${err.message}`);
130     });
131   }
132   ```
133
1343. Set the UIAbility to be started by the controller. The UIAbility configured here is started when a user operates the UI of the controller, for example, clicking a widget in Media Controller.
135   The UIAbility is set through the **WantAgent** API. For details, see [WantAgent](../../reference/apis-ability-kit/js-apis-app-ability-wantAgent.md).
136 
137   ```ts
138   import { wantAgent } from '@kit.AbilityKit';
139   ```
140
141   ```ts
142   import { avSession as AVSessionManager } from '@kit.AVSessionKit';
143   import { wantAgent } from '@kit.AbilityKit';
144
145   let context: Context = getContext(this);
146   async function getWantAgent() {
147     let type: AVSessionManager.AVSessionType = 'audio';
148     // It is assumed that an AVSession object has been created. For details about how to create an AVSession object, see the node snippet in step 1.
149     let session = await AVSessionManager.createAVSession(context, 'SESSION_NAME', type);
150     let wantAgentInfo: wantAgent.WantAgentInfo = {
151       wants: [
152         {
153           bundleName: 'com.example.musicdemo',
154           abilityName: 'MainAbility'
155         }
156       ],
157       operationType: wantAgent.OperationType.START_ABILITIES,
158       requestCode: 0,
159       wantAgentFlags: [wantAgent.WantAgentFlags.UPDATE_PRESENT_FLAG]
160     }
161     wantAgent.getWantAgent(wantAgentInfo).then((agent) => {
162       session.setLaunchAbility(agent);
163     })
164   }
165   ```
166
1674. Set a custom session event. The controller performs an operation after receiving the event.
168
169   > **NOTE**
170   > 
171   > The data set through **dispatchSessionEvent** is not saved in the **AVSession** object or AVSession service.
172
173   ```ts
174
175   import { avSession as AVSessionManager } from '@kit.AVSessionKit';
176   import { BusinessError } from '@kit.BasicServicesKit';
177
178   let context: Context = getContext(this);
179   async function dispatchSessionEvent() {
180     // It is assumed that an AVSession object has been created. For details about how to create an AVSession object, see the node snippet in step 1.
181     let type: AVSessionManager.AVSessionType = 'audio';
182     let session = await AVSessionManager.createAVSession(context, 'SESSION_NAME', type);
183     let eventName = 'dynamic_lyric';
184     await session.dispatchSessionEvent(eventName, {lyric : 'This is my lyric'}).then(() => {
185       console.info(`Dispatch session event successfully`);
186     }).catch((err: BusinessError) => {
187       console.error(`Failed to dispatch session event. Code: ${err.code}, message: ${err.message}`);
188     })
189   }
190
191   ```
192
1935. Set a custom media packet. The controller performs an operation after receiving the event.
194
195   > **NOTE**
196   > 
197   > The data set by using **setExtras** is stored in the AVSession service. The data lifecycle is the same as that of the **AVSession** object, and the controller corresponding to the object can use **getExtras** to obtain the data.
198
199   ```ts
200   import { avSession as AVSessionManager } from '@kit.AVSessionKit';
201   import { BusinessError } from '@kit.BasicServicesKit';
202
203   let context: Context = getContext(this);
204   async function setExtras() {
205     // It is assumed that an AVSession object has been created. For details about how to create an AVSession object, see the node snippet in step 1.
206     let type: AVSessionManager.AVSessionType = 'audio';
207     let session = await AVSessionManager.createAVSession(context, 'SESSION_NAME', type);
208     await session.setExtras({extra : 'This is my custom meida packet'}).then(() => {
209       console.info(`Set extras successfully`);
210     }).catch((err: BusinessError) => {
211       console.error(`Failed to set extras. Code: ${err.code}, message: ${err.message}`);
212     })
213   }
214   ```
215
2166. Listen for playback control commands or events delivered by the controller, for example, Media Controller.
217
218   Both fixed playback control commands and advanced playback control events can be listened for.
219
220   6.1 Listening for Fixed Playback Control Commands
221
222   > **NOTE**
223   >
224   > After the provider registers a listener for fixed playback control commands, the commands will be reflected in **getValidCommands()** of the controller. In other words, the controller determines that the command is valid and triggers the corresponding event (not used temporarily) as required. To ensure that the playback control commands delivered by the controller can be executed normally, the provider should not use a null implementation for listening.
225
226   Fixed playback control commands on the session side include basic operation commands such as play, pause, previous, and next. For details, see [AVControlCommand](../../reference/apis-avsession-kit/js-apis-avsession.md).
227     
228   ```ts
229   import { avSession as AVSessionManager } from '@kit.AVSessionKit';
230
231   let context: Context = getContext(this);
232   async function setListenerForMesFromController() {
233     // It is assumed that an AVSession object has been created. For details about how to create an AVSession object, see the node snippet in step 1.
234     let type: AVSessionManager.AVSessionType = 'audio';
235     let session = await AVSessionManager.createAVSession(context, 'SESSION_NAME', type);
236     // Generally, logic processing on the player is implemented in the listener.
237     // After the processing is complete, use the setter to synchronize the playback information. For details, see the code snippet above.
238     session.on('play', () => {
239       console.info(`on play , do play task`);
240       // If this command is not supported, do not register it. If the command has been registered but is not used temporarily, use session.off('play') to cancel listening.
241       // After the processing is complete, call SetAVPlayState to report the playback state.
242     });
243     session.on('pause', () => {
244       console.info(`on pause , do pause task`);
245        // If this command is not supported, do not register it. If the command has been registered but is not used temporarily, use session.off('pause') to cancel listening.
246        // After the processing is complete, call SetAVPlayState to report the playback state.
247     });
248     session.on('stop', () => {
249       console.info(`on stop , do stop task`);
250        // If this command is not supported, do not register it. If the command has been registered but is not used temporarily, use session.off('stop') to cancel listening.
251        // After the processing is complete, call SetAVPlayState to report the playback state.
252     });
253     session.on('playNext', () => {
254       console.info(`on playNext , do playNext task`);
255        // If this command is not supported, do not register it. If the command has been registered but is not used temporarily, use session.off('playNext') to cancel listening.
256        // After the processing is complete, call SetAVPlayState to report the playback state and call SetAVMetadata to report the media information.
257     });
258     session.on('playPrevious', () => {
259       console.info(`on playPrevious , do playPrevious task`);
260        // If this command is not supported, do not register it. If the command has been registered but is not used temporarily, use session.off('playPrevious') to cancel listening.
261        // After the processing is complete, call SetAVPlayState to report the playback state and call SetAVMetadata to report the media information.
262     });
263     session.on('fastForward', () => {
264       console.info(`on fastForward , do fastForward task`);
265        // If this command is not supported, do not register it. If the command has been registered but is not used temporarily, use session.off('fastForward') to cancel listening.
266        // After the processing is complete, call SetAVPlayState to report the playback state and position.
267     });
268     session.on('rewind', () => {
269       console.info(`on rewind , do rewind task`);
270        // If this command is not supported, do not register it. If the command has been registered but is not used temporarily, use session.off('rewind') to cancel listening.
271        // After the processing is complete, call SetAVPlayState to report the playback state and position.
272     });
273
274     session.on('seek', (time) => {
275       console.info(`on seek , the seek time is ${time}`);
276        // If this command is not supported, do not register it. If the command has been registered but is not used temporarily, use session.off('seek') to cancel listening.
277        // After the processing is complete, call SetAVPlayState to report the playback state and position.
278     });
279     session.on('setSpeed', (speed) => {
280       console.info(`on setSpeed , the speed is ${speed}`);
281       // do some tasks ···
282     });
283     session.on('setLoopMode', (mode) => {
284       console.info(`on setLoopMode , the loop mode is ${mode}`);
285        // If this command is not supported, do not register it. If the command has been registered but is not used temporarily, use session.off('setLoopMode') to cancel listening.
286        // The application determines the next loop mode. After the processing is complete, call SetAVPlayState to report the new loop mode.
287     });
288     session.on('toggleFavorite', (assetId) => {
289       console.info(`on toggleFavorite , the target asset Id is ${assetId}`);
290        // If this command is not supported, do not register it. If the command has been registered but is not used temporarily, use session.off('toggleFavorite') to cancel listening.
291        // After the processing is complete, call SetAVPlayState to report the value of isFavorite.
292     });
293   }
294   ```
295
296   6.2 Listening for Advanced Playback Control Events
297
298   The following advanced playback control events can be listened for:
299
300   - **skipToQueueItem**: triggered when an item in the playlist is selected.
301   - **handleKeyEvent**: triggered when a key is pressed.
302   - **outputDeviceChange**: triggered when the output device changes.
303   - **commonCommand**: triggered when a custom playback control command changes.
304
305   ```ts
306   import { avSession as AVSessionManager } from '@kit.AVSessionKit';
307
308   let context: Context = getContext(this);
309   async function setListenerForMesFromController() {
310     // It is assumed that an AVSession object has been created. For details about how to create an AVSession object, see the node snippet in step 1.
311     let type: AVSessionManager.AVSessionType = 'audio';
312     let session = await AVSessionManager.createAVSession(context, 'SESSION_NAME', type);
313     // Generally, logic processing on the player is implemented in the listener.
314     // After the processing is complete, use the setter to synchronize the playback information. For details, see the code snippet above.
315     session.on('skipToQueueItem', (itemId) => {
316       console.info(`on skipToQueueItem , do skip task`);
317       // do some tasks ···
318     });
319     session.on('handleKeyEvent', (event) => {
320       console.info(`on handleKeyEvent , the event is ${JSON.stringify(event)}`);
321       // do some tasks ···
322     });
323     session.on('outputDeviceChange', (device) => {
324       console.info(`on outputDeviceChange , the device info is ${JSON.stringify(device)}`);
325       // do some tasks ···
326     });
327     session.on('commonCommand', (commandString, args) => {
328       console.info(`on commonCommand , command is ${commandString}, args are ${JSON.stringify(args)}`);
329       // do some tasks ···
330     });
331   }
332   ```
333
3347. Obtain an **AVSessionController** object for this **AVSession** object for interaction.
335     
336   ```ts
337   import { avSession as AVSessionManager } from '@kit.AVSessionKit';
338
339   let context: Context = getContext(this);
340   async function createControllerFromSession() {
341     // It is assumed that an AVSession object has been created. For details about how to create an AVSession object, see the node snippet in step 1.
342     let type: AVSessionManager.AVSessionType = 'audio';
343     let session = await AVSessionManager.createAVSession(context, 'SESSION_NAME', type);
344
345     // Obtain an AVSessionController object for this AVSession object.
346     let controller = await session.getController();
347
348     // The AVSessionController object can interact with the AVSession object, for example, by delivering a playback control command.
349     let avCommand: AVSessionManager.AVControlCommand = {command:'play'};
350     controller.sendControlCommand(avCommand);
351
352     // Alternatively, listen for state changes.
353     controller.on('playbackStateChange', 'all', (state) => {
354
355       // do some things
356     });
357
358     // The AVSessionController object can perform many operations. For details, see the description of the controller.
359   }
360   ```
361
3628. When the audio and video application exits and does not need to continue playback, cancel the listener and destroy the **AVSession** object.
363
364   The code snippet below is used for canceling the listener for playback control commands:
365
366   ```ts
367   import { avSession as AVSessionManager } from '@kit.AVSessionKit';
368
369   let context: Context = getContext(this);
370   async function unregisterSessionListener() {
371     // It is assumed that an AVSession object has been created. For details about how to create an AVSession object, see the node snippet in step 1.
372     let type: AVSessionManager.AVSessionType = 'audio';
373     let session = await AVSessionManager.createAVSession(context, 'SESSION_NAME', type);
374
375     // Cancel the listener of the AVSession object.
376     session.off('play');
377     session.off('pause');
378     session.off('stop');
379     session.off('playNext');
380     session.off('playPrevious');
381     session.off('skipToQueueItem');
382     session.off('handleKeyEvent');
383     session.off('outputDeviceChange');
384     session.off('commonCommand');
385   }
386   ```
387
388     The code snippet below is used for destroying the AVSession object:
389     
390   ```ts
391   import { avSession as AVSessionManager } from '@kit.AVSessionKit';
392
393   let context: Context = getContext(this);
394   async function destroySession() {
395     // It is assumed that an AVSession object has been created. For details about how to create an AVSession object, see the node snippet in step 1.
396     let type: AVSessionManager.AVSessionType = 'audio';
397     let session = await AVSessionManager.createAVSession(context, 'SESSION_NAME', type);
398     // Destroy the AVSession object.
399     session.destroy((err) => {
400       if (err) {
401         console.error(`Failed to destroy session. Code: ${err.code}, message: ${err.message}`);
402       } else {
403         console.info(`Destroy : SUCCESS `);
404       }
405     });
406   }
407   ```
408