目录

Accessing AVSession

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.

Scenarios That Require AVSession Access

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.

Access Process

The process for implementing AVSession access is as follows:

  1. Determine the type of AVSession to be created for the application, and then create one. The AVSession type determines the style of the control template displayed in the controller.
  2. Create a background task.
  3. Set necessary metadata to display corresponding information in the controller. The metadata includes but is not limited to the IDs of the current media asset (assetId), previous media asset (previousAssetId), and next media asset (nextAssetId), title, author, album, writer, and duration.
  4. Set playback state information. The information includes but is not limited to the playback state (state), position (position), speed (speed), buffered time (bufferedTime), loop mode (loopMode), whether the media asset is favorited (isFavorite), media ID being played (activeItemId), and custom media data (extras).
  5. Register control commands as required, including but not limited to play/pause, previous/next, fast-forward/rewind, favorite, loop mode, and progress bar.
  6. Destroy AVSession when the application exits or stops providing service.

Creating AVSession

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.

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%')
  }
}

Creating a Background Task

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.

Setting Metadata Information

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.

[h2]Metadata Information

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%')
  }
}

[h2]Setting Lyrics Field Information

Metadata AVMetadata contains lyric fields. The application can set lyric fields to display lyrics in certain scenarios. Currently, two lyric fields can be set:

  • 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%')
  }
}

[h2]Setting Progress Bar Information

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.

  1. 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.

  2. 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.

  3. Special contents such as ads

    For media assets with pre-roll or post-roll ads, you are advised to:

    • Set the ad duration separately.
    • Set a new duration for the actual content, to distinguish it from the ad.

[h2]Historical Playlists

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)
    }
}

[h2]Display Tags of Media Assets

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%')
  }
}

Setting Playback State

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.

[h2]Playback State Information

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%')
  }
}

Control Command Processing

[h2]Supported Control Commands

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.

[h2]Handling Unsupported Control Commands

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%')
  }
}

[h2]Fast-Forward/Rewind

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.

[h2]Favoriting Media Assets

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%')
  }
}

[h2]Implementing Loop Mode

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%')
  }
}

[h2]Performing Progress Control

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%')
  }
}

Adapting to Media Notification

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.

Adapting to Bluetooth and Wired Key Events

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:

  1. Both methods require the accurate configuration of media information AVMetadata and the registration of corresponding control interfaces to receive control commands and key events.
  2. Choose either method for integration. Method 1 is recommended.

Sample Code