• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# AVSession Controller
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 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 control command or key event, without holding an **AVSessionController** object.
12
13## Available APIs
14
15The table below lists the key APIs used by the controller. 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.
16
17For details, see [AVSession Management](../reference/apis/js-apis-avsession.md).
18
19| API| Description|
20| -------- | -------- |
21| getAllSessionDescriptors(callback: AsyncCallback<Array<Readonly<AVSessionDescriptor>>>): void | Obtains the descriptors of all AVSessions in the system.|
22| createController(sessionId: string, callback: AsyncCallback<AVSessionController>): void | Creates an AVSessionController.|
23| getValidCommands(callback: AsyncCallback&lt;Array&lt;AVControlCommandType&gt;&gt;): void | Obtains valid commands supported by the AVSession.<br>Control commands listened by an audio and video application when it accesses the AVSession are considered as valid commands supported by the AVSession. For details, see [Provider of AVSession](using-avsession-developer.md).|
24| getLaunchAbility(callback: AsyncCallback&lt;WantAgent&gt;): void | Obtains the UIAbility that is configured in the AVSession and can be started.<br>The UIAbility configured here is started when a user operates the UI of the controller, for example, clicking a widget in Media Controller.|
25| sendAVKeyEvent(event: KeyEvent, callback: AsyncCallback&lt;void&gt;): void | Sends a key event to an AVSession through the AVSessionController object.|
26| sendSystemAVKeyEvent(event: KeyEvent, callback: AsyncCallback&lt;void&gt;): void | Sends a key event to the top session.|
27| sendControlCommand(command: AVControlCommand, callback: AsyncCallback&lt;void&gt;): void | Sends a control command to an AVSession through the AVSessionController object.|
28| sendSystemControlCommand(command: AVControlCommand, callback: AsyncCallback&lt;void&gt;): void | Sends a control command to the top session.|
29
30## How to Develop
31
32To enable a system application to access the AVSession service as a controller, proceed as follows:
33
341. Obtain **AVSessionDescriptor** through AVSessionManager and create an **AVSessionController** object.
35   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.
36
37   ```ts
38   // Import the AVSessionManager module.
39   import AVSessionManager from '@ohos.multimedia.avsession';
40
41   // Define global variables.
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   // Obtain the session descriptors and create an AVSessionController object.
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. Listen for the session state and service state events.
61
62   The following session state events are available:
63
64   - **sessionCreate**: triggered when a session is created.
65   - **sessionDestroy**: triggered when a session is destroyed.
66   - **topSessionChange**: triggered when the top session is changed.
67
68   The service state event **sessionServiceDie** is reported when the AVSession service is abnormal.
69
70   ```ts
71   // Subscribe to the 'sessionCreate' event and create an AVSessionController object.
72   AVSessionManager.on('sessionCreate', (session) => {
73     // After an AVSession is added, you must create an AVSessionController object.
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   // Subscribe to the 'sessionDestroy' event to enable the application to get notified when the session dies.
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   // Subscribe to the 'topSessionChange' event.
92   AVSessionManager.on('topSessionChange', (session) => {
93      let index = g_controller.findIndex((controller) => {
94          return controller.sessionId === session.sessionId;
95      });
96      // Place the session on the top.
97      if (index !== 0) {
98          g_controller.sort((a, b) => {
99              return a.sessionId === session.sessionId ? -1 : 0;
100          });
101      }
102   });
103   // Subscribe to the 'sessionServiceDie' event.
104   AVSessionManager.on('sessionServiceDie', () => {
105      // The server is abnormal, and the application clears resources.
106      console.info("Server exception.");
107   })
108   ```
109
1103. Subscribe to media information changes and other session events.
111
112   The following media information change events are available:
113
114   - **metadataChange**: triggered when the session metadata changes.
115   - **playbackStateChange**: triggered when the playback state changes.
116   - **activeStateChange**: triggered when the activation state of the session changes.
117   - **validCommandChange**: triggered when the valid commands supported by the session changes.
118   - **outputDeviceChange**: triggered when the output device changes.
119   - **sessionDestroy**: triggered when a session is destroyed.
120
121   The controller can listen for events as required.
122
123   ```ts
124   // Subscribe to the 'activeStateChange' event.
125   controller.on('activeStateChange', (isActive) => {
126     if (isActive) {
127       console.info("The widget corresponding to the controller is highlighted.");
128     } else {
129       console.info("The widget corresponding to the controller is invalid.");
130     }
131   });
132   // Subscribe to the 'sessionDestroy' event to enable the controller to get notified when the session dies.
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   // Subscribe to metadata changes.
143   let metaFilter = ['assetId', 'title', 'description'];
144   controller.on('metadataChange', metaFilter, (metadata) => {
145      console.info(`on metadataChange assetId : ${metadata.assetId}`);
146   });
147   // Subscribe to playback state changes.
148   let playbackFilter = ['state', 'speed', 'loopMode'];
149   controller.on('playbackStateChange', playbackFilter, (playbackState) => {
150      console.info(`on playbackStateChange state : ${playbackState.state}`);
151   });
152   // Subscribe to supported command changes.
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   // Subscribe to output device changes.
164   controller.on('outputDeviceChange', (device) => {
165      console.info(`on outputDeviceChange device isRemote : ${device.isRemote}`);
166   });
167   ```
168
1694. 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.
170
171   ```ts
172   async getInfoFromSessionByController() {
173     // 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.
174     let controller: AVSessionManager.AVSessionController = ALLREADY_HAVE_A_CONTROLLER;
175     // Obtain the session ID.
176     let sessionId: string = controller.sessionId;
177     console.info(`get sessionId by controller : isActive : ${sessionId}`);
178     // Obtain the activation state of the session.
179     let isActive: boolean = await controller.isActive();
180     console.info(`get activeState by controller : ${isActive}`);
181     // Obtain the media information of the 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     // Obtain the playback information of the 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. Control the playback behavior, for example, sending a command to operate (play/pause/previous/next) the item being played in Media Controller.
193
194   After listening for the control command event, the audio and video application serving as the provider needs to implement the corresponding operation.
195
196
197   ```ts
198   async sendCommandToSessionByController() {
199     // 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.
200     let controller: AVSessionManager.AVSessionController = ALLREADY_HAVE_A_CONTROLLER;
201     // Obtain the commands supported by the session.
202     let validCommandTypeArray: Array<AVSessionManager.AVControlCommandType> = await controller.getValidCommands();
203     console.info(`get validCommandArray by controller : length : ${validCommandTypeArray.length}`);
204     // Deliver the 'play' command.
205     // If the 'play' command is valid, deliver it. Normal sessions should provide and implement the playback.
206     if (validCommandTypeArray.indexOf('play') >= 0) {
207       let avCommand: AVSessionManager.AVControlCommand = {command:'play'};
208       controller.sendControlCommand(avCommand);
209     }
210     // Deliver the 'pause' command.
211     if (validCommandTypeArray.indexOf('pause') >= 0) {
212       let avCommand: AVSessionManager.AVControlCommand = {command:'pause'};
213       controller.sendControlCommand(avCommand);
214     }
215     // Deliver the 'playPrevious' command.
216     if (validCommandTypeArray.indexOf('playPrevious') >= 0) {
217       let avCommand: AVSessionManager.AVControlCommand = {command:'playPrevious'};
218       controller.sendControlCommand(avCommand);
219     }
220     // Deliver the 'playNext' command.
221     if (validCommandTypeArray.indexOf('playNext') >= 0) {
222       let avCommand: AVSessionManager.AVControlCommand = {command:'playNext'};
223       controller.sendControlCommand(avCommand);
224     }
225   }
226   ```
227
2286. When the audio and video application exits, cancel the listener and release the resources.
229
230   ```ts
231   async destroyController() {
232     // 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.
233     let controller: AVSessionManager.AVSessionController = ALLREADY_HAVE_A_CONTROLLER;
234
235     // Destroy the AVSessionController object. After being destroyed, it is no longer available.
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