# Taking Over the Media Playback on Web Pages The **Web** component provides the capability for applications to take over web media player, so that applications can better enhance web media playback capabilities (for example, image quality). ## When to Use There are unsatisfactory scenarios when media is played on a web page, such as unclear video quality, overly simplistic and feature-lacking web player interface, or even videos that cannot be played. In this case, if you want to improve the web media playback experience by taking over web media playback with your own or third-party players, you can utilize this functionality. ## Implementation Principle ### Framework for the ArkWeb Kernel to Play Media When this functionality is disabled, the playback architecture of the ArkWeb kernel is as follows: ![arkweb media pipeline](figures/arkweb_media_pipeline.png) > **NOTE** > - In the preceding figure, step 1 indicates that the ArkWeb kernel creates a **WebMdiaPlayer** to play media resources on web pages. > - Step 2 indicates that the **WebMdiaPlayer** uses the system decoder to render media data. When this functionality is enabled, the playback architecture of the ArkWeb kernel is as follows: ![arkweb native media player](figures/arkweb_native_media_player.png) > **NOTE** > - In the preceding figure, step 1 indicates that the ArkWeb kernel creates a **WebMdiaPlayer** to play media resources on web pages. > - Step 2 indicates that the **WebMdiaPlayer** uses the **NativeMediaPlayer** provided by the application to render media data. ### Interactions Between the ArkWeb Kernel and Application ![interactions between arkweb and native media player](figures/interactions_between_arkweb_and_native_media_player.png) > **NOTE** > - For details about step 1 in the preceding figure, see [Enabling Web Media Playback Takeover](#enabling-web-media-playback-takeover). > - For details about step 2, see [Creating a Native Media Player](#creating-a-native-media-player). > - For details about step 3, see [Drawing Native Media Player Components](#drawing-native-media-player-components). > - For details about step 4, see [Executing Playback Control Commands Sent by ArkWeb Kernel to the Native Media Player](#executing-playback-control-commands-sent-by-arkweb-kernel-to-the-native-media-player). > - For details about step 5, see [Notifying the State Information of Native Media Player to the ArkWeb Kernel](#notifying-the-state-information-of-native-media-player-to-the-arkweb-kernel). ## How to Develop ### Enabling Web Media Playback Takeover To take over web media playback, you need to enable this functionality using [enableNativeMediaPlayer](../reference/apis-arkweb/ts-basic-components-web.md#enablenativemediaplayer12). ```ts // xxx.ets import { webview } from '@kit.ArkWeb'; @Entry @Component struct WebComponent { controller: webview.WebviewController = new webview.WebviewController(); build() { Column() { Web({ src: 'www.example.com', controller: this.controller }) .enableNativeMediaPlayer({ enable: true, shouldOverlay: false }) } } } ``` For details about the API and parameters, see [enableNativeMediaPlayer](../reference/apis-arkweb/ts-basic-components-web.md#enablenativemediaplayer12). ### Creating a Native Media Player Once this functionality is enabled, the ArkWeb kernel triggers the callback function registered by [onCreateNativeMediaPlayer](../reference/apis-arkweb/js-apis-webview.md#oncreatenativemediaplayer12) each time a media file needs to be played on a web page. You need to register a callback function for creating a native media player by invoking **onCreateNativeMediaPlayer**. The callback function determines whether to create a native media player to take over the web page media resources based on the media information. * If the application does not take over the web page media resource, **null** is returned in the callback function. * If the application takes over the web page media resource, a native media player instance is returned in the callback function. The native media player needs to implement the [NativeMediaPlayerBridge](../reference/apis-arkweb/js-apis-webview.md#nativemediaplayerbridge12) API so that the ArkWeb kernel can control the playback on the native media player. ```ts // xxx.ets import { webview } from '@kit.ArkWeb'; // Implement the webview.NativeMediaPlayerBridge API. // The ArkWeb kernel calls the APIs to control playback on NativeMediaPlayer. class NativeMediaPlayerImpl implements webview.NativeMediaPlayerBridge { // ...Implement the APIs in NativeMediaPlayerBridge... constructor(handler: webview.NativeMediaPlayerHandler, mediaInfo: webview.MediaInfo) {} updateRect(x: number, y: number, width: number, height: number) {} play() {} pause() {} seek(targetTime: number) {} release() {} setVolume(volume: number) {} setMuted(muted: boolean) {} setPlaybackRate(playbackRate: number) {} enterFullscreen() {} exitFullscreen() {} } @Entry @Component struct WebComponent { controller: webview.WebviewController = new webview.WebviewController(); build() { Column() { Web({ src: 'www.example.com', controller: this.controller }) .enableNativeMediaPlayer({ enable: true, shouldOverlay: false }) .onPageBegin((event) => { this.controller.onCreateNativeMediaPlayer((handler: webview.NativeMediaPlayerHandler, mediaInfo: webview.MediaInfo) => { // Determine whether to take over the media. if (!shouldHandle(mediaInfo)) { // The native media player does not take over the media. // Return null. The ArkWeb kernel will play the media with the web media player. return null; } // Take over the web media. // Return a native media player instance to the ArkWeb kernel. let nativePlayer: webview.NativeMediaPlayerBridge = new NativeMediaPlayerImpl(handler, mediaInfo); return nativePlayer; }); }) } } } // stub function shouldHandle(mediaInfo: webview.MediaInfo) { return true; } ``` For details about the APIs and parameters, see [onCreateNativeMediaPlayer](../reference/apis-arkweb/js-apis-webview.md#oncreatenativemediaplayer12). ### Drawing Native Media Player Components When the application takes over the media of the web page, you need to draw the native media player components and video images on the surface provided by the ArkWeb kernel. Then the ArkWeb kernel combines the surface with the web page and displays the web page on the screen. This process is the same as that of [Rendering and Drawing XComponent+AVPlayer and Button Components at the Same Layer](web-same-layer.md#) 1. Save the **UIContext** when the application is started, which will be used in the subsequent rendering and drawing at the same layer. ```ts // xxxAbility.ets import { UIAbility } from '@kit.AbilityKit'; import { window } from '@kit.ArkUI'; export default class EntryAbility extends UIAbility { onWindowStageCreate(windowStage: window.WindowStage): void { windowStage.loadContent('pages/Index', (err, data) => { if (err.code) { return; } // Save the UIContext, which will be used in subsequent rendering and drawing at the same layer. AppStorage.setOrCreate("UIContext", windowStage.getMainWindowSync().getUIContext()); }); } // ...Other APIs that need to be overridden... } ``` 2. Use the surface created by the ArkWeb kernel is for rendering and drawing at the same layer. ```ts // xxx.ets import { webview } from '@kit.ArkWeb'; import { BuilderNode, FrameNode, NodeController, NodeRenderType } from '@kit.ArkUI'; interface ComponentParams {} class MyNodeController extends NodeController { private rootNode: BuilderNode<[ComponentParams]> | undefined; constructor(surfaceId: string, renderType: NodeRenderType) { super(); // Obtain the saved UIContext. let uiContext = AppStorage.get("UIContext"); this.rootNode = new BuilderNode(uiContext as UIContext, { surfaceId: surfaceId, type: renderType }); } makeNode(uiContext: UIContext): FrameNode | null { if (this.rootNode) { return this.rootNode.getFrameNode() as FrameNode; } return null; } build() { // Construct the native media player component. } } @Entry @Component struct WebComponent { node_controller?: MyNodeController; controller: webview.WebviewController = new webview.WebviewController(); @State show_native_media_player: boolean = false; build() { Column() { Stack({ alignContent: Alignment.TopStart }) { if (this.show_native_media_player) { NodeContainer(this.node_controller) .width(300) .height(150) .backgroundColor(Color.Transparent) .border({ width: 2, color: Color.Orange }) } Web({ src: 'www.example.com', controller: this.controller }) .enableNativeMediaPlayer({ enable: true, shouldOverlay: false }) .onPageBegin((event) => { this.controller.onCreateNativeMediaPlayer((handler: webview.NativeMediaPlayerHandler, mediaInfo: webview.MediaInfo) => { // Take over the web media. // Use the surface provided by the rendering at the same layer to construct a native media player component. this.node_controller = new MyNodeController(mediaInfo..surfaceInfo.id, NodeRenderType. RENDER_TYPE_TEXTURE); this.node_controller.build(); // Show the native media player component. this.show_native_media_player = true; // Return a native media player instance to the ArkWeb kernel. return null; }); }) } } } } ``` For details about how to dynamically create components and draw them on the surface, see [Rendering and Drawing XComponent+AVPlayer and Button Components at the Same Layer](web-same-layer.md#). ### Executing Playback Control Commands Sent by ArkWeb Kernel to the Native Media Player To facilitate the control over native media player by the ArkWeb kernel, you need to implement the [NativeMediaPlayerBridge](../reference/apis-arkweb/js-apis-webview.md#nativemediaplayerbridge12) API on the native media player and perform operations on the native media player based on the functionality of each API. ```ts // xxx.ets import { webview } from '@kit.ArkWeb'; class ActualNativeMediaPlayerListener { constructor(handler: webview.NativeMediaPlayerHandler) {} } class NativeMediaPlayerImpl implements webview.NativeMediaPlayerBridge { constructor(handler: webview.NativeMediaPlayerHandler, mediaInfo: webview.MediaInfo) { // 1. Create a listener for the native media player. let listener: ActualNativeMediaPlayerListener = new ActualNativeMediaPlayerListener(handler); // 2. Create a native media player. // 3. Listen for the local player. // ... } updateRect(x: number, y: number, width: number, height: number) { // The position and size of the