In addition to implementing audio and video features, audio and video applications need to access AVSession provided by AVSession Kit. This topic uses typical cases to describe display and control scenarios for accessing AVSession, providing adaptation references for developers.
Different UIs are displayed in the system controller for different scenarios. In different scenarios, application access processing must also follow different specifications and constraints.
AVSession restricts background audio playback and VoIP calls. Therefore, applications that provide long-duration audio playback, audiobooks, long-duration video playback, and VoIP calls need to access AVSession. If such an application does not create an AVSession during these services, the system stops the corresponding audio playback or mutes the call when detecting that the application is running in the background. In this way, the application behavior is restricted. You can verify the restriction locally before the application is released.
For other applications that use audio playback, such as games and live streams, accessing AVSession is optional, depending on whether the application requires background playback. If background playback is required, AVSession access is still mandatory. Otherwise, normal service functions will be restricted.
To implement background playback, the application must also use Background Tasks Kit to request a continuous task to avoid being suspended.
The process for implementing AVSession access is as follows:
AVSessionType in the constructor determines the type of AVSession to create. Different AVSession types represent the control capabilities in various scenarios and display different control templates in the controller.
For audio AVSession, the controller provides the following control buttons: favorite, previous, play/pause, next, and loop mode.
For video AVSession, the controller provides the following control buttons: rewind, previous, play/pause, next, and fast-forward.
For voice_call AVSession, the application is not displayed in the controller.
Refer to the code snippet below:
The sample code below demonstrates only the API call for creating an AVSession object. When actually using it, the application must ensure that the AVSession object remains throughout the application's background playback activities. This prevents the system from reclaiming or releasing it, which could lead to playback being controlled by the system.
import { avSession as AVSessionManager } from '@kit.AVSessionKit';
// ...
@Entry
@Component
struct Index {
@State message: string = 'hello world';
// ...
build() {
Column() {
// ...
Text(this.message)
.onClick(async () => {
// Start to create and activate an AVSession object.
// Create an AVSession object.
let context = this.getUIContext().getHostContext() as Context;
let type: AVSessionManager.AVSessionType = 'audio';
let session = await AVSessionManager.createAVSession(context, 'SESSION_NAME', type);
// Call activate() after the metadata and control commands are registered.
await session.activate();
console.info(`session create done : sessionId : ${session.sessionId}`);
// ...
})
}
.width('100%')
.height('100%')
}
} To implement background playback, the application must also use Background Tasks Kit to request a continuous task to avoid being suspended.
Media playback applications must request a continuous task of the AUDIO_PLAYBACK background mode.
The application uses setAVMetadata to set the metadata information of the current media session to the system. The system controller displays information based on the metadata set by the application.
Metadata information AVMetadata includes the ID of the current media (assetId), ID of the previous media (previousAssetId), ID of the next media (nextAssetId), title (title), album author (author), artist (artist), album name (album), lyricist (writer), media image (mediaImage), and media duration (duration).
import { avSession as AVSessionManager } from '@kit.AVSessionKit';
import { BusinessError } from '@kit.BasicServicesKit';
// ...
@Entry
@Component
struct Index {
@State message: string = 'hello world';
// ...
build() {
Column() {
// ...
Text(this.message)
.onClick(async () => {
try {
let context = this.getUIContext().getHostContext() as Context;
// It is assumed that an AVSession object has been created. For details about how to create an AVSession object, see the preceding example.
let session = await AVSessionManager.createAVSession(context, 'SESSION_NAME', 'audio');
// Set necessary AVSession metadata.
let metadata: AVSessionManager.AVMetadata = {
assetId: '0', // Specified by the application, used to identify the media asset in the application media library.
title: 'TITLE',
mediaImage: 'IMAGE',
artist: 'ARTIST',
};
session.setAVMetadata(metadata).then(() => {
console.info(`SetAVMetadata successfully`);
// ...
}).catch((err: BusinessError) => {
console.error(`Failed to set AVMetadata. Code: ${err.code}, message: ${err.message}`);
// ...
});
} catch (err) {
if (err) {
console.error(`AVSession create Error: Code: ${err.code}, message: ${err.message}`);
// ...
}
}
})
}
.width('100%')
.height('100%')
}
} Metadata AVMetadata contains lyric fields. The application can set lyric fields to display lyrics in certain scenarios. Currently, two lyric fields can be set:
lyric: complete lyrics of the media asset. The system controller displays lyric content based on this field. The application needs to concatenate the lyric content into a string and pass it in.
singleLyricText: a single line of lyric text. The system Bluetooth module displays lyric content in certain scenarios, such as Bluetooth speakers, based on this field.
The lyric field supports only lyrics in LRC format (time tags plus lyric information, for example, [00:25.44]lyric information). If you pass lyrics in other formats, the system Media Controller may fail to parse them, causing abnormal lyric display.
The size of both the lyric field and the singleLyricText field must not exceed 40960 bytes. Otherwise, the lyric information fails to be set due to system transmission limits.
import { avSession as AVSessionManager } from '@kit.AVSessionKit';
import { BusinessError } from '@kit.BasicServicesKit';
// ...
@Entry
@Component
struct Index {
@State message: string = 'hello world';
// ...
build() {
Column() {
// ...
Text(this.message)
.onClick(async () => {
let context = this.getUIContext().getHostContext() as Context;
// It is assumed that an AVSession object has been created. For details about how to create an AVSession object, see the preceding example.
let type: AVSessionManager.AVSessionType = 'audio';
let session = await AVSessionManager.createAVSession(context, 'SESSION_NAME', type);
// Set the lyric to AVSession.
let metadata: AVSessionManager.AVMetadata = {
assetId: '0',
title: 'TITLE',
mediaImage: 'IMAGE',
// The LRC contains two types of elements: time tag + lyrics, and ID tag.
// Example: [00:25.44]xxx\r\n[00:26.44]xxx\r\n
lyric: 'Lyrics in LRC format',
// The singleLyricText field stores a single line of lyric text without timestamps.
// Example: "Content of a single lyric line"
singleLyricText: 'Content of a single lyric line',
};
session.setAVMetadata(metadata).then(() => {
console.info(`SetAVMetadata successfully`);
// ...
}).catch((err: BusinessError) => {
console.error(`Failed to set AVMetadata. Code: ${err.code}, message: ${err.message}`);
// ...
});
// ...
})
}
.width('100%')
.height('100%')
}
} The metadata AVMetadata contains the duration field, in ms. To display the progress bar of a media asset in the controller, set the correct playback duration in duration.
import { avSession as AVSessionManager } from '@kit.AVSessionKit';
import { BusinessError } from '@kit.BasicServicesKit';
// ...
@Entry
@Component
struct Index {
@State message: string = 'hello world';
// ...
build() {
Column() {
// ...
Text(this.message)
.onClick(async () => {
let context = this.getUIContext().getHostContext() as Context;
// It is assumed that an AVSession object has been created. For details about how to create an AVSession object, see the preceding example.
let type: AVSessionManager.AVSessionType = 'audio';
let session = await AVSessionManager.createAVSession(context, 'SESSION_NAME', type);
// Set the media resource duration.
let metadata: AVSessionManager.AVMetadata = {
assetId: '0',
title: 'TITLE',
mediaImage: 'IMAGE',
duration: 23000, // Duration of the media asset, in milliseconds.
};
session.setAVMetadata(metadata).then(() => {
console.info(`SetAVMetadata successfully`);
// ...
}).catch((err: BusinessError) => {
console.error(`Failed to set AVMetadata. Code: ${err.code}, message: ${err.message}`);
// ...
});
// Set the playback state information, including the playback state, position, speed, and buffered time.
let playbackState: AVSessionManager.AVPlaybackState = {
state: AVSessionManager.PlaybackState.PLAYBACK_STATE_PLAY, // Playing state.
position: {
elapsedTime: 1000, // Playback position, in milliseconds.
updateTime: new Date().getTime(), // Timestamp when the application updates the current position, in milliseconds.
},
speed: 1.0, // Optional. The default value is 1.0. The playback speed is set based on the speed supported by the application. The system does not verify the speed.
bufferedTime: 14000, // Optional. Buffered time, in milliseconds.
};
session.setAVPlaybackState(playbackState, (err) => {
if (err) {
console.error(`Failed to set AVPlaybackState. Code: ${err.code}, message: ${err.message}`);
// ...
} else {
console.info(`SetAVPlaybackState successfully`);
// ...
}
});
// ...
})
}
.width('100%')
.height('100%')
}
} The system controller automatically calculates the playback progress based on the information set by the application. The application does not need to update the playback progress in real time. However, when the state, position, or speed changes, the application must update AVPlaybackState. Otherwise, the application state information and progress bar information displayed in the controller may be abnormal.
The application reports the start position of the progress once the actual playback starts. If the playback is in the buffer state, the application can report AVSessionManager.PlaybackState.PLAYBACK_STATE_BUFFERING to instruct the system not to update the progress.
Certain special processing is required when setting the progress bar.
Songs that can be previewed
(1) The application sets the preview duration, rather than the total duration, for a song. In this case, when the user performs progress control in the controller, the application receives the relative timestamp within the preview duration, rather than that within the total duration. The application needs to calculate the absolute timestamp from the very beginning of the song.
(2) The application sets the total duration for a song but requires the system to provide preview, the application can report the start position of the progress when the playback starts, and report the end position when the received seek instruction is not within the preview duration. In the latter case, the playback control progress of the system rebounds.
Songs that do not support preview
If a song cannot be previewed, it cannot be displayed by the application. In this case, the application should set the duration to -1, so the system does not display the actual duration.
Special contents such as ads
For media assets with pre-roll or post-roll ads, you are advised to:
For music and audiobook apps, the media controller provides a series of quick playback capabilities, including instant cold start playback and access to historical playlists. The supported audio content for the playlists includes music tracks, audiobook collections, and podcast series. Video and live streaming media do not support the playlist features. To integrate the preceding features, your app needs to register and adapt to the playback intent for background startup on the device. For details about the experience self-check after the integration, see Quick Playback.
You can refer to the code snippet below to register the playback intent, set playlist information, and start intent-based playback.
Registering the Playback Intent
Your app can register the PlayMusicList intent (for music apps) or PlayAudio intent (for audiobook apps) based on the playback service. Edit the intent configuration file PROJECT_HOME/entry/src/main/resources/base/profile/insight_intent.json to register the playback intent.
The following is an example of intent registration:
{
// List of intents supported by the app.
"insightIntents": [
{
// Intent name.
// The name must comply with the Intents Kit specifications. Currently, only predefined intents for specific vertical domains are supported.
// Each intent name must be unique in an app.
"intentName": "PlayMusicList", // PlayMusicList intent for music apps; PlayAudio intent for audiobook apps.
// Vertical domain to which the intent belongs.
"domain": "MusicDomain", // MusicDomain for music apps; AudioDomain for audiobook apps.
// Intent version number.
// The version number is verified when a plug-in references the intent. The intent can be called only when the version number is the same as that defined by the plug-in.
"intentVersion": "1.0.1",
// Entry to the intent call logic.
"srcEntry": "./ets/entryability/InsightIntentExecutorImpl.ets",
"uiAbility": {
// Module and ability to which the intent belongs, as well as the relative path entry of the code.
"ability": "EntryAbility",
// UIAbility supports two execution modes: foreground and background.
"executeMode": [
"background", // The features of instant cold start playback and access to the historical playlist require the app to support the background launch mode.
"foreground"
]
}
}
]
} Setting Playlist Information
Call the setAVMetadata API to set the playlist information for the content that is being played. The playlist information consists of the following fields:
The system updates the media information in real time based on the information reported by the app. Therefore, once accessing a playlist, the app must keep reporting the playlist data in AVMetadata.
import { avSession as AVSessionManager } from '@kit.AVSessionKit';
import { BusinessError } from '@kit.BasicServicesKit';
let context: Context = getContext(this);
async function setListener() {
// It is assumed that an AVSession object has been created. For details about how to create an AVSession object, see the node snippet above.
let type: AVSessionManager.AVSessionType = 'audio';
let session = await AVSessionManager.createAVSession(context, 'SESSION_NAME', type);
// Set the playlist information on AVSession.
let metadata: AVSessionManager.AVMetadata = {
// The following content is set by the app.
assetId: 'musicid123',
avQueueName: 'myQueue',
avQueueId: 'myQueue123',
avQueueImage: "PIXELMAP_OBJECT",
};
session.setAVMetadata(metadata).then(() => {
console.info(`SetAVMetadata successfully`);
}).catch((err: BusinessError) => {
console.error(`Failed to set AVMetadata. Code: ${err.code}, message: ${err.message}`);
});
// Report the playback state. For details, see the playback state.
} Implementing Intent-based Playback
After the app integrates the playlist feature, users can play its playlists on the media controller. If the app process is terminated, users can initiate cold start of the app again for background playback via the media controller.
import { insightIntent, InsightIntentExecutor } from '@kit.AbilityKit';
import { window } from '@kit.ArkUI';
import { BusinessError } from '@kit.BasicServicesKit';
/**
* Intent call example.
*/
export default class InsightIntentExecutorImpl extends InsightIntentExecutor {
/**
* Override the background UIAbility launch intent.
*
* @param intentName Intent name.
* @param intentParam Intent parameter.
* @returns Intent call result.
*/
async onExecuteInUIAbilityBackgroundMode(intentName: string, intentParam: Record<string, Object>):
Promise<insightIntent.ExecuteResult> {
// Distribute the processing logic based on the intent name.
switch (intentName) {
case 'PlayMusicList':
// Parse PlayMusicList as follows:
const entityId: string = (typeof intentParam.entityId === 'string') ? intentParam.entityId : '';
return this.playFunc(entityId);
case 'PlayAudio':
// Parse PlayAudio as follows:
let data = intentParam as Record<string, string>;
return this.playFunc(data.entityId);
default:
break;
}
const data: insightIntent.ExecuteResult = {
code: -1,
result: {
message: 'unknown intent'
}
};
return Promise.resolve(data);
}
/**
* Implement the playback.
*
* @param entityId ID of the content to play.
*/
private playFunc(entityId: string): Promise<insightIntent.ExecuteResult> {
// If entityId is not empty, the content (playlist or album) specified by the user will be played.
// If entityId is empty (entityId.length == 0), the app determines the content to be played, which can be a historical or recommended playlist.
// The app is launched in the background for playback. It needs to initialize the playback resources, set AVMetadata, register playback control callbacks, and request a continuous playback task.
// TODO: Implement the specific playback service.
return Promise.resolve({
code: 0,
result: {
message: 'Intent execute succeed'
}
} as insightIntent.ExecuteResult)
}
} The metadata AVMetadata provides the displayTags field for displaying the media asset tag, which identifies the audio source of the application. After the application sets displayTags, the system controller displays the tag synchronously. Currently, only the Audio Vivid tag is supported.
import { avSession as AVSessionManager } from '@kit.AVSessionKit';
import { BusinessError } from '@kit.BasicServicesKit';
// ...
@Entry
@Component
struct Index {
@State message: string = 'hello world';
// ...
build() {
Column() {
// ...
Text(this.message)
.onClick(async () => {
let context = this.getUIContext().getHostContext() as Context;
// It is assumed that an AVSession object has been created. For details about how to create an AVSession object, see the preceding example.
let type: AVSessionManager.AVSessionType = 'audio';
let session = await AVSessionManager.createAVSession(context, 'SESSION_NAME', type);
// Set the media audio source information to AVSession.
let metadata: AVSessionManager.AVMetadata = {
assetId: '0',
title: 'TITLE',
mediaImage: 'IMAGE',
// The media audio source is Audio Vivid.
displayTags: AVSessionManager.DisplayTag.TAG_AUDIO_VIVID,
};
session.setAVMetadata(metadata).then(() => {
console.info(`SetAVMetadata successfully`);
// ...
}).catch((err: BusinessError) => {
console.error(`Failed to set AVMetadata. Code: ${err.code}, message: ${err.message}`);
// ...
});
// ...
})
}
.width('100%')
.height('100%')
}
} The application uses setAVPlaybackState to set the playback state information of the current media session to the system. The system controller strictly displays information based on the playback state information passed by the application.
Playback state information AVPlaybackState includes the playback state of the current media (state), playback position (position, which contains the elapsed playback time elapsedTime and the update timestamp updateTime), playback speed (speed), buffered time (bufferedTime), loop mode (loopMode), whether the media is marked as favorite (isFavorite), ID of the media being played (activeItemId), and custom media data (extras).
import { avSession as AVSessionManager } from '@kit.AVSessionKit';
import { BusinessError } from '@kit.BasicServicesKit';
// ...
@Entry
@Component
struct Index {
@State message: string = 'hello world';
// ...
build() {
Column() {
// ...
Text(this.message)
.onClick(async () => {
let context = this.getUIContext().getHostContext() as Context;
// It is assumed that an AVSession object has been created. For details about how to create an AVSession object, see the preceding example.
let session = await AVSessionManager.createAVSession(context, 'SESSION_NAME', 'audio');
// Player logic that triggers changes in media information and playback state is omitted here.
// Set the playback state to paused and set isFavorite to false.
let playbackState: AVSessionManager.AVPlaybackState = {
state: AVSessionManager.PlaybackState.PLAYBACK_STATE_PAUSE,
isFavorite: false
};
session.setAVPlaybackState(playbackState, (err: BusinessError) => {
if (err) {
console.error(`Failed to set AVPlaybackState. Code: ${err.code}, message: ${err.message}`);
// ...
} else {
console.info(`SetAVPlaybackState successfully`);
// ...
}
});
// ...
})
}
.width('100%')
.height('100%')
}
} After an application accesses AVSession, it can register control commands through on() to implement the corresponding control button operations in the controller.
After an AVSession object is created, register control commands supported by the application before activating the object.
The following table lists the control commands supported by audio and video applications.
| Control Command | Description |
|---|---|
| play | Play command. |
| pause | Pause command. |
| stop | Stop command. |
| playNext | Play next command. |
| playPrevious | Play previous command. |
| fastForward | Fast-forward command. |
| rewind | Rewind command. |
| playWithAssetId | Plays a media asset based on a specified asset ID. |
| seek | Seek command. |
| setSpeed | Set playback speed command. |
| setLoopMode | Set loop mode command. |
| toggleFavorite | Sets whether a media asset is favorited. |
| skipToQueueItem | Selects an item in the playlist for playback. |
| handleKeyEvent | Sets a key event command. |
| commonCommand | Sets a custom control command. |
The following table lists the control commands supported by call applications.
| Control Command | Description |
|---|---|
| answer | Answer call command. |
| hangUp | Hang up call command. |
| toggleCallMute | Mutes or unmutes a call. |
If the application does not support certain control command operations, for example, the playPrevious command, it can use off() to deregister the corresponding control command. The system controller then grays out or hides the corresponding control button to clearly inform users that the application does not support this control operation.
import { avSession as AVSessionManager } from '@kit.AVSessionKit';
@Entry
@Component
struct Index {
@State message: string = 'hello world';
build() {
Column() {
Text(this.message)
.onClick(async () => {
let context = this.getUIContext().getHostContext() as Context;
// It is assumed that an AVSession object has been created. For details about how to create an AVSession object, see the preceding example.
let type: AVSessionManager.AVSessionType = 'audio';
let session = await AVSessionManager.createAVSession(context, 'SESSION_NAME', type);
// Cancel the listener of the AVSession object.
session.off('play');
session.off('pause');
session.off('stop');
session.off('playNext');
session.off('playPrevious');
// ...
})
}
.width('100%')
.height('100%')
}
} The application can call APIs to set the fast-forward/rewind intervals in three different ways. It also registers the fast-forward/rewind control command to respond to user operations.
When applications register commands for fast-forward/rewind and next/previous track switching, there are differences in the display on the controller.
When AVSessionType is audio:
| Registered Event Combination | Controller Buttons | Button Availability |
|---|---|---|
| No events registered | Previous, Next | All buttons are unavailable. |
| Previous/Next events registered | Previous, Next | If previous events registered, the Previous button is available. If next events registered, the Next button is available. Buttons corresponding to unregistered events are unavailable. |
| Fast-forward/rewind events registered | Previous, Next | All buttons are unavailable. |
| Previous/Next and fast-forward/rewind events registered | Previous, Next | If previous events registered, the Previous button is available. If next events registered, the Next button is available. Buttons corresponding to unregistered events are unavailable. |
When AVSessionType is video:
| Registered Event Combination | Controller Buttons | Button Availability |
|---|---|---|
| No events registered | Fast-Forward, Rewind | All buttons are unavailable. |
| Previous/Next events registered | Previous, Next | If previous events registered, the Previous button is available. If next events registered, the Next button is available. Buttons corresponding to unregistered events are unavailable. |
| Fast-forward/rewind events registered | Fast-Forward, Rewind | If fast-forward events are registered, the Fast-Forward button is available. If rewind events are registered, the Rewind button is available. Buttons corresponding to unregistered events are unavailable. |
| Previous/Next and fast-forward/rewind events registered | Fast-Forward, Rewind | If fast-forward events are registered, the Fast-Forward button is available. If rewind events are registered, the Rewind button is available. Buttons corresponding to unregistered events are unavailable. |
import { avSession as AVSessionManager } from '@kit.AVSessionKit';
import { BusinessError } from '@kit.BasicServicesKit';
// ...
@Entry
@Component
struct Index {
@State message: string = 'hello world';
build() {
Column() {
Text(this.message)
.onClick(async () => {
let context = this.getUIContext().getHostContext() as Context;
// It is assumed that an AVSession object has been created. For details about how to create an AVSession object, see the preceding example.
let type: AVSessionManager.AVSessionType = 'audio';
let session = await AVSessionManager.createAVSession(context, 'SESSION_NAME', type);
// Set the supported fast-forward or rewind duration for AVSession.
let metadata: AVSessionManager.AVMetadata = {
assetId: '0', // Specified by the application, used to identify the media asset in the application media library.
title: 'TITLE',
mediaImage: 'IMAGE',
skipIntervals: AVSessionManager.SkipIntervals.SECONDS_10,
};
session.setAVMetadata(metadata).then(() => {
console.info(`SetAVMetadata successfully`);
}).catch((err: BusinessError) => {
console.error(`Failed to set AVMetadata. Code: ${err.code}, message: ${err.message}`);
});
session.on('fastForward', (time?: number) => {
console.info(`on fastForward , do fastForward task`);
// Do some tasks.
});
session.on('rewind', (time?: number) => {
console.info(`on rewind , do rewind task`);
// Do some tasks.
});
})
}
.width('100%')
.height('100%')
}
} To implement favoriting, a music application must call on('toggleFavorite') to register the toggleFavorite control command.
import { avSession as AVSessionManager } from '@kit.AVSessionKit';
import { BusinessError } from '@kit.BasicServicesKit';
@Entry
@Component
struct Index {
@State message: string = 'hello world';
build() {
Column() {
Text(this.message)
.onClick(async () => {
let context = this.getUIContext().getHostContext() as Context;
// It is assumed that an AVSession object has been created. For details about how to create an AVSession object, see the preceding example.
let type: AVSessionManager.AVSessionType = 'audio';
let session = await AVSessionManager.createAVSession(context, 'SESSION_NAME', type);
session.on('toggleFavorite', (assetId) => {
console.info(`on toggleFavorite `);
// The application receives the toggleFavorite command and favorites or unfavorites the media asset.
// Set the new state to AVSession after the application finishes favoriting or unfavoriting.
let playbackState: AVSessionManager.AVPlaybackState = {
isFavorite: true,
};
session.setAVPlaybackState(playbackState).then(() => {
console.info(`SetAVPlaybackState successfully`);
}).catch((err: BusinessError) => {
console.error(`SetAVPlaybackState BusinessError: code: ${err.code}, message: ${err.message}`);
});
});
})
}
.width('100%')
.height('100%')
}
} For music applications, the system controller displays loop mode control operations by default. Currently, the system supports four fixed loop mode controls. For details, see LoopMode.
The controller supports switching between four fixed loop modes: shuffle, sequential playback, single loop, and playlist loop. After the application receives the loop mode switching command and completes the switching, it needs to report the switched LoopMode to the system.
If the LoopMode supported by the application is not one of the four fixed loop modes of the system, select one of the four fixed loop modes to report to the system. The mapping is customized by the application.
Refer to the code snippet below:
import { avSession as AVSessionManager } from '@kit.AVSessionKit';
import { BusinessError } from '@kit.BasicServicesKit';
@Entry
@Component
struct Index {
@State message: string = 'hello world';
build() {
Column() {
Text(this.message)
.onClick(async () => {
let context = this.getUIContext().getHostContext() as Context;
// It is assumed that an AVSession object has been created. For details about how to create an AVSession object, see the preceding example.
let type: AVSessionManager.AVSessionType = 'audio';
let session = await AVSessionManager.createAVSession(context, 'SESSION_NAME', type);
// When the application starts or switches the loop mode, it sets the loop mode in use to the AVSession.
let playBackState: AVSessionManager.AVPlaybackState = {
loopMode: AVSessionManager.LoopMode.LOOP_MODE_SINGLE,
};
session.setAVPlaybackState(playBackState).then(() => {
console.info(`set AVPlaybackState successfully`);
}).catch((err: BusinessError) => {
console.error(`Failed to set AVPlaybackState. Code: ${err.code}, message: ${err.message}`);
});
// The application listens for loop mode changes.
session.on('setLoopMode', (mode) => {
console.info(`on setLoopMode ${mode}`);
// After receiving the instruction for setting the loop mode, the application determines the next mode. After the switching is complete, the application reports the new loop mode through AVPlaybackState.
let playBackState: AVSessionManager.AVPlaybackState = {
loopMode: AVSessionManager.LoopMode.LOOP_MODE_SINGLE,
};
session.setAVPlaybackState(playBackState).then(() => {
console.info(`set AVPlaybackState successfully`);
}).catch((err: BusinessError) => {
console.error(`Failed to set AVPlaybackState. Code: ${err.code}, message: ${err.message}`);
});
});
})
}
.width('100%')
.height('100%')
}
} An application that supports progress display can further support progress control. To support progress control, the application must respond to the seek control command. When users drag the progress bar in the controller, the application receives a callback. Refer to the code snippet below:
import { avSession as AVSessionManager } from '@kit.AVSessionKit';
@Entry
@Component
struct Index {
@State message: string = 'hello world';
build() {
Column() {
Text(this.message)
.onClick(async () => {
let context = this.getUIContext().getHostContext() as Context;
// It is assumed that an AVSession object has been created. For details about how to create an AVSession object, see the preceding example.
let type: AVSessionManager.AVSessionType = 'audio';
let session = await AVSessionManager.createAVSession(context, 'SESSION_NAME', type);
session.on('seek', (time: number) => {
console.info(`on seek , the time is ${time}`);
// The seek operation may trigger a long buffering time. You can set the playback state to PLAYBACK_STATE_BUFFERING.
let playbackState: AVSessionManager.AVPlaybackState = {
state: AVSessionManager.PlaybackState.PLAYBACK_STATE_BUFFERING, // Buffering state.
};
session.setAVPlaybackState(playbackState, (err) => {
if (err) {
console.error(`Failed to set AVPlaybackState. Code: ${err.code}, message: ${err.message}`);
} else {
console.info(`SetAVPlaybackState successfully`);
}
});
// The application responds to the seek command and seeks to the specified position.
// After seeking to the specified position, the application synchronizes the new position to the system.
playbackState.state = AVSessionManager.PlaybackState.PLAYBACK_STATE_PLAY; // Playing state.
playbackState.position = {
elapsedTime: time, // Playback position, in milliseconds.
updateTime: new Date().getTime(), // Timestamp when the application updates the current position, in milliseconds.
}
session.setAVPlaybackState(playbackState, (err) => {
if (err) {
console.error(`Failed to set AVPlaybackState. Code: ${err.code}, message: ${err.message}`);
} else {
console.info(`SetAVPlaybackState successfully`);
}
});
});
})
}
.width('100%')
.height('100%')
}
} When an application correctly accesses AVSession according to the preceding process, sets metadata information and correct playback state information, and registers control commands, the system notification and lock screen display information about the playing application when the application enters the playing state.
After an application correctly accesses AVSession, it can listen for Bluetooth and wired headset key events by registering control commands. AVSession provides the following two implementation methods:
Method 1 (recommended)
You can register the required control commands as needed by referring to Control Command Processing. The AVSession control commands that can be converted are as follows:
| Control Command | Description |
|---|---|
| play | Plays the media. |
| pause | Pauses the playback. |
| stop | Stops the playback. |
| playNext | Plays the next media asset. |
| playPrevious | Plays the previous media asset. |
| fastForward | Fast-forwards. |
| rewind | Rewinds. |
import { avSession as AVSessionManager } from '@kit.AVSessionKit';
import { BusinessError } from '@kit.BasicServicesKit';
// ...
@Entry
@Component
struct Index {
@State message: string = 'hello world';
// ...
build() {
Column() {
// ...
Text(this.message)
.onClick(async () => {
try {
let context = this.getUIContext().getHostContext() as Context;
let type: AVSessionManager.AVSessionType = 'audio';
let session = await AVSessionManager.createAVSession(context, 'SESSION_NAME', type);
// ...
// Set the necessary media information. This must be set; otherwise, control events cannot be received.
let metadata: AVSessionManager.AVMetadata = {
assetId: '0', // Specified by the application to identify the media in the application's media library.
title: 'TITLE',
mediaImage: 'IMAGE',
artist: 'ARTIST'
};
session.setAVMetadata(metadata).then(() => {
console.info(`SetAVMetadata successfully`);
// ...
}).catch((err: BusinessError) => {
console.error(`Failed to set AVMetadata. Code: ${err.code}, message: ${err.message}`);
// ...
});
// Generally, corresponding logic processing is performed on the player in the listener.
// After processing, synchronize the playback-related information through the set API. Refer to the use case above.
session.on('play', () => {
console.info(`on play , do play task`);
// ...
// If this command is not supported yet, do not register it; or if it is registered but not used temporarily, cancel the listening through session.off('play').
// After processing, use setAVPlaybackState to report the playback state.
});
session.on('pause', () => {
console.info(`on pause , do pause task`);
// ...
// If this command is not supported yet, do not register it; or if it is registered but not used temporarily, cancel the listening through session.off('pause').
// After processing, use setAVPlaybackState to report the playback state.
});
// ...
} catch (err) {
if (err) {
console.error(`AVSession create Error: Code: ${err.code}, message: ${err.message}`);
// ...
}
}
})
}
.width('100%')
.height('100%')
}
} Method 2
Register the on('handleKeyEvent') command through AVSession. This callback directly forwards the media key event KeyEvent. You need to identify the type of the key event and respond to the event to implement the corresponding function. The key event types that can be forwarded are as follows:
| Key Type (KeyCode) | Description |
|---|---|
| KEYCODE_MEDIA_PLAY_PAUSE | Play/Pause key. |
| KEYCODE_MEDIA_STOP | Stop key. |
| KEYCODE_MEDIA_NEXT | Next key. |
| KEYCODE_MEDIA_PREVIOUS | Previous key. |
| KEYCODE_MEDIA_REWIND | Rewind key. |
| KEYCODE_MEDIA_FAST_FORWARD | Fast-forward key. |
| KEYCODE_MEDIA_PLAY | Play key. |
| KEYCODE_MEDIA_PAUSE | Pause key. |
import { avSession as AVSessionManager } from '@kit.AVSessionKit';
import { BusinessError } from '@kit.BasicServicesKit';
@Entry
@Component
struct Index {
@State message: string = 'hello world';
build() {
Column() {
Text(this.message)
.onClick(async () => {
let context = this.getUIContext().getHostContext() as Context;
let type: AVSessionManager.AVSessionType = 'audio';
let session = await AVSessionManager.createAVSession(context, 'SESSION_NAME', type);
// Set the necessary media information. This step is mandatory. Otherwise, the application cannot receive key events.
let metadata: AVSessionManager.AVMetadata = {
assetId: '0', // Specified by the application, used to identify the media asset in the application media library.
title: 'TITLE',
mediaImage: 'IMAGE',
artist: 'ARTIST'
};
session.setAVMetadata(metadata).then(() => {
console.info(`SetAVMetadata successfully`);
}).catch((err: BusinessError) => {
console.error(`Failed to set AVMetadata. Code: ${err.code}, message: ${err.message}`);
});
session.on('handleKeyEvent', (event) => {
// Parse the key code. The application must perform logic processing on the player based on the key code.
console.info(`on handleKeyEvent, keyCode=${event.key.code}`);
});
})
}
.width('100%')
.height('100%')
}
}