From 8f07bbf6e8c32b967a7b19ce10eacd4614f65cfb Mon Sep 17 00:00:00 2001 From: Gloria Date: Mon, 6 Feb 2023 17:23:29 +0800 Subject: [PATCH] Update docs against 13297+13974 Signed-off-by: wusongqing --- en/application-dev/media/avplayer-playback.md | 507 ++ en/application-dev/media/avrecorder.md | 488 ++ .../figures/en-us_image_avplayer_audio.png | Bin 0 -> 26215 bytes .../en-us_image_avplayer_state_machine.png | Bin 0 -> 38357 bytes .../figures/en-us_image_avplayer_video.png | Bin 0 -> 35229 bytes ...us_image_avrecorder_module_interaction.png | Bin 0 -> 83868 bytes .../en-us_image_avrecorder_state_machine.png | Bin 0 -> 56548 bytes .../reference/apis/js-apis-media.md | 5171 ++++++++++++----- 8 files changed, 4725 insertions(+), 1441 deletions(-) create mode 100644 en/application-dev/media/avplayer-playback.md create mode 100644 en/application-dev/media/avrecorder.md create mode 100644 en/application-dev/media/figures/en-us_image_avplayer_audio.png create mode 100644 en/application-dev/media/figures/en-us_image_avplayer_state_machine.png create mode 100644 en/application-dev/media/figures/en-us_image_avplayer_video.png create mode 100644 en/application-dev/media/figures/en-us_image_avrecorder_module_interaction.png create mode 100644 en/application-dev/media/figures/en-us_image_avrecorder_state_machine.png diff --git a/en/application-dev/media/avplayer-playback.md b/en/application-dev/media/avplayer-playback.md new file mode 100644 index 0000000000..270081373f --- /dev/null +++ b/en/application-dev/media/avplayer-playback.md @@ -0,0 +1,507 @@ +# AVPlayer Development + +## Introduction + +The AVPlayer converts audio or video resources into audible analog signals or renderable images and plays the signals or images using output devices. You can manage playback tasks on the AVPlayer. For example, you can control the playback (start/pause/stop/seek), set the volume, obtain track information, and release resources. + +## Working Principles + +The following figures show the [AVPlayer state](../reference/apis/js-apis-media.md#avplayerstate9) transition and interaction with external audio and video playback modules. + +**Figure 1** AVPlayer state transition + +![en-us_image_avplayer_state_machine](figures/en-us_image_avplayer_state_machine.png) + +**Figure 2** Interaction with external modules for audio playback + +![en-us_image_avplayer_audio](figures/en-us_image_avplayer_audio.png) + +**NOTE**: When an application calls the **AVPlayer** JS APIs at the JS interface layer to implement a feature, the framework layer parses the resources into audio data streams through the playback service of the player framework. The audio data streams are then decoded by software and output to the audio service of the audio framework. The audio framework outputs the audio data streams to the audio HDI at the hardware interface layer to implement audio playback. A complete audio playback process requires the cooperation of the application (application adaptation required), player framework, audio framework, and audio HDI (driver adaptation required). + +1. An application passes a URL into the **AVPlayer** JS API. +2. The playback service outputs the audio PCM data streams to the audio service, and the audio service outputs the data streams to the audio HDI. + + +**Figure 3** Interaction with external modules for video playback + +![en-us_image_avplayer_video](figures/en-us_image_avplayer_video.png) + +**NOTE**: When an application calls the **AVPlayer** JS APIs at the JS interface layer to implement a feature, the framework layer parses the resources into separate audio data streams and video data streams through the playback service of the player framework. The audio data streams are then decoded by software and output to the audio service of the audio framework. The audio framework outputs the audio data streams to the audio HDI at the hardware interface layer to implement audio playback. The video data streams are then decoded by hardware (recommended) or software and output to the renderer service of the graphic framework. The renderer service outputs the video data streams to the display HDI at the hardware interface layer. A complete video playback process requires the cooperation of the application (application adaptation required), XComponent, player framework, graphic framework, audio framework, display HDI (driver adaptation required), and audio HDI (driver adaptation required). + +1. An application obtains the surface ID from the XComponent. For details about the obtaining method, see [XComponent](../reference/arkui-ts/ts-basic-components-xcomponent.md). +2. The application passes a URL and the surface ID into the **AVPlayer** JS API. +3. The playback service outputs video elementary streams (ESs) to the codec HDI, which decodes the ESs to obtain video frames (NV12/NV21/RGBA). +4. The playback service outputs the audio PCM data streams to the audio service, and the audio service outputs the data streams to the audio HDI. +5. The playback service outputs video frames (NV12/NV21/RGBA) to the renderer service, and the renderer service outputs the video frames to the display HDI. + +## Compatibility + +Use the mainstream playback formats and resolutions, rather than custom ones to avoid playback failures, frame freezing, and artifacts. The system will not be affected by incompatibility issues. If such an issue occurs, you can exit stream playback. + +The table below lists the mainstream playback formats and resolutions. + +| Video Container Format| Description | Resolution | +| :----------: | :-----------------------------------------------: | :--------------------------------: | +| mp4 | Video format: H.264/MPEG-2/MPEG-4/H.263; audio format: AAC/MP3| Mainstream resolutions, such as 1080p, 720p, 480p, and 270p| +| mkv | Video format: H.264/MPEG-2/MPEG-4/H.263; audio format: AAC/MP3| Mainstream resolutions, such as 1080p, 720p, 480p, and 270p| +| ts | Video format: H.264/MPEG-2/MPEG-4; audio format: AAC/MP3 | Mainstream resolutions, such as 1080p, 720p, 480p, and 270p| +| webm | Video format: VP8; audio format: VORBIS | Mainstream resolutions, such as 1080p, 720p, 480p, and 270p| + +| Audio Container Format | Description | +| :----------: | :----------: | +| m4a | Audio format: AAC| +| aac | Audio format: AAC| +| mp3 | Audio format: MP3| +| ogg | Audio format: VORBIS | +| wav | Audio format: PCM | + +## How to Develop + +For details about the APIs, see the [AVPlayer APIs in the Media Class](../reference/apis/js-apis-media.md#avplayer9). + +### Full-Process Scenario + +The full playback process includes creating an instance, setting resources, setting a video window, preparing for playback, controlling playback, and resetting or releasing the resources. (During the preparation, you can obtain track information, volume, speed, focus mode, and zoom mode, and set bit rates. To control the playback, you can start, pause, and stop the playback, seek to a playback position, and set the volume.) + +1. Call [createAVPlayer()](../reference/apis/js-apis-media.md#mediacreateavplayer9) to create an **AVPlayer** instance. The AVPlayer is initialized to the [idle](#avplayer_state) state. + +2. Set the events to listen for, which will be used in the full-process scenario. + +3. Set the resource [URL](../reference/apis/js-apis-media.md#avplayer_attributes). When the AVPlayer enters the [initialized](#avplayer_state) state, you can set the [surface ID](../reference/apis/js-apis-media.md#avplayer_attributes) for the video window. For details about the supported specifications, see [AVPlayer Attributes](../reference/apis/js-apis-media.md#avplayer_attributes). + +4. Call [prepare()](../reference/apis/js-apis-media.md#avplayer_prepare) to switch the AVPlayer to the [prepared](#avplayer_state) state. + +5. Perform video playback control. For example, you can call [play()](../reference/apis/js-apis-media.md#avplayer_play), [pause()](../reference/apis/js-apis-media.md#avplayer_pause), [seek()](../reference/apis/js-apis-media.md#avplayer_seek), and [stop()](../reference/apis/js-apis-media.md#avplayer_stop) to control the playback. + +6. Call [reset()](../reference/apis/js-apis-media.md#avplayer_reset) to reset resources. The AVPlayer enters the [idle](#avplayer_state) state again, and you can change the resource [URL](../reference/apis/js-apis-media.md#avplayer_attributes). + +7. Call [release()](../reference/apis/js-apis-media.md#avplayer_release) to release the instance. The AVPlayer enters the [released](#avplayer_state) state and exits the playback. + +> **NOTE** +> +> When the AVPlayer is in the prepared, playing, paused, or completed state, the playback engine is working and a large amount of system running memory is occupied. If your application does not need to use the AVPlayer, call **reset()** or **release()** to release the resources. + +### Listening Events + +| Event Type | Description | +| ------------------------------------------------- | ------------------------------------------------------------ | +| stateChange | Mandatory; used to listen for player state changes. | +| error | Mandatory; used to listen for player error information. | +| durationUpdate | Used to listen for progress bar updates to refresh the resource duration. | +| timeUpdate | Used to listen for the current position of the progress bar to refresh the current time. | +| seekDone | Used to listen for the completion status of the **seek()** request. | +| speedDone | Used to listen for the completion status of the **setSpeed()** request. | +| volumeChange | Used to listen for the completion status of the **setVolume()** request. | +| bitrateDone | Used to listen for the completion status of the **setBitrate()** request, which is used for HTTP Live Streaming (HLS) streams. | +| availableBitrates | Used to listen for available bit rates of HLS resources. The available bit rates are provided for **setBitrate()**. | +| bufferingUpdate | Used to listen for network playback buffer information. | +| startRenderFrame | Used to listen for the rendering time of the first frame during video playback. | +| videoSizeChange | Used to listen for the width and height of video playback and adjust the window size and ratio.| +| audioInterrupt | Used to listen for audio interruption during video playback. This event is used together with the **audioInterruptMode** attribute.| + +### Full-Process Scenario API Example + +```js +import media from '@ohos.multimedia.media' +import audio from '@ohos.multimedia.audio'; +import fileIO from '@ohos.fileio' + +const TAG = 'AVPlayerDemo:' +export class AVPlayerDemo { + private count:number = 0 + private avPlayer + private surfaceID:string // The surfaceID parameter is used for screen display. Its value is obtained through the XComponent API. + + // Set AVPlayer callback functions. + setAVPlayerCallback() { + // Callback function for state changes. + this.avPlayer.on('stateChange', async (state, reason) => { + switch (state) { + case 'idle': // This state is reported upon a successful callback of reset(). + console.info(TAG + 'state idle called') + this.avPlayer.release() // Release the AVPlayer instance. + break; + case 'initialized': // This state is reported when the AVPlayer sets the playback source. + console.info(TAG + 'state initialized called ') + this.avPlayer.surfaceId = this.surfaceID // Set the image to be displayed. This setting is not required when a pure audio resource is to be played. + this.avPlayer.prepare().then(() => { + console.info(TAG+ 'prepare success'); + }, (err) => { + console.error(TAG + 'prepare filed,error message is :' + err.message) + }) + break; + case 'prepared': // This state is reported upon a successful callback of prepare(). + console.info(TAG + 'state prepared called') + this.avPlayer.play() // Call play() to start playback. + break; + case 'playing': // This state is reported upon a successful callback of play(). + console.info(TAG + 'state playing called') + if (this.count == 0) { + this.avPlayer.pause() // Call pause() to pause the playback. + } else { + this.avPlayer.seek(10000, media.SeekMode.SEEK_PREV_SYNC) // Seek to 10 seconds. The seekDone callback is triggered. + } + break; + case 'paused': // This state is reported upon a successful callback of pause(). + console.info(TAG + 'state paused called') + if (this.count == 0) { + this.count++ + this.avPlayer.play() // Call play() to continue the playback. + } + break; + case 'completed': // This state is reported upon the completion of the playback. + console.info(TAG + 'state completed called') + this.avPlayer.stop() // Call stop() to stop the playback. + break; + case 'stopped': // This state is reported upon a successful callback of stop(). + console.info(TAG + 'state stopped called') + this.avPlayer.reset() // Call reset() to initialize the AVPlayer state. + break; + case 'released': + console.info(TAG + 'state released called') + break; + case 'error': + console.info(TAG + 'state error called') + break; + default: + console.info(TAG + 'unkown state :' + state) + break; + } + }) + // Callback function for time updates. + this.avPlayer.on('timeUpdate', (time:number) => { + console.info(TAG + 'timeUpdate success,and new time is :' + time) + }) + // Callback function for volume updates. + this.avPlayer.on('volumeChange', (vol:number) => { + console.info(TAG + 'volumeChange success,and new volume is :' + vol) + this.avPlayer.setSpeed(media.AVPlayerSpeed.SPEED_FORWARD_2_00_X) // Double the playback speed. The speedDone callback is triggered. + }) + // Callback function for the video playback completion event. + this.avPlayer.on('endOfStream', () => { + console.info(TAG + 'endOfStream success') + }) + // Callback function for the seek operation. + this.avPlayer.on('seekDone', (seekDoneTime:number) => { + console.info(TAG + 'seekDone success,and seek time is:' + seekDoneTime) + this.avPlayer.setVolume(0.5) // Set the volume to 0.5. The volumeChange callback is triggered. + }) + // Callback function for the speed setting operation. + this.avPlayer.on('speedDone', (speed:number) => { + console.info(TAG + 'speedDone success,and speed value is:' + speed) + }) + // Callback function for successful bit rate setting. + this.avPlayer.on('bitrateDone', (bitrate:number) => { + console.info(TAG + 'bitrateDone success,and bitrate value is:' + bitrate) + }) + // Callback function for buffering updates. + this.avPlayer.on('bufferingUpdate', (infoType: media.BufferingInfoType, value: number) => { + console.info(TAG + 'bufferingUpdate success,and infoType value is:' + infoType + ', value is :' + value) + }) + // Callback function invoked when frame rendering starts. + this.avPlayer.on('startRenderFrame', () => { + console.info(TAG + 'startRenderFrame success') + }) + // Callback function for video width and height changes. + this.avPlayer.on('videoSizeChange', (width: number, height: number) => { + console.info(TAG + 'videoSizeChange success,and width is:' + width + ', height is :' + height) + }) + // Callback function for the audio interruption event. + this.avPlayer.on('audioInterrupt', (info: audio.InterruptEvent) => { + console.info(TAG + 'audioInterrupt success,and InterruptEvent info is:' + info) + }) + // Callback function to report the available bit rates of HLS. + this.avPlayer.on('availableBitrates', (bitrates: Array) => { + console.info(TAG + 'availableBitrates success,and availableBitrates length is:' + bitrates.length) + }) + } + + async avPlayerDemo() { + // Create an AVPlayer instance. + this.avPlayer = await media.createAVPlayer() + let fdPath = 'fd://' + let pathDir = "/data/storage/el2/base/haps/entry/files" // The path used here is an example. Obtain the path based on project requirements. + // The stream in the path can be pushed to the device by running the "hdc file send D:\xxx\H264_AAC.mp4 /data/app/el2/100/base/ohos.acts.multimedia.media.avplayer/haps/entry/files" command. + let path = pathDir + '/H264_AAC.mp4' + await fileIO.open(path).then((fdNumber) => { + fdPath = fdPath + '' + fdNumber + console.info('open fd success fd is' + fdPath) + }, (err) => { + console.info('open fd failed err is' + err) + }).catch((err) => { + console.info('open fd failed err is' + err) + }); + this.avPlayer.url = fdPath + } +} +``` + +### Normal Playback Scenario + +```js +import media from '@ohos.multimedia.media' +import fileIO from '@ohos.fileio' + +const TAG = 'AVPlayerDemo:' +export class AVPlayerDemo { + private avPlayer + private surfaceID:string // The surfaceID parameter is used for screen display. Its value is obtained through the XComponent API. + + // Set AVPlayer callback functions. + setAVPlayerCallback() { + // Callback function for state changes. + this.avPlayer.on('stateChange', async (state, reason) => { + switch (state) { + case 'idle': // This state is reported upon a successful callback of reset(). + console.info(TAG + 'state idle called') + break; + case 'initialized': // This state is reported when the AVPlayer sets the playback source. + console.info(TAG + 'state initialized called ') + this.avPlayer.surfaceId = this.surfaceID // Set the image to be displayed. This setting is not required when a pure audio resource is to be played. + this.avPlayer.prepare().then(() => { + console.info(TAG+ 'prepare success'); + }, (err) => { + console.error(TAG + 'prepare filed,error message is :' + err.message) + }) + break; + case 'prepared': // This state is reported upon a successful callback of prepare(). + console.info(TAG + 'state prepared called') + this.avPlayer.play() // Call play() to start playback. + break; + case 'playing': // This state is reported upon a successful callback of play(). + console.info(TAG + 'state playing called') + break; + case 'paused': // This state is reported upon a successful callback of pause(). + console.info(TAG + 'state paused called') + break; + case 'completed': // This state is reported upon the completion of the playback. + console.info(TAG + 'state completed called') + this.avPlayer.stop() // Call stop() to stop the playback. + break; + case 'stopped': // This state is reported upon a successful callback of stop(). + console.info(TAG + 'state stopped called') + this.avPlayer.reset() // Call reset() to initialize the AVPlayer state. + break; + case 'released': + console.info(TAG + 'state released called') + break; + case 'error': + console.info(TAG + 'state error called') + break; + default: + console.info(TAG + 'unkown state :' + state) + break; + } + }) + } + + async avPlayerDemo() { + // Create an AVPlayer instance. + this.avPlayer = await media.createAVPlayer() + let fdPath = 'fd://' + let pathDir = "/data/storage/el2/base/haps/entry/files" // The path used here is an example. Obtain the path based on project requirements. + // The stream in the path can be pushed to the device by running the "hdc file send D:\xxx\H264_AAC.mp4 /data/app/el2/100/base/ohos.acts.multimedia.media.avplayer/haps/entry/files" command. + let path = pathDir + '/H264_AAC.mp4' + await fileIO.open(path).then((fdNumber) => { + fdPath = fdPath + '' + fdNumber + console.info('open fd success fd is' + fdPath) + }, (err) => { + console.info('open fd failed err is' + err) + }).catch((err) => { + console.info('open fd failed err is' + err) + }); + this.avPlayer.url = fdPath + } +} +``` + +### Switching to the Next Video Clip + +```js +import media from '@ohos.multimedia.media' +import fileIO from '@ohos.fileio' + +const TAG = 'AVPlayerDemo:' +export class AVPlayerDemo { + private count:number = 0 + private avPlayer + private surfaceID:string // The surfaceID parameter is used for screen display. Its value is obtained through the XComponent API. + + // Set AVPlayer callback functions. + setAVPlayerCallback() { + // Callback function for state changes. + this.avPlayer.on('stateChange', async (state, reason) => { + switch (state) { + case 'idle': // This state is reported upon a successful callback of reset(). + console.info(TAG + 'state idle called') + break; + case 'initialized': // This state is reported when the AVPlayer sets the playback source. + console.info(TAG + 'state initialized called ') + this.avPlayer.surfaceId = this.surfaceID // Set the image to be displayed. This setting is not required when a pure audio resource is to be played. + this.avPlayer.prepare().then(() => { + console.info(TAG+ 'prepare success'); + }, (err) => { + console.error(TAG + 'prepare filed,error message is :' + err.message) + }) + break; + case 'prepared': // This state is reported upon a successful callback of prepare(). + console.info(TAG + 'state prepared called') + this.avPlayer.loop = true // Set the AVPlayer to loop a single item. The endOfStream callback is triggered when the previous round of the playback is complete. + this.avPlayer.play() // Call play() to start playback. + break; + case 'playing': // This state is reported upon a successful callback of play(). + console.info(TAG + 'state playing called') + break; + case 'paused': // This state is reported upon a successful callback of pause(). + console.info(TAG + 'state paused called') + break; + case 'completed': // This state is reported upon the completion of the playback. + console.info(TAG + 'state completed called') + // Cancel the loop playback when the endOfStream callback is triggered for the second time. The completed state is reported when the next round of the playback is complete. + this.avPlayer.stop() // Call stop() to stop the playback. + break; + case 'stopped': // This state is reported upon a successful callback of stop(). + console.info(TAG + 'state stopped called') + this.avPlayer.reset() // Call reset() to initialize the AVPlayer state. + break; + case 'released': + console.info(TAG + 'state released called') + break; + case 'error': + console.info(TAG + 'state error called') + break; + default: + console.info(TAG + 'unkown state :' + state) + break; + } + }) + // Callback function for the video playback completion event. + this.avPlayer.on('endOfStream', () => { + console.info(TAG + 'endOfStream success') + if (this.count == 1) { + this.avPlayer.loop = false // Cancel loop playback. + } else { + this.count++ + } + }) + } + + async avPlayerDemo() { + // Create an AVPlayer instance. + this.avPlayer = await media.createAVPlayer() + let fdPath = 'fd://' + let pathDir = "/data/storage/el2/base/haps/entry/files" // The path used here is an example. Obtain the path based on project requirements. + // The stream in the path can be pushed to the device by running the "hdc file send D:\xxx\H264_AAC.mp4 /data/app/el2/100/base/ohos.acts.multimedia.media.avplayer/haps/entry/files" command. + let path = pathDir + '/H264_AAC.mp4' + await fileIO.open(path).then((fdNumber) => { + fdPath = fdPath + '' + fdNumber + console.info('open fd success fd is' + fdPath) + }, (err) => { + console.info('open fd failed err is' + err) + }).catch((err) => { + console.info('open fd failed err is' + err) + }); + this.avPlayer.url = fdPath + } +} +``` +### Looping a Song + +```js +import media from '@ohos.multimedia.media' +import fileIO from '@ohos.fileio' + +const TAG = 'AVPlayerDemo:' +export class AVPlayerDemo { + private count:number = 0 + private avPlayer + private surfaceID:string // The surfaceID parameter is used for screen display. Its value is obtained through the XComponent API. + + async nextVideo() { + let fdPath = 'fd://' + let pathDir = "/data/storage/el2/base/haps/entry/files" // The path used here is an example. Obtain the path based on project requirements. + // The stream in the path can be pushed to the device by running the "hdc file send D:\xxx\H264_MP3.mp4 /data/app/el2/100/base/ohos.acts.multimedia.media.avplayer/haps/entry/files" command. + let path = pathDir + '/H264_MP3.mp4' + await fileIO.open(path).then((fdNumber) => { + fdPath = fdPath + '' + fdNumber + console.info('open fd success fd is' + fdPath) + }, (err) => { + console.info('open fd failed err is' + err) + }).catch((err) => { + console.info('open fd failed err is' + err) + }); + this.avPlayer.url = fdPath // The initialized state is reported again. + } + + // Set AVPlayer callback functions. + setAVPlayerCallback() { + // Callback function for state changes. + this.avPlayer.on('stateChange', async (state, reason) => { + switch (state) { + case 'idle': // This state is reported upon a successful callback of reset(). + console.info(TAG + 'state idle called') + await this.nextVideo() // Switch to the next video. + break; + case 'initialized': // This state is reported when the AVPlayer sets the playback source. + console.info(TAG + 'state initialized called ') + this.avPlayer.surfaceId = this.surfaceID // Set the image to be displayed. This setting is not required when a pure audio resource is to be played. + this.avPlayer.prepare().then(() => { + console.info(TAG+ 'prepare success'); + }, (err) => { + console.error(TAG + 'prepare filed,error message is :' + err.message) + }) + break; + case 'prepared': // This state is reported upon a successful callback of prepare(). + console.info(TAG + 'state prepared called') + this.avPlayer.play() // Call play() to start playback. + break; + case 'playing': // This state is reported upon a successful callback of play(). + console.info(TAG + 'state playing called') + break; + case 'paused': // This state is reported upon a successful callback of pause(). + console.info(TAG + 'state paused called') + break; + case 'completed': // This state is reported upon the completion of the playback. + console.info(TAG + 'state completed called') + if (this.count == 0) { + this.count++ + this.avPlayer.reset() // Call reset() to prepare for switching to the next video. + } else { + this.avPlayer.release() // Release the AVPlayer instance when the new video finishes playing. + } + break; + case 'stopped': // This state is reported upon a successful callback of stop(). + console.info(TAG + 'state stopped called') + break; + case 'released': + console.info(TAG + 'state released called') + break; + case 'error': + console.info(TAG + 'state error called') + break; + default: + console.info(TAG + 'unkown state :' + state) + break; + } + }) + } + + async avPlayerDemo() { + // Create an AVPlayer instance. + this.avPlayer = await media.createAVPlayer() + let fdPath = 'fd://' + let pathDir = "/data/storage/el2/base/haps/entry/files" // The path used here is an example. Obtain the path based on project requirements. + // The stream in the path can be pushed to the device by running the "hdc file send D:\xxx\H264_AAC.mp4 /data/app/el2/100/base/ohos.acts.multimedia.media.avplayer/haps/entry/files" command. + let path = pathDir + '/H264_AAC.mp4' + await fileIO.open(path).then((fdNumber) => { + fdPath = fdPath + '' + fdNumber + console.info('open fd success fd is' + fdPath) + }, (err) => { + console.info('open fd failed err is' + err) + }).catch((err) => { + console.info('open fd failed err is' + err) + }); + this.avPlayer.url = fdPath + } +} +``` diff --git a/en/application-dev/media/avrecorder.md b/en/application-dev/media/avrecorder.md new file mode 100644 index 0000000000..b897c68a65 --- /dev/null +++ b/en/application-dev/media/avrecorder.md @@ -0,0 +1,488 @@ +# AVRecorder Development + +## Introduction + +The AVRecorder captures audio signals, receives video signals, encodes audio and video signals, and saves them to files. With the AVRecorder, you can easily implement audio and video recording, including starting, pausing, resuming, and stopping recording, and releasing resources. You can also specify parameters such as the encoding format, encapsulation format, and file path for recording. + +## Working Principles + +The following figures show the AVRecorder state transition and the interaction with external modules for audio and video recording. + +**Figure 1** AVRecorder state transition + +![en-us_image_video_recorder_state_machine](figures/en-us_image_avrecorder_state_machine.png) + +**Figure 2** Interaction between external modules for audio and video recording + +![en-us_image_video_recorder_zero](figures/en-us_image_avrecorder_module_interaction.png) + +**NOTE**: During audio recording, the framework layer calls the audio subsystem through the media service of the native framework to capture audio data through the audio HDI, encodes and encapsulates the data by using software, and saves the data to a file. During video recording, the camera subsystem captures image data through the video HDI. The media service encodes the image data through the video encoding HDI and encapsulates the encoded image data into a file. With the AVRecorder, you can implement pure audio recording, pure video recording, and audio and video recording. + +## Constraints + +Before developing the recording feature, configure permissions for your application. If audio recording is involved, obtain the permission **ohos.permission.MICROPHONE** by following the instructions provided in [Permission Application Guide](../security/accesstoken-guidelines.md). + +To use the camera to record videos, the camera module is required. For details about how to use the APIs and obtain permissions, see [Camera Management](../reference/apis/js-apis-camera.md). + +## How to Develop + +For details about the AVRecorder APIs, see the [AVRecorder APIs in the Media Class](../reference/apis/js-apis-media.md#avrecorder9). + +For details about the processes related to the media library, see [Media Library Management](../reference/apis/js-apis-medialibrary.md). + +For details about the camera-related process, see [Camera Management](../reference/apis/js-apis-camera.md). + +### Full-Process Scenario of Audio and Video Recording + +The full audio and video recording process includes creating an instance, setting recording parameters, obtaining the input surface, starting, pausing, resuming, and stopping recording, and releasing resources. + +The value range that can be set for the audio recording parameters is restricted by the codec performance of the device and the performance of the audio subsystem. + +The video range that can be set for the video recording parameters is restricted by the codec performance of the device and the performance of the camera subsystem. + +``` +import media from '@ohos.multimedia.media' +import camera from '@ohos.multimedia.camera' +import mediaLibrary from '@ohos.multimedia.mediaLibrary' + +export class AVRecorderDemo { + private testFdNumber; // Used to save the File Descriptor (FD) address. + + // Obtain the FD corresponding to fileName of the recorded file. The media library capability is required. To use the media library, configure the following permissions: ohos.permission.MEDIA_LOCATION, ohos.permission.WRITE_MEDIA, and ohos.permission.READ_MEDIA. + async getFd(fileName) { + // For details about the implementation mode, see the media library documentation. + this.testFdNumber = "fd://" + fdNumber.toString(); // e.g. fd://54 + } + + // Error callback triggered in the case of an error in the promise mode. + failureCallback(error) { + console.info('error happened, error message is ' + error.message); + } + + // Error callback triggered in the case of an exception in the promise mode. + catchCallback(error) { + console.info('catch error happened, error message is ' + error.message); + } + + async AVRecorderDemo() { + let AVRecorder; // Assign a value to the empty AVRecorder instance upon a successful call of createAVRecorder(). + let surfaceID; // The surface ID is obtained by calling getInputSurface and transferred to the videoOutput object of the camera. + await this.getFd('01.mp4'); + + // Configure the parameters related to audio and video recording. + let avProfile = { + audioBitrate : 48000, + audioChannels : 2, + audioCodec : media.CodecMimeType.AUDIO_AAC, + audioSampleRate : 48000, + fileFormat : media.ContainerFormatType.CFT_MPEG_4, + videoBitrate : 48000, + videoCodec : media.CodecMimeType.VIDEO_MPEG4, + videoFrameWidth : 640, + videoFrameHeight : 480, + videoFrameRate : 30 + } + let avConfig = { + audioSourceType : media.AudioSourceType.AUDIO_SOURCE_TYPE_MIC, + videoSourceType : media.VideoSourceType.VIDEO_SOURCE_TYPE_SURFACE_YUV, + profile : avProfile, + url : 'fd://', + rotation : 0, + location : { latitude : 30, longitude : 130 } + } + + // Create an AVRecorder instance. + await media.createAVRecorder().then((recorder) => { + console.info('case createAVRecorder called'); + if (typeof (recorder) != 'undefined') { + AVRecorder = recorder; + console.info('createAVRecorder success'); + } else { + console.info('createAVRecorder failed'); + } + }, this.failureCallback).catch(this.catchCallback); + + // After the instance is created, use the on('stateChange') and on('error') callbacks to listen for state changes and errors. + AVRecorder.on('stateChange', async (state, reason) => { + console.info('case state has changed, new state is :' + state); + switch (state) { + // Your can set the desired behavior in different states as required. + case 'idle': + // This state is reported upon a successful call of rest() or create(). + break; + case 'prepared': + // This state is reported upon a successful call of prepare(). + break; + case 'started': + // This state is reported upon a successful call of start(). + break; + case 'paused': + // This state is reported upon a successful call of pause(). + break; + case 'stopped': + // This state is reported upon a successful call of stop(). + break; + case 'released': + // This state is reported upon a successful call of release(). + break; + case 'error': + // The error state indicates that an error occurs at the bottom layer. You must rectify the fault and create an AVRecorder instance again. + break; + default: + console.info('case state is unknown'); + } + }); + AVRecorder.on('error', (err) => { + // Listen for non-interface errors. + console.info('case avRecorder.on(error) called, errMessage is ' + err.message); + }); + + // Call prepare() to prepare for recording. The bottom layer determines whether to record audio, video, or audio and video based on the input parameters of prepare(). + await AVRecorder.prepare(avConfig).then(() => { + console.info('prepare success'); + }, this.failureCallback).catch(this.catchCallback); + + // If video recording is involved, call getInputSurface to obtain the input surface and pass the returned surface ID to the related camera API. + await AVRecorder.getInputSurface().then((surface) => { + console.info('getInputSurface success'); + surfaceID = surface; // The surfaceID is passed into createVideoOutput() of the camera as an input parameter. + }, this.failureCallback).catch(this.catchCallback); + + // Video recording depends on camera-related APIs. The following operations can be performed only after the video output start API is invoked. + // Start video recording. + await AVRecorder.start().then(() => { + console.info('start success'); + }, this.failureCallback).catch(this.catchCallback); + + // Pause video recording before the video output stop API of the camera is invoked. + await AVRecorder.pause().then(() => { + console.info('pause success'); + }, this.failureCallback).catch(this.catchCallback); + + // Resume video recording after the video output start API of the camera is invoked. + await AVRecorder.resume().then(() => { + console.info('resume success'); + }, this.failureCallback).catch(this.catchCallback); + + // Stop video recording after the video output stop API of the camera is invoked. + await AVRecorder.stop().then(() => { + console.info('stop success'); + }, this.failureCallback).catch(this.catchCallback); + + // Reset the recording configuration. + await AVRecorder.reset().then(() => { + console.info('reset success'); + }, this.failureCallback).catch(this.catchCallback); + + // Disable the listeners. The configured callbacks will be invalid after release() is invoked, even if you do not call off(). + AVRecorder.off('stateChange'); + AVRecorder.off('error'); + + // Release the video recording resources and camera object resources. + await AVRecorder.release().then(() => { + console.info('release success'); + }, this.failureCallback).catch(this.catchCallback); + + // Set the AVRecorder instance to null. + AVRecorder = undefined; + surfaceID = undefined; + } +} +``` + +### Full-Process Scenario of Pure Audio Recording + +The full audio recording process includes creating an instance, setting recording parameters, starting, pausing, resuming, and stopping recording, and releasing resources. + +The value range that can be set for the audio recording parameters is restricted by the codec performance of the device and the performance of the audio subsystem. + +``` +import media from '@ohos.multimedia.media' +import mediaLibrary from '@ohos.multimedia.mediaLibrary' + +export class AudioRecorderDemo { + private testFdNumber; // Used to save the FD address. + + // Obtain the FD corresponding to fileName of the recorded file. The media library capability is required. To use the media library, configure the following permissions: ohos.permission.MEDIA_LOCATION, ohos.permission.WRITE_MEDIA, and ohos.permission.READ_MEDIA. + async getFd(fileName) { + // For details about the implementation mode, see the media library documentation. + this.testFdNumber = "fd://" + fdNumber.toString(); // e.g. fd://54 + } + + // Error callback triggered in the case of an error in the promise mode. + failureCallback(error) { + console.info('error happened, error message is ' + error.message); + } + + // Error callback triggered in the case of an exception in the promise mode. + catchCallback(error) { + console.info('catch error happened, error message is ' + error.message); + } + + async audioRecorderDemo() { + let audioRecorder; // Assign a value to the empty AudioRecorder instance upon a successful call of createAVRecorder(). + await this.getFd('01.m4a'); + // Configure the parameters related to audio recording. + let audioProfile = { + audioBitrate : 48000, + audioChannels : 2, + audioCodec : media.CodecMimeType.AUDIO_AAC, + audioSampleRate : 48000, + fileFormat : media.ContainerFormatType.CFT_MPEG_4, + } + let audioConfig = { + audioSourceType : media.AudioSourceType.AUDIO_SOURCE_TYPE_MIC, + profile : audioProfile, + url : this.testFdNumber, + rotation : 0, + location : { latitude : 30, longitude : 130 } + } + + // Create an AudioRecorder instance. + await media.createAVRecorder().then((recorder) => { + console.info('case createAVRecorder called'); + if (typeof (recorder) != 'undefined') { + audioRecorder = recorder; + console.info('createAudioRecorder success'); + } else { + console.info('createAudioRecorder failed'); + } + }, this.failureCallback).catch(this.catchCallback); + + // After the instance is created, use the on('stateChange') and on('error') callbacks to listen for state changes and errors. + audioRecorder.on('stateChange', async (state, reason) => { + console.info('case state has changed, new state is :' + state); + switch (state) { + // Your can set the desired behavior in different states as required. + case 'idle': + // This state is reported upon a successful call of rest() or create(). + break; + case 'prepared': + // This state is reported upon a successful call of prepare(). + break; + case 'started': + // This state is reported upon a successful call of start(). + break; + case 'paused': + // This state is reported upon a successful call of pause(). + break; + case 'stopped': + // This state is reported upon a successful call of stop(). + break; + case 'released': + // This state is reported upon a successful call of release(). + break; + case 'error': + // The error state indicates that an error occurs at the bottom layer. You must rectify the fault and create an AudioRecorder instance again. + break; + default: + console.info('case state is unknown'); + } + }); + audioRecorder.on('error', (err) => { + // Listen for non-interface errors. + console.info('case avRecorder.on(error) called, errMessage is ' + err.message); + }); + + // Call prepare() to prepare for recording. The bottom layer determines whether to record audio, video, or audio and video based on the input parameters of prepare(). + await audioRecorder.prepare(audioConfig).then(() => { + console.info('prepare success'); + }, this.failureCallback).catch(this.catchCallback); + + // Call start() to start audio recording. + await audioRecorder.start().then(() => { + console.info('start success'); + }, this.failureCallback).catch(this.catchCallback); + + // Call pause() to pause audio recording. + await audioRecorder.pause().then(() => { + console.info('pause success'); + }, this.failureCallback).catch(this.catchCallback); + + // Call resume() to resume audio recording. + await audioRecorder.resume().then(() => { + console.info('resume success'); + }, this.failureCallback).catch(this.catchCallback); + + // Call stop() to stop audio recording. + await audioRecorder.stop().then(() => { + console.info('stop success'); + }, this.failureCallback).catch(this.catchCallback); + + // Call reset() to reset the recording configuration. + await audioRecorder.reset().then(() => { + console.info('reset success'); + }, this.failureCallback).catch(this.catchCallback); + + // Disable the listeners. The configured callbacks will be invalid after release() is invoked, even if you do not call off(). + avRecorder.off('stateChange'); + avRecorder.off('error'); + + // Call release() to release audio recording resources. + await audioRecorder.release().then(() => { + console.info('release success'); + }, this.failureCallback).catch(this.catchCallback); + + // Set the AudioRecorder instance to null. + audioRecorder = undefined; + } +} + +``` + +### Full-Process Scenario of Pure Video Recording + +The full video recording process includes creating an instance, setting recording parameters, obtaining the input surface, starting, pausing, resuming, and stopping recording, and releasing resources. + +The video range that can be set for the video recording parameters is restricted by the codec performance of the device and the performance of the camera subsystem. + +``` +import media from '@ohos.multimedia.media' +import camera from '@ohos.multimedia.camera' +import mediaLibrary from '@ohos.multimedia.mediaLibrary' + +export class VideoRecorderDemo { + private testFdNumber; // Used to save the FD address. + + // Obtain the FD corresponding to fileName of the recorded file. The media library capability is required. To use the media library, configure the following permissions: ohos.permission.MEDIA_LOCATION, ohos.permission.WRITE_MEDIA, and ohos.permission.READ_MEDIA. + async getFd(fileName) { + // For details about the implementation mode, see the media library documentation. + this.testFdNumber = "fd://" + fdNumber.toString(); // e.g. fd://54 + } + + // Error callback triggered in the case of an error in the promise mode. + failureCallback(error) { + console.info('error happened, error message is ' + error.message); + } + + // Error callback triggered in the case of an exception in the promise mode. + catchCallback(error) { + console.info('catch error happened, error message is ' + error.message); + } + + async videoRecorderDemo() { + let videoRecorder; // Assign a value to the empty VideoRecorder instance upon a successful call of createAVRecorder(). + let surfaceID; // The surface ID is obtained by calling getInputSurface and transferred to the videoOutput object of the camera. + await this.getFd('01.mp4'); + + // Configure the parameters related to video recording. + let videoProfile = { + fileFormat : media.ContainerFormatType.CFT_MPEG_4, + videoBitrate : 48000, + videoCodec : media.CodecMimeType.VIDEO_MPEG4, + videoFrameWidth : 640, + videoFrameHeight : 480, + videoFrameRate : 30 + } + let videoConfig = { + videoSourceType : media.VideoSourceType.VIDEO_SOURCE_TYPE_SURFACE_YUV, + profile : videoProfile, + url : 'fd://', + rotation : 0, + location : { latitude : 30, longitude : 130 } + } + + // Create a VideoRecorder instance. + await media.createAVRecorder().then((recorder) => { + console.info('case createVideoRecorder called'); + if (typeof (recorder) != 'undefined') { + videoRecorder = recorder; + console.info('createVideoRecorder success'); + } else { + console.info('createVideoRecorder failed'); + } + }, this.failureCallback).catch(this.catchCallback); + + // After the instance is created, use the on('stateChange') and on('error') callbacks to listen for state changes and errors. + videoRecorder.on('stateChange', async (state, reason) => { + console.info('case state has changed, new state is :' + state); + switch (state) { + // Your can set the desired behavior in different states as required. + case 'idle': + // This state is reported upon a successful call of rest() or create(). + break; + case 'prepared': + // This state is reported upon a successful call of prepare(). + break; + case 'started': + // This state is reported upon a successful call of start(). + break; + case 'paused': + // This state is reported upon a successful call of pause(). + break; + case 'stopped': + // This state is reported upon a successful call of stop(). + break; + case 'released': + // This state is reported upon a successful call of release(). + break; + case 'error': + // The error state indicates that an error occurs at the bottom layer. You must rectify the fault and create a VideoRecorder instance again. + break; + default: + console.info('case state is unknown'); + } + }); + videoRecorder.on('error', (err) => { + // Listen for non-interface errors. + console.info('case avRecorder.on(error) called, errMessage is ' + err.message); + }); + + // Call prepare() to prepare for recording. The bottom layer determines whether to record audio, video, or audio and video based on the input parameters of prepare(). + await videoRecorder.prepare(videoConfig).then(() => { + console.info('prepare success'); + }, this.failureCallback).catch(this.catchCallback); + + // If video recording is involved, call getInputSurface to obtain the input surface and pass the returned surface ID to the related camera API. + await videoRecorder.getInputSurface().then((surface) => { + console.info('getInputSurface success'); + surfaceID = surface; // The surfaceID is passed into createVideoOutput() of the camera as an input parameter. + }, this.failureCallback).catch(this.catchCallback); + + // Video recording depends on camera-related APIs. The following operations can be performed only after the video output start API is invoked. + // Start video recording. + await videoRecorder.start().then(() => { + console.info('start success'); + }, this.failureCallback).catch(this.catchCallback); + + // Pause video recording before the video output stop API of the camera is invoked. + await videoRecorder.pause().then(() => { + console.info('pause success'); + }, this.failureCallback).catch(this.catchCallback); + + // Resume video recording after the video output start API of the camera is invoked. + await videoRecorder.resume().then(() => { + console.info('resume success'); + }, this.failureCallback).catch(this.catchCallback); + + // Stop video recording after the video output stop API of the camera is invoked. + await videoRecorder.stop().then(() => { + console.info('stop success'); + }, this.failureCallback).catch(this.catchCallback); + + // Reset the recording configuration. + await videoRecorder.reset().then(() => { + console.info('reset success'); + }, this.failureCallback).catch(this.catchCallback); + + // Disable the listeners. The configured callbacks will be invalid after release() is invoked, even if you do not call off(). + videoRecorder.off('stateChange'); + videoRecorder.off('error'); + + // Release the video recording resources and camera object resources. + await videoRecorder.release().then(() => { + console.info('release success'); + }, this.failureCallback).catch(this.catchCallback); + + // Set the VideoRecorder instance to null. + videoRecorder = undefined; + surfaceID = undefined; + } +} +``` + +### AVRecorder App + +The AVRecorder app provides a complete audio and video recording process, which includes creating an instance, setting recording parameters, obtaining the input surface, starting, pausing, resuming, and stopping recording, and releasing resources. + +For details about the code, see [AVRecorderDemo]([multimedia_player_framework: Implementation of media playback and recording](https://gitee.com/openharmony/multimedia_player_framework/tree/master/test/appdemo/AVRecorderDemo)). diff --git a/en/application-dev/media/figures/en-us_image_avplayer_audio.png b/en/application-dev/media/figures/en-us_image_avplayer_audio.png new file mode 100644 index 0000000000000000000000000000000000000000..b5eb9b02a977d0e4551a236c7cc8a154710f5517 GIT binary patch literal 26215 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 literal 0 HcmV?d00001 diff --git a/en/application-dev/media/figures/en-us_image_avplayer_state_machine.png b/en/application-dev/media/figures/en-us_image_avplayer_state_machine.png new file mode 100644 index 0000000000000000000000000000000000000000..aa8afdbcbf142fd745cee03fc422caec51cfe41b GIT binary patch literal 38357 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 W@uXpso{tfApoAz)q~N8F_x}QbC4mV5 literal 0 HcmV?d00001 diff --git a/en/application-dev/media/figures/en-us_image_avrecorder_module_interaction.png b/en/application-dev/media/figures/en-us_image_avrecorder_module_interaction.png new file mode 100644 index 0000000000000000000000000000000000000000..7d5da3bdc91fe8fb7be9f0b4054f934ec054b8e6 GIT binary patch literal 83868 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 I3h4*@9|(|f5C8xG literal 0 HcmV?d00001 diff --git a/en/application-dev/media/figures/en-us_image_avrecorder_state_machine.png b/en/application-dev/media/figures/en-us_image_avrecorder_state_machine.png new file mode 100644 index 0000000000000000000000000000000000000000..7ffcb21f09365e9b072bdaf48f8b98d7d45a8aaa GIT binary patch literal 56548 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 z

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 **NOTE** +> > The initial APIs of this module are supported since API version 6. Newly added APIs will be marked with a superscript to indicate their earliest API version. The multimedia subsystem provides a set of simple and easy-to-use APIs for you to access the system and use media resources. -This subsystem offers various media services covering audio and video, which provide the following capabilities: +This subsystem offers the following audio and video services: -- Audio playback ([AudioPlayer](#audioplayer)) -- Video playback ([VideoPlayer](#videoplayer8)) -- Audio recording ([AudioRecorder](#audiorecorder)) -- Video recording ([VideoRecorder](#videorecorder9)) - -The following capabilities will be provided in later versions: data source audio/video playback, audio/video encoding and decoding, container encapsulation and decapsulation, and media capability query. +- Audio and video playback, implemented by the [AVPlayer](#avplayer9)9+ class. This class has integrated [AudioPlayer](#audioplayerdeprecated)6+ and [VideoPlayer](#videoplayer)8+, with the state machine and error codes upgraded. It is recommended. +- Audio and video recording, implemented by the [AVRecorder](#avrecorder9)9+ class. This class has integrated [AudioRecorder](#audiorecorderdeprecated)6+ and [VideoRecorder](#videorecorder9)9+. It is recommended. +- Audio playback, implemented by the [AudioPlayer](#audioplayerdeprecated)6+ class. It is deprecated. You are advised to use [AVPlayer](#avplayer9)9+. +- Video playback, implemented by the [VideoPlayer](#videoplayerdeprecated)8+ class. It is deprecated. You are advised to use [AVPlayer](#avplayer9)9+. +- Audio recording, implemented by the [AudioRecorder](#audiorecorderdeprecated)6+ class. It is deprecated. You are advised to use [AVRecorder](#avrecorder9)9+. +- Video recording, implemented by the [VideoRecorder](#videorecorder9)9+ class. It is deprecated. You are advised to use [AVRecorder](#avrecorder9)9+. ## Modules to Import @@ -20,113 +21,166 @@ The following capabilities will be provided in later versions: data source audio import media from '@ohos.multimedia.media'; ``` -## media.createAudioPlayer +## media.createAVPlayer9+ -createAudioPlayer(): [AudioPlayer](#audioplayer) +createAVPlayer(callback: AsyncCallback\): void -Creates an **AudioPlayer** instance in synchronous mode. +Creates an **AVPlayer** instance. This API uses an asynchronous callback to return the result. -**System capability**: SystemCapability.Multimedia.Media.AudioPlayer +**System capability**: SystemCapability.Multimedia.Media.AVPlayer -**Return value** +**Parameters** -| Type | Description | -| --------------------------- | ------------------------------------------------------------ | -| [AudioPlayer](#audioplayer) | Returns the **AudioPlayer** instance if the operation is successful; returns **null** otherwise. After the instance is created, you can start, pause, or stop audio playback.| +| Name | Type | Mandatory| Description | +| -------- | ------------------------------------- | ---- | ------------------------------------------------------------ | +| callback | AsyncCallback\<[AVPlayer](#avplayer9)> | Yes | Callback used to return the result. If the operation is successful, an **AVPlayer** instance is returned; otherwise, **null** is returned. The instance can be used to play audio and video.| + +**Error codes** + +For details about the error codes, see [Media Error Codes](../errorcodes/errorcode-media.md). + +| ID| Error Message | +| -------- | ------------------------------ | +| 5400101 | No memory. Return by callback. | **Example** ```js -let audioPlayer = media.createAudioPlayer(); +let avPlayer + +media.createAVPlayer((error, video) => { + if (video != null) { + avPlayer = video; + console.info('createAVPlayer success'); + } else { + console.info(`createAVPlayer fail, error:${error}`); + } +}); ``` -## media.createVideoPlayer8+ +## media.createAVPlayer9+ -createVideoPlayer(callback: AsyncCallback\<[VideoPlayer](#videoplayer8)>): void +createAVPlayer(): Promise\ -Creates a **VideoPlayer** instance. This API uses an asynchronous callback to return the result. +Creates an **AVPlayer** instance. This API uses a promise to return the result. -**System capability**: SystemCapability.Multimedia.Media.VideoPlayer +**System capability**: SystemCapability.Multimedia.Media.AVPlayer -**Parameters** +**Return value** + +| Type | Description | +| ------------------------------- | ------------------------------------------------------------ | +| Promise\<[AVPlayer](#avplayer9)> | Promise used to return the result. If the operation is successful, an **AVPlayer** instance is returned; otherwise, **null** is returned. The instance can be used to play audio and video.| + +**Error codes** + +For details about the error codes, see [Media Error Codes](../errorcodes/errorcode-media.md). -| Name | Type | Mandatory| Description | -| -------- | ------------------------------------------- | ---- | ------------------------------ | -| callback | AsyncCallback<[VideoPlayer](#videoplayer8)> | Yes | Callback used to return the result. If the operation is successful, the **VideoPlayer** instance is returned; otherwise, **null** is returned. The instance can be used to manage and play video.| +| ID| Error Message | +| -------- | ----------------------------- | +| 5400101 | No memory. Return by promise. | **Example** ```js -let videoPlayer +let avPlayer -media.createVideoPlayer((error, video) => { - if (video != null) { - videoPlayer = video; - console.info('video createVideoPlayer success'); +media.createAVPlayer().then((video) => { + if (video != null) { + avPlayer = video; + console.info('createAVPlayer success'); } else { - console.info(`video createVideoPlayer fail, error:${error}`); + console.info('createAVPlayer fail'); } +}).catch((error) => { + console.info(`AVPlayer catchCallback, error:${error}`); }); ``` -## media.createVideoPlayer8+ +## media.createAVRecorder9+ -createVideoPlayer(): Promise<[VideoPlayer](#videoplayer8)> +createAVRecorder(callback: AsyncCallback\): void -Creates a **VideoPlayer** instance. This API uses a promise to return the result. +Creates an **AVRecorder** instance. This API uses an asynchronous callback to return the result. +Only one **AVRecorder** instance can be created per device. -**System capability**: SystemCapability.Multimedia.Media.VideoPlayer +**System capability**: SystemCapability.Multimedia.Media.AVRecorder -**Return value** +**Parameters** + +| Name | Type | Mandatory| Description | +| -------- | ------------------------------------------ | ---- | ------------------------------------------------------------ | +| callback | AsyncCallback\<[AVRecorder](#avrecorder9)> | Yes | Callback used to return the result. If the operation is successful, an **AVRecorder** instance is returned; otherwise, **null** is returned. The instance can be used to record audio and video.| -| Type | Description | -| ------------------------------------- | ------------------------------------------------------------ | -| Promise<[VideoPlayer](#videoplayer8)> | Promise used to return the result. If the operation is successful, the **VideoPlayer** instance is returned; otherwise, **null** is returned. The instance can be used to manage and play video.| +**Error codes** + +For details about the error codes, see [Media Error Codes](../errorcodes/errorcode-media.md). + +| ID| Error Message | +| -------- | ------------------------------ | +| 5400101 | No memory. Return by callback. | **Example** ```js -let videoPlayer +let avRecorder -media.createVideoPlayer().then((video) => { - if (video != null) { - videoPlayer = video; - console.info('video createVideoPlayer success'); +media.createAVRecorder((error, recorder) => { + if (recorder != null) { + avRecorder = recorder; + console.info('createAVRecorder success'); } else { - console.info('video createVideoPlayer fail'); + console.info(`createAVRecorder fail, error:${error}`); } -}).catch((error) => { - console.info(`video catchCallback, error:${error}`); }); ``` -## media.createAudioRecorder +## media.createAVRecorder9+ -createAudioRecorder(): AudioRecorder +createAVRecorder(): Promise\ -Creates an **AudioRecorder** instance to control audio recording. -Only one **AudioRecorder** instance can be created per device. +Creates an **AVRecorder** instance. This API uses a promise to return the result. +Only one **AVRecorder** instance can be created per device. -**System capability**: SystemCapability.Multimedia.Media.AudioRecorder +**System capability**: SystemCapability.Multimedia.Media.AVRecorder **Return value** -| Type | Description | -| ------------------------------- | ------------------------------------------------------------ | -| [AudioRecorder](#audiorecorder) | Returns the **AudioRecorder** instance if the operation is successful; returns **null** otherwise. The instance can be used to record audio.| +| Type | Description | +| ------------------------------------ | ------------------------------------------------------------ | +| Promise\<[AVRecorder](#avrecorder9)> | Promise used to return the result. If the operation is successful, an **AVRecorder** instance is returned; otherwise, **null** is returned. The instance can be used to record audio and video.| + +**Error codes** + +For details about the error codes, see [Media Error Codes](../errorcodes/errorcode-media.md). + +| ID| Error Message | +| -------- | ----------------------------- | +| 5400101 | No memory. Return by promise. | **Example** ```js -let audioRecorder = media.createAudioRecorder(); +let avRecorder + +media.createAVRecorder().then((recorder) => { + if (recorder != null) { + avRecorder = recorder; + console.info('createAVRecorder success'); + } else { + console.info('createAVRecorder fail'); + } +}).catch((error) => { + console.info(`createAVRecorder catchCallback, error:${error}`); +}); ``` ## media.createVideoRecorder9+ -createVideoRecorder(callback: AsyncCallback\<[VideoRecorder](#videorecorder9)>): void +createVideoRecorder(callback: AsyncCallback\): void Creates a **VideoRecorder** instance. This API uses an asynchronous callback to return the result. -Only one **AudioRecorder** instance can be created per device. +Only one **VideoRecorder** instance can be created per device. **System capability**: SystemCapability.Multimedia.Media.VideoRecorder @@ -134,9 +188,9 @@ Only one **AudioRecorder** instance can be created per device. **Parameters** -| Name | Type | Mandatory| Description | -| -------- | ----------------------------------------------- | ---- | ------------------------------ | -| callback | AsyncCallback<[VideoRecorder](#videorecorder9)> | Yes | Callback used to return the result. If the operation is successful, the **VideoRecorder** instance is returned; otherwise, **null** is returned. The instance can be used to record video.| +| Name | Type | Mandatory| Description | +| -------- | ----------------------------------------------- | ---- | ------------------------------------------------------------ | +| callback | AsyncCallback<[VideoRecorder](#videorecorder9)> | Yes | Callback used to return the result. If the operation is successful, a **VideoRecorder** instance is returned; otherwise, **null** is returned. The instance can be used to record video.| **Error codes** @@ -163,10 +217,10 @@ media.createVideoRecorder((error, video) => { ## media.createVideoRecorder9+ -createVideoRecorder(): Promise<[VideoRecorder](#videorecorder9)> +createVideoRecorder(): Promise\ Creates a **VideoRecorder** instance. This API uses a promise to return the result. -Only one **AudioRecorder** instance can be created per device. +Only one **VideoRecorder** instance can be created per device. **System capability**: SystemCapability.Multimedia.Media.VideoRecorder @@ -176,7 +230,7 @@ Only one **AudioRecorder** instance can be created per device. | Type | Description | | ----------------------------------------- | ------------------------------------------------------------ | -| Promise<[VideoRecorder](#videorecorder9)> | Promise used to return the result. If the operation is successful, the **VideoRecorder** instance is returned; otherwise, **null** is returned. The instance can be used to record video.| +| Promise<[VideoRecorder](#videorecorder9)> | Promise used to return the result. If the operation is successful, a **VideoRecorder** instance is returned; otherwise, **null** is returned. The instance can be used to record video.| **Error codes** @@ -203,26 +257,24 @@ media.createVideoRecorder().then((video) => { }); ``` +## AVErrorCode9+ - -## MediaErrorCode8+ - -Enumerates the media error codes. +Enumerates the [media error codes](../errorcodes/errorcode-media.md). **System capability**: SystemCapability.Multimedia.Media.Core -| Name | Value | Description | -| -------------------------- | ---- | -------------------------------------- | -| MSERR_OK | 0 | The operation is successful. | -| MSERR_NO_MEMORY | 1 | Failed to allocate memory. The system may have no available memory.| -| MSERR_OPERATION_NOT_PERMIT | 2 | No permission to perform this operation. | -| MSERR_INVALID_VAL | 3 | Invalid input parameter. | -| MSERR_IO | 4 | An I/O error occurs. | -| MSERR_TIMEOUT | 5 | The operation times out. | -| MSERR_UNKNOWN | 6 | An unknown error occurs. | -| MSERR_SERVICE_DIED | 7 | Invalid server. | -| MSERR_INVALID_STATE | 8 | The operation is not allowed in the current state. | -| MSERR_UNSUPPORTED | 9 | The operation is not supported in the current version. | +| Name | Value | Description | +| :------------------------- | ------- | ------------------------------------ | +| AVERR_OK | 0 | The operation is successful. | +| AVERR_NO_PERMISSION | 201 | You do not have the permission to perform the operation. | +| AVERR_INVALID_PARAMETER | 401 | Invalid input parameter. | +| AVERR_UNSUPPORT_CAPABILITY | 801 | Unsupported API. | +| AVERR_NO_MEMORY | 5400101 | The system memory is insufficient or the number of services reaches the upper limit.| +| AVERR_OPERATE_NOT_PERMIT | 5400102 | The operation is not allowed in the current state or you do not have the permission to perform the operation.| +| AVERR_IO | 5400103 | The data stream is abnormal. | +| AVERR_TIMEOUT | 5400104 | The system or network response times out. | +| AVERR_SERVICE_DIED | 5400105 | The service process is dead. | +| AVERR_UNSUPPORT_FORMAT | 5400106 | The format of the media asset is not supported. | ## MediaType8+ @@ -284,1120 +336,1083 @@ Enumerates the buffering event types. | BUFFERING_PERCENT | 3 | Buffering progress, in percent. | | CACHED_DURATION | 4 | Cache duration, in ms.| -## AudioPlayer +## StateChangeReason9+ -Provides APIs to manage and play audio. Before calling an API of **AudioPlayer**, you must use [createAudioPlayer()](#mediacreateaudioplayer) to create an **AudioPlayer** instance. +Enumerates the reasons for the state transition of the **AVPlayer** or **AVRecorder** instance. The enum value is reported together with **state**. -For details about the audio playback demo, see [Audio Playback Development](../../media/audio-playback.md). +**System capability**: SystemCapability.Multimedia.Media.Core -### Attributes +| Name | Value | Description | +| ---------- | ---- | ------------------------------------------------------------ | +| USER | 1 | State transition triggered by user behavior. It happens when a user or the client calls an API.| +| BACKGROUND | 2 | State transition caused by system behavior. For example, if an application does not have the permission of Media Controller, the application is forcibly suspended or stopped by the system when it switches to the background.| -**System capability**: SystemCapability.Multimedia.Media.AudioPlayer +## AVPlayer9+ -| Name | Type | Readable| Writable| Description | -| ------------------------------- | ------------------------------------------------------ | ---- | ---- | ------------------------------------------------------------ | -| src | string | Yes | Yes | Audio file URI. The mainstream audio formats (M4A, AAC, MPEG-3, OGG, and WAV) are supported.
**Examples of supported URI schemes**:
1. FD: fd://xx
![](figures/en-us_image_url.png)
2. HTTP: http://xx
3. HTTPS: https://xx
4. HLS: http://xx or https://xx
**Required permissions**: ohos.permission.READ_MEDIA or ohos.permission.INTERNET| -| fdSrc9+ | [AVFileDescriptor](#avfiledescriptor9) | Yes | Yes | Description of the audio file. This attribute is required when audio resources of an application are continuously stored in a file.
**Example:**
Assume that a music file that stores continuous music resources consists of the following:
Music 1 (address offset: 0, byte length: 100)
Music 2 (address offset: 101; byte length: 50)
Music 3 (address offset: 151, byte length: 150)
1. To play music 1: AVFileDescriptor {fd = resource handle; offset = 0; length = 100; }
2. To play music 2: AVFileDescriptor {fd = resource handle; offset = 101; length = 50; }
3. To play music 3: AVFileDescriptor {fd = resource handle; offset = 151; length = 150; }
To play an independent music file, use **src=fd://xx**.
| -| loop | boolean | Yes | Yes | Whether to loop audio playback. The value **true** means to loop audio playback, and **false** means the opposite. | -| audioInterruptMode9+ | [audio.InterruptMode](js-apis-audio.md#interruptmode9) | Yes | Yes | Audio interruption mode. | -| currentTime | number | Yes | No | Current audio playback position, in ms. | -| duration | number | Yes | No | Audio duration, in ms. | -| state | [AudioState](#audiostate) | Yes | No | Audio playback state. This state cannot be used as the condition for triggering the call of **play()**, **pause()**, or **stop()**.| -### play +A playback management class that provides APIs to manage and play media assets. Before calling any API in **AVPlayer**, you must use [createAVPlayer()](#mediacreateavplayer9) to create an **AVPlayer** instance. -play(): void +For details about the AVPlayer demo, see [AVPlayer Development](../../media/avplayer-playback.md). -Starts to play audio resources. This API can be called only after the [dataLoad](#audioplayer_on) event is triggered. +### Attributes -**System capability**: SystemCapability.Multimedia.Media.AudioPlayer +**System capability**: SystemCapability.Multimedia.Media.AVPlayer -**Example** +| Name | Type | Readable| Writable| Description | +| --------------------------------------------------- | ------------------------------------------------------ | ---- | ---- | ------------------------------------------------------------ | +| url9+ | string | Yes | Yes | URL of the media asset. It is a static attribute and can be set only when the AVPlayer is in the idle state.
The video formats MP4, MPEG-TS, WebM, and MKV are supported.
The audio formats M4A, AAC, MP3, OGG, and WAV are supported.
**Examples of supported URLs**:
1. FD: fd://xx
![](figures/en-us_image_url.png)
2. HTTP: http://xx
3. HTTPS: https://xx
4. HLS: http://xx or https://xx| +| fdSrc9+ | [AVFileDescriptor](#avfiledescriptor9) | Yes | Yes | FD of the media asset. It is a static attribute and can be set only when the AVPlayer is in the idle state.
This attribute is required when media assets of an application are continuously stored in a file.
**Example:**
Assume that a media file that stores continuous assets consists of the following:
Video 1 (address offset: 0, byte length: 100)
Video 2 (address offset: 101; byte length: 50)
Video 3 (address offset: 151, byte length: 150)
1. To play video 1: AVFileDescriptor {fd = resource handle; offset = 0; length = 100; }
2. To play video 2: AVFileDescriptor {fd = resource handle; offset = 101; length = 50; }
3. To play video 3: AVFileDescriptor {fd = resource handle; offset = 151; length = 150; }
To play an independent media file, use **src=fd://xx**.| +| surfaceId9+ | string | Yes | Yes | Video window ID. By default, there is no video window. It is a static attribute and can be set only when the AVPlayer is in the initialized state.
It is used to render the window for video playback and therefore is not required in audio-only playback scenarios.
**Example:**
[Create a surface ID through XComponent](../arkui-ts/ts-basic-components-xcomponent.md#getxcomponentsurfaceid).| +| loop9+ | boolean | Yes | Yes | Whether to loop playback. The value **true** means to loop playback, and **false** (default) means the opposite. It is a dynamic attribute
and can be set only when the AVPlayer is in the prepared, playing, paused, or completed state.| +| videoScaleType9+ | [VideoScaleType](#videoscaletype9) | Yes | Yes | Video scaling type. The default value is **VIDEO_SCALE_TYPE_FIT_CROP**. It is a dynamic attribute
and can be set only when the AVPlayer is in the prepared, playing, paused, or completed state.| +| audioInterruptMode9+ | [audio.InterruptMode](js-apis-audio.md#interruptmode9) | Yes | Yes | Audio interruption mode. The default value is **SHARE_MODE**. It is a dynamic attribute
and can be set only when the AVPlayer is in the prepared, playing, paused, or completed state.| +| audioRendererInfo10+ | [audio.AudioRendererInfo](js-apis-audio.md#audiorendererinfo8) | Yes | Yes | Audio renderer information. The default value of **contentType** is **CONTENT_TYPE_MUSIC**, and the default value of **streamUsage** is **STREAM_USAGE_MEDIA**.
It can be set only when the AVPlayer is in the initialized state.| +| state9+ | [AVPlayerState](#avplayerstate9) | Yes | No | AVPlayer state. It can be used as a query parameter when the AVPlayer is in any state. | +| currentTime9+ | number | Yes | No | Current video playback position, in ms. It can be used as a query parameter when the AVPlayer is in the prepared, playing, paused, or completed state.
The value **-1** indicates an invalid value.| +| duration9+ | number | Yes | No | Video duration, in ms. It can be used as a query parameter when the AVPlayer is in the prepared, playing, paused, or completed state.
The value **-1** indicates an invalid value.
In live streaming scenarios, **-1** is returned by default.| +| width9+ | number | Yes | No | Video width, in pixels. It can be used as a query parameter when the AVPlayer is in the prepared, playing, paused, or completed state.
The value **0** indicates an invalid value.| +| height9+ | number | Yes | No | Video height, in pixels. It can be used as a query parameter when the AVPlayer is in the prepared, playing, paused, or completed state.
The value **0** indicates an invalid value.| -```js -audioPlayer.on('play', () => { // Set the 'play' event callback. - console.log('audio play success'); -}); -audioPlayer.play(); -``` +### on('stateChange')9+ -### pause +on(type: 'stateChange', callback: (state: AVPlayerState, reason: StateChangeReason) => void): void -pause(): void +Subscribes to AVPlayer state changes. -Pauses audio playback. +**System capability**: SystemCapability.Multimedia.Media.AVPlayer -**System capability**: SystemCapability.Multimedia.Media.AudioPlayer +**Parameters** + +| Name | Type | Mandatory| Description | +| -------- | -------- | ---- | ------------------------------------------------------------ | +| type | string | Yes | Event type, which is **'stateChange'** in this case. This event can be triggered by both user operations and the system.| +| callback | function | Yes | Callback invoked when the event is triggered. It reports the following information:
state: [AVPlayerState](#avplayerstate9), indicating the AVPlayer state.
reason: [StateChangeReason](#statechangereason9), indicating the reason for the state transition.| **Example** ```js -audioPlayer.on('pause', () => { // Set the 'pause' event callback. - console.log('audio pause success'); -}); -audioPlayer.pause(); +avPlayer.on('stateChange', async (state, reason) => { + switch (state) { + case 'idle': + console.info('state idle called') + break; + case 'initialized': + console.info('initialized prepared called') + break; + case 'prepared': + console.info('state prepared called') + break; + case 'playing': + console.info('state playing called') + break; + case 'paused': + console.info('state paused called') + break; + case 'completed': + console.info('state completed called') + break; + case 'stopped': + console.info('state stopped called') + break; + case 'released': + console.info('state released called') + break; + case 'error': + console.info('state error called') + break; + default: + console.info('unkown state :' + state) + break; + } +}) ``` -### stop +### off('stateChange')9+ -stop(): void +off(type: 'stateChange'): void -Stops audio playback. +Unsubscribes from AVPlayer state changes. -**System capability**: SystemCapability.Multimedia.Media.AudioPlayer +**System capability**: SystemCapability.Multimedia.Media.AVPlayer + +**Parameters** + +| Name| Type | Mandatory| Description | +| ------ | ------ | ---- | ----------------------------------------------------- | +| type | string | Yes | Event type, which is **'stateChange'** in this case.| **Example** ```js -audioPlayer.on('stop', () => { // Set the 'stop' event callback. - console.log('audio stop success'); -}); -audioPlayer.stop(); +avPlayer.off('stateChange') ``` -### reset7+ +### on('error')9+ -reset(): void +on(type: 'error', callback: ErrorCallback): void -Resets the audio asset to be played. +Subscribes to AVPlayer errors. This event is used only for error prompt and does not require the user to stop playback control. If the [AVPlayer state](#avplayerstate9) is also switched to error, call **reset()** or **release()** to exit the playback. -**System capability**: SystemCapability.Multimedia.Media.AudioPlayer +**System capability**: SystemCapability.Multimedia.Media.AVPlayer + +**Parameters** + +| Name | Type | Mandatory| Description | +| -------- | -------- | ---- | ------------------------------------------------------------ | +| type | string | Yes | Event type, which is **'error'** in this case. This event can be triggered by both user operations and the system.| +| callback | function | Yes | Callback used to return the error code ID and error message.| + +The AVPlayer provides the following error types: + +| ID| Error Message | Description | +| -------- | --------------------- | ------------------------------------------------------------ | +| 201 | No Permission: | No permission to perform the operation. The [AVPlayer state](#avplayerstate9) is error.| +| 401 | Invalid Parameter: | Incorrect input parameter, causing an invalid call. | +| 801 | Unsupport Capability: | Unsupported API, causing an invalid call. | +| 5400101 | No Memory: | Insufficient memory. The [AVPlayer state](#avplayerstate9) is error.| +| 5400102 | Operate Not Permit: | Unsupported operation in the current state, causing an invalid call. | +| 5400103 | IO Error: | Abnormal stream. | +| 5400104 | Network Timeout: | The response times out due to a network error. The [AVPlayer state](#avplayerstate9) is error.| +| 5400105 | Service Died: | The playback process is dead. The [AVPlayer state](#avplayerstate9) is error.| +| 5400106 | Unsupport Format: | Unsupported file format. The [AVPlayer state](#avplayerstate9) is error.| **Example** ```js -audioPlayer.on('reset', () => { // Set the 'reset' event callback. - console.log('audio reset success'); -}); -audioPlayer.reset(); +avPlayer.on('error', (error) => { + console.info('error happened,and error message is :' + error.message) + console.info('error happened,and error code is :' + error.code) +}) ``` -### seek +### off('error')9+ -seek(timeMs: number): void +off(type: 'error'): void -Seeks to the specified playback position. +Unsubscribes from AVPlayer errors. -**System capability**: SystemCapability.Multimedia.Media.AudioPlayer +**System capability**: SystemCapability.Multimedia.Media.AVPlayer **Parameters** -| Name| Type | Mandatory| Description | -| ------ | ------ | ---- | ----------------------------------------------------------- | -| timeMs | number | Yes | Position to seek to, in ms. The value range is [0, duration].| +| Name| Type | Mandatory| Description | +| ------ | ------ | ---- | ----------------------------------------- | +| type | string | Yes | Event type, which is **'error'** in this case.| **Example** ```js -audioPlayer.on('timeUpdate', (seekDoneTime) => { // Set the 'timeUpdate' event callback. - if (seekDoneTime == null) { - console.info('audio seek fail'); - return; - } - console.log('audio seek success. seekDoneTime: ' + seekDoneTime); -}); -audioPlayer.seek(30000); // Seek to 30000 ms. +avPlayer.off('error') ``` -### setVolume +### prepare9+ -setVolume(vol: number): void +prepare(callback: AsyncCallback\): void -Sets the volume. +Prepares for audio and video playback. This API uses an asynchronous callback to return the result. It can be called only when the AVPlayer is in the initialized state. -**System capability**: SystemCapability.Multimedia.Media.AudioPlayer +**System capability**: SystemCapability.Multimedia.Media.AVPlayer **Parameters** -| Name| Type | Mandatory| Description | -| ------ | ------ | ---- | ------------------------------------------------------------ | -| vol | number | Yes | Relative volume. The value ranges from 0.00 to 1.00. The value **1** indicates the maximum volume (100%).| +| Name | Type | Mandatory| Description | +| -------- | -------- | ---- | -------------------- | +| callback | function | Yes | Callback used to return the result.| + +**Error codes** + +For details about the error codes, see [Media Error Codes](../errorcodes/errorcode-media.md). + +| ID| Error Message | +| -------- | ------------------------------------------ | +| 5400102 | Operation not allowed. Return by callback. | +| 5400106 | Unsupport format. Return by callback. | **Example** ```js -audioPlayer.on('volumeChange', () => { // Set the 'volumeChange' event callback. - console.log('audio volumeChange success'); -}); -audioPlayer.setVolume(1); // Set the volume to 100%. +avPlayer.prepare((err) => { + if (err == null) { + console.info('prepare success'); + } else { + console.error('prepare filed,error message is :' + err.message) + } +}) ``` -### release +### prepare9+ -release(): void +prepare(): Promise\ -Releases the audio playback resource. +Prepares for audio and video playback. This API uses a promise to return the result. It can be called only when the AVPlayer is in the initialized state. -**System capability**: SystemCapability.Multimedia.Media.AudioPlayer +**System capability**: SystemCapability.Multimedia.Media.AVPlayer + +**Return value** + +| Type | Description | +| -------------- | ------------------------- | +| Promise\ | Promise used to return the result.| + +**Error codes** + +For details about the error codes, see [Media Error Codes](../errorcodes/errorcode-media.md). + +| ID| Error Message | +| -------- | ----------------------------------------- | +| 5400102 | Operation not allowed. Return by promise. | +| 5400106 | Unsupport format. Return by promise. | **Example** ```js -audioPlayer.release(); -audioPlayer = undefined; +avPlayer.prepare().then(() => { + console.info('prepare success'); +}, (err) => { + console.error('prepare filed,error message is :' + err.message) +}) ``` -### getTrackDescription8+ +### play9+ -getTrackDescription(callback: AsyncCallback>): void +play(callback: AsyncCallback\): void -Obtains the audio track information. This API uses an asynchronous callback to return the result. It can be called only after the [dataLoad](#audioplayer_on) event is triggered. +Starts to play an audio and video asset. This API uses an asynchronous callback to return the result. It can be called only when the AVPlayer is in the prepared, paused, or completed state. -**System capability**: SystemCapability.Multimedia.Media.AudioPlayer +**System capability**: SystemCapability.Multimedia.Media.AVPlayer **Parameters** -| Name | Type | Mandatory| Description | -| -------- | ------------------------------------------------------------ | ---- | ------------------------------------------ | -| callback | AsyncCallback> | Yes | Callback used to return a **MediaDescription** array, which records the audio track information.| +| Name | Type | Mandatory| Description | +| -------- | -------- | ---- | -------------------- | +| callback | function | Yes | Callback used to return the result.| + +**Error codes** + +For details about the error codes, see [Media Error Codes](../errorcodes/errorcode-media.md). + +| ID| Error Message | +| -------- | ------------------------------------------ | +| 5400102 | Operation not allowed. Return by callback. | **Example** ```js -function printfDescription(obj) { - for (let item in obj) { - let property = obj[item]; - console.info('audio key is ' + item); - console.info('audio value is ' + property); - } -} - -audioPlayer.getTrackDescription((error, arrList) => { - if (arrList != null) { - for (let i = 0; i < arrList.length; i++) { - printfDescription(arrList[i]); - } +avPlayer.play((err) => { + if (err == null) { + console.info('play success'); } else { - console.log(`audio getTrackDescription fail, error:${error}`); + console.error('play filed,error message is :' + err.message) } -}); +}) ``` -### getTrackDescription8+ +### play9+ -getTrackDescription(): Promise> +play(): Promise\ -Obtains the audio track information. This API uses a promise to return the result. It can be called only after the [dataLoad](#audioplayer_on) event is triggered. +Starts to play an audio and video asset. This API uses a promise to return the result. It can be called only when the AVPlayer is in the prepared, paused, or completed state. -**System capability**: SystemCapability.Multimedia.Media.AudioPlayer +**System capability**: SystemCapability.Multimedia.Media.AVPlayer **Return value** -| Type | Description | -| ------------------------------------------------------ | ----------------------------------------------- | -| Promise> | Promise used to return a **MediaDescription** array, which records the audio track information.| +| Type | Description | +| -------------- | ------------------------- | +| Promise\ | Promise used to return the result.| + +**Error codes** + +For details about the error codes, see [Media Error Codes](../errorcodes/errorcode-media.md). + +| ID| Error Message | +| -------- | ----------------------------------------- | +| 5400102 | Operation not allowed. Return by promise. | **Example** ```js -function printfDescription(obj) { - for (let item in obj) { - let property = obj[item]; - console.info('audio key is ' + item); - console.info('audio value is ' + property); - } -} -let arrayDescription = null -audioPlayer.getTrackDescription().then((arrList) => { - if (arrList != null) { - arrayDescription = arrList; - } else { - console.log('audio getTrackDescription fail'); - } -}).catch((error) => { - console.info(`audio catchCallback, error:${error}`); -}); - -for (let i = 0; i < arrayDescription.length; i++) { - printfDescription(arrayDescription[i]); -} +avPlayer.play().then(() => { + console.info('play success'); +}, (err) => { + console.error('play filed,error message is :' + err.message) +}) ``` -### on('bufferingUpdate')8+ +### pause9+ -on(type: 'bufferingUpdate', callback: (infoType: [BufferingInfoType](#bufferinginfotype8), value: number) => void): void +pause(callback: AsyncCallback\): void -Subscribes to the audio buffering update event. This API works only under online playback. +Pauses audio and video playback. This API uses an asynchronous callback to return the result. It can be called only when the AVPlayer is in the playing state. -**System capability**: SystemCapability.Multimedia.Media.AudioPlayer +**System capability**: SystemCapability.Multimedia.Media.AVPlayer **Parameters** -| Name | Type | Mandatory| Description | -| -------- | -------- | ---- | ------------------------------------------------------------ | -| type | string | Yes | Event type, which is **'bufferingUpdate'** in this case. | -| callback | function | Yes | Callback invoked when the event is triggered.
When [BufferingInfoType](#bufferinginfotype8) is set to **BUFFERING_PERCENT** or **CACHED_DURATION**, **value** is valid. Otherwise, **value** is fixed at **0**.| +| Name | Type | Mandatory| Description | +| -------- | -------- | ---- | -------------------- | +| callback | function | Yes | Callback used to return the result.| + +**Error codes** + +For details about the error codes, see [Media Error Codes](../errorcodes/errorcode-media.md). + +| ID| Error Message | +| -------- | ------------------------------------------ | +| 5400102 | Operation not allowed. Return by callback. | **Example** ```js -audioPlayer.on('bufferingUpdate', (infoType, value) => { - console.log('audio bufferingInfo type: ' + infoType); - console.log('audio bufferingInfo value: ' + value); -}); +avPlayer.pause((err) => { + if (err == null) { + console.info('pause success'); + } else { + console.error('pause filed,error message is :' + err.message) + } +}) ``` - ### on('play' | 'pause' | 'stop' | 'reset' | 'dataLoad' | 'finish' | 'volumeChange') +### pause9+ -on(type: 'play' | 'pause' | 'stop' | 'reset' | 'dataLoad' | 'finish' | 'volumeChange', callback: () => void): void +pause(): Promise\ -Subscribes to the audio playback events. +Pauses audio and video playback. This API uses a promise to return the result. It can be called only when the AVPlayer is in the playing state. -**System capability**: SystemCapability.Multimedia.Media.AudioPlayer +**System capability**: SystemCapability.Multimedia.Media.AVPlayer -**Parameters** +**Return value** -| Name | Type | Mandatory| Description | -| -------- | ---------- | ---- | ------------------------------------------------------------ | -| type | string | Yes | Event type. The following events are supported:
- 'play': triggered when the [play()](#audioplayer_play) API is called and audio playback starts.
- 'pause': triggered when the [pause()](#audioplayer_pause) API is called and audio playback is paused.
- 'stop': triggered when the [stop()](#audioplayer_stop) API is called and audio playback stops.
- 'reset': triggered when the [reset()](#audioplayer_reset) API is called and audio playback is reset.
- 'dataLoad': triggered when the audio data is loaded, that is, when the **src** attribute is configured.
- 'finish': triggered when the audio playback is finished.
- 'volumeChange': triggered when the [setVolume()](#audioplayer_setvolume) API is called and the playback volume is changed.| -| callback | () => void | Yes | Callback invoked when the event is triggered. | +| Type | Description | +| -------------- | ------------------------- | +| Promise\ | Promise used to return the result.| -**Example** +**Error codes** -```js -import fileio from '@ohos.fileio' +For details about the error codes, see [Media Error Codes](../errorcodes/errorcode-media.md). -let audioPlayer = media.createAudioPlayer(); // Create an AudioPlayer instance. -audioPlayer.on('dataLoad', () => { // Set the 'dataLoad' event callback, which is triggered when the src attribute is set successfully. - console.info('audio set source success'); - audioPlayer.play(); // Start the playback and trigger the 'play' event callback. -}); -audioPlayer.on('play', () => { // Set the 'play' event callback. - console.info('audio play success'); - audioPlayer.seek(30000); // Call the seek() API and trigger the 'timeUpdate' event callback. -}); -audioPlayer.on('pause', () => { // Set the 'pause' event callback. - console.info('audio pause success'); - audioPlayer.stop(); // Stop the playback and trigger the 'stop' event callback. -}); -audioPlayer.on('reset', () => { // Set the 'reset' event callback. - console.info('audio reset success'); - audioPlayer.release(); // Release the AudioPlayer instance. - audioPlayer = undefined; -}); -audioPlayer.on('timeUpdate', (seekDoneTime) => { // Set the 'timeUpdate' event callback. - if (seekDoneTime == null) { - console.info('audio seek fail'); - return; - } - console.info('audio seek success, and seek time is ' + seekDoneTime); - audioPlayer.setVolume(0.5); // Set the volume to 50% and trigger the 'volumeChange' event callback. -}); -audioPlayer.on('volumeChange', () => { // Set the 'volumeChange' event callback. - console.info('audio volumeChange success'); - audioPlayer.pause(); // Pause the playback and trigger the 'pause' event callback. -}); -audioPlayer.on('finish', () => { // Set the 'finish' event callback. - console.info('audio play finish'); - audioPlayer.stop(); // Stop the playback and trigger the 'stop' event callback. -}); -audioPlayer.on('error', (error) => { // Set the 'error' event callback. - console.info(`audio error called, error: ${error}`); -}); +| ID| Error Message | +| -------- | ----------------------------------------- | +| 5400102 | Operation not allowed. Return by promise. | -// Set the FD (local playback) of the video file selected by the user. -let fdPath = 'fd://'; -// The stream in the path can be pushed to the device by running the "hdc file send D:\xxx\01.mp3 /data/accounts/account_0/appdata" command. -let path = '/data/accounts/account_0/appdata/ohos.xxx.xxx.xxx/01.mp3'; -fileio.open(path).then((fdValue) => { - fdPath = fdPath + '' + fdValue; - console.info('open fd success fd is' + fdPath); +**Example** + +```js +avPlayer.pause().then(() => { + console.info('pause success'); }, (err) => { - console.info('open fd failed err is' + err); -}).catch((err) => { - console.info('open fd failed err is' + err); -}); -audioPlayer.src = fdPath; // Set the src attribute and trigger the 'dataLoad' event callback. + console.error('pause filed,error message is :' + err.message) +}) ``` -### on('timeUpdate') +### stop9+ -on(type: 'timeUpdate', callback: Callback\): void +stop(callback: AsyncCallback\): void -Subscribes to the **'timeUpdate'** event. This event is reported every second when the audio playback is in progress. +Stops audio and video playback. This API uses an asynchronous callback to return the result. It can be called only when the AVPlayer is in the prepared, playing, paused, or completed state. -**System capability**: SystemCapability.Multimedia.Media.AudioPlayer +**System capability**: SystemCapability.Multimedia.Media.AVPlayer **Parameters** -| Name | Type | Mandatory| Description | -| -------- | ----------------- | ---- | ------------------------------------------------------------ | -| type | string | Yes | Event type, which is **'timeUpdate'** in this case.
The **'timeUpdate'** event is triggered when the audio playback starts after an audio playback timestamp update.| -| callback | Callback\ | Yes | Callback invoked when the event is triggered. The input parameter is the updated timestamp. | +| Name | Type | Mandatory| Description | +| -------- | -------- | ---- | -------------------- | +| callback | function | Yes | Callback used to return the result.| + +**Error codes** + +For details about the error codes, see [Media Error Codes](../errorcodes/errorcode-media.md). + +| ID| Error Message | +| -------- | ------------------------------------------ | +| 5400102 | Operation not allowed. Return by callback. | **Example** ```js -audioPlayer.on('timeUpdate', (newTime) => { // Set the 'timeUpdate' event callback. - if (newTime == null) { - console.info('audio timeUpadate fail'); - return; +avPlayer.stop((err) => { + if (err == null) { + console.info('stop success'); + } else { + console.error('stop filed,error message is :' + err.message) } - console.log('audio timeUpadate success. seekDoneTime: ' + newTime); -}); -audioPlayer.play(); // The 'timeUpdate' event is triggered when the playback starts. +}) ``` -### on('error') +### stop9+ -on(type: 'error', callback: ErrorCallback): void +stop(): Promise\ -Subscribes to audio playback error events. After an error event is reported, you must handle the event and exit the playback. +Stops audio and video playback. This API uses a promise to return the result. It can be called only when the AVPlayer is in the prepared, playing, paused, or completed state. -**System capability**: SystemCapability.Multimedia.Media.AudioPlayer +**System capability**: SystemCapability.Multimedia.Media.AVPlayer -**Parameters** +**Return value** -| Name | Type | Mandatory| Description | -| -------- | ------------- | ---- | ------------------------------------------------------------ | -| type | string | Yes | Event type, which is **'error'** in this case.
The **'error'** event is triggered when an error occurs during audio playback.| -| callback | ErrorCallback | Yes | Callback invoked when the event is triggered. | +| Type | Description | +| -------------- | ------------------------- | +| Promise\ | Promise used to return the result.| + +**Error codes** + +For details about the error codes, see [Media Error Codes](../errorcodes/errorcode-media.md). + +| ID| Error Message | +| -------- | ----------------------------------------- | +| 5400102 | Operation not allowed. Return by promise. | **Example** ```js -audioPlayer.on('error', (error) => { // Set the 'error' event callback. - console.info(`audio error called, error: ${error}`); -}); -audioPlayer.setVolume(3); // Set volume to an invalid value to trigger the 'error' event. +avPlayer.stop().then(() => { + console.info('stop success'); +}, (err) => { + console.error('stop filed,error message is :' + err.message) +}) ``` -## AudioState - -Enumerates the audio playback states. You can obtain the state through the **state** attribute. +### reset9+ -**System capability**: SystemCapability.Multimedia.Media.AudioPlayer +reset(callback: AsyncCallback\): void -| Name | Type | Description | -| ------- | ------ | ---------------------------------------------- | -| idle | string | No audio playback is in progress. The audio player is in this state after the **'dataload'** or **'reset'** event is triggered.| -| playing | string | Audio playback is in progress. The audio player is in this state after the **'play'** event is triggered. | -| paused | string | Audio playback is paused. The audio player is in this state after the **'pause'** event is triggered. | -| stopped | string | Audio playback is stopped. The audio player is in this state after the **'stop'** event is triggered. | -| error | string | Audio playback is in the error state. | +Resets audio and video playback. This API uses an asynchronous callback to return the result. It can be called only when the AVPlayer is in the initialized, prepared, playing, paused, completed, stopped, or error state. -## AVFileDescriptor9+ +**System capability**: SystemCapability.Multimedia.Media.AVPlayer -Describes audio and video file resources. It is used to specify a particular resource for playback based on its offset and length within a file. +**Parameters** -**System capability**: SystemCapability.Multimedia.Media.Core +| Name | Type | Mandatory| Description | +| -------- | -------- | ---- | -------------------- | +| callback | function | Yes | Callback used to return the result.| -| Name| Type | Mandatory| Description | -| ------ | ------ | ---- | ------------------------------------------------------------ | -| fd | number | Yes | Resource handle, which is obtained by calling **resourceManager.getRawFileDescriptor**. | -| offset | number | Yes | Resource offset, which needs to be entered based on the preset resource information. An invalid value causes a failure to parse audio and video resources.| -| length | number | Yes | Resource length, which needs to be entered based on the preset resource information. An invalid value causes a failure to parse audio and video resources.| +**Error codes** -## VideoPlayer8+ +For details about the error codes, see [Media Error Codes](../errorcodes/errorcode-media.md). -Provides APIs to manage and play video. Before calling an API of **VideoPlayer**, you must use [createVideoPlayer()](#mediacreatevideoplayer8) to create a [VideoPlayer](#videoplayer8) instance. +| ID| Error Message | +| -------- | ------------------------------------------ | +| 5400102 | Operation not allowed. Return by callback. | -For details about the video playback demo, see [Video Playback Development](../../media/video-playback.md). +**Example** -### Attributes +```js +avPlayer.reset((err) => { + if (err == null) { + console.info('reset success'); + } else { + console.error('reset filed,error message is :' + err.message) + } +}) +``` -**System capability**: SystemCapability.Multimedia.Media.VideoPlayer +### reset9+ -| Name | Type | Readable| Writable| Description | -| ------------------------ | ---------------------------------- | ---- | ---- | ------------------------------------------------------------ | -| url8+ | string | Yes | Yes | Video URL. The mainstream video formats (MPEG-4, MPEG-TS, WebM, and MKV) are supported.
**Example of supported URIs**:
1. FD: fd://xx
![](figures/en-us_image_url.png)
2. HTTP: http://xx
3. HTTPS: https://xx
4. HLS: http://xx or https://xx
| -| fdSrc9+ | [AVFileDescriptor](#avfiledescriptor9) | Yes| Yes| Description of a video file. This attribute is required when video resources of an application are continuously stored in a file.
**Example:**
Assume that a music file that stores continuous music resources consists of the following:
Video 1 (address offset: 0, byte length: 100)
Video 2 (address offset: 101; byte length: 50)
Video 3 (address offset: 151, byte length: 150)
1. To play video 1: AVFileDescriptor {fd = resource handle; offset = 0; length = 100; }
2. To play video 2: AVFileDescriptor {fd = resource handle; offset = 101; length = 50; }
3. To play video 3: AVFileDescriptor {fd = resource handle; offset = 151; length = 150; }
To play an independent video file, use **src=fd://xx**.
| -| loop8+ | boolean | Yes | Yes | Whether to loop video playback. The value **true** means to loop video playback, and **false** means the opposite. | -| videoScaleType9+ | [VideoScaleType](#videoscaletype9) | Yes | Yes | Video scale type. | -| audioInterruptMode9+ | [audio.InterruptMode](js-apis-audio.md#interruptmode9) | Yes | Yes | Audio interruption mode. | -| currentTime8+ | number | Yes | No | Current video playback position, in ms. | -| duration8+ | number | Yes | No | Video duration, in ms. The value **-1** indicates the live mode. | -| state8+ | [VideoPlayState](#videoplaystate8) | Yes | No | Video playback state. | -| width8+ | number | Yes | No | Video width, in pixels. | -| height8+ | number | Yes | No | Video height, in pixels. | +reset(): Promise\ -### setDisplaySurface8+ +Resets audio and video playback. This API uses a promise to return the result. It can be called only when the AVPlayer is in the initialized, prepared, playing, paused, completed, stopped, or error state. -setDisplaySurface(surfaceId: string, callback: AsyncCallback\): void +**System capability**: SystemCapability.Multimedia.Media.AVPlayer -Sets **SurfaceId**. This API uses an asynchronous callback to return the result. +**Return value** -*Note: **SetDisplaySurface** must be called between the URL setting and the calling of **prepare**. A surface must be set for video streams without audio. Otherwise, the calling of **prepare** fails. +| Type | Description | +| -------------- | ------------------------- | +| Promise\ | Promise used to return the result.| -**System capability**: SystemCapability.Multimedia.Media.VideoPlayer +**Error codes** -**Parameters** +For details about the error codes, see [Media Error Codes](../errorcodes/errorcode-media.md). -| Name | Type | Mandatory| Description | -| --------- | -------------------- | ---- | ------------------------- | -| surfaceId | string | Yes | Surface ID to set. | -| callback | AsyncCallback\ | Yes | Callback used to return the result.| +| ID| Error Message | +| -------- | ----------------------------------------- | +| 5400102 | Operation not allowed. Return by promise. | **Example** ```js -let surfaceId = null; -videoPlayer.setDisplaySurface(surfaceId, (err) => { - if (err == null) { - console.info('setDisplaySurface success!'); - } else { - console.info('setDisplaySurface fail!'); - } -}); +avPlayer.reset().then(() => { + console.info('reset success'); +}, (err) => { + console.error('reset filed,error message is :' + err.message) +}) ``` -### setDisplaySurface8+ - -setDisplaySurface(surfaceId: string): Promise\ +### release9+ -Sets **SurfaceId**. This API uses a promise to return the result. +release(callback: AsyncCallback\): void -*Note: **SetDisplaySurface** must be called between the URL setting and the calling of **prepare**. A surface must be set for video streams without audio. Otherwise, the calling of **prepare** fails. +Releases the playback resources. This API uses an asynchronous callback to return the result. It can be called when the AVPlayer is in any state except released. -**System capability**: SystemCapability.Multimedia.Media.VideoPlayer +**System capability**: SystemCapability.Multimedia.Media.AVPlayer **Parameters** -| Name | Type | Mandatory| Description | -| --------- | ------ | ---- | --------- | -| surfaceId | string | Yes | Surface ID to set.| - -**Return value** - -| Type | Description | -| -------------- | ------------------------------ | -| Promise\ | Promise used to return the result.| - -**Example** - -```js -let surfaceId = null; -videoPlayer.setDisplaySurface(surfaceId).then(() => { - console.info('setDisplaySurface success'); -}).catch((error) => { - console.info(`video catchCallback, error:${error}`); -}); -``` - -### prepare8+ - -prepare(callback: AsyncCallback\): void +| Name | Type | Mandatory| Description | +| -------- | -------- | ---- | -------------------- | +| callback | function | Yes | Callback used to return the result.| -Prepares for video playback. This API uses an asynchronous callback to return the result. - -**System capability**: SystemCapability.Multimedia.Media.VideoPlayer +**Error codes** -**Parameters** +For details about the error codes, see [Media Error Codes](../errorcodes/errorcode-media.md). -| Name | Type | Mandatory| Description | -| -------- | -------------------- | ---- | ------------------------ | -| callback | AsyncCallback\ | Yes | Callback used to return the result.| +| ID| Error Message | +| -------- | ------------------------------------------ | +| 5400102 | Operation not allowed. Return by callback. | **Example** ```js -videoPlayer.prepare((err) => { +avPlayer.release((err) => { if (err == null) { - console.info('prepare success!'); + console.info('reset success'); } else { - console.info('prepare fail!'); + console.error('release filed,error message is :' + err.message) } -}); +}) ``` -### prepare8+ +### release9+ -prepare(): Promise\ +release(): Promise\ -Prepares for video playback. This API uses a promise to return the result. +Releases the playback resources. This API uses a promise to return the result. It can be called when the AVPlayer is in any state except released. -**System capability**: SystemCapability.Multimedia.Media.VideoPlayer +**System capability**: SystemCapability.Multimedia.Media.AVPlayer **Return value** -| Type | Description | -| -------------- | ----------------------------- | +| Type | Description | +| -------------- | ------------------------- | | Promise\ | Promise used to return the result.| +**Error codes** + +For details about the error codes, see [Media Error Codes](../errorcodes/errorcode-media.md). + +| ID| Error Message | +| -------- | ----------------------------------------- | +| 5400102 | Operation not allowed. Return by promise. | + **Example** ```js -videoPlayer.prepare().then(() => { - console.info('prepare success'); -}).catch((error) => { - console.info(`video catchCallback, error:${error}`); -}); +avPlayer.release().then(() => { + console.info('release success'); +}, (err) => { + console.error('release filed,error message is :' + err.message) +}) ``` -### play8+ +### getTrackDescription9+ -play(callback: AsyncCallback\): void; +getTrackDescription(callback: AsyncCallback\>): void -Starts to play video resources. This API uses an asynchronous callback to return the result. +Obtains the audio and video track information. This API uses an asynchronous callback to return the result. It can be called only when the AVPlayer is in the prepared, playing, or paused state. -**System capability**: SystemCapability.Multimedia.Media.VideoPlayer +**System capability**: SystemCapability.Multimedia.Media.AVPlayer **Parameters** -| Name | Type | Mandatory| Description | -| -------- | -------------------- | ---- | ------------------------ | -| callback | AsyncCallback\ | Yes | Callback used to return the result.| +| Name | Type | Mandatory| Description | +| -------- | ------------------------------------------------------------ | ---- | -------------------------------------------- | +| callback | AsyncCallback> | Yes | Callback used to return a **MediaDescription** array, which records the audio and video track information.| + +**Error codes** + +For details about the error codes, see [Media Error Codes](../errorcodes/errorcode-media.md). + +| ID| Error Message | +| -------- | ------------------------------------------ | +| 5400102 | Operation not allowed. Return by callback. | **Example** ```js -videoPlayer.play((err) => { - if (err == null) { - console.info('play success!'); +avPlayer.getTrackDescription((error, arrList) => { + if ((arrList) != null) { + for (let i = 0; i < arrList.length; i++) { + printfDescription(arrList[i]); + } } else { - console.info('play fail!'); + console.log(`video getTrackDescription fail, error:${error}`); } }); ``` -### play8+ +### getTrackDescription9+ -play(): Promise\; +getTrackDescription(): Promise\> -Starts to play video resources. This API uses a promise to return the result. +Obtains the audio and video track information. This API uses a promise to return the result. It can be called only when the AVPlayer is in the prepared, playing, or paused state. -**System capability**: SystemCapability.Multimedia.Media.VideoPlayer +**System capability**: SystemCapability.Multimedia.Media.AVPlayer **Return value** -| Type | Description | -| -------------- | ----------------------------- | -| Promise\ | Promise used to return the result.| +| Type | Description | +| ------------------------------------------------------ | ------------------------------------------------- | +| Promise> | Promise used to return a **MediaDescription** array, which records the audio and video track information.| + +**Error codes** + +For details about the error codes, see [Media Error Codes](../errorcodes/errorcode-media.md). + +| ID| Error Message | +| -------- | ----------------------------------------- | +| 5400102 | Operation not allowed. Return by promise. | **Example** ```js -videoPlayer.play().then(() => { - console.info('play success'); +let arrayDescription; +avPlayer.getTrackDescription().then((arrList) => { + if (arrList != null) { + arrayDescription = arrList; + } else { + console.log('video getTrackDescription fail'); + } }).catch((error) => { - console.info(`video catchCallback, error:${error}`); + console.info(`video catchCallback, error:${error}`); }); +for (let i = 0; i < arrayDescription.length; i++) { + printfDescription(arrayDescription[i]); +} ``` -### pause8+ +### seek9+ -pause(callback: AsyncCallback\): void +seek(timeMs: number, mode?:SeekMode): void -Pauses video playback. This API uses an asynchronous callback to return the result. +Seeks to the specified playback position. This API can be called only when the AVPlayer is in the prepared, playing, paused, or completed state. You can check whether the seek operation takes effect by subscribing to the [seekDone](#seekDone_on) event. -**System capability**: SystemCapability.Multimedia.Media.VideoPlayer +**System capability**: SystemCapability.Multimedia.Media.AVPlayer **Parameters** -| Name | Type | Mandatory| Description | -| -------- | -------------------- | ---- | ------------------------ | -| callback | AsyncCallback\ | Yes | Callback used to return the result.| +| Name| Type | Mandatory| Description | +| ------ | ---------------------- | ---- | ------------------------------------------------------------ | +| timeMs | number | Yes | Position to seek to, in ms. The value range is [0, [duration](#avplayer_duration)].| +| mode | [SeekMode](#seekmode8) | No | Seek mode based on the video I frame. **Set this parameter only for video playback.** | **Example** ```js -videoPlayer.pause((err) => { - if (err == null) { - console.info('pause success!'); - } else { - console.info('pause fail!'); - } -}); +let seekTime = 1000 +avPlayer.seek(seekTime, media.SeekMode.SEEK_PREV_SYNC) ``` -### pause8+ +### on('seekDone')9+ -pause(): Promise\ +on(type: 'seekDone', callback: Callback\): void -Pauses video playback. This API uses a promise to return the result. +Subscribes to the event to check whether the seek operation takes effect. -**System capability**: SystemCapability.Multimedia.Media.VideoPlayer +**System capability**: SystemCapability.Multimedia.Media.AVPlayer -**Return value** +**Parameters** -| Type | Description | -| -------------- | ----------------------------- | -| Promise\ | Promise used to return the result.| +| Name | Type | Mandatory| Description | +| -------- | -------- | ---- | ------------------------------------------------------------ | +| type | string | Yes | Event type, which is **'seekDone'** in this case. This event is triggered each time **seek()** is called.| +| callback | Callback\ | Yes | Callback invoked when the event is triggered. It reports the time position requested by the user.
For video playback, [SeekMode](#seekmode8) may cause the actual position to be different from that requested by the user. The exact position can be obtained from the **currentTime** attribute. The time in this callback only means that the requested seek operation is complete.| **Example** ```js -videoPlayer.pause().then(() => { - console.info('pause success'); -}).catch((error) => { - console.info(`video catchCallback, error:${error}`); -}); +avPlayer.on('seekDone', (seekDoneTime:number) => { + console.info('seekDone success,and seek time is:' + seekDoneTime) +}) ``` -### stop8+ +### off('seekDone')9+ -stop(callback: AsyncCallback\): void +off(type: 'seekDone'): void -Stops video playback. This API uses an asynchronous callback to return the result. +Unsubscribes from the event that checks whether the seek operation takes effect. -**System capability**: SystemCapability.Multimedia.Media.VideoPlayer +**System capability**: SystemCapability.Multimedia.Media.AVPlayer **Parameters** -| Name | Type | Mandatory| Description | -| -------- | -------------------- | ---- | ------------------------ | -| callback | AsyncCallback\ | Yes | Callback used to return the result.| +| Name| Type | Mandatory| Description | +| ------ | ------ | ---- | ---------------------------------------------------- | +| type | string | Yes | Event type, which is **'seekDone'** in this case.| **Example** ```js -videoPlayer.stop((err) => { - if (err == null) { - console.info('stop success!'); - } else { - console.info('stop fail!'); - } -}); +avPlayer.off('seekDone') ``` -### stop8+ +### setSpeed9+ -stop(): Promise\ +setSpeed(speed: PlaybackSpeed): void -Stops video playback. This API uses a promise to return the result. +Sets the playback speed. This API can be called only when the AVPlayer is in the prepared, playing, paused, or completed state. You can check whether the setting takes effect by subscribing to the [speedDone](#speedDone_on) event. -**System capability**: SystemCapability.Multimedia.Media.VideoPlayer +**System capability**: SystemCapability.Multimedia.Media.AVPlayer -**Return value** +**Parameters** -| Type | Description | -| -------------- | ----------------------------- | -| Promise\ | Promise used to return the result.| +| Name| Type | Mandatory| Description | +| ------ | -------------------------------- | ---- | ------------------ | +| speed | [PlaybackSpeed](#playbackspeed8) | Yes | Playback speed to set.| **Example** ```js -videoPlayer.stop().then(() => { - console.info('stop success'); -}).catch((error) => { - console.info(`video catchCallback, error:${error}`); -}); +avPlayer.setSpeed(media.AVPlayerSpeed.SPEED_FORWARD_2_00_X) ``` -### reset8+ +### on('speedDone')9+ -reset(callback: AsyncCallback\): void +on(type: 'speedDone', callback: Callback\): void -Resets the video asset to be played. This API uses an asynchronous callback to return the result. +Subscribes to the event to check whether the playback speed is successfully set. -**System capability**: SystemCapability.Multimedia.Media.VideoPlayer +**System capability**: SystemCapability.Multimedia.Media.AVPlayer **Parameters** -| Name | Type | Mandatory| Description | -| -------- | -------------------- | ---- | ------------------------ | -| callback | AsyncCallback\ | Yes | Callback used to return the result.| +| Name | Type | Mandatory| Description | +| -------- | -------- | ---- | ------------------------------------------------------------ | +| type | string | Yes | Event type, which is **'speedDone'** in this case. This event is triggered each time **setSpeed()** is called.| +| callback | Callback\ | Yes | Callback invoked when the event is triggered. It reports the speed set. For details, see [PlaybackSpeed](#playbackspeed8).| **Example** ```js -videoPlayer.reset((err) => { - if (err == null) { - console.info('reset success!'); - } else { - console.info('reset fail!'); - } -}); +avPlayer.on('speedDone', (speed:number) => { + console.info('speedDone success,and speed value is:' + speed) +}) ``` -### reset8+ +### off('speedDone')9+ -reset(): Promise\ +off(type: 'speedDone'): void -Resets the video asset to be played. This API uses a promise to return the result. +Unsubscribes from the event that checks whether the playback speed is successfully set. -**System capability**: SystemCapability.Multimedia.Media.VideoPlayer +**System capability**: SystemCapability.Multimedia.Media.AVPlayer -**Return value** +**Parameters** -| Type | Description | -| -------------- | ----------------------------- | -| Promise\ | Promise used to return the result.| +| Name| Type | Mandatory| Description | +| ------ | ------ | ---- | --------------------------------------------------------- | +| type | string | Yes | Event type, which is **'speedDone'** in this case.| **Example** ```js -videoPlayer.reset().then(() => { - console.info('reset success'); -}).catch((error) => { - console.info(`video catchCallback, error:${error}`); -}); +avPlayer.off('speedDone') ``` -### seek8+ +### setBitrate9+ -seek(timeMs: number, callback: AsyncCallback\): void +setBitrate(bitrate: number): void -Seeks to the specified playback position. The next key frame at the specified position is played. This API uses an asynchronous callback to return the result. +Sets the bit rate, which is valid only for HTTP Live Streaming (HLS) streams. This API can be called only when the AVPlayer is in the prepared, playing, paused, or completed state. You can check whether the setting takes effect by subscribing to the [bitrateDone](#bitrateDone_on) event. -**System capability**: SystemCapability.Multimedia.Media.VideoPlayer +**System capability**: SystemCapability.Multimedia.Media.AVPlayer **Parameters** -| Name | Type | Mandatory| Description | -| -------- | ---------------------- | ---- | ------------------------------------------------------------ | -| timeMs | number | Yes | Position to seek to, in ms. The value range is [0, duration].| -| callback | AsyncCallback\ | Yes | Callback used to return the result. | +| Name | Type | Mandatory| Description | +| ------- | ------ | ---- | ------------------------------------------------------------ | +| bitrate | number | Yes | Bit rate to set. You can obtain the available bit rates of the current HLS stream by subscribing to the [availableBitrates](#availableBitrates_on) event. If the bit rate to set is not in the list of the available bit rates, the AVPlayer selects from the list the minimum bit rate that is closed to the bit rate to set.| **Example** ```js -let seekTime = 5000; -videoPlayer.seek(seekTime, (err, result) => { - if (err == null) { - console.info('seek success!'); - } else { - console.info('seek fail!'); - } -}); +let bitrate = 96000 +avPlayer.setBitrate(bitrate) ``` -### seek8+ +### on('bitrateDone')9+ -seek(timeMs: number, mode:SeekMode, callback: AsyncCallback\): void +on(type: 'bitrateDone', callback: Callback\): void -Seeks to the specified playback position. This API uses an asynchronous callback to return the result. +Subscribes to the event to check whether the bit rate is successfully set. -**System capability**: SystemCapability.Multimedia.Media.VideoPlayer +**System capability**: SystemCapability.Multimedia.Media.AVPlayer **Parameters** -| Name | Type | Mandatory| Description | -| -------- | ---------------------- | ---- | ------------------------------------------------------------ | -| timeMs | number | Yes | Position to seek to, in ms. The value range is [0, duration].| -| mode | [SeekMode](#seekmode8) | Yes | Seek mode. | -| callback | AsyncCallback\ | Yes | Callback used to return the result. | +| Name | Type | Mandatory| Description | +| -------- | -------- | ---- | ------------------------------------------------------------ | +| type | string | Yes | Event type, which is **'bitrateDone'** in this case. This event is triggered each time **setBitrate()** is called.| +| callback | function | Yes | Callback invoked when the event is triggered. It reports the effective bit rate. | **Example** ```js -import media from '@ohos.multimedia.media' -let seekTime = 5000; -videoPlayer.seek(seekTime, media.SeekMode.SEEK_NEXT_SYNC, (err, result) => { - if (err == null) { - console.info('seek success!'); - } else { - console.info('seek fail!'); - } -}); +avPlayer.on('bitrateDone', (bitrate:number) => { + console.info('bitrateDone success,and bitrate value is:' + bitrate) +}) ``` -### seek8+ +### off('bitrateDone')9+ -seek(timeMs: number, mode?:SeekMode): Promise\ +off(type: 'bitrateDone'): void -Seeks to the specified playback position. If **mode** is not specified, the next key frame at the specified position is played. This API uses a promise to return the result. +Unsubscribes from the event that checks whether the bit rate is successfully set. -**System capability**: SystemCapability.Multimedia.Media.VideoPlayer +**System capability**: SystemCapability.Multimedia.Media.AVPlayer **Parameters** -| Name| Type | Mandatory| Description | -| ------ | ---------------------- | ---- | ------------------------------------------------------------ | -| timeMs | number | Yes | Position to seek to, in ms. The value range is [0, duration].| -| mode | [SeekMode](#seekmode8) | No | Seek mode. | +| Name| Type | Mandatory| Description | +| ------ | ------ | ---- | ------------------------------------------------------------ | +| type | string | Yes | Event type, which is **'bitrateDone'** in this case| -**Return value** +**Example** -| Type | Description | -| -------------- | ------------------------------------------- | -| Promise\| Promise used to return the playback position, in ms.| +```js +avPlayer.off('bitrateDone') +``` + +### on('availableBitrates')9+ + +on(type: 'availableBitrates', callback: (bitrates: Array\) => void): void + +Subscribes to available bit rates of HLS streams. This event is reported only after the AVPlayer switches to the prepared state. + +**System capability**: SystemCapability.Multimedia.Media.AVPlayer + +**Parameters** + +| Name | Type | Mandatory| Description | +| -------- | -------- | ---- | ------------------------------------------------------------ | +| type | string | Yes | Event type, which is **'availableBitrates'** in this case. This event is triggered once after the AVPlayer switches to the prepared state.| +| callback | function | Yes | Callback invoked when the event is triggered. It returns an array that holds the available bit rates.| **Example** ```js -import media from '@ohos.multimedia.media' -let seekTime = 5000; -videoPlayer.seek(seekTime).then((seekDoneTime) => { // seekDoneTime indicates the position after the seek operation is complete. - console.info('seek success'); -}).catch((error) => { - console.info(`video catchCallback, error:${error}`); -}); - -videoPlayer.seek(seekTime, media.SeekMode.SEEK_NEXT_SYNC).then((seekDoneTime) => { - console.info('seek success'); -}).catch((error) => { - console.info(`video catchCallback, error:${error}`); -}); +avPlayer.on('availableBitrates', (bitrates: Array) => { + console.info('availableBitrates success,and availableBitrates length is:' + bitrates.length) +}) ``` -### setVolume8+ +### off('availableBitrates')9+ -setVolume(vol: number, callback: AsyncCallback\): void +off(type: 'availableBitrates'): void -Sets the volume. This API uses an asynchronous callback to return the result. +Unsubscribes from available bit rates of HLS streams. -**System capability**: SystemCapability.Multimedia.Media.VideoPlayer +**System capability**: SystemCapability.Multimedia.Media.AVPlayer **Parameters** -| Name | Type | Mandatory| Description | -| -------- | -------------------- | ---- | ------------------------------------------------------------ | -| vol | number | Yes | Relative volume. The value ranges from 0.00 to 1.00. The value **1** indicates the maximum volume (100%).| -| callback | AsyncCallback\ | Yes | Callback used to return the result. | +| Name| Type | Mandatory| Description | +| ------ | ------ | ---- | ------------------------------------------------------------ | +| type | string | Yes | Event type, which is **'availableBitrates'** in this case.| **Example** ```js -let vol = 0.5; -videoPlayer.setVolume(vol, (err, result) => { - if (err == null) { - console.info('setVolume success!'); - } else { - console.info('setVolume fail!'); - } -}); +avPlayer.off('availableBitrates') ``` -### setVolume8+ +### setVolume9+ -setVolume(vol: number): Promise\ +setVolume(volume: number): void -Sets the volume. This API uses a promise to return the result. +Sets the volume. This API can be called only when the AVPlayer is in the prepared, playing, paused, or completed state. You can check whether the setting takes effect by subscribing to the [volumeChange](#volumeChange_on) event. -**System capability**: SystemCapability.Multimedia.Media.VideoPlayer +**System capability**: SystemCapability.Multimedia.Media.AVPlayer **Parameters** | Name| Type | Mandatory| Description | | ------ | ------ | ---- | ------------------------------------------------------------ | -| vol | number | Yes | Relative volume. The value ranges from 0.00 to 1.00. The value **1** indicates the maximum volume (100%).| - -**Return value** - -| Type | Description | -| -------------- | ------------------------- | -| Promise\ | Promise used to return the result.| +| volume | number | Yes | Relative volume. The value ranges from 0.00 to 1.00. The value **1.00** indicates the maximum volume (100%).| **Example** ```js -let vol = 0.5; -videoPlayer.setVolume(vol).then(() => { - console.info('setVolume success'); -}).catch((error) => { - console.info(`video catchCallback, error:${error}`); -}); +let volume = 1.0 +avPlayer.setVolume(volume) ``` -### release8+ +### on('volumeChange')9+ -release(callback: AsyncCallback\): void +on(type: 'volumeChange', callback: Callback\): void -Releases the video playback resource. This API uses an asynchronous callback to return the result. +Subscribes to the event to check whether the volume is successfully set. -**System capability**: SystemCapability.Multimedia.Media.VideoPlayer +**System capability**: SystemCapability.Multimedia.Media.AVPlayer **Parameters** -| Name | Type | Mandatory| Description | -| -------- | -------------------- | ---- | ------------------------ | -| callback | AsyncCallback\ | Yes | Callback used to return the result.| +| Name | Type | Mandatory| Description | +| -------- | -------- | ---- | ------------------------------------------------------------ | +| type | string | Yes | Event type, which is **'volumeChange'** in this case. This event is triggered each time **setVolume()** is called.| +| callback | function | Yes | Callback invoked when the event is triggered. It reports the effective volume. | **Example** ```js -videoPlayer.release((err) => { - if (err == null) { - console.info('release success!'); - } else { - console.info('release fail!'); - } -}); +avPlayer.on('volumeChange', (vol:number) => { + console.info('volumeChange success,and new volume is :' + vol) +}) ``` -### release8+ +### off('volumeChange')9+ -release(): Promise\ +off(type: 'volumeChange'): void -Releases the video playback resource. This API uses a promise to return the result. +Unsubscribes from the event that checks whether the volume is successfully set. -**System capability**: SystemCapability.Multimedia.Media.VideoPlayer +**System capability**: SystemCapability.Multimedia.Media.AVPlayer -**Return value** +**Parameters** -| Type | Description | -| -------------- | ----------------------------- | -| Promise\ | Promise used to return the result.| +| Name| Type | Mandatory| Description | +| ------ | ------ | ---- | ------------------------------------------------------------ | +| type | string | Yes | Event type, which is **'volumeChange'** in this case.| **Example** ```js -videoPlayer.release().then(() => { - console.info('release success'); -}).catch((error) => { - console.info(`video catchCallback, error:${error}`); -}); +avPlayer.off('volumeChange') ``` -### getTrackDescription8+ +### on('endOfStream')9+ -getTrackDescription(callback: AsyncCallback>): void +on(type: 'endOfStream', callback: Callback\): void -Obtains the video track information. This API uses an asynchronous callback to return the result. +Subscribes to the event that indicates the end of the stream being played. If **loop=1** is set, the AVPlayer seeks to the beginning of the stream and plays the stream again. If **loop** is not set, the completed state is reported through the [stateChange](#stateChange_on) event. -**System capability**: SystemCapability.Multimedia.Media.VideoPlayer +**System capability**: SystemCapability.Multimedia.Media.AVPlayer **Parameters** -| Name | Type | Mandatory| Description | -| -------- | ------------------------------------------------------------ | ---- | ------------------------------------------ | -| callback | AsyncCallback> | Yes | Callback used to return a **MediaDescription** array, which records the video track information.| +| Name | Type | Mandatory| Description | +| -------- | -------- | ---- | ------------------------------------------------------------ | +| type | string | Yes | Event type, which is **'endOfStream'** in this case. This event is triggered when the AVPlayer finishes playing the media asset.| +| callback | Callback\ | Yes | Callback invoked when the event is triggered. | **Example** ```js -function printfDescription(obj) { - for (let item in obj) { - let property = obj[item]; - console.info('video key is ' + item); - console.info('video value is ' + property); - } -} - -videoPlayer.getTrackDescription((error, arrList) => { - if ((arrList) != null) { - for (let i = 0; i < arrList.length; i++) { - printfDescription(arrList[i]); - } - } else { - console.log(`video getTrackDescription fail, error:${error}`); - } -}); +avPlayer.on('endOfStream', () => { + console.info('endOfStream success') +}) ``` -### getTrackDescription8+ +### off('endOfStream')9+ -getTrackDescription(): Promise> +off(type: 'endOfStream'): void -Obtains the video track information. This API uses a promise to return the result. +Unsubscribes from the event that indicates the end of the stream being played. -**System capability**: SystemCapability.Multimedia.Media.VideoPlayer +**System capability**: SystemCapability.Multimedia.Media.AVPlayer -**Return value** +**Parameters** -| Type | Description | -| ------------------------------------------------------ | ----------------------------------------------- | -| Promise> | Promise used to return a **MediaDescription** array, which records the video track information.| +| Name| Type | Mandatory| Description | +| ------ | ------ | ---- | ------------------------------------------------------------ | +| type | string | Yes | Event type, which is **'endOfStream'** in this case.| **Example** ```js -function printfDescription(obj) { - for (let item in obj) { - let property = obj[item]; - console.info('video key is ' + item); - console.info('video value is ' + property); - } -} - -let arrayDescription; -videoPlayer.getTrackDescription().then((arrList) => { - if (arrList != null) { - arrayDescription = arrList; - } else { - console.log('video getTrackDescription fail'); - } -}).catch((error) => { - console.info(`video catchCallback, error:${error}`); -}); -for (let i = 0; i < arrayDescription.length; i++) { - printfDescription(arrayDescription[i]); -} +avPlayer.off('endOfStream') ``` -### setSpeed8+ +### on('timeUpdate')9+ -setSpeed(speed:number, callback: AsyncCallback\): void +on(type: 'timeUpdate', callback: Callback\): void -Sets the video playback speed. This API uses an asynchronous callback to return the result. +Subscribes to playback position changes. It is used to refresh the current position of the progress bar. By default, this event is reported every 1 second. However, it is reported immediately upon a successful seek operation. -**System capability**: SystemCapability.Multimedia.Media.VideoPlayer +**System capability**: SystemCapability.Multimedia.Media.AVPlayer **Parameters** -| Name | Type | Mandatory| Description | -| -------- | ---------------------- | ---- | ---------------------------------------------------------- | -| speed | number | Yes | Video playback speed. For details, see [PlaybackSpeed](#playbackspeed8).| -| callback | AsyncCallback\ | Yes | Callback used to return the result. | +| Name | Type | Mandatory| Description | +| -------- | -------- | ---- | ---------------------------------------------- | +| type | string | Yes | Event type, which is **'timeUpdate'** in this case.| +| callback | function | Yes | Callback invoked when the event is triggered. It reports the current playback position, in ms. | **Example** ```js -import media from '@ohos.multimedia.media' -let speed = media.PlaybackSpeed.SPEED_FORWARD_2_00_X; - -videoPlayer.setSpeed(speed, (err, result) => { - if (err == null) { - console.info('setSpeed success!'); - } else { - console.info('setSpeed fail!'); - } -}); +avPlayer.on('timeUpdate', (time:number) => { + console.info('timeUpdate success,and new time is :' + time) +}) ``` -### setSpeed8+ +### off('timeUpdate')9+ -setSpeed(speed:number): Promise\ +off(type: 'timeUpdate'): void -Sets the video playback speed. This API uses a promise to return the result. +Unsubscribes from playback position changes. -**System capability**: SystemCapability.Multimedia.Media.VideoPlayer +**System capability**: SystemCapability.Multimedia.Media.AVPlayer **Parameters** -| Name| Type | Mandatory| Description | -| ------ | ------ | ---- | ---------------------------------------------------------- | -| speed | number | Yes | Video playback speed. For details, see [PlaybackSpeed](#playbackspeed8).| +| Name| Type | Mandatory| Description | +| ------ | ------ | ---- | -------------------------------------------------- | +| type | string | Yes | Event type, which is **'timeUpdate'** in this case.| -**Return value** +**Example** -| Type | Description | -| ---------------- | ------------------------------------------------------------ | -| Promise\| Promise used to return playback speed. For details, see [PlaybackSpeed](#playbackspeed8).| +```js +avPlayer.off('timeUpdate') +``` + +### on('durationUpdate')9+ + +on(type: 'durationUpdate', callback: Callback\): void + +Subscribes to media asset duration changes. It is used to refresh the length of the progress bar. By default, this event is reported once when the AVPlayer switches to the prepared state. However, it can be repeatedly reported for special streams that trigger duration changes. + +**System capability**: SystemCapability.Multimedia.Media.AVPlayer + +**Parameters** + +| Name | Type | Mandatory| Description | +| -------- | -------- | ---- | -------------------------------------------------- | +| type | string | Yes | Event type, which is **'durationUpdate'** in this case.| +| callback | function | Yes | Callback invoked when the event is triggered. It reports the media asset duration, in ms. | **Example** ```js -import media from '@ohos.multimedia.media' -let speed = media.PlaybackSpeed.SPEED_FORWARD_2_00_X; - -videoPlayer.setSpeed(speed).then(() => { - console.info('setSpeed success'); -}).catch((error) => { - console.info(`video catchCallback, error:${error}`); -}); +avPlayer.on('durationUpdate', (duration) => { + console.info('durationUpdate success,new duration is :' + duration) +}) ``` -### on('playbackCompleted')8+ +### off('durationUpdate')9+ -on(type: 'playbackCompleted', callback: Callback\): void +off(type: 'durationUpdate'): void -Subscribes to the video playback completion event. +Unsubscribes from media asset duration changes. -**System capability**: SystemCapability.Multimedia.Media.VideoPlayer +**System capability**: SystemCapability.Multimedia.Media.AVPlayer **Parameters** -| Name | Type | Mandatory| Description | -| -------- | -------- | ---- | ----------------------------------------------------------- | -| type | string | Yes | Event type, which is **'playbackCompleted'** in this case.| -| callback | function | Yes | Callback invoked when the event is triggered. | +| Name| Type | Mandatory| Description | +| ------ | ------ | ---- | ------------------------------------------------------ | +| type | string | Yes | Event type, which is **'durationUpdate'** in this case.| **Example** ```js -videoPlayer.on('playbackCompleted', () => { - console.info('playbackCompleted success!'); -}); +avPlayer.off('durationUpdate') ``` -### on('bufferingUpdate')8+ +### on('bufferingUpdate')9+ on(type: 'bufferingUpdate', callback: (infoType: BufferingInfoType, value: number) => void): void -Subscribes to the video buffering update event. Only network playback supports this subscription. +Subscribes to audio and video buffer changes. This subscription is supported only in network playback scenarios. -**System capability**: SystemCapability.Multimedia.Media.VideoPlayer +**System capability**: SystemCapability.Multimedia.Media.AVPlayer **Parameters** @@ -1409,122 +1424,189 @@ Subscribes to the video buffering update event. Only network playback supports t **Example** ```js -videoPlayer.on('bufferingUpdate', (infoType, value) => { - console.log('video bufferingInfo type: ' + infoType); - console.log('video bufferingInfo value: ' + value); -}); +avPlayer.on('bufferingUpdate', (infoType: media.BufferingInfoType, value: number) => { + console.info('bufferingUpdate success,and infoType value is:' + infoType + ', value is :' + value) +}) ``` -### on('startRenderFrame')8+ +### off('bufferingUpdate')9+ -on(type: 'startRenderFrame', callback: Callback\): void +off(type: 'bufferingUpdate'): void -Subscribes to the frame rendering start event. +Unsubscribes from audio and video buffer changes. -**System capability**: SystemCapability.Multimedia.Media.VideoPlayer +**System capability**: SystemCapability.Multimedia.Media.AVPlayer **Parameters** -| Name | Type | Mandatory| Description | -| -------- | --------------- | ---- | ------------------------------------------------------------ | -| type | string | Yes | Event type, which is **'startRenderFrame'** in this case.| -| callback | Callback\ | Yes | Callback invoked when the event is triggered. | +| Name| Type | Mandatory| Description | +| ------ | ------ | ---- | --------------------------------------------------------- | +| type | string | Yes | Event type, which is **'bufferingUpdate'** in this case.| **Example** ```js -videoPlayer.on('startRenderFrame', () => { - console.info('startRenderFrame success!'); -}); +avPlayer.off('bufferingUpdate') ``` -### on('videoSizeChanged')8+ +### on('startRenderFrame')9+ -on(type: 'videoSizeChanged', callback: (width: number, height: number) => void): void +on(type: 'startRenderFrame', callback: Callback\): void -Subscribes to the video width and height change event. +Subscribes to the event that indicates rendering starts for the first frame. This subscription is supported only in the video playback scenarios. This event only means that the playback service sends the first frame to the display module. The actual rendering effect depends on the rendering performance of the display service. -**System capability**: SystemCapability.Multimedia.Media.VideoPlayer +**System capability**: SystemCapability.Multimedia.Media.AVPlayer **Parameters** | Name | Type | Mandatory| Description | | -------- | -------- | ---- | ------------------------------------------------------------ | -| type | string | Yes | Event type, which is **'videoSizeChanged'** in this case.| -| callback | function | Yes | Callback invoked when the event is triggered. **width** indicates the video width, and **height** indicates the video height. | +| type | string | Yes | Event type, which is **'startRenderFrame'** in this case.| +| callback | Callback\ | Yes | Callback invoked when the event is triggered. | **Example** ```js -videoPlayer.on('videoSizeChanged', (width, height) => { - console.log('video width is: ' + width); - console.log('video height is: ' + height); -}); +avPlayer.on('startRenderFrame', () => { + console.info('startRenderFrame success') +}) ``` -### on('error')8+ +### off('startRenderFrame')9+ -on(type: 'error', callback: ErrorCallback): void +off(type: 'startRenderFrame'): void -Subscribes to video playback error events. After an error event is reported, you must handle the event and exit the playback. +Unsubscribes from the event that indicates rendering starts for the first frame. -**System capability**: SystemCapability.Multimedia.Media.VideoPlayer +**System capability**: SystemCapability.Multimedia.Media.AVPlayer **Parameters** -| Name | Type | Mandatory| Description | -| -------- | ------------- | ---- | ------------------------------------------------------------ | -| type | string | Yes | Event type, which is **'error'** in this case.
The **'error'** event is triggered when an error occurs during video playback.| -| callback | ErrorCallback | Yes | Callback invoked when the event is triggered. | +| Name| Type | Mandatory| Description | +| ------ | ------ | ---- | ------------------------------------------------------------ | +| type | string | Yes | Event type, which is **'startRenderFrame'** in this case.| **Example** ```js -videoPlayer.on('error', (error) => { // Set the 'error' event callback. - console.info(`video error called, error: ${error}`); -}); -videoPlayer.url = 'fd://error'; // Set an incorrect URL to trigger the 'error' event. +avPlayer.off('startRenderFrame') ``` -### on('availableBitratesCollect')9+ +### on('videoSizeChange')9+ -on(type: 'availableBitratesCollect', callback: (bitrates: Array\) => void): void +on(type: 'videoSizeChange', callback: (width: number, height: number) => void): void -Subscribes to the video playback bit rate reporting event. +Subscribes to video size (width and height) changes. This subscription is supported only in the video playback scenarios. By default, this event is reported only once in the prepared state. However, it is also reported upon resolution changes in the case of HLS streams. -**System capability**: SystemCapability.Multimedia.Media.VideoPlayer +**System capability**: SystemCapability.Multimedia.Media.AVPlayer **Parameters** | Name | Type | Mandatory| Description | | -------- | -------- | ---- | ------------------------------------------------------------ | -| type | string | Yes | Event type, which is **'availableBitratesCollect'** in this case. This event is reported only once when the playback starts.| -| callback | function | Yes | Callback used to return supported bit rates, in an array. | +| type | string | Yes | Event type, which is **'videoSizeChange'** in this case.| +| callback | function | Yes | Callback invoked when the event is triggered. **width** indicates the video width, and **height** indicates the video height. | **Example** ```js -videoPlayer.on('availableBitratesCollect', (bitrates) => { - for (let i = 0; i < bitrates.length; i++) { - console.info('case availableBitratesCollect bitrates: ' + bitrates[i]); // Print bit rates. - } -}); +avPlayer.on('videoSizeChange', (width: number, height: number) => { + console.info('videoSizeChange success,and width is:' + width + ', height is :' + height) +}) ``` -## VideoPlayState8+ +### off('videoSizeChange')9+ -Enumerates the video playback states. You can obtain the state through the **state** attribute. +off(type: 'videoSizeChange'): void -**System capability**: SystemCapability.Multimedia.Media.VideoPlayer +Unsubscribes from video size changes. -| Name | Type | Description | -| -------- | ------ | -------------- | -| idle | string | The video player is idle.| -| prepared | string | Video playback is being prepared.| -| playing | string | Video playback is in progress.| -| paused | string | Video playback is paused.| -| stopped | string | Video playback is stopped.| -| error | string | Video playback is in the error state. | +**System capability**: SystemCapability.Multimedia.Media.AVPlayer + +**Parameters** + +| Name| Type | Mandatory| Description | +| ------ | ------ | ---- | ------------------------------------------------------------ | +| type | string | Yes | Event type, which is **'videoSizeChange'** in this case.| + +**Example** + +```js +avPlayer.off('videoSizeChange') +``` + +### on('audioInterrupt')9+ + +on(type: 'audioInterrupt', callback: (info: audio.InterruptEvent) => void): void + +Subscribes to the audio interruption event. When multiple audio and video assets are played at the same time, this event is triggered based on the audio interruption mode [audio.InterruptMode](js-apis-audio.md#interruptmode9). + +**System capability**: SystemCapability.Multimedia.Media.AVPlayer + +**Parameters** + +| Name | Type | Mandatory| Description | +| -------- | ------------------------------------------------------------ | ---- | -------------------------------------------------------- | +| type | string | Yes | Event type, which is **'audioInterrupt'** in this case.| +| callback | [audio.InterruptEvent9+](js-apis-audio.md#interruptevent9) | Yes | Callback invoked when the event is triggered. | + +**Example** + +```js +avPlayer.on('audioInterrupt', (info: audio.InterruptEvent) => { + console.info('audioInterrupt success,and InterruptEvent info is:' + info) +}) +``` + +### off('audioInterrupt')9+ + +off(type: 'audioInterrupt'): void + +Unsubscribes from the audio interruption event. + +**System capability**: SystemCapability.Multimedia.Media.AVPlayer + +**Parameters** + +| Name| Type | Mandatory| Description | +| ------ | ------ | ---- | ------------------------------------------------------------ | +| type | string | Yes | Event type, which is **'audioInterrupt'** in this case.| + +**Example** + +```js +avPlayer.off('audioInterrupt') +``` + +## AVPlayerState9+ + +Enumerates the states of the [AVPlayer](#avplayer9). Your application can proactively obtain the AVPlayer state through the **state** attribute or obtain the reported AVPlayer state by subscribing to the [stateChange](#stateChange_on) event. For details about the rules for state transition, see [AVPlayer Development](../../media/avplayer-playback.md). + +**System capability**: SystemCapability.Multimedia.Media.AVPlayer + +| Name | Type | Description | +| :-----------------------------: | :----: | :----------------------------------------------------------- | +| idle | string | The AVPlayer enters this state after [createAVPlayer()](#mediacreateavplayer9) or **reset()** is called.
In case **createAVPlayer()** is used, all attributes are set to their default values.
In case **reset()** is invoked, the **url9+** or **fdSrc9+** attribute is reset, and other attributes set by the application are retained.| +| initialized | string | The AVPlayer enters this state after **url9+** or **fdSrc9+** attribute is set in the idle state. In this case, you can configure static attributes such as the window and audio.| +| prepared | string | The AVPlayer enters this state when **prepare()** is called in the initialized state. In this case, the playback engine has prepared the resources.| +| playing | string | The AVPlayer enters this state when **play()** is called in the prepared, paused, or completed state.| +| paused | string | The AVPlayer enters this state when **pause()** is called in the playing state.| +| completed | string | The AVPlayer enters this state when a media asset finishes playing and loop playback is not set (no **loop = 1**). In this case, if **play()** is called, the AVPlayer enters the playing state and replays the media asset; if **stop()** is called, the AVPlayer enters the stopped state.| +| stopped | string | The AVPlayer enters this state when **stop()** is called in the prepared, playing, paused, or completed state. In this case, the playback engine retains the attributes but releases the memory resources. You can call **prepare()** to prepare the resources again, call **reset()** to reset the attributes, or call **release()** to destroy the playback engine.| +| released | string | The AVPlayer enters this state when **release()** is called. The playback engine associated with the **AVPlayer** instance is destroyed, and the playback process ends. This is the final state.| +| error | string | The AVPlayer enters this state when an irreversible error occurs in the playback engine. You can call **reset()** to reset the attributes or call **release()** to destroy the playback engine. For details on the errors, see [Error Classification](#error_info).
**NOTE** Relationship between the error state and the [on('error')](#error_on) event
1. When the AVPlayer enters the error state, the [on('error')](#error_on) event is triggered. You can obtain the detailed error information through this event.
2. When the AVPlayer enters the error state, the playback service stops. This requires the client to design a fault tolerance mechanism to call **reset()** or **release()**.
3. The client receives [on('error')](#error_on) event but the AVPlayer does not enter the error state. This situation occurs due to either of the following reasons:
Cause 1: The client calls an API in an incorrect state or passes in an incorrect parameter, and the AVPlayer intercepts the call. If this is the case, the client must correct its code logic.
Cause 2: A stream error is detected during playback. As a result, the container and decoding are abnormal for a short period of time, but continuous playback and playback control operations are not affected. If this is the case, the client does not need to design a fault tolerance mechanism.| + +## AVFileDescriptor9+ + +Describes an audio and video file asset. It is used to specify a particular asset for playback based on its offset and length within a file. + +**System capability**: SystemCapability.Multimedia.Media.Core + +| Name | Type | Mandatory| Description | +| ------ | ------ | ---- | ------------------------------------------------------------ | +| fd | number | Yes | Resource handle, which is obtained by calling **resourceManager.getRawFileDescriptor**. | +| offset | number | Yes | Resource offset, which needs to be entered based on the preset asset information. An invalid value causes a failure to parse audio and video assets.| +| length | number | Yes | Resource length, which needs to be entered based on the preset asset information. An invalid value causes a failure to parse audio and video assets.| ## SeekMode8+ @@ -1557,10 +1639,10 @@ Enumerates the video scale modes. **System capability**: SystemCapability.Multimedia.Media.VideoPlayer -| Name | Value| Description | -| ---------------------------- | ------ | ---------- | -| VIDEO_SCALE_TYPE_FIT | 0 | The video will be stretched to fit the window.| -| VIDEO_SCALE_TYPE_FIT_CROP| 1 | The video will be stretched to fit the window, without changing its aspect ratio. The content may be cropped. | +| Name | Value | Description | +| ------------------------- | ---- | ------------------------------------------------ | +| VIDEO_SCALE_TYPE_FIT | 0 | The video will be stretched to fit the window. | +| VIDEO_SCALE_TYPE_FIT_CROP | 1 | The video will be stretched to fit the window, without changing its aspect ratio. The content may be cropped.| ## MediaDescription8+ @@ -1589,852 +1671,915 @@ audioPlayer.getTrackDescription((error, arrList) => { }); ``` -## AudioRecorder +## AVRecorder9+ -Implements audio recording. Before calling an API of **AudioRecorder**, you must use [createAudioRecorder()](#mediacreateaudiorecorder) to create an [AudioRecorder](#audiorecorder) instance. +A recording management class that provides APIs to record media assets. Before calling any API in **AVRecorder**, you must use **createAVRecorder()** to create an **AVRecorder** instance. -For details about the audio recording demo, see [Audio Recording Development](../../media/audio-recorder.md). +For details about the AVRecorder demo, see [AVRecorder Development](../../media/avrecorder.md). -### prepare +### Attributes -prepare(config: AudioRecorderConfig): void +**System capability**: SystemCapability.Multimedia.Media.AVRecorder -Prepares for recording. +| Name | Type | Readable| Writable| Description | +| ------- | ------------------------------------ | ---- | ---- | ------------------ | +| state9+ | [AVRecorderState](#avrecorderstate9) | Yes | No | AVRecorder state.| + +### prepare9+ + +prepare(config: AVRecorderConfig, callback: AsyncCallback\): void + +Sets audio and video recording parameters. This API uses an asynchronous callback to return the result. **Required permissions:** ohos.permission.MICROPHONE -**System capability**: SystemCapability.Multimedia.Media.AudioRecorder +This permission is required only if audio recording is involved. + +To use the camera to record videos, the camera module is required. For details about how to obtain the permissions and use the APIs, see [Camera Management](js-apis-camera.md). + +**System capability**: SystemCapability.Multimedia.Media.AVRecorder **Parameters** -| Name| Type | Mandatory| Description | -| ------ | ------------------------------------------- | ---- | ------------------------------------------------------------ | -| config | [AudioRecorderConfig](#audiorecorderconfig) | Yes | Audio recording parameters, including the audio output URI, encoding format, sampling rate, number of audio channels, and output format.| +| Name | Type | Mandatory| Description | +| -------- | -------------------------------------- | ---- | ------------------------------------- | +| config | [AVRecorderConfig](#avrecorderconfig9) | Yes | Audio and video recording parameters to set. | +| callback | AsyncCallback\ | Yes | Callback used to return the result.| + +**Error codes** + +For details about the error codes, see [Media Error Codes](../errorcodes/errorcode-media.md). + +| ID| Error Message | +| -------- | --------------------------------------- | +| 201 | Permission denied. Return by callback. | +| 401 | Parameter error. Return by callback. | +| 5400102 | Operate not permit. Return by callback. | +| 5400105 | Service died. Return by callback. | **Example** ```js -let audioRecorderConfig = { - audioEncoder : media.AudioEncoder.AAC_LC, - audioEncodeBitRate : 22050, - audioSampleRate : 22050, - numberOfChannels : 2, - format : media.AudioOutputFormat.AAC_ADTS, - uri : 'fd://1', // The file must be created by the caller and granted with proper permissions. - location : { latitude : 30, longitude : 130}, +let AVRecorderProfile = { + audioBitrate : 48000, + audioChannels : 2, + audioCodec : media.CodecMimeType.AUDIO_AAC, + audioSampleRate : 48000, + fileFormat : media.ContainerFormatType.CFT_MPEG_4, + videoBitrate : 48000, + videoCodec : media.CodecMimeType.VIDEO_MPEG4, + videoFrameWidth : 640, + videoFrameHeight : 480, + videoFrameRate : 30 } -audioRecorder.on('prepare', () => { // Set the 'prepare' event callback. - console.log('prepare success'); -}); -audioRecorder.prepare(audioRecorderConfig); +let AVRecorderConfig = { + audioSourceType : media.AudioSourceType.AUDIO_SOURCE_TYPE_MIC, + videoSourceType : media.VideoSourceType.VIDEO_SOURCE_TYPE_SURFACE_YUV, + profile : AVRecorderProfile, + url : 'fd://', // Before passing in an FD to this parameter, the file must be created by the caller and granted with the read and write permissions. Example value: eg.fd://45. + rotation: 0, // The value can be 0, 90, 180, or 270. If any other value is used, prepare() reports an error. + location : { latitude : 30, longitude : 130 } +} + +AVRecorder.prepare(AVRecorderConfig, (err) => { + if (err == null) { + console.info('prepare success'); + } else { + console.info('prepare failed and error is ' + err.message); + } +}) ``` +### prepare9+ -### start +prepare(config: AVRecorderConfig): Promise\ -start(): void +Sets audio and video recording parameters. This API uses a promise to return the result. -Starts audio recording. This API can be called only after the [prepare](#audiorecorder_on) event is triggered. +**Required permissions:** ohos.permission.MICROPHONE -**System capability**: SystemCapability.Multimedia.Media.AudioRecorder +This permission is required only if audio recording is involved. -**Example** +To use the camera to record videos, the camera module is required. For details about how to obtain the permissions and use the APIs, see [Camera Management](js-apis-camera.md). -```js -audioRecorder.on('start', () => { // Set the 'start' event callback. - console.log('audio recorder start success'); -}); -audioRecorder.start(); -``` +**System capability**: SystemCapability.Multimedia.Media.AVRecorder -### pause +**Parameters** -pause():void +| Name| Type | Mandatory| Description | +| ------ | -------------------------------------- | ---- | -------------------------- | +| config | [AVRecorderConfig](#avrecorderconfig9) | Yes | Audio and video recording parameters to set.| -Pauses audio recording. This API can be called only after the [start](#audiorecorder_on) event is triggered. +**Return value** -**System capability**: SystemCapability.Multimedia.Media.AudioRecorder +| Type | Description | +| -------------- | ------------------------------------------ | +| Promise\ | Promise used to return the result.| + +**Error codes** + +For details about the error codes, see [Media Error Codes](../errorcodes/errorcode-media.md). + +| ID| Error Message | +| -------- | -------------------------------------- | +| 201 | Permission denied. Return by promise. | +| 401 | Parameter error. Return by promise. | +| 5400102 | Operate not permit. Return by promise. | +| 5400105 | Service died. Return by promise. | **Example** ```js -audioRecorder.on('pause', () => { // Set the 'pause' event callback. - console.log('audio recorder pause success'); +let AVRecorderProfile = { + audioBitrate : 48000, + audioChannels : 2, + audioCodec : media.CodecMimeType.AUDIO_AAC, + audioSampleRate : 48000, + fileFormat : media.ContainerFormatType.CFT_MPEG_4, + videoBitrate : 48000, + videoCodec : media.CodecMimeType.VIDEO_MPEG4, + videoFrameWidth : 640, + videoFrameHeight : 480, + videoFrameRate : 30 +} +let AVRecorderConfig = { + audioSourceType : media.AudioSourceType.AUDIO_SOURCE_TYPE_MIC, + videoSourceType : media.VideoSourceType.VIDEO_SOURCE_TYPE_SURFACE_YUV, + profile : AVRecorderProfile, + url : 'fd://', // Before passing in an FD to this parameter, the file must be created by the caller and granted with the read and write permissions. Example value: eg.fd://45. + rotation: 0, // The value can be 0, 90, 180, or 270. If any other value is used, prepare() reports an error. + location : { latitude : 30, longitude : 130 } +} + +AVRecorder.prepare(AVRecorderConfig).then(() => { + console.info('prepare success'); +}).catch((err) => { + console.info('prepare failed and catch error is ' + err.message); }); -audioRecorder.pause(); + ``` -### resume +### getInputSurface9+ -resume():void +getInputSurface(callback: AsyncCallback\): void -Resumes audio recording. This API can be called only after the [pause](#audiorecorder_on) event is triggered. +Obtains the surface required for recording. This API uses an asynchronous callback to return the result. The caller obtains the **surfaceBuffer** from this surface and fills in the corresponding video data. -**System capability**: SystemCapability.Multimedia.Media.AudioRecorder +Note that the video data must carry the timestamp (in ns) and buffer size, and the start time of the timestamp must be based on the system startup time. + +This API can be called only after the **prepare()** API is called. + +**System capability**: SystemCapability.Multimedia.Media.AVRecorder + +**Parameters** + +| Name | Type | Mandatory| Description | +| -------- | ---------------------- | ---- | --------------------------- | +| callback | AsyncCallback\ | Yes | Callback used to obtain the result.| + +**Error codes** + +For details about the error codes, see [Media Error Codes](../errorcodes/errorcode-media.md). + +| ID| Error Message | +| -------- | --------------------------------------- | +| 5400102 | Operate not permit. Return by callback. | +| 5400103 | IO error. Return by callback. | +| 5400105 | Service died. Return by callback. | **Example** ```js -audioRecorder.on('resume', () => { // Set the 'resume' event callback. - console.log('audio recorder resume success'); +let surfaceID = null; // The surfaceID is transferred to the camera API to create a videoOutput instance. + +AVRecorder.getInputSurface((err, surfaceId) => { + if (err == null) { + console.info('getInputSurface success'); + surfaceID = surfaceId; + } else { + console.info('getInputSurface failed and error is ' + err.message); + } }); -audioRecorder.resume(); + +// videoOutput = await cameraManager.createVideoOutput(videoProfiles[0], surfaceID); + ``` -### stop +### getInputSurface9+ -stop(): void +getInputSurface(): Promise\ -Stops audio recording. +Obtains the surface required for recording. This API uses a promise to return the result. The caller obtains the **surfaceBuffer** from this surface and fills in the corresponding video data. -**System capability**: SystemCapability.Multimedia.Media.AudioRecorder +Note that the video data must carry the timestamp (in ns) and buffer size, and the start time of the timestamp must be based on the system startup time. + +This API can be called only after the **prepare()** API is called. + +**System capability**: SystemCapability.Multimedia.Media.AVRecorder + +**Return value** + +| Type | Description | +| ---------------- | -------------------------------- | +| Promise\ | Promise used to return the result.| + +**Error codes** + +For details about the error codes, see [Media Error Codes](../errorcodes/errorcode-media.md). + +| ID| Error Message | +| -------- | -------------------------------------- | +| 5400102 | Operate not permit. Return by promise. | +| 5400103 | IO error. Return by promise. | +| 5400105 | Service died. Return by promise. | **Example** ```js -audioRecorder.on('stop', () => { // Set the 'stop' event callback. - console.log('audio recorder stop success'); +let surfaceID = null; // The surfaceID is transferred to the camera API to create a videoOutput instance. + +AVRecorder.getInputSurface().then((surfaceId) => { + console.info('getInputSurface success'); + surfaceID = surfaceId; +}).catch((err) => { + console.info('getInputSurface failed and catch error is ' + err.message); }); -audioRecorder.stop(); + +// videoOutput = await cameraManager.createVideoOutput(videoProfiles[0], surfaceID); ``` -### release +### start9+ -release(): void +start(callback: AsyncCallback\): void -Releases the audio recording resource. +Starts recording. This API uses an asynchronous callback to return the result. -**System capability**: SystemCapability.Multimedia.Media.AudioRecorder +For audio-only recording, this API can be called only after the **prepare()** API is called. For video-only recording, this API can be called only after the **getInputSurface()** API is called. + +**System capability**: SystemCapability.Multimedia.Media.AVRecorder + +**Parameters** + +| Name | Type | Mandatory| Description | +| -------- | -------------------- | ---- | ---------------------------- | +| callback | AsyncCallback\ | Yes | Callback used to return the result.| + +**Error codes** + +For details about the error codes, see [Media Error Codes](../errorcodes/errorcode-media.md). + +| ID| Error Message | +| -------- | --------------------------------------- | +| 5400102 | Operate not permit. Return by callback. | +| 5400103 | IO error. Return by callback. | +| 5400105 | Service died. Return by callback. | **Example** ```js -audioRecorder.on('release', () => { // Set the 'release' event callback. - console.log('audio recorder release success'); +AVRecorder.start((err) => { + if (err == null) { + console.info('start AVRecorder success'); + } else { + console.info('start AVRecorder failed and error is ' + err.message); + } }); -audioRecorder.release(); -audioRecorder = undefined; ``` -### reset +### start9+ -reset(): void +start(): Promise\ -Resets audio recording. +Starts recording. This API uses a promise to return the result. -Before resetting audio recording, you must call [stop()](#audiorecorder_stop) to stop recording. After audio recording is reset, you must call [prepare()](#audiorecorder_prepare) to set the recording parameters for another recording. +For audio-only recording, this API can be called only after the **prepare()** API is called. For video-only recording, this API can be called only after the **getInputSurface()** API is called. -**System capability**: SystemCapability.Multimedia.Media.AudioRecorder +**System capability**: SystemCapability.Multimedia.Media.AVRecorder + +**Return value** + +| Type | Description | +| -------------- | ------------------------------------- | +| Promise\ | Promise used to return the result.| + +**Error codes** + +For details about the error codes, see [Media Error Codes](../errorcodes/errorcode-media.md). + +| ID| Error Message | +| -------- | -------------------------------------- | +| 5400102 | Operate not permit. Return by promise. | +| 5400103 | IO error. Return by promise. | +| 5400105 | Service died. Return by promise. | **Example** ```js -audioRecorder.on('reset', () => { // Set the 'reset' event callback. - console.log('audio recorder reset success'); +AVRecorder.start().then(() => { + console.info('start AVRecorder success'); +}).catch((err) => { + console.info('start AVRecorder failed and catch error is ' + err.message); }); -audioRecorder.reset(); ``` -### on('prepare' | 'start' | 'pause' | 'resume' | 'stop' | 'release' | 'reset') +### pause9+ -on(type: 'prepare' | 'start' | 'pause' | 'resume' | 'stop' | 'release' | 'reset', callback: () => void): void +pause(callback: AsyncCallback\): void -Subscribes to the audio recording events. +Pauses recording. This API uses an asynchronous callback to return the result. -**System capability**: SystemCapability.Multimedia.Media.AudioRecorder +This API can be called only after the **start()** API is called. You can call **resume()** to resume recording. + +**System capability**: SystemCapability.Multimedia.Media.AVRecorder **Parameters** -| Name | Type | Mandatory| Description | -| -------- | -------- | ---- | ------------------------------------------------------------ | -| type | string | Yes | Event type. The following events are supported:
- 'prepare': triggered when the [prepare](#audiorecorder_prepare) API is called and the audio recording parameters are set.
- 'start': triggered when the [start](#audiorecorder_start) API is called and audio recording starts.
- 'pause': triggered when the [pause](#audiorecorder_pause) API is called and audio recording is paused.
- 'resume': triggered when the [resume](#audiorecorder_resume) API is called and audio recording is resumed.
- 'stop': triggered when the [stop](#audiorecorder_stop) API is called and audio recording stops.
- 'release': triggered when the [release](#audiorecorder_release) API is called and the recording resource is released.
- 'reset': triggered when the [reset](#audiorecorder_reset) API is called and audio recording is reset.| -| callback | ()=>void | Yes | Callback invoked when the event is triggered. | +| Name | Type | Mandatory| Description | +| -------- | -------------------- | ---- | --------------------------- | +| callback | AsyncCallback\ | Yes | Callback used to obtain the result.| -**Example** +**Error codes** -```js -let audioRecorder = media.createAudioRecorder(); // Create an AudioRecorder instance. -let audioRecorderConfig = { - audioEncoder : media.AudioEncoder.AAC_LC, - audioEncodeBitRate : 22050, - audioSampleRate : 22050, - numberOfChannels : 2, - format : media.AudioOutputFormat.AAC_ADTS, - uri : 'fd://xx', // The file must be created by the caller and granted with proper permissions. - location : { latitude : 30, longitude : 130}, -} -audioRecorder.on('error', (error) => { // Set the 'error' event callback. - console.info(`audio error called, error: ${error}`); -}); -audioRecorder.on('prepare', () => { // Set the 'prepare' event callback. - console.log('prepare success'); - audioRecorder.start(); // Start recording and trigger the 'start' event callback. -}); -audioRecorder.on('start', () => { // Set the 'start' event callback. - console.log('audio recorder start success'); -}); -audioRecorder.on('pause', () => { // Set the 'pause' event callback. - console.log('audio recorder pause success'); -}); -audioRecorder.on('resume', () => { // Set the 'resume' event callback. - console.log('audio recorder resume success'); -}); -audioRecorder.on('stop', () => { // Set the 'stop' event callback. - console.log('audio recorder stop success'); -}); -audioRecorder.on('release', () => { // Set the 'release' event callback. - console.log('audio recorder release success'); -}); -audioRecorder.on('reset', () => { // Set the 'reset' event callback. - console.log('audio recorder reset success'); +For details about the error codes, see [Media Error Codes](../errorcodes/errorcode-media.md). + +| ID| Error Message | +| -------- | --------------------------------------- | +| 5400102 | Operate not permit. Return by callback. | +| 5400103 | IO error. Return by callback. | +| 5400105 | Service died. Return by callback. | + +**Example** + +```js +AVRecorder.pause((err) => { + if (err == null) { + console.info('pause AVRecorder success'); + } else { + console.info('pause AVRecorder failed and error is ' + err.message); + } }); -audioRecorder.prepare(audioRecorderConfig) // Set recording parameters and trigger the 'prepare' event callback. ``` -### on('error') +### pause9+ -on(type: 'error', callback: ErrorCallback): void +pause(): Promise\ -Subscribes to audio recording error events. After an error event is reported, you must handle the event and exit the recording. +Pauses recording. This API uses a promise to return the result. -**System capability**: SystemCapability.Multimedia.Media.AudioRecorder +This API can be called only after the **start()** API is called. You can call **resume()** to resume recording. -**Parameters** +**System capability**: SystemCapability.Multimedia.Media.AVRecorder -| Name | Type | Mandatory| Description | -| -------- | ------------- | ---- | ------------------------------------------------------------ | -| type | string | Yes | Event type, which is **'error'** in this case.
The **'error'** event is triggered when an error occurs during audio recording.| -| callback | ErrorCallback | Yes | Callback invoked when the event is triggered. | +**Return value** + +| Type | Description | +| -------------- | ------------------------------------- | +| Promise\ | Promise used to return the result.| + +**Error codes** + +For details about the error codes, see [Media Error Codes](../errorcodes/errorcode-media.md). + +| ID| Error Message | +| -------- | -------------------------------------- | +| 5400102 | Operate not permit. Return by promise. | +| 5400103 | IO error. Return by promise. | +| 5400105 | Service died. Return by promise. | **Example** ```js -let audioRecorderConfig = { - audioEncoder : media.AudioEncoder.AAC_LC, - audioEncodeBitRate : 22050, - audioSampleRate : 22050, - numberOfChannels : 2, - format : media.AudioOutputFormat.AAC_ADTS, - uri : 'fd://xx', // The file must be created by the caller and granted with proper permissions. - location : { latitude : 30, longitude : 130}, -} -audioRecorder.on('error', (error) => { // Set the 'error' event callback. - console.info(`audio error called, error: ${error}`); +AVRecorder.pause().then(() => { + console.info('pause AVRecorder success'); +}).catch((err) => { + console.info('pause AVRecorder failed and catch error is ' + err.message); }); -audioRecorder.prepare(audioRecorderConfig); // Do no set any parameter in prepare and trigger the 'error' event callback. ``` -## AudioRecorderConfig +### resume9+ -Describes audio recording configurations. +resume(callback: AsyncCallback\): void -**System capability**: SystemCapability.Multimedia.Media.AudioRecorder +Resumes recording. This API uses an asynchronous callback to return the result. -| Name | Type | Mandatory| Description | -| --------------------- | --------------------------------------- | ---- | ------------------------------------------------------------ | -| audioEncoder(deprecated) | [AudioEncoder](#audioencoder) | No | Audio encoding format. The default value is **AAC_LC**.
**Note**: This parameter is deprecated since API version 8. Use **audioEncoderMime** instead. | -| audioEncodeBitRate | number | No | Audio encoding bit rate. The default value is **48000**. | -| audioSampleRate | number | No | Audio sampling rate. The default value is **48000**. | -| numberOfChannels | number | No | Number of audio channels. The default value is **2**. | -| format(deprecated) | [AudioOutputFormat](#audiooutputformat) | No | Audio output format. The default value is **MPEG_4**.
**Note**: This parameter is deprecated since API version 8. Use **fileFormat** instead. | -| location | [Location](#location) | No | Geographical location of the recorded audio. | -| uri | string | Yes | Audio output URI. Supported: fd://xx (fd number)
![](figures/en-us_image_url.png)
The file must be created by the caller and granted with proper permissions.| -| audioEncoderMime8+ | [CodecMimeType](#codecmimetype8) | No | Audio encoding format. | -| fileFormat8+ | [ContainerFormatType](#containerformattype8) | No | Audio encoding format. | +This API can be called only after the **pause()** API is called. -## AudioEncoder(deprecated) +**System capability**: SystemCapability.Multimedia.Media.AVRecorder -> **NOTE** -> This API is deprecated since API version 8. You are advised to use [CodecMimeType](#codecmimetype8) instead. +**Parameters** -Enumerates the audio encoding formats. +| Name | Type | Mandatory| Description | +| -------- | -------------------- | ---- | ---------------------------- | +| callback | AsyncCallback\ | Yes | Callback used to return the result.| -**System capability**: SystemCapability.Multimedia.Media.AudioRecorder +**Error codes** -| Name | Value | Description | -| ------- | ---- | ------------------------------------------------------------ | -| DEFAULT | 0 | Default encoding format.
This API is defined but not implemented yet. | -| AMR_NB | 1 | AMR-NB.
This API is defined but not implemented yet.| -| AMR_WB | 2 | Adaptive Multi Rate-Wide Band Speech Codec (AMR-WB).
This API is defined but not implemented yet.| -| AAC_LC | 3 | Advanced Audio Coding Low Complexity (AAC-LC).| -| HE_AAC | 4 | High-Efficiency Advanced Audio Coding (HE_AAC).
This API is defined but not implemented yet.| +For details about the error codes, see [Media Error Codes](../errorcodes/errorcode-media.md). +| ID| Error Message | +| -------- | --------------------------------------- | +| 5400102 | Operate not permit. Return by callback. | +| 5400103 | IO error. Return by callback. | +| 5400105 | Service died. Return by callback. | -## AudioOutputFormat(deprecated) +**Example** -> **NOTE** -> This API is deprecated since API version 8. You are advised to use [ContainerFormatType](#containerformattype8) instead. +```js +AVRecorder.resume((err) => { + if (err == null) { + console.info('resume AVRecorder success'); + } else { + console.info('resume AVRecorder failed and error is ' + err.message); + } +}); +``` -Enumerates the audio output formats. +### resume9+ -**System capability**: SystemCapability.Multimedia.Media.AudioRecorder +resume(): Promise\ -| Name | Value | Description | -| -------- | ---- | ------------------------------------------------------------ | -| DEFAULT | 0 | Default encapsulation format.
This API is defined but not implemented yet. | -| MPEG_4 | 2 | MPEG-4. | -| AMR_NB | 3 | AMR_NB.
This API is defined but not implemented yet. | -| AMR_WB | 4 | AMR_WB.
This API is defined but not implemented yet. | -| AAC_ADTS | 6 | Audio Data Transport Stream (ADTS), which is a transport stream format of AAC-based audio.| +Resumes recording. This API uses a promise to return the result. -## VideoRecorder9+ +This API can be called only after the **pause()** API is called. -Implements video recording. Before calling an API of the **VideoRecorder** class, you must call [createVideoRecorder()](#mediacreatevideorecorder9) to create a [VideoRecorder](#videorecorder9) instance. +**System capability**: SystemCapability.Multimedia.Media.AVRecorder -For details about the video recording demo, see [Video Recording Development](../../media/video-recorder.md). +**Return value** -### Attributes +| Type | Description | +| -------------- | ------------------------------------- | +| Promise\ | Promise used to return the result.| -**System capability**: SystemCapability.Multimedia.Media.VideoRecorder +**Error codes** -**System API**: This is a system API. +For details about the error codes, see [Media Error Codes](../errorcodes/errorcode-media.md). -| Name | Type | Readable| Writable| Description | -| ------------------ | -------------------------------------- | ---- | ---- | ---------------- | -| state9+ | [VideoRecordState](#videorecordstate9) | Yes | No | Video recording state.| +| ID| Error Message | +| -------- | -------------------------------------- | +| 5400102 | Operate not permit. Return by promise. | +| 5400103 | IO error. Return by promise. | +| 5400105 | Service died. Return by promise. | -### prepare9+ +**Example** -prepare(config: VideoRecorderConfig, callback: AsyncCallback\): void; +```js +AVRecorder.resume().then(() => { + console.info('resume AVRecorder success'); +}).catch((err) => { + console.info('resume AVRecorder failed and catch error is ' + err.message); +}); +``` -Sets video recording parameters. This API uses an asynchronous callback to return the result. +### stop9+ -**Required permissions:** ohos.permission.MICROPHONE +stop(callback: AsyncCallback\): void -**System capability**: SystemCapability.Multimedia.Media.VideoRecorder +Stops recording. This API uses an asynchronous callback to return the result. -**System API**: This is a system API. +This API can be called only after the **start()** or **pause()** API is called. + +For audio-only recording, you can call **prepare()** again for re-recording. For video-only recording or audio and video recording, you can call **prepare()** and **getInputSurface()** again for re-recording. + +**System capability**: SystemCapability.Multimedia.Media.AVRecorder **Parameters** -| Name | Type | Mandatory| Description | -| -------- | -------------------------------------------- | ---- | ----------------------------------- | -| config | [VideoRecorderConfig](#videorecorderconfig9) | Yes | Video recording parameters to set. | -| callback | AsyncCallback\ | Yes | Callback used to return the result.| +| Name | Type | Mandatory| Description | +| -------- | -------------------- | ---- | ---------------------------- | +| callback | AsyncCallback\ | Yes | Callback used to return the result.| **Error codes** For details about the error codes, see [Media Error Codes](../errorcodes/errorcode-media.md). -| ID| Error Message | -| -------- | ------------------------------------------ | -| 201 | Permission denied. Return by callback. | -| 401 | Parameter error. Return by callback. | -| 5400102 | Operation not allowed. Return by callback. | -| 5400105 | Service died. Return by callback. | +| ID| Error Message | +| -------- | --------------------------------------- | +| 5400102 | Operate not permit. Return by callback. | +| 5400103 | IO error. Return by callback. | +| 5400105 | Service died. Return by callback. | **Example** ```js -let videoProfile = { - audioBitrate : 48000, - audioChannels : 2, - audioCodec : 'audio/mp4a-latm', - audioSampleRate : 48000, - fileFormat : 'mp4', - videoBitrate : 48000, - videoCodec : 'video/mp4v-es', - videoFrameWidth : 640, - videoFrameHeight : 480, - videoFrameRate : 30 -} - -let videoConfig = { - audioSourceType : 1, - videoSourceType : 0, - profile : videoProfile, - url : 'fd://xx', // The file must be created by the caller and granted with proper permissions. - orientationHint : 0, - location : { latitude : 30, longitude : 130 }, -} - -// asyncallback -videoRecorder.prepare(videoConfig, (err) => { +AVRecorder.stop((err) => { if (err == null) { - console.info('prepare success'); + console.info('stop AVRecorder success'); } else { - console.info('prepare failed and error is ' + err.message); + console.info('stop AVRecorder failed and error is ' + err.message); } -}) +}); ``` -### prepare9+ - -prepare(config: VideoRecorderConfig): Promise\; - -Sets video recording parameters. This API uses a promise to return the result. +### stop9+ -**Required permissions:** ohos.permission.MICROPHONE +stop(): Promise\ -**System capability**: SystemCapability.Multimedia.Media.VideoRecorder +Stops recording. This API uses a promise to return the result. -**System API**: This is a system API. +This API can be called only after the **start()** or **pause()** API is called. -**Parameters** +For audio-only recording, you can call **prepare()** again for re-recording. For video-only recording or audio and video recording, you can call **prepare()** and **getInputSurface()** again for re-recording. -| Name| Type | Mandatory| Description | -| ------ | -------------------------------------------- | ---- | ------------------------ | -| config | [VideoRecorderConfig](#videorecorderconfig9) | Yes | Video recording parameters to set.| +**System capability**: SystemCapability.Multimedia.Media.AVRecorder **Return value** -| Type | Description | -| -------------- | ---------------------------------------- | +| Type | Description | +| -------------- | ------------------------------------- | | Promise\ | Promise used to return the result.| **Error codes** For details about the error codes, see [Media Error Codes](../errorcodes/errorcode-media.md). -| ID| Error Message | -| -------- | ----------------------------------------- | -| 201 | Permission denied. Return by promise. | -| 401 | Parameter error. Return by promise. | -| 5400102 | Operation not allowed. Return by promise. | -| 5400105 | Service died. Return by promise. | +| ID| Error Message | +| -------- | -------------------------------------- | +| 5400102 | Operate not permit. Return by promise. | +| 5400103 | IO error. Return by promise. | +| 5400105 | Service died. Return by promise. | **Example** ```js -let videoProfile = { - audioBitrate : 48000, - audioChannels : 2, - audioCodec : 'audio/mp4a-latm', - audioSampleRate : 48000, - fileFormat : 'mp4', - videoBitrate : 48000, - videoCodec : 'video/mp4v-es', - videoFrameWidth : 640, - videoFrameHeight : 480, - videoFrameRate : 30 -} - -let videoConfig = { - audioSourceType : 1, - videoSourceType : 0, - profile : videoProfile, - url : 'fd://xx', // The file must be created by the caller and granted with proper permissions. - orientationHint : 0, - location : { latitude : 30, longitude : 130 }, -} - -// promise -videoRecorder.prepare(videoConfig).then(() => { - console.info('prepare success'); +AVRecorder.stop().then(() => { + console.info('stop AVRecorder success'); }).catch((err) => { - console.info('prepare failed and catch error is ' + err.message); + console.info('stop AVRecorder failed and catch error is ' + err.message); }); ``` -### getInputSurface9+ - -getInputSurface(callback: AsyncCallback\): void; - -Obtains the surface required for recording in asynchronous mode. This surface is provided for the caller. The caller obtains the **surfaceBuffer** from this surface and fills in the corresponding data. +### reset9+ -Note that the video data must carry the timestamp (in ns) and buffer size, and the start time of the timestamp is based on the system startup time. +reset(callback: AsyncCallback\): void -This API can be called only after [prepare()](#videorecorder_prepare1) is called. +Resets audio and video recording. This API uses an asynchronous callback to return the result. -**System capability**: SystemCapability.Multimedia.Media.VideoRecorder +For audio-only recording, you can call **prepare()** again for re-recording. For video-only recording or audio and video recording, you can call **prepare()** and **getInputSurface()** again for re-recording. -**System API**: This is a system API. +**System capability**: SystemCapability.Multimedia.Media.AVRecorder **Parameters** -| Name | Type | Mandatory| Description | -| -------- | ---------------------- | ---- | --------------------------- | -| callback | AsyncCallback\ | Yes | Callback used to obtain the result.| +| Name | Type | Mandatory| Description | +| -------- | -------------------- | ---- | ------------------------------ | +| callback | AsyncCallback\ | Yes | Callback used to return the result.| **Error codes** For details about the error codes, see [Media Error Codes](../errorcodes/errorcode-media.md). -| ID| Error Message | -| -------- | ------------------------------------------ | -| 5400102 | Operation not allowed. Return by callback. | -| 5400103 | I/O error. Return by callback. | -| 5400105 | Service died. Return by callback. | +| ID| Error Message | +| -------- | --------------------------------- | +| 5400103 | IO error. Return by callback. | +| 5400105 | Service died. Return by callback. | **Example** ```js -// asyncallback -let surfaceID = null; // Surface ID passed to the external system. -videoRecorder.getInputSurface((err, surfaceId) => { +AVRecorder.reset((err) => { if (err == null) { - console.info('getInputSurface success'); - surfaceID = surfaceId; + console.info('reset AVRecorder success'); } else { - console.info('getInputSurface failed and error is ' + err.message); + console.info('reset AVRecorder failed and error is ' + err.message); } }); ``` -### getInputSurface9+ - -getInputSurface(): Promise\; - - Obtains the surface required for recording in asynchronous mode. This surface is provided for the caller. The caller obtains the **surfaceBuffer** from this surface and fills in the corresponding data. +### reset9+ -Note that the video data must carry the timestamp (in ns) and buffer size, and the start time of the timestamp is based on the system startup time. +reset(): Promise\ -This API can be called only after [prepare()](#videorecorder_prepare1) is called. +Resets audio and video recording. This API uses a promise to return the result. -**System capability**: SystemCapability.Multimedia.Media.VideoRecorder +For audio-only recording, you can call **prepare()** again for re-recording. For video-only recording or audio and video recording, you can call **prepare()** and **getInputSurface()** again for re-recording. -**System API**: This is a system API. +**System capability**: SystemCapability.Multimedia.Media.AVRecorder **Return value** -| Type | Description | -| ---------------- | -------------------------------- | -| Promise\ | Promise used to return the result.| +| Type | Description | +| -------------- | --------------------------------------- | +| Promise\ | Promise used to return the result.| **Error codes** For details about the error codes, see [Media Error Codes](../errorcodes/errorcode-media.md). -| ID| Error Message | -| -------- | ----------------------------------------- | -| 5400102 | Operation not allowed. Return by promise. | -| 5400103 | I/O error. Return by promise. | -| 5400105 | Service died. Return by promise. | +| ID| Error Message | +| -------- | -------------------------------- | +| 5400103 | IO error. Return by promise. | +| 5400105 | Service died. Return by promise. | **Example** ```js -// promise -let surfaceID = null; // Surface ID passed to the external system. -videoRecorder.getInputSurface().then((surfaceId) => { - console.info('getInputSurface success'); - surfaceID = surfaceId; +AVRecorder.reset().then(() => { + console.info('reset AVRecorder success'); }).catch((err) => { - console.info('getInputSurface failed and catch error is ' + err.message); + console.info('reset AVRecorder failed and catch error is ' + err.message); }); ``` -### start9+ - -start(callback: AsyncCallback\): void; +### release9+ -Starts video recording. This API uses an asynchronous callback to return the result. +release(callback: AsyncCallback\): void -This API can be called only after [prepare()](#videorecorder_prepare1) and [getInputSurface()](#getinputsurface9) are called, because the data source must pass data to the surface first. +Releases the audio and video recording resources. This API uses an asynchronous callback to return the result. -**System capability**: SystemCapability.Multimedia.Media.VideoRecorder +After the resources are released, you can no longer perform any operation on the **AVRecorder** instance. -**System API**: This is a system API. +**System capability**: SystemCapability.Multimedia.Media.AVRecorder **Parameters** -| Name | Type | Mandatory| Description | -| -------- | -------------------- | ---- | ---------------------------- | +| Name | Type | Mandatory| Description | +| -------- | -------------------- | ---- | ---------------------------------- | | callback | AsyncCallback\ | Yes | Callback used to return the result.| **Error codes** For details about the error codes, see [Media Error Codes](../errorcodes/errorcode-media.md). -| ID| Error Message | -| -------- | ------------------------------------------ | -| 5400102 | Operation not allowed. Return by callback. | -| 5400103 | I/O error. Return by callback. | -| 5400105 | Service died. Return by callback. | +| ID| Error Message | +| -------- | --------------------------------- | +| 5400105 | Service died. Return by callback. | **Example** ```js -// asyncallback -videoRecorder.start((err) => { +AVRecorder.release((err) => { if (err == null) { - console.info('start videorecorder success'); + console.info('release AVRecorder success'); } else { - console.info('start videorecorder failed and error is ' + err.message); + console.info('release AVRecorder failed and error is ' + err.message); } }); ``` -### start9+ - -start(): Promise\; +### release9+ -Starts video recording. This API uses a promise to return the result. +release(): Promise\ -This API can be called only after [prepare()](#videorecorder_prepare1) and [getInputSurface()](#getinputsurface9) are called, because the data source must pass data to the surface first. +Releases the audio and video recording resources. This API uses a promise to return the result. -**System capability**: SystemCapability.Multimedia.Media.VideoRecorder +After the resources are released, you can no longer perform any operation on the **AVRecorder** instance. -**System API**: This is a system API. +**System capability**: SystemCapability.Multimedia.Media.AVRecorder **Return value** -| Type | Description | -| -------------- | ------------------------------------- | +| Type | Description | +| -------------- | ------------------------------------------- | | Promise\ | Promise used to return the result.| **Error codes** For details about the error codes, see [Media Error Codes](../errorcodes/errorcode-media.md). -| ID| Error Message | -| -------- | ----------------------------------------- | -| 5400102 | Operation not allowed. Return by promise. | -| 5400103 | I/O error. Return by promise. | -| 5400105 | Service died. Return by promise. | +| ID| Error Message | +| -------- | --------------------------------- | +| 5400105 | Service died. Return by callback. | **Example** ```js -// promise -videoRecorder.start().then(() => { - console.info('start videorecorder success'); +AVRecorder.release().then(() => { + console.info('release AVRecorder success'); }).catch((err) => { - console.info('start videorecorder failed and catch error is ' + err.message); + console.info('release AVRecorder failed and catch error is ' + err.message); }); ``` -### pause9+ - -pause(callback: AsyncCallback\): void; - -Pauses video recording. This API uses an asynchronous callback to return the result. +### on('stateChange')9+ -This API can be called only after [start()](#videorecorder_start1) is called. You can resume recording by calling [resume()](#videorecorder_resume1). +on(type: 'stateChange', callback: (state: AVRecorderState, reason: StateChangeReason) => void): void -**System capability**: SystemCapability.Multimedia.Media.VideoRecorder +Subscribes to AVRecorder state changes. An application can subscribe to only one AVRecorder state change event. When the application initiates multiple subscriptions to this event, the last subscription prevails. -**System API**: This is a system API. +**System capability**: SystemCapability.Multimedia.Media.AVRecorder **Parameters** -| Name | Type | Mandatory| Description | -| -------- | -------------------- | ---- | ---------------------------- | -| callback | AsyncCallback\ | Yes | Callback used to return the result.| - -**Error codes** - -For details about the error codes, see [Media Error Codes](../errorcodes/errorcode-media.md). - -| ID| Error Message | -| -------- | ------------------------------------------ | -| 5400102 | Operation not allowed. Return by callback. | -| 5400103 | I/O error. Return by callback. | -| 5400105 | Service died. Return by callback. | +| Name | Type | Mandatory| Description | +| -------- | -------- | ---- | ------------------------------------------------------------ | +| type | string | Yes | Event type, which is **'stateChange'** in this case. This event can be triggered by both user operations and the system.| +| callback | function | Yes | Callback invoked when the event is triggered. It reports the following information:
**state**: [AVRecorderState](#avrecorderstate9), indicating the AVRecorder state.
**reason**: [StateChangeReason](#statechangereason9), indicating the reason for the state transition.| **Example** ```js -// asyncallback -videoRecorder.pause((err) => { - if (err == null) { - console.info('pause videorecorder success'); - } else { - console.info('pause videorecorder failed and error is ' + err.message); +AVRecorder.on('stateChange', async (state, reason) => { + console.info('case state has changed, new state is :' + state + ',and new reason is : ' + reason); } }); ``` -### pause9+ - -pause(): Promise\; - -Pauses video recording. This API uses a promise to return the result. - -This API can be called only after [start()](#videorecorder_start1) is called. You can resume recording by calling [resume()](#videorecorder_resume1). - -**System capability**: SystemCapability.Multimedia.Media.VideoRecorder - -**System API**: This is a system API. +### off('stateChange')9+ -**Return value** +off(type: 'stateChange'): void -| Type | Description | -| -------------- | ------------------------------------- | -| Promise\ | Promise used to return the result.| +Unsubscribes from AVRecorder state changes. -**Error codes** +**System capability**: SystemCapability.Multimedia.Media.AVRecorder -For details about the error codes, see [Media Error Codes](../errorcodes/errorcode-media.md). +**Parameters** -| ID| Error Message | -| -------- | ----------------------------------------- | -| 5400102 | Operation not allowed. Return by promise. | -| 5400103 | I/O error. Return by promise. | -| 5400105 | Service died. Return by promise. | +| Name| Type | Mandatory| Description | +| ------ | ------ | ---- | ------------------------------------------------------------ | +| type | string | Yes | Event type, which is **'stateChange'** in this case. This event can be triggered by both user operations and the system.| **Example** ```js -// promise -videoRecorder.pause().then(() => { - console.info('pause videorecorder success'); -}).catch((err) => { - console.info('pause videorecorder failed and catch error is ' + err.message); -}); +AVRecorder.off('stateChange'); ``` -### resume9+ +### on('error')9+ -resume(callback: AsyncCallback\): void; +on(type: 'error', callback: ErrorCallback): void -Resumes video recording. This API uses an asynchronous callback to return the result. +Subscribes to AVRecorder errors. This event is used only for error prompt and does not require the user to stop recording control. If the [AVRecorderState](#avrecorderstate9) is also switched to error, call **reset()** or **release()** to exit the recording. -**System capability**: SystemCapability.Multimedia.Media.VideoRecorder +An application can subscribe to only one AVRecorder error event. When the application initiates multiple subscriptions to this event, the last subscription prevails. -**System API**: This is a system API. +**System capability**: SystemCapability.Multimedia.Media.AVRecorder **Parameters** -| Name | Type | Mandatory| Description | -| -------- | -------------------- | ---- | ---------------------------- | -| callback | AsyncCallback\ | Yes | Callback used to return the result.| +| Name | Type | Mandatory| Description | +| -------- | ------------- | ---- | ------------------------------------------------------------ | +| type | string | Yes | Event type, which is **'error'** in this case.
This event is triggered when an error occurs during recording.| +| callback | ErrorCallback | Yes | Callback invoked when the event is triggered. | **Error codes** For details about the error codes, see [Media Error Codes](../errorcodes/errorcode-media.md). -| ID| Error Message | -| -------- | ------------------------------------------ | -| 5400102 | Operation not allowed. Return by callback. | -| 5400103 | I/O error. Return by callback. | -| 5400105 | Service died. Return by callback. | +| ID| Error Message | +| -------- | --------------------------------- | +| 5400103 | IO error. Return by callback. | +| 5400105 | Service died. Return by callback. | **Example** ```js -// asyncallback -videoRecorder.resume((err) => { - if (err == null) { - console.info('resume videorecorder success'); - } else { - console.info('resume videorecorder failed and error is ' + err.message); - } +AVRecorder.on('error', (err) => { + console.info('case avRecorder.on(error) called, errMessage is ' + err.message); }); ``` -### resume9+ - -resume(): Promise\; +### off('error')9+ -Resumes video recording. This API uses a promise to return the result. +off(type: 'error'): void -**System capability**: SystemCapability.Multimedia.Media.VideoRecorder +Unsubscribes from AVRecorder errors. After the unsubscription, your application can no longer receive AVRecorder errors. -**System API**: This is a system API. +**System capability**: SystemCapability.Multimedia.Media.AVRecorder -**Return value** +**Parameters** -| Type | Description | -| -------------- | ------------------------------------- | -| Promise\ | Promise used to return the result.| +| Name| Type | Mandatory| Description | +| ------ | ------ | ---- | ------------------------------------------------------------ | +| type | string | Yes | Event type, which is **'error'** in this case.
This event is triggered when an error occurs during recording.| **Error codes** For details about the error codes, see [Media Error Codes](../errorcodes/errorcode-media.md). -| ID| Error Message | -| -------- | ----------------------------------------- | -| 5400102 | Operation not allowed. Return by promise. | -| 5400103 | I/O error. Return by promise. | -| 5400105 | Service died. Return by promise. | +| ID| Error Message | +| -------- | --------------------------------- | +| 5400103 | IO error. Return by callback. | +| 5400105 | Service died. Return by callback. | **Example** ```js -// promise -videoRecorder.resume().then(() => { - console.info('resume videorecorder success'); -}).catch((err) => { - console.info('resume videorecorder failed and catch error is ' + err.message); -}); +AVRecorder.off('error'); ``` -### stop9+ +## AVRecorderState9+ -stop(callback: AsyncCallback\): void; +Enumerates the AVRecorder states. You can obtain the state through the **state** attribute. -Stops video recording. This API uses an asynchronous callback to return the result. +**System capability**: SystemCapability.Multimedia.Media.AVRecorder -To start another recording, you must call [prepare()](#videorecorder_prepare1) and [getInputSurface()](#getinputsurface9) again. +| Name | Type | Description | +| -------- | ------ | ------------------------------------------------------------ | +| idle | string | The AVRecorder enters this state when the AVRecorder is just created or the [reset()](#avrecorder_reset) API is called in any non-released state. In this state, you can call [prepare()](#avrecorder_prepare) to set recording parameters. | +| prepared | string | The AVRecorder enters this state when the parameters are set. In this state, you can call [start()](#avrecorder_start) to start recording.| +| started | string | The AVRecorder enters this state when the recording starts. In this state, you can call [pause()](#avrecorder_pause) to pause the recording or call [stop()](#avrecorder_stop) to stop recording.| +| paused | string | The AVRecorder enters this state when the recording is paused. In this state, you can call [resume()](#avrecorder_resume) to continue the recording or call [stop()](#avrecorder_stop) to stop recording.| +| stopped | string | The AVRecorder enters this state when the recording stops. In this state, you can call [prepare()](#avrecorder_prepare) to set recording parameters.| +| released | string | The AVRecorder enters this state when the recording resources are released. In this state, no operation can be performed. In any other state, you can call [release()](#avrecorder_release) to enter the released state.| +| error | string | The AVRecorder enters this state when an irreversible error occurs in the **AVRecorder** instance. In this state, the [on('error') event](#avrecorder_onerror) is reported, with the detailed error cause. In the error state, you must call [reset()](#avrecorder_reset) to reset the **AVRecorder** instance or call [release()](#avrecorder_release) to release the resources.| -**System capability**: SystemCapability.Multimedia.Media.VideoRecorder +## AVRecorderConfig9+ -**System API**: This is a system API. +Describes the audio and video recording parameters. -**Parameters** +**System capability**: SystemCapability.Multimedia.Media.AVRecorder -| Name | Type | Mandatory| Description | -| -------- | -------------------- | ---- | ---------------------------- | -| callback | AsyncCallback\ | Yes | Callback used to return the result.| +| Name | Type | Mandatory| Description | +| --------------- | ---------------------------------------- | ---- | ------------------------------------------------------------ | +| audioSourceType | [AudioSourceType](#audiosourcetype9) | No | Type of the audio source to record. This parameter is mandatory for audio recording. | +| videoSourceType | [VideoSourceType](#videosourcetype9) | No | Type of the video source to record. This parameter is mandatory for video recording. | +| profile | [AVRecorderProfile](#avrecorderprofile9) | Yes | Recording profile. This parameter is mandatory. | +| url | string | Yes | Recording output URL: fd://xx (fd number).
![img](figures/en-us_image_url.png)
This parameter is mandatory. | +| rotation | number | No | Rotation angle of the recorded video. The value can only be 0, 90, 180, or 270. | +| location | [Location](#location) | No | Geographical location of the recorded video. | -**Error codes** +The **audioSourceType** and **videoSourceType** parameters are used to distinguish audio-only recording, video-only recording, and audio and video recording. For audio-only recording, set only **audioSourceType**. For video-only recording, set only **videoSourceType**. For audio and video recording, set both **audioSourceType** and **videoSourceType**. -For details about the error codes, see [Media Error Codes](../errorcodes/errorcode-media.md). +## AVRecorderProfile9+ -| ID| Error Message | -| -------- | ------------------------------------------ | -| 5400102 | Operation not allowed. Return by callback. | -| 5400103 | I/O error. Return by callback. | -| 5400105 | Service died. Return by callback. | +Describes the audio and video recording profile. -**Example** +**System capability**: SystemCapability.Multimedia.Media.AVRecorder -```js -// asyncallback -videoRecorder.stop((err) => { - if (err == null) { - console.info('stop videorecorder success'); - } else { - console.info('stop videorecorder failed and error is ' + err.message); - } -}); -``` +| Name | Type | Mandatory| Description | +| ---------------- | -------------------------------------------- | ---- | ------------------------------------------------------------ | +| audioBitrate | number | No | Audio encoding bit rate. This parameter is mandatory for audio recording. | +| audioChannels | number | No | Number of audio channels. This parameter is mandatory for audio recording. | +| audioCodec | [CodecMimeType](#codecmimetype8) | No | Audio encoding format. This parameter is mandatory for audio recording. Only **AUDIO_AAC** is supported. | +| audioSampleRate | number | No | Audio sampling rate. This parameter is mandatory for audio recording. | +| fileFormat | [ContainerFormatType](#containerformattype8) | Yes | Container format of a file. This parameter is mandatory. | +| videoBitrate | number | No | Video encoding bit rate. This parameter is mandatory for video recording. | +| videoCodec | [CodecMimeType](#codecmimetype8) | No | Video encoding format. This parameter is mandatory for video recording. Only **VIDEO_AVC** and **VIDEO_MPEG4** are supported.| +| videoFrameWidth | number | No | Width of a video frame. This parameter is mandatory for video recording. | +| videoFrameHeight | number | No | Height of a video frame. This parameter is mandatory for video recording. | +| videoFrameRate | number | No | Video frame rate. This parameter is mandatory for video recording. | -### stop9+ +## AudioSourceType9+ -stop(): Promise\; +Enumerates the audio source types for video recording. -Stops video recording. This API uses a promise to return the result. +**System capability**: SystemCapability.Multimedia.Media.AVRecorder -To start another recording, you must call [prepare()](#videorecorder_prepare1) and [getInputSurface()](#getinputsurface9) again. +| Name | Value | Description | +| ------------------------- | ---- | ---------------------- | +| AUDIO_SOURCE_TYPE_DEFAULT | 0 | Default audio input source.| +| AUDIO_SOURCE_TYPE_MIC | 1 | Mic audio input source. | -**System capability**: SystemCapability.Multimedia.Media.VideoRecorder +## VideoSourceType9+ -**System API**: This is a system API. +Enumerates the video source types for video recording. -**Return value** +**System capability**: SystemCapability.Multimedia.Media.AVRecorder -| Type | Description | -| -------------- | ------------------------------------- | -| Promise\ | Promise used to return the result.| +| Name | Value | Description | +| ----------------------------- | ---- | ------------------------------- | +| VIDEO_SOURCE_TYPE_SURFACE_YUV | 0 | The input surface carries raw data.| +| VIDEO_SOURCE_TYPE_SURFACE_ES | 1 | The input surface carries ES data. | -**Error codes** +## ContainerFormatType8+ -For details about the error codes, see [Media Error Codes](../errorcodes/errorcode-media.md). +Enumerates the container format types (CFTs). -| ID| Error Message | -| -------- | ----------------------------------------- | -| 5400102 | Operation not allowed. Return by promise. | -| 5400103 | I/O error. Return by promise. | -| 5400105 | Service died. Return by promise. | +**System capability**: SystemCapability.Multimedia.Media.Core -**Example** +| Name | Value | Description | +| ----------- | ----- | --------------------- | +| CFT_MPEG_4 | 'mp4' | Video container format MP4.| +| CFT_MPEG_4A | 'm4a' | Audio container format M4A.| -```js -// promise -videoRecorder.stop().then(() => { - console.info('stop videorecorder success'); -}).catch((err) => { - console.info('stop videorecorder failed and catch error is ' + err.message); -}); -``` +## Location -### release9+ +Describes the geographical location of the recorded video. -release(callback: AsyncCallback\): void; +**System capability**: SystemCapability.Multimedia.Media.Core + +| Name | Type | Mandatory| Description | +| --------- | ------ | ---- | ---------------- | +| latitude | number | Yes | Latitude of the geographical location.| +| longitude | number | Yes | Longitude of the geographical location.| + +## VideoRecorder9+ + +> **NOTE** +> +> This class is deprecated after AVRecorder9+ is released. You are advised to use [AVRecorder](#avrecorder9) instead. + +Implements video recording. Before calling any API in the **VideoRecorder** class, you must use [createVideoRecorder()](#mediacreatevideorecorder9) to create a [VideoRecorder](#videorecorder9) instance. + +For details about the video recording demo, see [Video Recording Development](../../media/video-recorder.md). + +### Attributes + +**System capability**: SystemCapability.Multimedia.Media.VideoRecorder + +**System API**: This is a system API. + +| Name | Type | Readable| Writable| Description | +| ------------------ | -------------------------------------- | ---- | ---- | ---------------- | +| state9+ | [VideoRecordState](#videorecordstate9) | Yes | No | Video recording state.| + +### prepare9+ + +prepare(config: VideoRecorderConfig, callback: AsyncCallback\): void; + +Sets video recording parameters. This API uses an asynchronous callback to return the result. -Releases the video recording resource. This API uses an asynchronous callback to return the result. +**Required permissions:** ohos.permission.MICROPHONE **System capability**: SystemCapability.Multimedia.Media.VideoRecorder @@ -2442,73 +2587,134 @@ Releases the video recording resource. This API uses an asynchronous callback to **Parameters** -| Name | Type | Mandatory| Description | -| -------- | -------------------- | ---- | -------------------------------- | -| callback | AsyncCallback\ | Yes | Callback used to return the result.| +| Name | Type | Mandatory| Description | +| -------- | -------------------------------------------- | ---- | ----------------------------------- | +| config | [VideoRecorderConfig](#videorecorderconfig9) | Yes | Video recording parameters to set. | +| callback | AsyncCallback\ | Yes | Callback used to return the result.| **Error codes** For details about the error codes, see [Media Error Codes](../errorcodes/errorcode-media.md). -| ID| Error Message | -| -------- | --------------------------------- | -| 5400105 | Service died. Return by callback. | +| ID| Error Message | +| -------- | ------------------------------------------ | +| 201 | Permission denied. Return by callback. | +| 401 | Parameter error. Return by callback. | +| 5400102 | Operation not allowed. Return by callback. | +| 5400105 | Service died. Return by callback. | **Example** ```js +let videoProfile = { + audioBitrate : 48000, + audioChannels : 2, + audioCodec : 'audio/mp4a-latm', + audioSampleRate : 48000, + fileFormat : 'mp4', + videoBitrate : 48000, + videoCodec : 'video/mp4v-es', + videoFrameWidth : 640, + videoFrameHeight : 480, + videoFrameRate : 30 +} + +let videoConfig = { + audioSourceType : 1, + videoSourceType : 0, + profile : videoProfile, + url : 'fd://xx', // The file must be created by the caller and granted with proper permissions. + orientationHint : 0, + location : { latitude : 30, longitude : 130 }, +} + // asyncallback -videoRecorder.release((err) => { +videoRecorder.prepare(videoConfig, (err) => { if (err == null) { - console.info('release videorecorder success'); + console.info('prepare success'); } else { - console.info('release videorecorder failed and error is ' + err.message); + console.info('prepare failed and error is ' + err.message); } -}); +}) ``` -### release9+ +### prepare9+ -release(): Promise\; +prepare(config: VideoRecorderConfig): Promise\; + +Sets video recording parameters. This API uses a promise to return the result. -Releases the video recording resource. This API uses a promise to return the result. +**Required permissions:** ohos.permission.MICROPHONE **System capability**: SystemCapability.Multimedia.Media.VideoRecorder **System API**: This is a system API. +**Parameters** + +| Name| Type | Mandatory| Description | +| ------ | -------------------------------------------- | ---- | ------------------------ | +| config | [VideoRecorderConfig](#videorecorderconfig9) | Yes | Video recording parameters to set.| + **Return value** -| Type | Description | -| -------------- | ----------------------------------------- | +| Type | Description | +| -------------- | ---------------------------------------- | | Promise\ | Promise used to return the result.| **Error codes** For details about the error codes, see [Media Error Codes](../errorcodes/errorcode-media.md). -| ID| Error Message | -| -------- | --------------------------------- | -| 5400105 | Service died. Return by callback. | +| ID| Error Message | +| -------- | ----------------------------------------- | +| 201 | Permission denied. Return by promise. | +| 401 | Parameter error. Return by promise. | +| 5400102 | Operation not allowed. Return by promise. | +| 5400105 | Service died. Return by promise. | **Example** ```js +let videoProfile = { + audioBitrate : 48000, + audioChannels : 2, + audioCodec : 'audio/mp4a-latm', + audioSampleRate : 48000, + fileFormat : 'mp4', + videoBitrate : 48000, + videoCodec : 'video/mp4v-es', + videoFrameWidth : 640, + videoFrameHeight : 480, + videoFrameRate : 30 +} + +let videoConfig = { + audioSourceType : 1, + videoSourceType : 0, + profile : videoProfile, + url : 'fd://xx', // The file must be created by the caller and granted with proper permissions. + orientationHint : 0, + location : { latitude : 30, longitude : 130 }, +} + // promise -videoRecorder.release().then(() => { - console.info('release videorecorder success'); +videoRecorder.prepare(videoConfig).then(() => { + console.info('prepare success'); }).catch((err) => { - console.info('release videorecorder failed and catch error is ' + err.message); + console.info('prepare failed and catch error is ' + err.message); }); ``` -### reset9+ +### getInputSurface9+ -reset(callback: AsyncCallback\): void; +getInputSurface(callback: AsyncCallback\): void; -Resets video recording. This API uses an asynchronous callback to return the result. +Obtains the surface required for recording. This API uses an asynchronous callback to return the result. The caller obtains the **surfaceBuffer** from this surface and fills in the corresponding data. -To start another recording, you must call [prepare()](#videorecorder_prepare1) and [getInputSurface()](#getinputsurface9) again. +Note that the video data must carry the timestamp (in ns) and buffer size, and the start time of the timestamp must be based on the system startup time. + +This API can be called only after [prepare()](#videorecorder_prepare1) is called. **System capability**: SystemCapability.Multimedia.Media.VideoRecorder @@ -2516,39 +2722,44 @@ To start another recording, you must call [prepare()](#videorecorder_prepare1) a **Parameters** -| Name | Type | Mandatory| Description | -| -------- | -------------------- | ---- | ---------------------------- | -| callback | AsyncCallback\ | Yes | Callback used to return the result.| +| Name | Type | Mandatory| Description | +| -------- | ---------------------- | ---- | --------------------------- | +| callback | AsyncCallback\ | Yes | Callback used to obtain the result.| **Error codes** For details about the error codes, see [Media Error Codes](../errorcodes/errorcode-media.md). -| ID| Error Message | -| -------- | --------------------------------- | -| 5400103 | I/O error. Return by callback. | -| 5400105 | Service died. Return by callback. | +| ID| Error Message | +| -------- | ------------------------------------------ | +| 5400102 | Operation not allowed. Return by callback. | +| 5400103 | I/O error. Return by callback. | +| 5400105 | Service died. Return by callback. | **Example** ```js // asyncallback -videoRecorder.reset((err) => { +let surfaceID = null; // Surface ID passed to the external system. +videoRecorder.getInputSurface((err, surfaceId) => { if (err == null) { - console.info('reset videorecorder success'); + console.info('getInputSurface success'); + surfaceID = surfaceId; } else { - console.info('reset videorecorder failed and error is ' + err.message); + console.info('getInputSurface failed and error is ' + err.message); } }); ``` -### reset9+ +### getInputSurface9+ -reset(): Promise\; +getInputSurface(): Promise\; -Resets video recording. This API uses a promise to return the result. + Obtains the surface required for recording. This API uses a promise to return the result. The caller obtains the **surfaceBuffer** from this surface and fills in the corresponding data. -To start another recording, you must call [prepare()](#videorecorder_prepare1) and [getInputSurface()](#getinputsurface9) again. +Note that the video data must carry the timestamp (in ns) and buffer size, and the start time of the timestamp must be based on the system startup time. + +This API can be called only after [prepare()](#videorecorder_prepare1) is called. **System capability**: SystemCapability.Multimedia.Media.VideoRecorder @@ -2556,162 +2767,2240 @@ To start another recording, you must call [prepare()](#videorecorder_prepare1) a **Return value** -| Type | Description | -| -------------- | ------------------------------------- | -| Promise\ | Promise used to return the result.| +| Type | Description | +| ---------------- | -------------------------------- | +| Promise\ | Promise used to return the result.| **Error codes** For details about the error codes, see [Media Error Codes](../errorcodes/errorcode-media.md). -| ID| Error Message | -| -------- | -------------------------------- | -| 5400103 | I/O error. Return by promise. | -| 5400105 | Service died. Return by promise. | +| ID| Error Message | +| -------- | ----------------------------------------- | +| 5400102 | Operation not allowed. Return by promise. | +| 5400103 | I/O error. Return by promise. | +| 5400105 | Service died. Return by promise. | **Example** ```js // promise -videoRecorder.reset().then(() => { - console.info('reset videorecorder success'); +let surfaceID = null; // Surface ID passed to the external system. +videoRecorder.getInputSurface().then((surfaceId) => { + console.info('getInputSurface success'); + surfaceID = surfaceId; }).catch((err) => { - console.info('reset videorecorder failed and catch error is ' + err.message); + console.info('getInputSurface failed and catch error is ' + err.message); }); ``` -### on('error')9+ +### start9+ -on(type: 'error', callback: ErrorCallback): void +start(callback: AsyncCallback\): void; -Subscribes to video recording error events. After an error event is reported, you must handle the event and exit the recording. +Starts video recording. This API uses an asynchronous callback to return the result. + +This API can be called only after [prepare()](#videorecorder_prepare1) and [getInputSurface()](#getinputsurface9) are called, because the data source must pass data to the surface first. **System capability**: SystemCapability.Multimedia.Media.VideoRecorder +**System API**: This is a system API. + **Parameters** -| Name | Type | Mandatory| Description | -| -------- | ------------- | ---- | ------------------------------------------------------------ | -| type | string | Yes | Event type, which is **'error'** in this case.
The **'error'** event is triggered when an error occurs during video recording.| -| callback | ErrorCallback | Yes | Callback invoked when the event is triggered. | +| Name | Type | Mandatory| Description | +| -------- | -------------------- | ---- | ---------------------------- | +| callback | AsyncCallback\ | Yes | Callback used to return the result.| **Error codes** For details about the error codes, see [Media Error Codes](../errorcodes/errorcode-media.md). -| ID| Error Message | -| -------- | --------------------------------- | -| 5400103 | I/O error. Return by callback. | -| 5400105 | Service died. Return by callback. | +| ID| Error Message | +| -------- | ------------------------------------------ | +| 5400102 | Operation not allowed. Return by callback. | +| 5400103 | I/O error. Return by callback. | +| 5400105 | Service died. Return by callback. | **Example** ```js -// This event is reported when an error occurs during the retrieval of videoRecordState. -videoRecorder.on('error', (error) => { // Set the 'error' event callback. - console.info(`audio error called, error: ${error}`); -}) +// asyncallback +videoRecorder.start((err) => { + if (err == null) { + console.info('start videorecorder success'); + } else { + console.info('start videorecorder failed and error is ' + err.message); + } +}); ``` -## VideoRecordState9+ - -Enumerates the video recording states. You can obtain the state through the **state** attribute. - -**System capability**: SystemCapability.Multimedia.Media.VideoRecorder - -**System API**: This is a system API. +### start9+ -| Name | Type | Description | -| -------- | ------ | ---------------------- | -| idle | string | The video recorder is idle. | -| prepared | string | The video recording parameters are set.| -| playing | string | Video recording is in progress. | -| paused | string | Video recording is paused. | -| stopped | string | Video recording is stopped. | -| error | string | Video recording is in the error state. | +start(): Promise\; -## VideoRecorderConfig9+ +Starts video recording. This API uses a promise to return the result. -Describes the video recording parameters. +This API can be called only after [prepare()](#videorecorder_prepare1) and [getInputSurface()](#getinputsurface9) are called, because the data source must pass data to the surface first. **System capability**: SystemCapability.Multimedia.Media.VideoRecorder **System API**: This is a system API. -| Name | Type | Mandatory| Description | -| --------------- | ---------------------------------------------- | ---- | ------------------------------------------------------------ | -| audioSourceType | [AudioSourceType](#audiosourcetype9) | Yes | Type of the audio source for video recording. | -| videoSourceType | [VideoSourceType](#videosourcetype9) | Yes | Type of the video source for video recording. | -| profile | [VideoRecorderProfile](#videorecorderprofile9) | Yes | Video recording profile. | -| rotation | number | No | Rotation angle of the recorded video. | -| location | [Location](#location) | No | Geographical location of the recorded video. | -| url | string | Yes | Video output URL. Supported: fd://xx (fd number)
![](figures/en-us_image_url.png) | +**Return value** -## AudioSourceType9+ +| Type | Description | +| -------------- | ------------------------------------- | +| Promise\ | Promise used to return the result.| -Enumerates the audio source types for video recording. +**Error codes** + +For details about the error codes, see [Media Error Codes](../errorcodes/errorcode-media.md). + +| ID| Error Message | +| -------- | ----------------------------------------- | +| 5400102 | Operation not allowed. Return by promise. | +| 5400103 | I/O error. Return by promise. | +| 5400105 | Service died. Return by promise. | + +**Example** + +```js +// promise +videoRecorder.start().then(() => { + console.info('start videorecorder success'); +}).catch((err) => { + console.info('start videorecorder failed and catch error is ' + err.message); +}); +``` + +### pause9+ + +pause(callback: AsyncCallback\): void; + +Pauses video recording. This API uses an asynchronous callback to return the result. + +This API can be called only after [start()](#videorecorder_start1) is called. You can resume recording by calling [resume()](#videorecorder_resume1). **System capability**: SystemCapability.Multimedia.Media.VideoRecorder **System API**: This is a system API. -| Name | Value | Description | -| ------------------------- | ---- | ---------------------- | -| AUDIO_SOURCE_TYPE_DEFAULT | 0 | Default audio input source.| -| AUDIO_SOURCE_TYPE_MIC | 1 | Mic audio input source. | +**Parameters** -## VideoSourceType9+ +| Name | Type | Mandatory| Description | +| -------- | -------------------- | ---- | ---------------------------- | +| callback | AsyncCallback\ | Yes | Callback used to return the result.| -Enumerates the video source types for video recording. +**Error codes** + +For details about the error codes, see [Media Error Codes](../errorcodes/errorcode-media.md). + +| ID| Error Message | +| -------- | ------------------------------------------ | +| 5400102 | Operation not allowed. Return by callback. | +| 5400103 | I/O error. Return by callback. | +| 5400105 | Service died. Return by callback. | + +**Example** + +```js +// asyncallback +videoRecorder.pause((err) => { + if (err == null) { + console.info('pause videorecorder success'); + } else { + console.info('pause videorecorder failed and error is ' + err.message); + } +}); +``` + +### pause9+ + +pause(): Promise\; + +Pauses video recording. This API uses a promise to return the result. + +This API can be called only after [start()](#videorecorder_start1) is called. You can resume recording by calling [resume()](#videorecorder_resume1). **System capability**: SystemCapability.Multimedia.Media.VideoRecorder **System API**: This is a system API. -| Name | Value | Description | -| ----------------------------- | ---- | ------------------------------- | -| VIDEO_SOURCE_TYPE_SURFACE_YUV | 0 | The input surface carries raw data.| -| VIDEO_SOURCE_TYPE_SURFACE_ES | 1 | The input surface carries ES data. | +**Return value** -## VideoRecorderProfile9+ +| Type | Description | +| -------------- | ------------------------------------- | +| Promise\ | Promise used to return the result.| -Describes the video recording profile. +**Error codes** + +For details about the error codes, see [Media Error Codes](../errorcodes/errorcode-media.md). + +| ID| Error Message | +| -------- | ----------------------------------------- | +| 5400102 | Operation not allowed. Return by promise. | +| 5400103 | I/O error. Return by promise. | +| 5400105 | Service died. Return by promise. | + +**Example** + +```js +// promise +videoRecorder.pause().then(() => { + console.info('pause videorecorder success'); +}).catch((err) => { + console.info('pause videorecorder failed and catch error is ' + err.message); +}); +``` + +### resume9+ + +resume(callback: AsyncCallback\): void; + +Resumes video recording. This API uses an asynchronous callback to return the result. **System capability**: SystemCapability.Multimedia.Media.VideoRecorder **System API**: This is a system API. -| Name | Type | Mandatory| Description | -| ---------------- | -------------------------------------------- | ---- | ---------------- | -| audioBitrate | number | Yes | Audio encoding bit rate.| -| audioChannels | number | Yes | Number of audio channels.| -| audioCodec | [CodecMimeType](#codecmimetype8) | Yes | Audio encoding format. | -| audioSampleRate | number | Yes | Audio sampling rate. | -| fileFormat | [ContainerFormatType](#containerformattype8) | Yes | Container format of a file.| -| videoBitrate | number | Yes | Video encoding bit rate.| -| videoCodec | [CodecMimeType](#codecmimetype8) | Yes | Video encoding format. | -| videoFrameWidth | number | Yes | Width of the recorded video frame.| -| videoFrameHeight | number | Yes | Height of the recorded video frame.| -| videoFrameRate | number | Yes | Video frame rate. | +**Parameters** -## ContainerFormatType8+ +| Name | Type | Mandatory| Description | +| -------- | -------------------- | ---- | ---------------------------- | +| callback | AsyncCallback\ | Yes | Callback used to return the result.| -Enumerates the container format types (CFTs). +**Error codes** -**System capability**: SystemCapability.Multimedia.Media.Core +For details about the error codes, see [Media Error Codes](../errorcodes/errorcode-media.md). -| Name | Value | Description | -| ----------- | ----- | --------------------- | -| CFT_MPEG_4 | 'mp4' | Video container format MPEG-4.| -| CFT_MPEG_4A | 'm4a' | Audio container format M4A.| +| ID| Error Message | +| -------- | ------------------------------------------ | +| 5400102 | Operation not allowed. Return by callback. | +| 5400103 | I/O error. Return by callback. | +| 5400105 | Service died. Return by callback. | -## Location +**Example** -Describes the geographical location of the recorded video. +```js +// asyncallback +videoRecorder.resume((err) => { + if (err == null) { + console.info('resume videorecorder success'); + } else { + console.info('resume videorecorder failed and error is ' + err.message); + } +}); +``` -**System capability**: SystemCapability.Multimedia.Media.Core +### resume9+ -| Name | Type | Mandatory| Description | -| --------- | ------ | ---- | ---------------- | -| latitude | number | Yes | Latitude of the geographical location.| -| longitude | number | Yes | Longitude of the geographical location.| +resume(): Promise\; + +Resumes video recording. This API uses a promise to return the result. + +**System capability**: SystemCapability.Multimedia.Media.VideoRecorder + +**System API**: This is a system API. + +**Return value** + +| Type | Description | +| -------------- | ------------------------------------- | +| Promise\ | Promise used to return the result.| + +**Error codes** + +For details about the error codes, see [Media Error Codes](../errorcodes/errorcode-media.md). + +| ID| Error Message | +| -------- | ----------------------------------------- | +| 5400102 | Operation not allowed. Return by promise. | +| 5400103 | I/O error. Return by promise. | +| 5400105 | Service died. Return by promise. | + +**Example** + +```js +// promise +videoRecorder.resume().then(() => { + console.info('resume videorecorder success'); +}).catch((err) => { + console.info('resume videorecorder failed and catch error is ' + err.message); +}); +``` + +### stop9+ + +stop(callback: AsyncCallback\): void; + +Stops video recording. This API uses an asynchronous callback to return the result. + +To start another recording, you must call [prepare()](#videorecorder_prepare1) and [getInputSurface()](#getinputsurface9) again. + +**System capability**: SystemCapability.Multimedia.Media.VideoRecorder + +**System API**: This is a system API. + +**Parameters** + +| Name | Type | Mandatory| Description | +| -------- | -------------------- | ---- | ---------------------------- | +| callback | AsyncCallback\ | Yes | Callback used to return the result.| + +**Error codes** + +For details about the error codes, see [Media Error Codes](../errorcodes/errorcode-media.md). + +| ID| Error Message | +| -------- | ------------------------------------------ | +| 5400102 | Operation not allowed. Return by callback. | +| 5400103 | I/O error. Return by callback. | +| 5400105 | Service died. Return by callback. | + +**Example** + +```js +// asyncallback +videoRecorder.stop((err) => { + if (err == null) { + console.info('stop videorecorder success'); + } else { + console.info('stop videorecorder failed and error is ' + err.message); + } +}); +``` + +### stop9+ + +stop(): Promise\; + +Stops video recording. This API uses a promise to return the result. + +To start another recording, you must call [prepare()](#videorecorder_prepare1) and [getInputSurface()](#getinputsurface9) again. + +**System capability**: SystemCapability.Multimedia.Media.VideoRecorder + +**System API**: This is a system API. + +**Return value** + +| Type | Description | +| -------------- | ------------------------------------- | +| Promise\ | Promise used to return the result.| + +**Error codes** + +For details about the error codes, see [Media Error Codes](../errorcodes/errorcode-media.md). + +| ID| Error Message | +| -------- | ----------------------------------------- | +| 5400102 | Operation not allowed. Return by promise. | +| 5400103 | I/O error. Return by promise. | +| 5400105 | Service died. Return by promise. | + +**Example** + +```js +// promise +videoRecorder.stop().then(() => { + console.info('stop videorecorder success'); +}).catch((err) => { + console.info('stop videorecorder failed and catch error is ' + err.message); +}); +``` + +### release9+ + +release(callback: AsyncCallback\): void; + +Releases the video recording resources. This API uses an asynchronous callback to return the result. + +**System capability**: SystemCapability.Multimedia.Media.VideoRecorder + +**System API**: This is a system API. + +**Parameters** + +| Name | Type | Mandatory| Description | +| -------- | -------------------- | ---- | -------------------------------- | +| callback | AsyncCallback\ | Yes | Callback used to return the result.| + +**Error codes** + +For details about the error codes, see [Media Error Codes](../errorcodes/errorcode-media.md). + +| ID| Error Message | +| -------- | --------------------------------- | +| 5400105 | Service died. Return by callback. | + +**Example** + +```js +// asyncallback +videoRecorder.release((err) => { + if (err == null) { + console.info('release videorecorder success'); + } else { + console.info('release videorecorder failed and error is ' + err.message); + } +}); +``` + +### release9+ + +release(): Promise\; + +Releases the video recording resources. This API uses a promise to return the result. + +**System capability**: SystemCapability.Multimedia.Media.VideoRecorder + +**System API**: This is a system API. + +**Return value** + +| Type | Description | +| -------------- | ----------------------------------------- | +| Promise\ | Promise used to return the result.| + +**Error codes** + +For details about the error codes, see [Media Error Codes](../errorcodes/errorcode-media.md). + +| ID| Error Message | +| -------- | --------------------------------- | +| 5400105 | Service died. Return by callback. | + +**Example** + +```js +// promise +videoRecorder.release().then(() => { + console.info('release videorecorder success'); +}).catch((err) => { + console.info('release videorecorder failed and catch error is ' + err.message); +}); +``` + +### reset9+ + +reset(callback: AsyncCallback\): void; + +Resets video recording. This API uses an asynchronous callback to return the result. + +To start another recording, you must call [prepare()](#videorecorder_prepare1) and [getInputSurface()](#getinputsurface9) again. + +**System capability**: SystemCapability.Multimedia.Media.VideoRecorder + +**System API**: This is a system API. + +**Parameters** + +| Name | Type | Mandatory| Description | +| -------- | -------------------- | ---- | ---------------------------- | +| callback | AsyncCallback\ | Yes | Callback used to return the result.| + +**Error codes** + +For details about the error codes, see [Media Error Codes](../errorcodes/errorcode-media.md). + +| ID| Error Message | +| -------- | --------------------------------- | +| 5400103 | I/O error. Return by callback. | +| 5400105 | Service died. Return by callback. | + +**Example** + +```js +// asyncallback +videoRecorder.reset((err) => { + if (err == null) { + console.info('reset videorecorder success'); + } else { + console.info('reset videorecorder failed and error is ' + err.message); + } +}); +``` + +### reset9+ + +reset(): Promise\; + +Resets video recording. This API uses a promise to return the result. + +To start another recording, you must call [prepare()](#videorecorder_prepare1) and [getInputSurface()](#getinputsurface9) again. + +**System capability**: SystemCapability.Multimedia.Media.VideoRecorder + +**System API**: This is a system API. + +**Return value** + +| Type | Description | +| -------------- | ------------------------------------- | +| Promise\ | Promise used to return the result.| + +**Error codes** + +For details about the error codes, see [Media Error Codes](../errorcodes/errorcode-media.md). + +| ID| Error Message | +| -------- | -------------------------------- | +| 5400103 | I/O error. Return by promise. | +| 5400105 | Service died. Return by promise. | + +**Example** + +```js +// promise +videoRecorder.reset().then(() => { + console.info('reset videorecorder success'); +}).catch((err) => { + console.info('reset videorecorder failed and catch error is ' + err.message); +}); +``` + +### on('error')9+ + +on(type: 'error', callback: ErrorCallback): void + +Subscribes to video recording error events. After an error event is reported, you must handle the event and exit the recording. + +**System capability**: SystemCapability.Multimedia.Media.VideoRecorder + +**Parameters** + +| Name | Type | Mandatory| Description | +| -------- | ------------- | ---- | ------------------------------------------------------------ | +| type | string | Yes | Event type, which is **'error'** in this case.
This event is triggered when an error occurs during video recording.| +| callback | ErrorCallback | Yes | Callback invoked when the event is triggered. | + +**Error codes** + +For details about the error codes, see [Media Error Codes](../errorcodes/errorcode-media.md). + +| ID| Error Message | +| -------- | --------------------------------- | +| 5400103 | I/O error. Return by callback. | +| 5400105 | Service died. Return by callback. | + +**Example** + +```js +// This event is reported when an error occurs during the retrieval of videoRecordState. +videoRecorder.on('error', (error) => { // Set the 'error' event callback. + console.info(`audio error called, error: ${error}`); +}) +``` + +## VideoRecordState9+ + +Enumerates the video recording states. You can obtain the state through the **state** attribute. + +**System capability**: SystemCapability.Multimedia.Media.VideoRecorder + +**System API**: This is a system API. + +| Name | Type | Description | +| -------- | ------ | ---------------------- | +| idle | string | The video recorder is idle. | +| prepared | string | The video recording parameters are set.| +| playing | string | Video recording is in progress. | +| paused | string | Video recording is paused. | +| stopped | string | Video recording is stopped. | +| error | string | Video recording is in the error state. | + +## VideoRecorderConfig9+ + +Describes the video recording parameters. + +**System capability**: SystemCapability.Multimedia.Media.VideoRecorder + +**System API**: This is a system API. + +| Name | Type | Mandatory| Description | +| --------------- | ---------------------------------------------- | ---- | ------------------------------------------------------------ | +| audioSourceType | [AudioSourceType](#audiosourcetype9) | Yes | Type of the audio source for video recording. | +| videoSourceType | [VideoSourceType](#videosourcetype9) | Yes | Type of the video source for video recording. | +| profile | [VideoRecorderProfile](#videorecorderprofile9) | Yes | Video recording profile. | +| rotation | number | No | Rotation angle of the recorded video. | +| location | [Location](#location) | No | Geographical location of the recorded video. | +| url | string | Yes | Video output URL. Supported: fd://xx (fd number)
![](figures/en-us_image_url.png) | + +## VideoRecorderProfile9+ + +Describes the video recording profile. + +**System capability**: SystemCapability.Multimedia.Media.VideoRecorder + +**System API**: This is a system API. + +| Name | Type | Mandatory| Description | +| ---------------- | -------------------------------------------- | ---- | ---------------- | +| audioBitrate | number | Yes | Audio encoding bit rate.| +| audioChannels | number | Yes | Number of audio channels.| +| audioCodec | [CodecMimeType](#codecmimetype8) | Yes | Audio encoding format. | +| audioSampleRate | number | Yes | Audio sampling rate. | +| fileFormat | [ContainerFormatType](#containerformattype8) | Yes | Container format of a file.| +| videoBitrate | number | Yes | Video encoding bit rate.| +| videoCodec | [CodecMimeType](#codecmimetype8) | Yes | Video encoding format. | +| videoFrameWidth | number | Yes | Width of the recorded video frame.| +| videoFrameHeight | number | Yes | Height of the recorded video frame.| +| videoFrameRate | number | Yes | Video frame rate. | + +## media.createAudioPlayer(deprecated) + +createAudioPlayer(): AudioPlayer + +Creates an **AudioPlayer** instance in synchronous mode. + +> **NOTE** +> +> This API is supported since API version 6 and deprecated since API version 9. You are advised to use [createAVPlayer](#mediacreateavplayer9) instead. + +**System capability**: SystemCapability.Multimedia.Media.AudioPlayer + +**Return value** + +| Type | Description | +| --------------------------- | ------------------------------------------------------------ | +| [AudioPlayer](#audioplayerdeprecated) | If the operation is successful, an **AudioPlayer** instance is returned; otherwise, **null** is returned. After the instance is created, you can start, pause, or stop audio playback.| + +**Example** + +```js +let audioPlayer = media.createAudioPlayer(); +``` + +## media.createVideoPlayer(deprecated) + +createVideoPlayer(callback: AsyncCallback\): void + +Creates a **VideoPlayer** instance. This API uses an asynchronous callback to return the result. + +> **NOTE** +> +> This API is supported since API version 8 and deprecated since API version 9. You are advised to use [createAVPlayer](#mediacreateavplayer9) instead. + +**System capability**: SystemCapability.Multimedia.Media.VideoPlayer + +**Parameters** + +| Name | Type | Mandatory| Description | +| -------- | ------------------------------------------ | ---- | ------------------------------------------------------------ | +| callback | AsyncCallback<[VideoPlayer](#videoplayerdeprecated)> | Yes | Callback used to return the result. If the operation is successful, a **VideoPlayer** instance is returned; otherwise, **null** is returned. The instance can be used to manage and play video.| + +**Example** + +```js +let videoPlayer + +media.createVideoPlayer((error, video) => { + if (video != null) { + videoPlayer = video; + console.info('video createVideoPlayer success'); + } else { + console.info(`video createVideoPlayer fail, error:${error}`); + } +}); +``` + +## media.createVideoPlayer(deprecated) + +createVideoPlayer(): Promise\ + +Creates a **VideoPlayer** instance. This API uses a promise to return the result. + +> **NOTE** +> +> This API is supported since API version 8 and deprecated since API version 9. You are advised to use [createAVPlayer](#mediacreateavplayer9-1) instead. + +**System capability**: SystemCapability.Multimedia.Media.VideoPlayer + +**Return value** + +| Type | Description | +| ------------------------------------ | ------------------------------------------------------------ | +| Promise<[VideoPlayer](#videoplayerdeprecated)> | Promise used to return the result. If the operation is successful, a **VideoPlayer** instance is returned; otherwise, **null** is returned. The instance can be used to manage and play video.| + +**Example** + +```js +let videoPlayer + +media.createVideoPlayer().then((video) => { + if (video != null) { + videoPlayer = video; + console.info('video createVideoPlayer success'); + } else { + console.info('video createVideoPlayer fail'); + } +}).catch((error) => { + console.info(`video catchCallback, error:${error}`); +}); +``` + +## media.createAudioRecorder(deprecated) + +createAudioRecorder(): AudioRecorder + +Creates an **AudioRecorder** instance to control audio recording. +Only one **AudioRecorder** instance can be created per device. + +> **NOTE** +> +> This API is supported since API version 8 and deprecated since API version 9. You are advised to use [createAVRecorder](#mediacreateavrecorder9) instead. + +**System capability**: SystemCapability.Multimedia.Media.AudioRecorder + +**Return value** + +| Type | Description | +| ------------------------------- | ------------------------------------------------------------ | +| [AudioRecorder](#audiorecorderdeprecated) | If the operation is successful, the **AudioRecorder** instance is returned; otherwise, **null** is returned. The instance can be used to record audio.| + +**Example** + +```js +let audioRecorder = media.createAudioRecorder(); +``` + +## MediaErrorCode(deprecated) + +Enumerates the media error codes. + +> **NOTE** +> +> This enum is supported since API version 8 and deprecated since API version 9. You are advised to use [Media Error Codes](../errorcodes/errorcode-media.md) instead. + +**System capability**: SystemCapability.Multimedia.Media.Core + +| Name | Value | Description | +| -------------------------- | ---- | -------------------------------------- | +| MSERR_OK | 0 | The operation is successful. | +| MSERR_NO_MEMORY | 1 | Failed to allocate memory. The system may have no available memory.| +| MSERR_OPERATION_NOT_PERMIT | 2 | No permission to perform the operation. | +| MSERR_INVALID_VAL | 3 | Invalid input parameter. | +| MSERR_IO | 4 | An I/O error occurs. | +| MSERR_TIMEOUT | 5 | The operation times out. | +| MSERR_UNKNOWN | 6 | An unknown error occurs. | +| MSERR_SERVICE_DIED | 7 | Invalid server. | +| MSERR_INVALID_STATE | 8 | The operation is not allowed in the current state. | +| MSERR_UNSUPPORTED | 9 | The operation is not supported in the current version. | + +## AudioPlayer(deprecated) + +> **NOTE** +> +> This API is supported since API version 6 and deprecated since API version 9. You are advised to use [AVPlayer](#avplayer9) instead. + +Provides APIs to manage and play audio. Before calling any API in **AudioPlayer**, you must use [createAudioPlayer()](#mediacreateaudioplayerdeprecated) to create an **AudioPlayer** instance. + +### Attributes + +**System capability**: SystemCapability.Multimedia.Media.AudioPlayer + +| Name | Type | Readable| Writable| Description | +| ------------------------------- | ------------------------------------------------------ | ---- | ---- | ------------------------------------------------------------ | +| src | string | Yes | Yes | Audio file URI. The mainstream audio formats (M4A, AAC, MP3, OGG, and WAV) are supported.
**Examples of supported URLs**:
1. FD: fd://xx
![](figures/en-us_image_url.png)
2. HTTP: http://xx
3. HTTPS: https://xx
4. HLS: http://xx or https://xx
**Required permissions**: ohos.permission.READ_MEDIA or ohos.permission.INTERNET| +| fdSrc9+ | [AVFileDescriptor](#avfiledescriptor9) | Yes | Yes | Description of the audio file. This attribute is required when audio assets of an application are continuously stored in a file.
**Example:**
Assume that a music file that stores continuous music assets consists of the following:
Music 1 (address offset: 0, byte length: 100)
Music 2 (address offset: 101; byte length: 50)
Music 3 (address offset: 151, byte length: 150)
1. To play music 1: AVFileDescriptor {fd = resource handle; offset = 0; length = 100; }
2. To play music 2: AVFileDescriptor {fd = resource handle; offset = 101; length = 50; }
3. To play music 3: AVFileDescriptor {fd = resource handle; offset = 151; length = 150; }
To play an independent music file, use **src=fd://xx**.
| +| loop | boolean | Yes | Yes | Whether to loop audio playback. The value **true** means to loop audio playback, and **false** means the opposite. | +| audioInterruptMode9+ | [audio.InterruptMode](js-apis-audio.md#interruptmode9) | Yes | Yes | Audio interruption mode. | +| currentTime | number | Yes | No | Current audio playback position, in ms. | +| duration | number | Yes | No | Audio duration, in ms. | +| state | [AudioState](#audiostate) | Yes | No | Audio playback state. This state cannot be used as the condition for triggering the call of **play()**, **pause()**, or **stop()**.| + +### play + +play(): void + +Starts to play an audio asset. This API can be called only after the [dataLoad](#audioplayer_on) event is triggered. + +**System capability**: SystemCapability.Multimedia.Media.AudioPlayer + +**Example** + +```js +audioPlayer.on('play', () => { // Set the 'play' event callback. + console.log('audio play success'); +}); +audioPlayer.play(); +``` + +### pause + +pause(): void + +Pauses audio playback. + +**System capability**: SystemCapability.Multimedia.Media.AudioPlayer + +**Example** + +```js +audioPlayer.on('pause', () => { // Set the 'pause' event callback. + console.log('audio pause success'); +}); +audioPlayer.pause(); +``` + +### stop + +stop(): void + +Stops audio playback. + +**System capability**: SystemCapability.Multimedia.Media.AudioPlayer + +**Example** + +```js +audioPlayer.on('stop', () => { // Set the 'stop' event callback. + console.log('audio stop success'); +}); +audioPlayer.stop(); +``` + +### reset7+ + +reset(): void + +Resets the audio asset to be played. + +**System capability**: SystemCapability.Multimedia.Media.AudioPlayer + +**Example** + +```js +audioPlayer.on('reset', () => { // Set the 'reset' event callback. + console.log('audio reset success'); +}); +audioPlayer.reset(); +``` + +### seek + +seek(timeMs: number): void + +Seeks to the specified playback position. + +**System capability**: SystemCapability.Multimedia.Media.AudioPlayer + +**Parameters** + +| Name| Type | Mandatory| Description | +| ------ | ------ | ---- | ----------------------------------------------------------- | +| timeMs | number | Yes | Position to seek to, in ms. The value range is [0, duration].| + +**Example** + +```js +audioPlayer.on('timeUpdate', (seekDoneTime) => { // Set the 'timeUpdate' event callback. + if (seekDoneTime == null) { + console.info('audio seek fail'); + return; + } + console.log('audio seek success. seekDoneTime: ' + seekDoneTime); +}); +audioPlayer.seek(30000); // Seek to 30000 ms. +``` + +### setVolume + +setVolume(vol: number): void + +Sets the volume. + +**System capability**: SystemCapability.Multimedia.Media.AudioPlayer + +**Parameters** + +| Name| Type | Mandatory| Description | +| ------ | ------ | ---- | ------------------------------------------------------------ | +| vol | number | Yes | Relative volume. The value ranges from 0.00 to 1.00. The value **1.00** indicates the maximum volume (100%).| + +**Example** + +```js +audioPlayer.on('volumeChange', () => { // Set the 'volumeChange' event callback. + console.log('audio volumeChange success'); +}); +audioPlayer.setVolume(1); // Set the volume to 100%. +``` + +### release + +release(): void + +Releases the audio playback resources. + +**System capability**: SystemCapability.Multimedia.Media.AudioPlayer + +**Example** + +```js +audioPlayer.release(); +audioPlayer = undefined; +``` + +### getTrackDescription8+ + +getTrackDescription(callback: AsyncCallback\>): void + +Obtains the audio track information. This API uses an asynchronous callback to return the result. It can be called only after the [dataLoad](#audioplayer_on) event is triggered. + +**System capability**: SystemCapability.Multimedia.Media.AudioPlayer + +**Parameters** + +| Name | Type | Mandatory| Description | +| -------- | ------------------------------------------------------------ | ---- | ------------------------------------------ | +| callback | AsyncCallback\> | Yes | Callback used to return a **MediaDescription** array, which records the audio track information.| + +**Example** + +```js +function printfDescription(obj) { + for (let item in obj) { + let property = obj[item]; + console.info('audio key is ' + item); + console.info('audio value is ' + property); + } +} + +audioPlayer.getTrackDescription((error, arrList) => { + if (arrList != null) { + for (let i = 0; i < arrList.length; i++) { + printfDescription(arrList[i]); + } + } else { + console.log(`audio getTrackDescription fail, error:${error}`); + } +}); +``` + +### getTrackDescription8+ + +getTrackDescription(): Promise\> + +Obtains the audio track information. This API uses a promise to return the result. It can be called only after the [dataLoad](#audioplayer_on) event is triggered. + +**System capability**: SystemCapability.Multimedia.Media.AudioPlayer + +**Return value** + +| Type | Description | +| ------------------------------------------------------ | ----------------------------------------------- | +| Promise> | Promise used to return a **MediaDescription** array, which records the audio track information.| + +**Example** + +```js +function printfDescription(obj) { + for (let item in obj) { + let property = obj[item]; + console.info('audio key is ' + item); + console.info('audio value is ' + property); + } +} +let arrayDescription = null +audioPlayer.getTrackDescription().then((arrList) => { + if (arrList != null) { + arrayDescription = arrList; + } else { + console.log('audio getTrackDescription fail'); + } +}).catch((error) => { + console.info(`audio catchCallback, error:${error}`); +}); + +for (let i = 0; i < arrayDescription.length; i++) { + printfDescription(arrayDescription[i]); +} +``` + +### on('bufferingUpdate')8+ + +on(type: 'bufferingUpdate', callback: (infoType: BufferingInfoType, value: number) => void): void + +Subscribes to the audio buffering update event. This API works only under online playback. + +**System capability**: SystemCapability.Multimedia.Media.AudioPlayer + +**Parameters** + +| Name | Type | Mandatory| Description | +| -------- | -------- | ---- | ------------------------------------------------------------ | +| type | string | Yes | Event type, which is **'bufferingUpdate'** in this case. | +| callback | function | Yes | Callback invoked when the event is triggered.
When [BufferingInfoType](#bufferinginfotype8) is set to **BUFFERING_PERCENT** or **CACHED_DURATION**, **value** is valid. Otherwise, **value** is fixed at **0**.| + +**Example** + +```js +audioPlayer.on('bufferingUpdate', (infoType, value) => { + console.log('audio bufferingInfo type: ' + infoType); + console.log('audio bufferingInfo value: ' + value); +}); +``` + + ### on('play' | 'pause' | 'stop' | 'reset' | 'dataLoad' | 'finish' | 'volumeChange') + +on(type: 'play' | 'pause' | 'stop' | 'reset' | 'dataLoad' | 'finish' | 'volumeChange', callback: () => void): void + +Subscribes to the audio playback events. + +**System capability**: SystemCapability.Multimedia.Media.AudioPlayer + +**Parameters** + +| Name | Type | Mandatory| Description | +| -------- | ---------- | ---- | ------------------------------------------------------------ | +| type | string | Yes | Event type. The following events are supported:
- 'play': triggered when the [play()](#audioplayer_play) API is called and audio playback starts.
- 'pause': triggered when the [pause()](#audioplayer_pause) API is called and audio playback is paused.
- 'stop': triggered when the [stop()](#audioplayer_stop) API is called and audio playback stops.
- 'reset': triggered when the [reset()](#audioplayer_reset) API is called and audio playback is reset.
- 'dataLoad': triggered when the audio data is loaded, that is, when the **src** attribute is configured.
- 'finish': triggered when the audio playback is finished.
- 'volumeChange': triggered when the [setVolume()](#audioplayer_setvolume) API is called and the playback volume is changed. | +| callback | () => void | Yes | Callback invoked when the event is triggered. | + +**Example** + +```js +import fileio from '@ohos.fileio' + +let audioPlayer = media.createAudioPlayer(); // Create an AudioPlayer instance. +audioPlayer.on('dataLoad', () => { // Set the 'dataLoad' event callback, which is triggered when the src attribute is set successfully. + console.info('audio set source success'); + audioPlayer.play(); // Start the playback and trigger the 'play' event callback. +}); +audioPlayer.on('play', () => { // Set the 'play' event callback. + console.info('audio play success'); + audioPlayer.seek(30000); // Call the seek() API and trigger the 'timeUpdate' event callback. +}); +audioPlayer.on('pause', () => { // Set the 'pause' event callback. + console.info('audio pause success'); + audioPlayer.stop(); // Stop the playback and trigger the 'stop' event callback. +}); +audioPlayer.on('reset', () => { // Set the 'reset' event callback. + console.info('audio reset success'); + audioPlayer.release(); // Release the AudioPlayer instance. + audioPlayer = undefined; +}); +audioPlayer.on('timeUpdate', (seekDoneTime) => { // Set the 'timeUpdate' event callback. + if (seekDoneTime == null) { + console.info('audio seek fail'); + return; + } + console.info('audio seek success, and seek time is ' + seekDoneTime); + audioPlayer.setVolume(0.5); // Set the volume to 50% and trigger the 'volumeChange' event callback. +}); +audioPlayer.on('volumeChange', () => { // Set the 'volumeChange' event callback. + console.info('audio volumeChange success'); + audioPlayer.pause(); // Pause the playback and trigger the 'pause' event callback. +}); +audioPlayer.on('finish', () => { // Set the 'finish' event callback. + console.info('audio play finish'); + audioPlayer.stop(); // Stop the playback and trigger the 'stop' event callback. +}); +audioPlayer.on('error', (error) => { // Set the 'error' event callback. + console.info(`audio error called, error: ${error}`); +}); + +// Set the FD (local playback) of the video file selected by the user. +let fdPath = 'fd://'; +// The stream in the path can be pushed to the device by running the "hdc file send D:\xxx\01.mp3 /data/accounts/account_0/appdata" command. +let path = '/data/accounts/account_0/appdata/ohos.xxx.xxx.xxx/01.mp3'; +fileio.open(path).then((fdValue) => { + fdPath = fdPath + '' + fdValue; + console.info('open fd success fd is' + fdPath); +}, (err) => { + console.info('open fd failed err is' + err); +}).catch((err) => { + console.info('open fd failed err is' + err); +}); +audioPlayer.src = fdPath; // Set the src attribute and trigger the 'dataLoad' event callback. +``` + +### on('timeUpdate') + +on(type: 'timeUpdate', callback: Callback\): void + +Subscribes to the **'timeUpdate'** event. This event is reported every second when the audio playback is in progress. + +**System capability**: SystemCapability.Multimedia.Media.AudioPlayer + +**Parameters** + +| Name | Type | Mandatory| Description | +| -------- | ----------------- | ---- | ------------------------------------------------------------ | +| type | string | Yes | Event type, which is **'timeUpdate'** in this case.
The **'timeUpdate'** event is triggered when the audio playback starts after an audio playback timestamp update.| +| callback | Callback\ | Yes | Callback invoked when the event is triggered. The input parameter is the updated timestamp. | + +**Example** + +```js +audioPlayer.on('timeUpdate', (newTime) => { // Set the 'timeUpdate' event callback. + if (newTime == null) { + console.info('audio timeUpadate fail'); + return; + } + console.log('audio timeUpadate success. seekDoneTime: ' + newTime); +}); +audioPlayer.play(); // The 'timeUpdate' event is triggered when the playback starts. +``` + +### on('error') + +on(type: 'error', callback: ErrorCallback): void + +Subscribes to audio playback error events. After an error event is reported, you must handle the event and exit the playback. + +**System capability**: SystemCapability.Multimedia.Media.AudioPlayer + +**Parameters** + +| Name | Type | Mandatory| Description | +| -------- | ------------- | ---- | ------------------------------------------------------------ | +| type | string | Yes | Event type, which is **'error'** in this case.
This event is triggered when an error occurs during audio playback.| +| callback | ErrorCallback | Yes | Callback invoked when the event is triggered. | + +**Example** + +```js +audioPlayer.on('error', (error) => { // Set the 'error' event callback. + console.info(`audio error called, error: ${error}`); +}); +audioPlayer.setVolume(3); // Set volume to an invalid value to trigger the 'error' event. +``` + +## AudioState(deprecated) + +Enumerates the audio playback states. You can obtain the state through the **state** attribute. + +> **NOTE** +> +> This API is supported since API version 6 and deprecated since API version 9. You are advised to use [AVPlayerState](#avplayerstate9) instead. + +**System capability**: SystemCapability.Multimedia.Media.AudioPlayer + +| Name | Type | Description | +| ------- | ------ | ---------------------------------------------- | +| idle | string | No audio playback is in progress. The audio player is in this state after the **'dataload'** or **'reset'** event is triggered.| +| playing | string | Audio playback is in progress. The audio player is in this state after the **'play'** event is triggered. | +| paused | string | Audio playback is paused. The audio player is in this state after the **'pause'** event is triggered. | +| stopped | string | Audio playback is stopped. The audio player is in this state after the **'stop'** event is triggered. | +| error | string | Audio playback is in the error state. | + +## VideoPlayer(deprecated) + +> **NOTE** +> +> This API is supported since API version 8 and deprecated since API version 9. You are advised to use [AVPlayer](#avplayer9) instead. + +Provides APIs to manage and play video. Before calling any API of **VideoPlayer**, you must use [createVideoPlayer()](#createvideoplayer) to create a **VideoPlayer** instance. + +For details about the video playback demo, see [Video Playback Development](../../media/video-playback.md). + +### Attributes + +**System capability**: SystemCapability.Multimedia.Media.VideoPlayer + +| Name | Type | Readable| Writable| Description | +| ------------------------------- | ------------------------------------------------------ | ---- | ---- | ------------------------------------------------------------ | +| url8+ | string | Yes | Yes | Video URL. The mainstream video formats (MP4, MPEG-TS, WebM, and MKV) are supported.
**Example of supported URLs**:
1. FD: fd://xx
![](figures/en-us_image_url.png)
2. HTTP: http://xx
3. HTTPS: https://xx
4. HLS: http://xx or https://xx
| +| fdSrc9+ | [AVFileDescriptor](#avfiledescriptor9) | Yes | Yes | Description of a video file. This attribute is required when video assets of an application are continuously stored in a file.
**Example:**
Assume that a music file that stores continuous music assets consists of the following:
Video 1 (address offset: 0, byte length: 100)
Video 2 (address offset: 101; byte length: 50)
Video 3 (address offset: 151, byte length: 150)
1. To play video 1: AVFileDescriptor {fd = resource handle; offset = 0; length = 100; }
2. To play video 2: AVFileDescriptor {fd = resource handle; offset = 101; length = 50; }
3. To play video 3: AVFileDescriptor {fd = resource handle; offset = 151; length = 150; }
To play an independent video file, use **src=fd://xx**.
| +| loop8+ | boolean | Yes | Yes | Whether to loop video playback. The value **true** means to loop video playback, and **false** means the opposite. | +| videoScaleType9+ | [VideoScaleType](#videoscaletype9) | Yes | Yes | Video scale type. | +| audioInterruptMode9+ | [audio.InterruptMode](js-apis-audio.md#interruptmode9) | Yes | Yes | Audio interruption mode. | +| currentTime8+ | number | Yes | No | Current video playback position, in ms. | +| duration8+ | number | Yes | No | Video duration, in ms. The value **-1** indicates the live mode. | +| state8+ | [VideoPlayState](#videoplayerstate) | Yes | No | Video playback state. | +| width8+ | number | Yes | No | Video width, in pixels. | +| height8+ | number | Yes | No | Video height, in pixels. | + +### setDisplaySurface8+ + +setDisplaySurface(surfaceId: string, callback: AsyncCallback\): void + +Sets **SurfaceId**. This API uses an asynchronous callback to return the result. + +**SetDisplaySurface** must be called between the URL setting and the calling of **prepare**. A surface must be set for video streams without audio. Otherwise, the calling of **prepare** fails. + +**System capability**: SystemCapability.Multimedia.Media.VideoPlayer + +**Parameters** + +| Name | Type | Mandatory| Description | +| --------- | -------------------- | ---- | ------------------------- | +| surfaceId | string | Yes | Surface ID to set. | +| callback | AsyncCallback\ | Yes | Callback used to return the result.| + +**Example** + +```js +let surfaceId = null; +videoPlayer.setDisplaySurface(surfaceId, (err) => { + if (err == null) { + console.info('setDisplaySurface success!'); + } else { + console.info('setDisplaySurface fail!'); + } +}); +``` + +### setDisplaySurface8+ + +setDisplaySurface(surfaceId: string): Promise\ + +Sets **SurfaceId**. This API uses a promise to return the result. + +**SetDisplaySurface** must be called between the URL setting and the calling of **prepare**. A surface must be set for video streams without audio. Otherwise, the calling of **prepare** fails. + +**System capability**: SystemCapability.Multimedia.Media.VideoPlayer + +**Parameters** + +| Name | Type | Mandatory| Description | +| --------- | ------ | ---- | --------- | +| surfaceId | string | Yes | Surface ID to set.| + +**Return value** + +| Type | Description | +| -------------- | ------------------------------ | +| Promise\ | Promise used to return the result.| + +**Example** + +```js +let surfaceId = null; +videoPlayer.setDisplaySurface(surfaceId).then(() => { + console.info('setDisplaySurface success'); +}).catch((error) => { + console.info(`video catchCallback, error:${error}`); +}); +``` + +### prepare8+ + +prepare(callback: AsyncCallback\): void + +Prepares for video playback. This API uses an asynchronous callback to return the result. + +**System capability**: SystemCapability.Multimedia.Media.VideoPlayer + +**Parameters** + +| Name | Type | Mandatory| Description | +| -------- | -------------------- | ---- | ------------------------ | +| callback | AsyncCallback\ | Yes | Callback used to return the result.| + +**Example** + +```js +videoPlayer.prepare((err) => { + if (err == null) { + console.info('prepare success!'); + } else { + console.info('prepare fail!'); + } +}); +``` + +### prepare8+ + +prepare(): Promise\ + +Prepares for video playback. This API uses a promise to return the result. + +**System capability**: SystemCapability.Multimedia.Media.VideoPlayer + +**Return value** + +| Type | Description | +| -------------- | ----------------------------- | +| Promise\ | Promise used to return the result.| + +**Example** + +```js +videoPlayer.prepare().then(() => { + console.info('prepare success'); +}).catch((error) => { + console.info(`video catchCallback, error:${error}`); +}); +``` + +### play8+ + +play(callback: AsyncCallback\): void; + +Starts to play video assets. This API uses an asynchronous callback to return the result. + +**System capability**: SystemCapability.Multimedia.Media.VideoPlayer + +**Parameters** + +| Name | Type | Mandatory| Description | +| -------- | -------------------- | ---- | ------------------------ | +| callback | AsyncCallback\ | Yes | Callback used to return the result.| + +**Example** + +```js +videoPlayer.play((err) => { + if (err == null) { + console.info('play success!'); + } else { + console.info('play fail!'); + } +}); +``` + +### play8+ + +play(): Promise\; + +Starts to play video assets. This API uses a promise to return the result. + +**System capability**: SystemCapability.Multimedia.Media.VideoPlayer + +**Return value** + +| Type | Description | +| -------------- | ----------------------------- | +| Promise\ | Promise used to return the result.| + +**Example** + +```js +videoPlayer.play().then(() => { + console.info('play success'); +}).catch((error) => { + console.info(`video catchCallback, error:${error}`); +}); +``` + +### pause8+ + +pause(callback: AsyncCallback\): void + +Pauses video playback. This API uses an asynchronous callback to return the result. + +**System capability**: SystemCapability.Multimedia.Media.VideoPlayer + +**Parameters** + +| Name | Type | Mandatory| Description | +| -------- | -------------------- | ---- | ------------------------ | +| callback | AsyncCallback\ | Yes | Callback used to return the result.| + +**Example** + +```js +videoPlayer.pause((err) => { + if (err == null) { + console.info('pause success!'); + } else { + console.info('pause fail!'); + } +}); +``` + +### pause8+ + +pause(): Promise\ + +Pauses video playback. This API uses a promise to return the result. + +**System capability**: SystemCapability.Multimedia.Media.VideoPlayer + +**Return value** + +| Type | Description | +| -------------- | ----------------------------- | +| Promise\ | Promise used to return the result.| + +**Example** + +```js +videoPlayer.pause().then(() => { + console.info('pause success'); +}).catch((error) => { + console.info(`video catchCallback, error:${error}`); +}); +``` + +### stop8+ + +stop(callback: AsyncCallback\): void + +Stops video playback. This API uses an asynchronous callback to return the result. + +**System capability**: SystemCapability.Multimedia.Media.VideoPlayer + +**Parameters** + +| Name | Type | Mandatory| Description | +| -------- | -------------------- | ---- | ------------------------ | +| callback | AsyncCallback\ | Yes | Callback used to return the result.| + +**Example** + +```js +videoPlayer.stop((err) => { + if (err == null) { + console.info('stop success!'); + } else { + console.info('stop fail!'); + } +}); +``` + +### stop8+ + +stop(): Promise\ + +Stops video playback. This API uses a promise to return the result. + +**System capability**: SystemCapability.Multimedia.Media.VideoPlayer + +**Return value** + +| Type | Description | +| -------------- | ----------------------------- | +| Promise\ | Promise used to return the result.| + +**Example** + +```js +videoPlayer.stop().then(() => { + console.info('stop success'); +}).catch((error) => { + console.info(`video catchCallback, error:${error}`); +}); +``` + +### reset8+ + +reset(callback: AsyncCallback\): void + +Resets the video asset to be played. This API uses an asynchronous callback to return the result. + +**System capability**: SystemCapability.Multimedia.Media.VideoPlayer + +**Parameters** + +| Name | Type | Mandatory| Description | +| -------- | -------------------- | ---- | ------------------------ | +| callback | AsyncCallback\ | Yes | Callback used to return the result.| + +**Example** + +```js +videoPlayer.reset((err) => { + if (err == null) { + console.info('reset success!'); + } else { + console.info('reset fail!'); + } +}); +``` + +### reset8+ + +reset(): Promise\ + +Resets the video asset to be played. This API uses a promise to return the result. + +**System capability**: SystemCapability.Multimedia.Media.VideoPlayer + +**Return value** + +| Type | Description | +| -------------- | ----------------------------- | +| Promise\ | Promise used to return the result.| + +**Example** + +```js +videoPlayer.reset().then(() => { + console.info('reset success'); +}).catch((error) => { + console.info(`video catchCallback, error:${error}`); +}); +``` + +### seek8+ + +seek(timeMs: number, callback: AsyncCallback\): void + +Seeks to the specified playback position. The previous key frame at the specified position is played. This API uses an asynchronous callback to return the result. + +**System capability**: SystemCapability.Multimedia.Media.VideoPlayer + +**Parameters** + +| Name | Type | Mandatory| Description | +| -------- | ---------------------- | ---- | ------------------------------------------------------------ | +| timeMs | number | Yes | Position to seek to, in ms. The value range is [0, duration].| +| callback | AsyncCallback\ | Yes | Callback used to return the result. | + +**Example** + +```js +let seekTime = 5000; +videoPlayer.seek(seekTime, (err, result) => { + if (err == null) { + console.info('seek success!'); + } else { + console.info('seek fail!'); + } +}); +``` + +### seek8+ + +seek(timeMs: number, mode:SeekMode, callback: AsyncCallback\): void + +Seeks to the specified playback position. This API uses an asynchronous callback to return the result. + +**System capability**: SystemCapability.Multimedia.Media.VideoPlayer + +**Parameters** + +| Name | Type | Mandatory| Description | +| -------- | ---------------------- | ---- | ------------------------------------------------------------ | +| timeMs | number | Yes | Position to seek to, in ms. The value range is [0, duration].| +| mode | [SeekMode](#seekmode8) | Yes | Seek mode. | +| callback | AsyncCallback\ | Yes | Callback used to return the result. | + +**Example** + +```js +import media from '@ohos.multimedia.media' +let seekTime = 5000; +videoPlayer.seek(seekTime, media.SeekMode.SEEK_NEXT_SYNC, (err, result) => { + if (err == null) { + console.info('seek success!'); + } else { + console.info('seek fail!'); + } +}); +``` + +### seek8+ + +seek(timeMs: number, mode?:SeekMode): Promise\ + +Seeks to the specified playback position. If **mode** is not specified, the previous key frame at the specified position is played. This API uses a promise to return the result. + +**System capability**: SystemCapability.Multimedia.Media.VideoPlayer + +**Parameters** + +| Name| Type | Mandatory| Description | +| ------ | ---------------------- | ---- | ------------------------------------------------------------ | +| timeMs | number | Yes | Position to seek to, in ms. The value range is [0, duration].| +| mode | [SeekMode](#seekmode8) | No | Seek mode. | + +**Return value** + +| Type | Description | +| ---------------- | ------------------------------------------- | +| Promise\| Promise used to return the playback position, in ms.| + +**Example** + +```js +import media from '@ohos.multimedia.media' +let seekTime = 5000; +videoPlayer.seek(seekTime).then((seekDoneTime) => { // seekDoneTime indicates the position after the seek operation is complete. + console.info('seek success'); +}).catch((error) => { + console.info(`video catchCallback, error:${error}`); +}); + +videoPlayer.seek(seekTime, media.SeekMode.SEEK_NEXT_SYNC).then((seekDoneTime) => { + console.info('seek success'); +}).catch((error) => { + console.info(`video catchCallback, error:${error}`); +}); +``` + +### setVolume8+ + +setVolume(vol: number, callback: AsyncCallback\): void + +Sets the volume. This API uses an asynchronous callback to return the result. + +**System capability**: SystemCapability.Multimedia.Media.VideoPlayer + +**Parameters** + +| Name | Type | Mandatory| Description | +| -------- | -------------------- | ---- | ------------------------------------------------------------ | +| vol | number | Yes | Relative volume. The value ranges from 0.00 to 1.00. The value **1.00** indicates the maximum volume (100%).| +| callback | AsyncCallback\ | Yes | Callback used to return the result. | + +**Example** + +```js +let vol = 0.5; +videoPlayer.setVolume(vol, (err, result) => { + if (err == null) { + console.info('setVolume success!'); + } else { + console.info('setVolume fail!'); + } +}); +``` + +### setVolume8+ + +setVolume(vol: number): Promise\ + +Sets the volume. This API uses a promise to return the result. + +**System capability**: SystemCapability.Multimedia.Media.VideoPlayer + +**Parameters** + +| Name| Type | Mandatory| Description | +| ------ | ------ | ---- | ------------------------------------------------------------ | +| vol | number | Yes | Relative volume. The value ranges from 0.00 to 1.00. The value **1.00** indicates the maximum volume (100%).| + +**Return value** + +| Type | Description | +| -------------- | ------------------------- | +| Promise\ | Promise used to return the result.| + +**Example** + +```js +let vol = 0.5; +videoPlayer.setVolume(vol).then(() => { + console.info('setVolume success'); +}).catch((error) => { + console.info(`video catchCallback, error:${error}`); +}); +``` + +### release8+ + +release(callback: AsyncCallback\): void + +Releases the video playback resources. This API uses an asynchronous callback to return the result. + +**System capability**: SystemCapability.Multimedia.Media.VideoPlayer + +**Parameters** + +| Name | Type | Mandatory| Description | +| -------- | -------------------- | ---- | ------------------------ | +| callback | AsyncCallback\ | Yes | Callback used to return the result.| + +**Example** + +```js +videoPlayer.release((err) => { + if (err == null) { + console.info('release success!'); + } else { + console.info('release fail!'); + } +}); +``` + +### release8+ + +release(): Promise\ + +Releases the video playback resources. This API uses a promise to return the result. + +**System capability**: SystemCapability.Multimedia.Media.VideoPlayer + +**Return value** + +| Type | Description | +| -------------- | ----------------------------- | +| Promise\ | Promise used to return the result.| + +**Example** + +```js +videoPlayer.release().then(() => { + console.info('release success'); +}).catch((error) => { + console.info(`video catchCallback, error:${error}`); +}); +``` + +### getTrackDescription8+ + +getTrackDescription(callback: AsyncCallback\>): void + +Obtains the video track information. This API uses an asynchronous callback to return the result. + +**System capability**: SystemCapability.Multimedia.Media.VideoPlayer + +**Parameters** + +| Name | Type | Mandatory| Description | +| -------- | ------------------------------------------------------------ | ---- | ------------------------------------------ | +| callback | AsyncCallback\> | Yes | Callback used to return a **MediaDescription** array, which records the video track information.| + +**Example** + +```js +function printfDescription(obj) { + for (let item in obj) { + let property = obj[item]; + console.info('video key is ' + item); + console.info('video value is ' + property); + } +} + +videoPlayer.getTrackDescription((error, arrList) => { + if ((arrList) != null) { + for (let i = 0; i < arrList.length; i++) { + printfDescription(arrList[i]); + } + } else { + console.log(`video getTrackDescription fail, error:${error}`); + } +}); +``` + +### getTrackDescription8+ + +getTrackDescription(): Promise\> + +Obtains the video track information. This API uses a promise to return the result. + +**System capability**: SystemCapability.Multimedia.Media.VideoPlayer + +**Return value** + +| Type | Description | +| ------------------------------------------------------ | ----------------------------------------------- | +| Promise> | Promise used to return a **MediaDescription** array, which records the video track information.| + +**Example** + +```js +function printfDescription(obj) { + for (let item in obj) { + let property = obj[item]; + console.info('video key is ' + item); + console.info('video value is ' + property); + } +} + +let arrayDescription; +videoPlayer.getTrackDescription().then((arrList) => { + if (arrList != null) { + arrayDescription = arrList; + } else { + console.log('video getTrackDescription fail'); + } +}).catch((error) => { + console.info(`video catchCallback, error:${error}`); +}); +for (let i = 0; i < arrayDescription.length; i++) { + printfDescription(arrayDescription[i]); +} +``` + +### setSpeed8+ + +setSpeed(speed:number, callback: AsyncCallback\): void + +Sets the video playback speed. This API uses an asynchronous callback to return the result. + +**System capability**: SystemCapability.Multimedia.Media.VideoPlayer + +**Parameters** + +| Name | Type | Mandatory| Description | +| -------- | ---------------------- | ---- | ---------------------------------------------------------- | +| speed | number | Yes | Video playback speed. For details, see [PlaybackSpeed](#playbackspeed8).| +| callback | AsyncCallback\ | Yes | Callback used to return the result. | + +**Example** + +```js +import media from '@ohos.multimedia.media' +let speed = media.PlaybackSpeed.SPEED_FORWARD_2_00_X; + +videoPlayer.setSpeed(speed, (err, result) => { + if (err == null) { + console.info('setSpeed success!'); + } else { + console.info('setSpeed fail!'); + } +}); +``` + +### setSpeed8+ + +setSpeed(speed:number): Promise\ + +Sets the video playback speed. This API uses a promise to return the result. + +**System capability**: SystemCapability.Multimedia.Media.VideoPlayer + +**Parameters** + +| Name| Type | Mandatory| Description | +| ------ | ------ | ---- | ---------------------------------------------------------- | +| speed | number | Yes | Video playback speed. For details, see [PlaybackSpeed](#playbackspeed8).| + +**Return value** + +| Type | Description | +| ---------------- | ------------------------------------------------------------ | +| Promise\| Promise used to return playback speed. For details, see [PlaybackSpeed](#playbackspeed8).| + +**Example** + +```js +import media from '@ohos.multimedia.media' +let speed = media.PlaybackSpeed.SPEED_FORWARD_2_00_X; + +videoPlayer.setSpeed(speed).then(() => { + console.info('setSpeed success'); +}).catch((error) => { + console.info(`video catchCallback, error:${error}`); +}); +``` + +### on('playbackCompleted')8+ + +on(type: 'playbackCompleted', callback: Callback\): void + +Subscribes to the video playback completion event. + +**System capability**: SystemCapability.Multimedia.Media.VideoPlayer + +**Parameters** + +| Name | Type | Mandatory| Description | +| -------- | -------- | ---- | ----------------------------------------------------------- | +| type | string | Yes | Event type, which is **'playbackCompleted'** in this case.| +| callback | function | Yes | Callback invoked when the event is triggered. | + +**Example** + +```js +videoPlayer.on('playbackCompleted', () => { + console.info('playbackCompleted success!'); +}); +``` + +### on('bufferingUpdate')8+ + +on(type: 'bufferingUpdate', callback: (infoType: BufferingInfoType, value: number) => void): void + +Subscribes to the video buffering update event. Only network playback supports this subscription. + +**System capability**: SystemCapability.Multimedia.Media.VideoPlayer + +**Parameters** + +| Name | Type | Mandatory| Description | +| -------- | -------- | ---- | ------------------------------------------------------------ | +| type | string | Yes | Event type, which is **'bufferingUpdate'** in this case. | +| callback | function | Yes | Callback invoked when the event is triggered.
When [BufferingInfoType](#bufferinginfotype8) is set to **BUFFERING_PERCENT** or **CACHED_DURATION**, **value** is valid. Otherwise, **value** is fixed at **0**.| + +**Example** + +```js +videoPlayer.on('bufferingUpdate', (infoType, value) => { + console.log('video bufferingInfo type: ' + infoType); + console.log('video bufferingInfo value: ' + value); +}); +``` + +### on('startRenderFrame')8+ + +on(type: 'startRenderFrame', callback: Callback\): void + +Subscribes to the frame rendering start event. + +**System capability**: SystemCapability.Multimedia.Media.VideoPlayer + +**Parameters** + +| Name | Type | Mandatory| Description | +| -------- | --------------- | ---- | ------------------------------------------------------------ | +| type | string | Yes | Event type, which is **'startRenderFrame'** in this case.| +| callback | Callback\ | Yes | Callback invoked when the event is triggered. | + +**Example** + +```js +videoPlayer.on('startRenderFrame', () => { + console.info('startRenderFrame success!'); +}); +``` + +### on('videoSizeChanged')8+ + +on(type: 'videoSizeChanged', callback: (width: number, height: number) => void): void + +Subscribes to the video width and height change event. + +**System capability**: SystemCapability.Multimedia.Media.VideoPlayer + +**Parameters** + +| Name | Type | Mandatory| Description | +| -------- | -------- | ---- | ------------------------------------------------------------ | +| type | string | Yes | Event type, which is **'videoSizeChanged'** in this case.| +| callback | function | Yes | Callback invoked when the event is triggered. **width** indicates the video width, and **height** indicates the video height. | + +**Example** + +```js +videoPlayer.on('videoSizeChanged', (width, height) => { + console.log('video width is: ' + width); + console.log('video height is: ' + height); +}); +``` + +### on('error')8+ + +on(type: 'error', callback: ErrorCallback): void + +Subscribes to video playback error events. After an error event is reported, you must handle the event and exit the playback. + +**System capability**: SystemCapability.Multimedia.Media.VideoPlayer + +**Parameters** + +| Name | Type | Mandatory| Description | +| -------- | ------------- | ---- | ------------------------------------------------------------ | +| type | string | Yes | Event type, which is **'error'** in this case.
This event is triggered when an error occurs during video playback.| +| callback | ErrorCallback | Yes | Callback invoked when the event is triggered. | + +**Example** + +```js +videoPlayer.on('error', (error) => { // Set the 'error' event callback. + console.info(`video error called, error: ${error}`); +}); +videoPlayer.url = 'fd://error'; // Set an incorrect URL to trigger the 'error' event. +``` + +## VideoPlayState(deprecated) + +Enumerates the video playback states. You can obtain the state through the **state** attribute. + +> **NOTE** +> +> This API is supported since API version 8 and deprecated since API version 9. You are advised to use [AVPlayerState](#avplayerstate9) instead. + +**System capability**: SystemCapability.Multimedia.Media.VideoPlayer + +| Name | Type | Description | +| -------- | ------ | -------------- | +| idle | string | The video player is idle.| +| prepared | string | Video playback is being prepared.| +| playing | string | Video playback is in progress.| +| paused | string | Video playback is paused.| +| stopped | string | Video playback is stopped.| +| error | string | Video playback is in the error state. | + +## AudioRecorder(deprecated) + +> **NOTE** +> +> This API is supported since API version 6 and deprecated since API version 9. You are advised to use [AVRecorder](#avrecorder9) instead. + +Implements audio recording. Before calling any API of **AudioRecorder**, you must use [createAudioRecorder()](#mediacreateaudiorecorder) to create an **AudioRecorder** instance. + +For details about the audio recording demo, see [Audio Recording Development](../../media/audio-recorder.md). + +### prepare + +prepare(config: AudioRecorderConfig): void + +Prepares for recording. + +**Required permissions:** ohos.permission.MICROPHONE + +**System capability**: SystemCapability.Multimedia.Media.AudioRecorder + +**Parameters** + +| Name| Type | Mandatory| Description | +| ------ | ------------------------------------------- | ---- | ------------------------------------------------------------ | +| config | [AudioRecorderConfig](#audiorecorderconfigdeprecated) | Yes | Audio recording parameters, including the audio output URI, encoding format, sampling rate, number of audio channels, and output format.| + +**Example** + +```js +let audioRecorderConfig = { + audioEncoder : media.AudioEncoder.AAC_LC, + audioEncodeBitRate : 22050, + audioSampleRate : 22050, + numberOfChannels : 2, + format : media.AudioOutputFormat.AAC_ADTS, + uri : 'fd://1', // The file must be created by the caller and granted with proper permissions. + location : { latitude : 30, longitude : 130}, +} +audioRecorder.on('prepare', () => { // Set the 'prepare' event callback. + console.log('prepare success'); +}); +audioRecorder.prepare(audioRecorderConfig); +``` + + +### start + +start(): void + +Starts audio recording. This API can be called only after the [prepare](#audiorecorder_on) event is triggered. + +**System capability**: SystemCapability.Multimedia.Media.AudioRecorder + +**Example** + +```js +audioRecorder.on('start', () => { // Set the 'start' event callback. + console.log('audio recorder start success'); +}); +audioRecorder.start(); +``` + +### pause + +pause():void + +Pauses audio recording. This API can be called only after the [start](#audiorecorder_on) event is triggered. + +**System capability**: SystemCapability.Multimedia.Media.AudioRecorder + +**Example** + +```js +audioRecorder.on('pause', () => { // Set the 'pause' event callback. + console.log('audio recorder pause success'); +}); +audioRecorder.pause(); +``` + +### resume + +resume():void + +Resumes audio recording. This API can be called only after the [pause](#audiorecorder_on) event is triggered. + +**System capability**: SystemCapability.Multimedia.Media.AudioRecorder + +**Example** + +```js +audioRecorder.on('resume', () => { // Set the 'resume' event callback. + console.log('audio recorder resume success'); +}); +audioRecorder.resume(); +``` + +### stop + +stop(): void + +Stops audio recording. + +**System capability**: SystemCapability.Multimedia.Media.AudioRecorder + +**Example** + +```js +audioRecorder.on('stop', () => { // Set the 'stop' event callback. + console.log('audio recorder stop success'); +}); +audioRecorder.stop(); +``` + +### release + +release(): void + +Releases the audio recording resources. + +**System capability**: SystemCapability.Multimedia.Media.AudioRecorder + +**Example** + +```js +audioRecorder.on('release', () => { // Set the 'release' event callback. + console.log('audio recorder release success'); +}); +audioRecorder.release(); +audioRecorder = undefined; +``` + +### reset + +reset(): void + +Resets audio recording. + +Before resetting audio recording, you must call [stop()](#audiorecorder_stop) to stop recording. After audio recording is reset, you must call [prepare()](#audiorecorder_prepare) to set the recording parameters for another recording. + +**System capability**: SystemCapability.Multimedia.Media.AudioRecorder + +**Example** + +```js +audioRecorder.on('reset', () => { // Set the 'reset' event callback. + console.log('audio recorder reset success'); +}); +audioRecorder.reset(); +``` + +### on('prepare' | 'start' | 'pause' | 'resume' | 'stop' | 'release' | 'reset') + +on(type: 'prepare' | 'start' | 'pause' | 'resume' | 'stop' | 'release' | 'reset', callback: () => void): void + +Subscribes to the audio recording events. + +**System capability**: SystemCapability.Multimedia.Media.AudioRecorder + +**Parameters** + +| Name | Type | Mandatory| Description | +| -------- | -------- | ---- | ------------------------------------------------------------ | +| type | string | Yes | Event type. The following events are supported:
- 'prepare': triggered when the [prepare](#audiorecorder_prepare) API is called and the audio recording parameters are set.
- 'start': triggered when the [start](#audiorecorder_start) API is called and audio recording starts.
- 'pause': triggered when the [pause](#audiorecorder_pause) API is called and audio recording is paused.
- 'resume': triggered when the [resume](#audiorecorder_resume) API is called and audio recording is resumed.
- 'stop': triggered when the [stop](#audiorecorder_stop) API is called and audio recording stops.
- 'release': triggered when the [release](#audiorecorder_release) API is called and the recording resources are released.
- 'reset': triggered when the [reset](#audiorecorder_reset) API is called and audio recording is reset. | +| callback | ()=>void | Yes | Callback invoked when the event is triggered. | + +**Example** + +```js +let audioRecorder = media.createAudioRecorder(); // Create an AudioRecorder instance. +let audioRecorderConfig = { + audioEncoder : media.AudioEncoder.AAC_LC, + audioEncodeBitRate : 22050, + audioSampleRate : 22050, + numberOfChannels : 2, + format : media.AudioOutputFormat.AAC_ADTS, + uri : 'fd://xx', // The file must be created by the caller and granted with proper permissions. + location : { latitude : 30, longitude : 130}, +} +audioRecorder.on('error', (error) => { // Set the 'error' event callback. + console.info(`audio error called, error: ${error}`); +}); +audioRecorder.on('prepare', () => { // Set the 'prepare' event callback. + console.log('prepare success'); + audioRecorder.start(); // Start recording and trigger the 'start' event callback. +}); +audioRecorder.on('start', () => { // Set the 'start' event callback. + console.log('audio recorder start success'); +}); +audioRecorder.on('pause', () => { // Set the 'pause' event callback. + console.log('audio recorder pause success'); +}); +audioRecorder.on('resume', () => { // Set the 'resume' event callback. + console.log('audio recorder resume success'); +}); +audioRecorder.on('stop', () => { // Set the 'stop' event callback. + console.log('audio recorder stop success'); +}); +audioRecorder.on('release', () => { // Set the 'release' event callback. + console.log('audio recorder release success'); +}); +audioRecorder.on('reset', () => { // Set the 'reset' event callback. + console.log('audio recorder reset success'); +}); +audioRecorder.prepare(audioRecorderConfig) // Set recording parameters and trigger the 'prepare' event callback. +``` + +### on('error') + +on(type: 'error', callback: ErrorCallback): void + +Subscribes to audio recording error events. After an error event is reported, you must handle the event and exit the recording. + +**System capability**: SystemCapability.Multimedia.Media.AudioRecorder + +**Parameters** + +| Name | Type | Mandatory| Description | +| -------- | ------------- | ---- | ------------------------------------------------------------ | +| type | string | Yes | Event type, which is **'error'** in this case.
This event is triggered when an error occurs during audio recording.| +| callback | ErrorCallback | Yes | Callback invoked when the event is triggered. | + +**Example** + +```js +let audioRecorderConfig = { + audioEncoder : media.AudioEncoder.AAC_LC, + audioEncodeBitRate : 22050, + audioSampleRate : 22050, + numberOfChannels : 2, + format : media.AudioOutputFormat.AAC_ADTS, + uri : 'fd://xx', // The file must be created by the caller and granted with proper permissions. + location : { latitude : 30, longitude : 130}, +} +audioRecorder.on('error', (error) => { // Set the 'error' event callback. + console.info(`audio error called, error: ${error}`); +}); +audioRecorder.prepare(audioRecorderConfig); // Do no set any parameter in prepare and trigger the 'error' event callback. +``` + +## AudioRecorderConfig(deprecated) + +> **NOTE** +> +> This API is supported since API version 6 and deprecated since API version 9. You are advised to use [AVRecorderConfig](#avrecorderconfig9) instead. + +Describes audio recording configurations. + +**System capability**: SystemCapability.Multimedia.Media.AudioRecorder + +| Name | Type | Mandatory| Description | +| ----------------------------------- | -------------------------------------------- | ---- | ------------------------------------------------------------ | +| audioEncoder | [AudioEncoder](#audioencoderdeprecated) | No | Audio encoding format. The default value is **AAC_LC**.
**Note**: This parameter is deprecated since API version 8. Use **audioEncoderMime** instead.| +| audioEncodeBitRate | number | No | Audio encoding bit rate. The default value is **48000**. | +| audioSampleRate | number | No | Audio sampling rate. The default value is **48000**. | +| numberOfChannels | number | No | Number of audio channels. The default value is **2**. | +| format | [AudioOutputFormat](#audiooutputformatdeprecated) | No | Audio output format. The default value is **MPEG_4**.
**Note**: This parameter is deprecated since API version 8. Use **fileFormat** instead.| +| location | [Location](#location) | No | Geographical location of the recorded audio. | +| uri | string | Yes | Audio output URI. Supported: fd://xx (fd number)
![](figures/en-us_image_url.png)
The file must be created by the caller and granted with proper permissions.| +| audioEncoderMime8+ | [CodecMimeType](#codecmimetype8) | No | Audio encoding format. | +| fileFormat8+ | [ContainerFormatType](#containerformattype8) | No | Audio encoding format. | + +## AudioEncoder(deprecated) + +> **NOTE** +> +> This API is supported since API version 6 and deprecated since API version 8. You are advised to use [CodecMimeType](#codecmimetype8) instead. + +Enumerates the audio encoding formats. + +**System capability**: SystemCapability.Multimedia.Media.AudioRecorder + +| Name | Value | Description | +| ------- | ---- | ------------------------------------------------------------ | +| DEFAULT | 0 | Default encoding format.
This API is defined but not implemented yet. | +| AMR_NB | 1 | AMR-NB.
This API is defined but not implemented yet.| +| AMR_WB | 2 | Adaptive Multi Rate-Wide Band Speech Codec (AMR-WB).
This API is defined but not implemented yet.| +| AAC_LC | 3 | Advanced Audio Coding Low Complexity (AAC-LC).| +| HE_AAC | 4 | High-Efficiency Advanced Audio Coding (HE_AAC).
This API is defined but not implemented yet.| + +## AudioOutputFormat(deprecated) + +> **NOTE** +> +> This API is supported since API version 6 and deprecated since API version 8. You are advised to use [ContainerFormatType](#containerformattype8) instead. + +Enumerates the audio output formats. + +**System capability**: SystemCapability.Multimedia.Media.AudioRecorder + +| Name | Value | Description | +| -------- | ---- | ------------------------------------------------------------ | +| DEFAULT | 0 | Default encapsulation format.
This API is defined but not implemented yet. | +| MPEG_4 | 2 | MPEG-4. | +| AMR_NB | 3 | AMR_NB.
This API is defined but not implemented yet. | +| AMR_WB | 4 | AMR_WB.
This API is defined but not implemented yet. | +| AAC_ADTS | 6 | Audio Data Transport Stream (ADTS), which is a transport stream format of AAC-based audio.| -- GitLab