1# AVSession Provider (ArkTS) 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<AVSession>): void<sup>10+<sup> | Creates an AVSession.<br>Only one AVSession can be created for a UIAbility.| 20| setAVMetadata(data: AVMetadata, callback: AsyncCallback<void>): void<sup>10+<sup> | Sets AVSession metadata.| 21| setAVPlaybackState(state: AVPlaybackState, callback: AsyncCallback<void>): void<sup>10+<sup> | Sets the AVSession playback state.| 22| setLaunchAbility(ability: WantAgent, callback: AsyncCallback<void>): void<sup>10+<sup> | Starts a UIAbility.| 23| getController(callback: AsyncCallback<AVSessionController>): void<sup>10+<sup> | Obtains the controller of the AVSession.| 24| getOutputDevice(callback: AsyncCallback<OutputDeviceInfo>): void<sup>10+<sup> | Obtains the output device information.| 25| activate(callback: AsyncCallback<void>): void<sup>10+<sup> | Activates the AVSession.| 26| deactivate(callback: AsyncCallback<void>): void<sup>10+<sup> | Deactivates this session.| 27| destroy(callback: AsyncCallback<void>): void<sup>10+<sup> | Destroys the AVSession.| 28| setAVQueueItems(items: Array<AVQueueItem>, callback: AsyncCallback<void>): void <sup>10+<sup> | Sets a playlist.| 29| setAVQueueTitle(title: string, callback: AsyncCallback<void>): void<sup>10+<sup> | Sets a name for the playlist.| 30| dispatchSessionEvent(event: string, args: {[key: string]: Object}, callback: AsyncCallback<void>): void<sup>10+<sup> | Dispatches a custom session event.| 31| setExtras(extras: {[key: string]: Object}, callback: AsyncCallback<void>): 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 AVSessionManager from '@ohos.multimedia.avsession'; 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 AVSessionManager from '@ohos.multimedia.avsession'; 62 import { BusinessError } from '@ohos.base'; 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 artist: 'ARTIST' 74 }; 75 session.setAVMetadata(metadata).then(() => { 76 console.info(`SetAVMetadata successfully`); 77 }).catch((err: BusinessError) => { 78 console.error(`Failed to set AVMetadata. Code: ${err.code}, message: ${err.message}`); 79 }); 80 // Set the playback state to paused and set isFavorite to false. 81 let playbackState: AVSessionManager.AVPlaybackState = { 82 state:AVSessionManager.PlaybackState.PLAYBACK_STATE_PAUSE, 83 isFavorite:false 84 }; 85 session.setAVPlaybackState(playbackState, (err) => { 86 if (err) { 87 console.error(`Failed to set AVPlaybackState. Code: ${err.code}, message: ${err.message}`); 88 } else { 89 console.info(`SetAVPlaybackState successfully`); 90 } 91 }); 92 // Set a playlist. 93 let queueItemDescription_1: AVSessionManager.AVMediaDescription = { 94 assetId: '001', 95 title: 'music_name', 96 subtitle: 'music_sub_name', 97 description: 'music_description', 98 mediaImage: "PIXELMAP_OBJECT", 99 extras: {'extras':'any'} 100 }; 101 let queueItem_1: AVSessionManager.AVQueueItem = { 102 itemId: 1, 103 description: queueItemDescription_1 104 }; 105 let queueItemDescription_2: AVSessionManager.AVMediaDescription = { 106 assetId: '002', 107 title: 'music_name', 108 subtitle: 'music_sub_name', 109 description: 'music_description', 110 mediaImage: "PIXELMAP_OBJECT", 111 extras: {'extras':'any'} 112 }; 113 let queueItem_2: AVSessionManager.AVQueueItem = { 114 itemId: 2, 115 description: queueItemDescription_2 116 }; 117 let queueItemsArray = [queueItem_1, queueItem_2]; 118 session.setAVQueueItems(queueItemsArray).then(() => { 119 console.info(`SetAVQueueItems successfully`); 120 }).catch((err: BusinessError) => { 121 console.error(`Failed to set AVQueueItem, error code: ${err.code}, error message: ${err.message}`); 122 }); 123 // Set a name for the playlist. 124 let queueTitle = 'QUEUE_TITLE'; 125 session.setAVQueueTitle(queueTitle).then(() => { 126 console.info(`SetAVQueueTitle successfully`); 127 }).catch((err: BusinessError) => { 128 console.info(`Failed to set AVQueueTitle, error code: ${err.code}, error message: ${err.message}`); 129 }); 130 } 131 ``` 132 1333. 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. 134 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 "@ohos.app.ability.wantAgent"; 139 ``` 140 141 ```ts 142 import AVSessionManager from '@ohos.multimedia.avsession'; 143 import wantAgent from '@ohos.app.ability.wantAgent'; 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: 'com.example.musicdemo.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 AVSessionManager from '@ohos.multimedia.avsession'; 176 import { BusinessError } from '@ohos.base'; 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 AVSessionManager from '@ohos.multimedia.avsession'; 201 import { BusinessError } from '@ohos.base'; 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 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 AVSessionManager from '@ohos.multimedia.avsession'; 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 // do some tasks ··· 241 }); 242 session.on('pause', () => { 243 console.info(`on pause , do pause task`); 244 // do some tasks ··· 245 }); 246 session.on('stop', () => { 247 console.info(`on stop , do stop task`); 248 // do some tasks ··· 249 }); 250 session.on('playNext', () => { 251 console.info(`on playNext , do playNext task`); 252 // do some tasks ··· 253 }); 254 session.on('playPrevious', () => { 255 console.info(`on playPrevious , do playPrevious task`); 256 // do some tasks ··· 257 }); 258 session.on('fastForward', () => { 259 console.info(`on fastForward , do fastForward task`); 260 // do some tasks ··· 261 }); 262 session.on('rewind', () => { 263 console.info(`on rewind , do rewind task`); 264 // do some tasks ··· 265 }); 266 267 session.on('seek', (time) => { 268 console.info(`on seek , the seek time is ${time}`); 269 // do some tasks ··· 270 }); 271 session.on('setSpeed', (speed) => { 272 console.info(`on setSpeed , the speed is ${speed}`); 273 // do some tasks ··· 274 }); 275 session.on('setLoopMode', (mode) => { 276 console.info(`on setLoopMode , the loop mode is ${mode}`); 277 // do some tasks ··· 278 }); 279 session.on('toggleFavorite', (assetId) => { 280 console.info(`on toggleFavorite , the target asset Id is ${assetId}`); 281 // do some tasks ··· 282 }); 283 } 284 ``` 285 286 6.2 Listening for Advanced Playback Control Events 287 288 The following advanced playback control events can be listened for: 289 290 - **skipToQueueItem**: triggered when an item in the playlist is selected. 291 - **handleKeyEvent**: triggered when a key is pressed. 292 - **outputDeviceChange**: triggered when the output device changes. 293 - **commonCommand**: triggered when a custom playback control command changes. 294 295 ```ts 296 import AVSessionManager from '@ohos.multimedia.avsession'; 297 298 let context: Context = getContext(this); 299 async function setListenerForMesFromController() { 300 // 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. 301 let type: AVSessionManager.AVSessionType = 'audio'; 302 let session = await AVSessionManager.createAVSession(context, 'SESSION_NAME', type); 303 // Generally, logic processing on the player is implemented in the listener. 304 // After the processing is complete, use the setter to synchronize the playback information. For details, see the code snippet above. 305 session.on('skipToQueueItem', (itemId) => { 306 console.info(`on skipToQueueItem , do skip task`); 307 // do some tasks ··· 308 }); 309 session.on('handleKeyEvent', (event) => { 310 console.info(`on handleKeyEvent , the event is ${JSON.stringify(event)}`); 311 // do some tasks ··· 312 }); 313 session.on('outputDeviceChange', (device) => { 314 console.info(`on outputDeviceChange , the device info is ${JSON.stringify(device)}`); 315 // do some tasks ··· 316 }); 317 session.on('commonCommand', (commandString, args) => { 318 console.info(`on commonCommand , command is ${commandString}, args are ${JSON.stringify(args)}`); 319 // do some tasks ··· 320 }); 321 } 322 ``` 323 3247. Obtain an **AVSessionController** object for this **AVSession** object for interaction. 325 326 ```ts 327 import AVSessionManager from '@ohos.multimedia.avsession'; 328 329 let context: Context = getContext(this); 330 async function createControllerFromSession() { 331 // 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. 332 let type: AVSessionManager.AVSessionType = 'audio'; 333 let session = await AVSessionManager.createAVSession(context, 'SESSION_NAME', type); 334 335 // Obtain an AVSessionController object for this AVSession object. 336 let controller = await session.getController(); 337 338 // The AVSessionController object can interact with the AVSession object, for example, by delivering a playback control command. 339 let avCommand: AVSessionManager.AVControlCommand = {command:'play'}; 340 controller.sendControlCommand(avCommand); 341 342 // Alternatively, listen for state changes. 343 controller.on('playbackStateChange', 'all', (state) => { 344 345 // do some things 346 }); 347 348 // The AVSessionController object can perform many operations. For details, see the description of the controller. 349 } 350 ``` 351 3528. When the audio and video application exits and does not need to continue playback, cancel the listener and destroy the **AVSession** object. 353 354 The code snippet below is used for canceling the listener for playback control commands: 355 356 ```ts 357 import AVSessionManager from '@ohos.multimedia.avsession'; 358 359 let context: Context = getContext(this); 360 async function unregisterSessionListener() { 361 // 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. 362 let type: AVSessionManager.AVSessionType = 'audio'; 363 let session = await AVSessionManager.createAVSession(context, 'SESSION_NAME', type); 364 365 // Cancel the listener of the AVSession object. 366 session.off('play'); 367 session.off('pause'); 368 session.off('stop'); 369 session.off('playNext'); 370 session.off('playPrevious'); 371 session.off('skipToQueueItem'); 372 session.off('handleKeyEvent'); 373 session.off('outputDeviceChange'); 374 session.off('commonCommand'); 375 } 376 ``` 377 378 The code snippet below is used for destroying the AVSession object: 379 380 ```ts 381 import AVSessionManager from '@ohos.multimedia.avsession'; 382 383 let context: Context = getContext(this); 384 async function destroySession() { 385 // 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. 386 let type: AVSessionManager.AVSessionType = 'audio'; 387 let session = await AVSessionManager.createAVSession(context, 'SESSION_NAME', type); 388 // Destroy the AVSession object. 389 session.destroy((err) => { 390 if (err) { 391 console.error(`Failed to destroy session. Code: ${err.code}, message: ${err.message}`); 392 } else { 393 console.info(`Destroy : SUCCESS `); 394 } 395 }); 396 } 397 ``` 398