# 媒体播放器 (/zh-CN/realtime-media/rtc/build/audio/media-player)

> For AI agents: see the complete documentation index at [llms.txt](/llms.txt).

<_PlatformTabsGroup>
<_PlatformProcessedMarker groupMode="structured" canonicalPlatform="android" platform="android" />
## 前提条件 [#前提条件]

本文介绍如何调用媒体播放器相关的 API 播放本地或在线媒体资源，或将媒体资源分享给声网频道内的远端用户。在进行操作之前，请确保你已经在项目中实现了基本的实时音视频功能。有关详细信息，请参考[实现音视频互动](/zh-CN/realtime-media/rtc/get-started/quick-start)。

## 实现方法 [#实现方法]

参考如下步骤，在你的项目中使用媒体播放器：

1. 初始化 `RtcEngine` 后，创建一个 `IMediaPlayer` 对象，并调用 `registerPlayerObserver` 方法注册播放观测器。

    ```java
    engine = RtcEngine.create(config);

    ...
    // 创建媒体播放器对象
    mediaPlayer = engine.createMediaPlayer();
    // 注册播放观测器
    mediaPlayer.registerPlayerObserver(this);
    ```

2. 实现媒体播放器观测器的回调。根据你的需求，你可以通过 `onPlayerStateChanged` 回调来观测播放器的状态，通过 `onPositionChanged` 回调来获取当前媒体文件的播放进度，通过 `onPlayerEvent` 来获取播放器事件。

    ```java
    @Override
    // 报告播放器的状态
    public void onPlayerStateChanged(io.agora.mediaplayer.Constants.MediaPlayerState mediaPlayerState, io.agora.mediaplayer.Constants.MediaPlayerError mediaPlayerError) {
        Log.e(TAG, "onPlayerStateChanged mediaPlayerState " + mediaPlayerState);
        Log.e(TAG, "onPlayerStateChanged mediaPlayerError " + mediaPlayerError);
        if (mediaPlayerState.equals(PLAYER_STATE_OPEN_COMPLETED)) {
            setMediaPlayerViewEnable(true);
        } else if (mediaPlayerState.equals(PLAYER_STATE_IDLE) || mediaPlayerState.equals(PLAYER_STATE_PLAYBACK_COMPLETED) ) {
            setMediaPlayerViewEnable(false);
        }
    }

    @Override
    // 报告当前播放进度
    public void onPositionChanged(long position) {
        Log.e(TAG, "onPositionChanged position " + position);
        if (playerDuration > 0) {
            final int result = (int) ((float) position / (float) playerDuration * 100);
            handler.post(new Runnable() {
                @Override
                public void run() {
                    progressBar.setProgress(Long.valueOf(result).intValue());
                }
            });
        }
    }

    @Override
    // 报告播放器事件
    public void onPlayerEvent(io.agora.mediaplayer.Constants.MediaPlayerEvent mediaPlayerEvent) {
        Log.e(TAG, " onPlayerEvent mediaPlayerEvent " + mediaPlayerEvent);
    }
    ```

3. 调用 `setupLocalVideo` 方法渲染本地媒体播放视图。

    ```java
    VideoCanvas videoCanvas = new VideoCanvas(surfaceView, Constants.RENDER_MODE_HIDDEN, Constants.VIDEO_MIRROR_MODE_AUTO,
    Constants.VIDEO_SOURCE_MEDIA_PLAYER,  mediaPlayer.getMediaPlayerId(), 0);
    engine.setupLocalVideo(videoCanvas);
    ```

4. 调用 `joinChannel` 加入频道时，通过 `options` 参数设置媒体播放器 ID、发布媒体播放器的音视频、将媒体资源分享给声网频道内的远端用户。

    ```java
    private ChannelMediaOptions options = new ChannelMediaOptions();

    ...

    options.publishMediaPlayerId = mediaPlayer.getMediaPlayerId();
    options.publishMediaPlayerAudioTrack = true;
    options.publishMediaPlayerVideoTrack = true;

    int res = engine.joinChannel(accessToken, channelId, 0, options);
    ```

5. 调用 `open` 打开本地或在线媒体文件。

   ```java
   mediaPlayer.open(url, 0);
   ```

6. 调用 `play` 播放媒体文件。

   :::warning[注意]
   请在收到 `onPlayerStateChanged` 回调报告播放状态为 `PLAYER_STATE_OPEN_COMPLETED` 后再调用 `play` 方法播放媒体文件。
   :::

    ```java
    mediaPlayer.play();
    ```

7. 当用户离开频道时，调用 `stop` 停止播放、调用 `unRegisterPlayerObserver` 取消注册播放观测器、调用 `destroy` 销毁媒体播放器并释放已分配的资源。

    ```java
    mediaPlayer.stop();
    mediaPlayer.unRegisterPlayerObserver(this);
    mediaPlayer.destroy();
    ```

## 参考信息 [#参考信息]

### 示例项目 [#示例项目]

声网提供了开源的示例项目供你参考，你可以前往下载或查看其中的源代码。

<Cards>
  <Card title="MediaPlayer" href="https://github.com/Shengwang-Community/API-Examples/blob/main/Android/APIExample/app/src/main/java/io/agora/api/example/examples/advanced/MediaPlayer.java" />
</Cards>

### 支持的格式 [#支持的格式]

声网的媒体播放器支持下列格式及协议：

**视频编码格式**

- H.263、H.264、H.265、MPEG4、MPEG2、RMVB、Theora、VP3、VP8、AVS、WMV

**音频编码格式**

- WAV、MP2、MP3、AAC、OPUS、FLAC、Vorbis、AMR-NB、AMR-WB、WMA v1、WMA v2

**容器格式**

- WAV、FLAC、OGG、MOV、ASF、FLV、MP3、MP4、MPEG-TS、Matroska (MKV)、AVI、ASS、CONCAT、DTS、AVS

**支持的协议**

- HTTP、HTTPS、RTMP、HLS、RTP、RTSP

### API 参考 [#api-参考]

- [`createMediaPlayer`](/zh-CN/api-reference/rtc/android/play/mediaplayer/mediaplayer-initialize#api_irtcengine_createmediaplayer)
- [`destroy`](/zh-CN/api-reference/rtc/android/play/mediaplayer/mediaplayer-initialize#api_imediaplayer_destroy_imediaplayer)
- [`registerPlayerObserver`](/zh-CN/api-reference/rtc/android/play/mediaplayer/mediaplayer-observer#api_imediaplayer_registerplayersourceobserver)
- [`unRegisterPlayerObserver`](/zh-CN/api-reference/rtc/android/play/mediaplayer/mediaplayer-observer#api_imediaplayer_unregisterplayersourceobserver)
- [`getMediaPlayerId`](/zh-CN/api-reference/rtc/android/play/mediaplayer/mediaplayer-info#api_imediaplayer_getmediaplayerid)
- [`open`](/zh-CN/api-reference/rtc/android/play/mediaplayer/mediaplayer-open#api_imediaplayer_open)
- [`play`](/zh-CN/api-reference/rtc/android/play/mediaplayer/mediaplayer-control#api_imediaplayer_play)
- [`pause`](/zh-CN/api-reference/rtc/android/play/mediaplayer/mediaplayer-control#api_imediaplayer_pause)
- [`stop`](/zh-CN/api-reference/rtc/android/play/mediaplayer/mediaplayer-control#api_imediaplayer_stop)
- [`onPlayerSourceStateChanged`](/zh-CN/api-reference/rtc/android/play/mediaplayer/mediaplayer-observer#callback_imediaplayersourceobserver_onplayersourcestatechanged)
- [`onPositionChanged`](/zh-CN/api-reference/rtc/android/play/mediaplayer/mediaplayer-observer#callback_imediaplayersourceobserver_onpositionchanged)
<_PlatformProcessedMarker close="true" />

<_PlatformProcessedMarker groupMode="structured" canonicalPlatform="android" platform="ios" />
本文介绍如何调用媒体播放器相关的 API 播放本地或在线媒体资源，或将媒体资源同步分享给声网频道内的远端用户。
## 前提条件 [#前提条件-1]

在进行操作之前，请确保你已经在项目中实现了基本的实时音视频功能。详见[实现音视频互动](/zh-CN/realtime-media/rtc/get-started/quick-start)。

## 实现方法 [#实现方法-1]

参考如下步骤，在你的项目中使用媒体播放器：

1. 初始化 `AgoraRtcEngineKit` 后，调用 `createMediaPlayer` 创建 `AgoraRtcMediaPlayerProtocol` 对象。

   ```swift
   // 初始化 AgoraRtcEngineKit
   agoraKit = AgoraRtcEngineKit.sharedEngine(with: config, delegate: self)
   // 创建 mediaPlayerKit 对象
   mediaPlayerKit = agoraKit.createMediaPlayer(with: self)
   ```

2. 实现媒体播放器回调。根据你的需求，你可以通过 `didChangedToState` 回调来观测播放器的状态，通过 `didChangedToPosition` 回调来获取当前媒体文件的播放进度。

    ```swift
    extension MediaPlayerMain: AgoraRtcMediaPlayerDelegate {
        // 报告播放器的状态
        func agoraRtcMediaPlayer(_ playerKit: AgoraRtcMediaPlayerProtocol, didChangedTo state: AgoraMediaPlayerState, error: AgoraMediaPlayerError) {
            LogUtils.log(message: "player rtc channel publish helper state changed to: \(state.rawValue), error: \(error.rawValue)", level: .info)
            DispatchQueue.main.async { [weak self] in
                guard let weakself = self else { return }
                switch state {
                case .failed:
                    weakself.showAlert(message: "media player error: \(error.rawValue)")
                    break
                case .openCompleted:
                    let duration = weakself.mediaPlayerKit.getDuration()
                    weakself.playerControlStack.isHidden = false
                    weakself.playerDurationLabel.text = "\(String(format: "%02d", duration / 60)) : \(String(format: "%02d", duration % 60))"
                    weakself.playerProgressSlider.setValue(0, animated: true)
                    break
                case .stopped:
                    weakself.playerControlStack.isHidden = true
                    weakself.playerProgressSlider.setValue(0, animated: true)
                    weakself.playerDurationLabel.text = "00 : 00"
                    break
                default: break
                }
            }
        }

        // 报告当前的播放进度
        func agoraRtcMediaPlayer(_ playerKit: AgoraRtcMediaPlayerProtocol, didChangedToPosition position: Int) {
            let duration = Float(mediaPlayerKit.getDuration() * 1000)
            var progress: Float = 0
            var left: Int = 0
            if duration > 0 {
                progress = Float(mediaPlayerKit.getPosition()) / duration
                left = Int((mediaPlayerKit.getDuration() * 1000 - mediaPlayerKit.getPosition()) / 1000)
            }
            DispatchQueue.main.async { [weak self] in
                guard let weakself = self else { return }
                weakself.playerDurationLabel.text = "\(String(format: "%02d", left / 60)) : \(String(format: "%02d", left % 60))"
                if !weakself.playerProgressSlider.isTouchInside {
                    weakself.playerProgressSlider.setValue(progress, animated: true)
                }
            }
        }
    }
    ```

3. 调用 `setupLocalVideo` 渲染本地媒体播放视图。

    ```swift
    mediaPlayerKit.setView(localVideo.videoView)
    let videoCanvas = AgoraRtcVideoCanvas()
    videoCanvas.view = localVideo.videoView
    videoCanvas.renderMode = .hidden
    videoCanvas.sourceType = .mediaPlayer
    videoCanvas.sourceId = mediaPlayerKit.getMediaPlayerId()
    agoraKit.setupLocalVideo(videoCanvas)
    ```

4. 调用 `joinChannelByToken` 加入频道时，通过 `mediaOptions` 设置媒体播放器 ID，发布媒体播放器的音视频，将媒体资源分享给声网频道内的远端用户。

    ```swift
    let option1 = AgoraRtcChannelMediaOptions()

    ...

    option1.publishMediaPlayerId = .of((Int32)(mediaPlayerKit.getMediaPlayerId()))
    ```

5. 调用 `open` 打开本地或在线媒体文件。

    ```swift
    mediaPlayerKit.open(url, startPos: 0)
    ```

6. 调用 `play` 播放媒体文件。

    :::warning[注意]
    请在收到 `didChangedToState` 回调报告播放状态为 `AgoraMediaPlayerStateOpenCompleted` 后再调用 `play` 方法播放媒体文件。
    :::

    ```swift
    mediaPlayerKit.play()
	```


 7. 当用户离开频道时，调用 `stop` 停止播放、调用 `destroyMediaPlayer` 销毁媒体播放器、取消注册播放观测器，并销毁分配的资源。

    ```swift
    mediaPlayerKit.stop()
    agoraKit.destroyMediaPlayer(mediaPlayerKit)
    ```

## 参考信息 [#参考信息-1]

### 示例项目 [#示例项目-1]

声网提供了开源的示例项目供你参考，你可以前往下载或查看其中的源代码。

<Cards>
  <Card title="MediaPlayer" href="https://github.com/Shengwang-Community/API-Examples/tree/main/iOS/APIExample/APIExample/Examples/Advanced/MediaPlayer" />
</Cards>

### 支持的格式 [#支持的格式-1]

声网的媒体播放器支持下列格式及协议：

**视频编码格式**

- H.263、H.264、H.265、MPEG4、MPEG2、RMVB、Theora、VP3、VP8、AVS、WMV

**音频编码格式**

- WAV、MP2、MP3、AAC、OPUS、FLAC、Vorbis、AMR-NB、AMR-WB、WMA v1、WMA v2

**容器格式**

- WAV、FLAC、OGG、MOV、ASF、FLV、MP3、MP4、MPEG-TS、Matroska (MKV)、AVI、ASS、CONCAT、DTS、AVS

**支持的协议**

- HTTP、HTTPS、RTMP、HLS、RTP、RTSP

### API 参考 [#api-参考-1]

- [`createMediaPlayerWithDelegate`](/zh-CN/api-reference/rtc/ios/play/mediaplayer/mediaplayer-initialize#api_irtcengine_createmediaplayer)
- [`destroyMediaPlayer`](/zh-CN/api-reference/rtc/ios/play/mediaplayer/mediaplayer-initialize#api_irtcengine_destroymediaplayer)
- [`getMediaPlayerId`](/zh-CN/api-reference/rtc/ios/play/mediaplayer/mediaplayer-info#api_imediaplayer_getmediaplayerid)
- [`open`](/zh-CN/api-reference/rtc/ios/play/mediaplayer/mediaplayer-open#api_imediaplayer_open)
- [`play`](/zh-CN/api-reference/rtc/ios/play/mediaplayer/mediaplayer-control#api_imediaplayer_play)
- [`pause`](/zh-CN/api-reference/rtc/ios/play/mediaplayer/mediaplayer-control#api_imediaplayer_pause)
- [`stop`](/zh-CN/api-reference/rtc/ios/play/mediaplayer/mediaplayer-control#api_imediaplayer_stop)
<_PlatformProcessedMarker close="true" />

<_PlatformProcessedMarker groupMode="structured" canonicalPlatform="android" platform="macos" />
本文介绍如何调用媒体播放器相关的 API 播放本地或在线媒体资源，或将媒体资源同步分享给声网频道内的远端用户。
## 前提条件 [#前提条件-2]

在进行操作之前，请确保你已经在项目中实现了基本的实时音视频功能。详见[实现音视频互动](/zh-CN/realtime-media/rtc/get-started/quick-start)。

## 实现方法 [#实现方法-2]

参考如下步骤，在你的项目中使用媒体播放器：

1. 初始化 `AgoraRtcEngineKit` 后，调用 `createMediaPlayer` 创建 `AgoraRtcMediaPlayerProtocol` 对象。

   ```swift
   // 初始化 AgoraRtcEngineKit
   agoraKit = AgoraRtcEngineKit.sharedEngine(with: config, delegate: self)
   // 创建 mediaPlayerKit 对象
   mediaPlayerKit = agoraKit.createMediaPlayer(with: self)
   ```

2. 实现媒体播放器回调。根据你的需求，你可以通过 `didChangedToState` 回调来观测播放器的状态，通过 `didChangedToPosition` 回调来获取当前媒体文件的播放进度。

    ```swift
    extension MediaPlayerMain: AgoraRtcMediaPlayerDelegate {
        // 报告播放器的状态
        func agoraRtcMediaPlayer(_ playerKit: AgoraRtcMediaPlayerProtocol, didChangedTo state: AgoraMediaPlayerState, error: AgoraMediaPlayerError) {
            LogUtils.log(message: "player rtc channel publish helper state changed to: \(state.rawValue), error: \(error.rawValue)", level: .info)
            DispatchQueue.main.async { [weak self] in
                guard let weakself = self else { return }
                switch state {
                case .failed:
                    weakself.showAlert(message: "media player error: \(error.rawValue)")
                    break
                case .openCompleted:
                    let duration = weakself.mediaPlayerKit.getDuration()
                    weakself.playerControlStack.isHidden = false
                    weakself.playerDurationLabel.text = "\(String(format: "%02d", duration / 60)) : \(String(format: "%02d", duration % 60))"
                    weakself.playerProgressSlider.setValue(0, animated: true)
                    break
                case .stopped:
                    weakself.playerControlStack.isHidden = true
                    weakself.playerProgressSlider.setValue(0, animated: true)
                    weakself.playerDurationLabel.text = "00 : 00"
                    break
                default: break
                }
            }
        }

        // 报告当前的播放进度
        func agoraRtcMediaPlayer(_ playerKit: AgoraRtcMediaPlayerProtocol, didChangedToPosition position: Int) {
            let duration = Float(mediaPlayerKit.getDuration() * 1000)
            var progress: Float = 0
            var left: Int = 0
            if duration > 0 {
                progress = Float(mediaPlayerKit.getPosition()) / duration
                left = Int((mediaPlayerKit.getDuration() * 1000 - mediaPlayerKit.getPosition()) / 1000)
            }
            DispatchQueue.main.async { [weak self] in
                guard let weakself = self else { return }
                weakself.playerDurationLabel.text = "\(String(format: "%02d", left / 60)) : \(String(format: "%02d", left % 60))"
                if !weakself.playerProgressSlider.isTouchInside {
                    weakself.playerProgressSlider.setValue(progress, animated: true)
                }
            }
        }
    }
    ```

3. 调用 `setupLocalVideo` 渲染本地媒体播放视图。

    ```swift
    mediaPlayerKit.setView(localVideo.videoView)
    let videoCanvas = AgoraRtcVideoCanvas()
    videoCanvas.view = localVideo.videoView
    videoCanvas.renderMode = .hidden
    videoCanvas.sourceType = .mediaPlayer
    videoCanvas.sourceId = mediaPlayerKit.getMediaPlayerId()
    agoraKit.setupLocalVideo(videoCanvas)
    ```

4. 调用 `joinChannelByToken` 加入频道时，通过 `mediaOptions` 设置媒体播放器 ID，发布媒体播放器的音视频，将媒体资源分享给声网频道内的远端用户。

    ```swift
    let option1 = AgoraRtcChannelMediaOptions()

    ...

    option1.publishMediaPlayerId = .of((Int32)(mediaPlayerKit.getMediaPlayerId()))
    ```

5. 调用 `open` 打开本地或在线媒体文件。

    ```swift
    mediaPlayerKit.open(url, startPos: 0)
    ```

6. 调用 `play` 播放媒体文件。

    :::warning[注意]
    请在收到 `didChangedToState` 回调报告播放状态为 `AgoraMediaPlayerStateOpenCompleted` 后再调用 `play` 方法播放媒体文件。
    :::

    ```swift
    mediaPlayerKit.play()
	```


 7. 当用户离开频道时，调用 `stop` 停止播放、调用 `destroyMediaPlayer` 销毁媒体播放器、取消注册播放观测器，并销毁分配的资源。

    ```swift
    mediaPlayerKit.stop()
    agoraKit.destroyMediaPlayer(mediaPlayerKit)
    ```

## 参考信息 [#参考信息-2]

### 示例项目 [#示例项目-2]

声网提供了开源的示例项目供你参考，你可以前往下载或查看其中的源代码。

<Cards>
  <Card title="MediaPlayer" href="https://github.com/Shengwang-Community/API-Examples/tree/main/macOS/APIExample/Examples/Advanced/MediaPlayer" />
</Cards>

### 支持的格式 [#支持的格式-2]

声网的媒体播放器支持下列格式及协议：

**视频编码格式**

- H.263、H.264、H.265、MPEG4、MPEG2、RMVB、Theora、VP3、VP8、AVS、WMV

**音频编码格式**

- WAV、MP2、MP3、AAC、OPUS、FLAC、Vorbis、AMR-NB、AMR-WB、WMA v1、WMA v2

**容器格式**

- WAV、FLAC、OGG、MOV、ASF、FLV、MP3、MP4、MPEG-TS、Matroska (MKV)、AVI、ASS、CONCAT、DTS、AVS

**支持的协议**

- HTTP、HTTPS、RTMP、HLS、RTP、RTSP

### API 参考 [#api-参考-2]

- [`createMediaPlayerWithDelegate`](/zh-CN/api-reference/rtc/macos/play/mediaplayer/mediaplayer-initialize#api_irtcengine_createmediaplayer)
- [`destroyMediaPlayer`](/zh-CN/api-reference/rtc/macos/play/mediaplayer/mediaplayer-initialize#api_irtcengine_destroymediaplayer)
- [`getMediaPlayerId`](/zh-CN/api-reference/rtc/macos/play/mediaplayer/mediaplayer-info#api_imediaplayer_getmediaplayerid)
- [`open`](/zh-CN/api-reference/rtc/macos/play/mediaplayer/mediaplayer-open#api_imediaplayer_open)
- [`play`](/zh-CN/api-reference/rtc/macos/play/mediaplayer/mediaplayer-control#api_imediaplayer_play)
- [`pause`](/zh-CN/api-reference/rtc/macos/play/mediaplayer/mediaplayer-control#api_imediaplayer_pause)
- [`stop`](/zh-CN/api-reference/rtc/macos/play/mediaplayer/mediaplayer-control#api_imediaplayer_stop)
<_PlatformProcessedMarker close="true" />

<_PlatformProcessedMarker groupMode="structured" canonicalPlatform="android" platform="windows" />
本文介绍如何调用媒体播放器相关的 API 播放本地或在线媒体资源，或将媒体资源分享给声网频道内的远端用户。
## 前提条件 [#前提条件-3]

在进行操作之前，请确保你已经在项目中实现了基本的实时音视频功能。有关详细信息，请参考[实现音视频互动](/zh-CN/realtime-media/rtc/get-started/quick-start)。

## 实现方法 [#实现方法-3]

参考如下步骤，在你的项目中使用媒体播放器：

1. 初始化 `IRtcEngine` 后，创建一个 `IMediaPlayer` 对象。

    ```cpp
    void CAgoraMediaPlayer::InitMediaPlayerKit() {
        // 创建声网媒体播放器
        m_mediaPlayer = m_rtcEngine->createMediaPlayer().get();
        m_lstInfo.InsertString(m_lstInfo.GetCount(), _T("createAgoraMediaPlayer"));
        m_lstInfo.InsertString(m_lstInfo.GetCount(), _T("mediaplayer initialize"));
        // 设置播放器渲染视图
        RECT rc = {0};
        m_localVideoWnd.GetWindowRect(&rc);
        int ret = m_mediaPlayer->setView(
            (agora::media::base::view_t)m_localVideoWnd.GetSafeHwnd());
        // 设置接收播放器事件的窗口
        m_mediaPlayerEvent.SetMsgReceiver(m_hWnd);
    }
    ```

2. 调用 `registerPlayerSourceObserver` 方法注册播放观测器。

    ```cpp
    void CAgoraMediaPlayer::OnBnClickedButtonJoinchannel() {

        // ...
        // 注册播放观测器
        ret = m_mediaPlayer->registerPlayerSourceObserver(&m_mediaPlayerEvent);
        m_lstInfo.InsertString(m_lstInfo.GetCount(),
                            _T("registerPlayerSourceObserver"));
        if (0 ==
            m_rtcEngine->joinChannel(APP_TOKEN, szChannelId.c_str(), 0, options)) {
            strInfo.Format(_T("join channel %s, use ChannelMediaOptions"),
                        getCurrentTime());
        }
    }
    else {
        // 取消注册播放观测器
        ret = m_mediaPlayer->unregisterPlayerSourceObserver(&m_mediaPlayerEvent);
        m_lstInfo.InsertString(m_lstInfo.GetCount(),
                            _T("registerPlayerSourceObserver"));
        // leave channel in the engine.
        if (0 == m_rtcEngine->leaveChannel()) {
            strInfo.Format(_T("leave channel %s"), getCurrentTime());
        }
    }
    m_lstInfo.InsertString(m_lstInfo.GetCount(), strInfo);
    ```

3. 实现媒体播放器观测器的回调。

    ```cpp
    // 报告播放器状态改变
    LRESULT CAgoraMediaPlayer::OnmediaPlayerStateChanged(WPARAM wParam,
                                                        LPARAM lParam) {
        CString strState;
        CString strError;
        switch ((agora::media::base::MEDIA_PLAYER_STATE)wParam) {
            case agora::media::base::PLAYER_STATE_OPEN_COMPLETED:
                strState = _T("PLAYER_STATE_OPEN_COMPLETED");
                m_mediaPlayerState = mediaPLAYER_OPEN;
                int64_t duration;
                m_mediaPlayer->getDuration(duration);
                m_sldVideo.SetRangeMax((int)duration);

                break;
                // ...
        }

        switch ((agora::media::base::MEDIA_PLAYER_ERROR)lParam) {
            case agora::media::base::PLAYER_ERROR_URL_NOT_FOUND:
                strError = _T("PLAYER_ERROR_URL_NOT_FOUND");
                break;
                // ...
        }
        CString strInfo;
        strInfo.Format(_T("sta:%s,\nerr:%s"), strState, strError);
        m_lstInfo.InsertString(m_lstInfo.GetCount(), strInfo);
        return TRUE;
    }

    // 报告当前播放进度
    LRESULT CAgoraMediaPlayer::OnmediaPlayerPositionChanged(WPARAM wParam,
                                                            LPARAM lParam) {
        int64_t *p = (int64_t *)wParam;
        m_sldVideo.SetPos((int)*p);
        delete p;
        return TRUE;
    }
    ```

4. 调用 `joinChannel` 加入频道时，通过 `options` 参数设置媒体播放器 ID，发布媒体播放器的音视频，将媒体资源分享给声网频道内的远端用户。

    ```cpp
    void CAgoraMediaPlayer::OnBnClickedButtonPublishVideo() {
        if (m_publishMeidaplayer) {
            ChannelMediaOptions op;
            op.clientRoleType = CLIENT_ROLE_BROADCASTER;
            op.publishMediaPlayerVideoTrack = false;
            op.publishMediaPlayerAudioTrack = false;
            op.publishMediaPlayerId = m_mediaPlayer->getMediaPlayerId();
            int ret = m_rtcEngine->updateChannelMediaOptions(op);
            ChannelMediaOptions op2;
            op2.clientRoleType = CLIENT_ROLE_BROADCASTER;
            op2.publishCameraTrack = true;
            ret = m_rtcEngine->updateChannelMediaOptions(op2);
            m_publishMeidaplayer = false;
        } else {
            ChannelMediaOptions options;
            options.clientRoleType = CLIENT_ROLE_BROADCASTER;
            options.publishMediaPlayerVideoTrack = true;
            options.publishMediaPlayerAudioTrack = true;
            options.publishMediaPlayerId = m_mediaPlayer->getMediaPlayerId();
            options.publishCameraTrack = false;
            options.publishAudioTrack = false;
            options.autoSubscribeAudio = false;
            options.autoSubscribeVideo = false;
            m_rtcEngine->updateChannelMediaOptions(options);
            m_publishMeidaplayer = true;
        }
    }
    ```

5. 调用 `open` 打开本地或在线媒体文件。

    ```cpp
    void CAgoraMediaPlayer::OnBnClickedButtonOpen() {
        CString strUrl;
        CString strInfo;
        m_edtVideoSource.GetWindowText(strUrl);
        std::string tmp = cs2utf8(strUrl);
        switch (m_mediaPlayerState) {
            case mediaPLAYER_READY:
            case mediaPLAYER_STOP:

                if (tmp.empty()) {
                    AfxMessageBox(_T("you can fill video source."));
                    return;
                }
                // 打开媒体文件
                m_mediaPlayer->open(tmp.c_str(), 0);
                break;
            default:
                m_lstInfo.InsertString(m_lstInfo.GetCount(),
                                    _T("can not open player."));
                break;
        }
    }
    ```

6. 调用 `play` 播放媒体文件。如果你需要暂停播放文件，可调用 `pause` 方法。

   :::warning[注意]
   请在收到 `onPlayerSourceStateChanged` 回调报告播放状态为 `PLAYER_STATE_OPEN_COMPLETED` 后再调用 `play` 方法播放媒体文件。
   :::

    ```cpp
    void CAgoraMediaPlayer::OnBnClickedButtonPlay() {
        int ret;
        switch (m_mediaPlayerState) {
            case mediaPLAYER_PAUSE:
            case mediaPLAYER_OPEN:
                // 播放媒体文件
                ret = m_mediaPlayer->play();
                if (ret == 0) {
                    m_mediaPlayerState = mediaPLAYER_PLAYING;
                }
                break;
            case mediaPLAYER_PLAYING:
                // 暂停播放
                ret = m_mediaPlayer->pause();
                if (ret == 0) {
                    m_mediaPlayerState = mediaPLAYER_PAUSE;
                }
                break;
            default:
                break;
        }
    }
    ```

7. 当用户离开频道时，停止播放、销毁媒体播放器、取消注册播放观测器，并销毁分配的资源。

    ```cpp
    void CAgoraMediaPlayer::OnBnClickedButtonStop() {
        if (m_mediaPlayerState == mediaPLAYER_OPEN ||
            m_mediaPlayerState == mediaPLAYER_PLAYING ||
            m_mediaPlayerState == mediaPLAYER_PAUSE) {
            // 停止播放
            m_mediaPlayer->stop();
            m_mediaPlayerState = mediaPLAYER_STOP;
        }
    }

    void CAgoraMediaPlayer::OnDestroy() {
        // 销毁媒体播放器
        CDialogEx::OnDestroy();
        UnInitMediaPlayerKit();
    }
    ```

## 参考信息 [#参考信息-3]

### 示例项目 [#示例项目-3]

声网提供了开源的示例项目供你参考，你可以前往下载或查看其中的源代码。

<Cards>
  <Card title="MediaPlayer" href="https://github.com/Shengwang-Community/API-Examples/tree/main/windows/APIExample/APIExample/Advanced/MediaPlayer" />
</Cards>

### 支持的格式 [#支持的格式-3]

声网的媒体播放器支持下列格式及协议：

**视频编码格式**

- H.263、H.264、H.265、MPEG4、MPEG2、RMVB、Theora、VP3、VP8、AVS、WMV

**音频编码格式**

- WAV、MP2、MP3、AAC、OPUS、FLAC、Vorbis、AMR-NB、AMR-WB、WMA v1、WMA v2

**容器格式**

- WAV、FLAC、OGG、MOV、ASF、FLV、MP3、MP4、MPEG-TS、Matroska (MKV)、AVI、ASS、CONCAT、DTS、AVS

**支持的协议**

- HTTP、HTTPS、RTMP、HLS、RTP、RTSP

### API 参考 [#api-参考-3]

- [`createMediaPlayer`](/zh-CN/api-reference/rtc/cpp-all-platforms/play/mediaplayer/mediaplayer-initialize#api_irtcengine_createmediaplayer)
- [`destroyMediaPlayer`](/zh-CN/api-reference/rtc/cpp-all-platforms/play/mediaplayer/mediaplayer-initialize#api_irtcengine_destroymediaplayer)
- [`registerPlayerSourceObserver`](/zh-CN/api-reference/rtc/cpp-all-platforms/play/mediaplayer/mediaplayer-observer#api_imediaplayer_registerplayersourceobserver)
- [`unregisterPlayerSourceObserver`](/zh-CN/api-reference/rtc/cpp-all-platforms/play/mediaplayer/mediaplayer-observer#api_imediaplayer_unregisterplayersourceobserver)
- [`getMediaPlayerId`](/zh-CN/api-reference/rtc/cpp-all-platforms/play/mediaplayer/mediaplayer-info#api_imediaplayer_getmediaplayerid)
- [`open`](/zh-CN/api-reference/rtc/cpp-all-platforms/play/mediaplayer/mediaplayer-open#api_imediaplayer_open)
- [`play`](/zh-CN/api-reference/rtc/cpp-all-platforms/play/mediaplayer/mediaplayer-control#api_imediaplayer_play)
- [`pause`](/zh-CN/api-reference/rtc/cpp-all-platforms/play/mediaplayer/mediaplayer-control#api_imediaplayer_pause)
- [`stop`](/zh-CN/api-reference/rtc/cpp-all-platforms/play/mediaplayer/mediaplayer-control#api_imediaplayer_stop)
- [`onPlayerSourceStateChanged`](/zh-CN/api-reference/rtc/cpp-all-platforms/play/mediaplayer/mediaplayer-observer#callback_imediaplayersourceobserver_onplayersourcestatechanged)
- [`onPositionChanged`](/zh-CN/api-reference/rtc/cpp-all-platforms/play/mediaplayer/mediaplayer-observer#callback_imediaplayersourceobserver_onpositionchanged)
<_PlatformProcessedMarker close="true" />

<_PlatformProcessedMarker groupMode="structured" canonicalPlatform="android" platform="electron" />
本文介绍如何调用媒体播放器相关的 API 播放本地或在线媒体资源，或将媒体资源分享给声网频道内的远端用户。
## 前提条件 [#前提条件-4]

在进行操作之前，请确保你已经在项目中实现了基本的实时音视频功能。有关详细信息，请参考[实现音视频互动](/zh-CN/realtime-media/rtc/get-started/quick-start)。

## 实现方法 [#实现方法-4]

参考如下步骤，在你的项目中使用媒体播放器：

1. 初始化 `IRtcEngine` 后，创建一个 `IMediaPlayer` 对象。

    ```typescript
    // 创建并初始化引擎
    let rtcEngine = createAgoraRtcEngine();
    rtcEngine.initialize({
      appId,
    });
    // 创建媒体播放器对象
    let mediaPlayer = rtcEngine.createMediaPlayer();
    ```

2. 调用 `registerPlayerSourceObserver` 方法注册播放观测器。

    ```typescript
    // 注册播放观测器
    mediaPlayer.registerPlayerSourceObserver(this);
    ```

3. 根据你的需求，你可以注册以下媒体播放器观测器的回调：
    -  `onPlayerSourceStateChanged`：报告播放器状态改变。
    -  `onPositionChanged`：报告当前媒体文件的播放进度。
    -  `onPlayerEvent`：报告播放器事件。

    ```typescript
    const EventHandles = {
        // 报告播放器状态改变
        onPlayerSourceStateChanged: (state, ec) {
            console.log(`state:${state}, ec:${ec}`);
        };
        
        // 报告当前媒体文件的播放进度
        onPositionChanged: (position) {
            console.log(`position:${position}`);
        };
        
        // 报告播放器事件
        onPlayerEvent: (
            eventCode,
            elapsedTime,
            message
        ) {
            console.log(
            `eventCode:${eventCode},
            elapsedTime:${elapsedTime},
            message:${message}`
            );
        };
        };
    // 添加主回调事件
    rtcEngine.registerEventHandler(EventHandles);
    ```

4. 调用 `open` 打开本地或在线媒体文件。

    ```typescript
    open = () => {
    const url = 'https://example/video.mov';
    if (!url) {
        this.error("url is invalid");
    }
    mediaPlayer.open(url, 0);
    };
    ```

5. 调用 `play` 播放媒体文件。

    ```typescript
    // 播放媒体文件
    play = () => {
    const { position, duration } = this.state;
    if (position === duration && duration !== 0) {
        mediaPlayer.seek(0);
    } else {
        mediaPlayer.play();
    }
    };
    // 暂停播放媒体文件
    pause = () => {
    mediaPlayer.pause();
    };
    // 恢复播放媒体文件
    resume = () => {
    mediaPlayer.resume();
    };
    ```

6. 停止播放并释放资源。

    ```typescript
    // 停止播放
    mediaPlayer.stop();
    // 销毁媒体播放器
    rtcEngine.destroyMediaPlayer(this.player);
    // 取消注册播放观测器
    rtcEngine.unregisterEventHandler(this);
    ```

## 参考信息 [#参考信息-4]

### 示例项目 [#示例项目-4]

声网提供了开源的实现媒体播放器示例项目供你参考，你可以前往下载或查看其中的源代码。

<Cards>
  <Card title={<RepositoryCardTitle provider="gitee">MediaPlayer</RepositoryCardTitle>} href="https://gitee.com/agoraio-community/Electron-SDK/tree/main/example/src/renderer/examples/advanced/MediaPlayer/MediaPlayer.tsx" />
  <Card title={<RepositoryCardTitle provider="github">MediaPlayer</RepositoryCardTitle>} href="https://github.com/AgoraIO-Extensions/Electron-SDK/blob/main/example/src/renderer/examples/advanced/MediaPlayer/MediaPlayer.tsx" />
</Cards>

### API 参考 [#api-参考-4]

- [`createMediaPlayer`](/zh-CN/api-reference/rtc/electron/play/mediaplayer/mediaplayer-initialize#api_irtcengine_createmediaplayer)
- [`destroy`](/zh-CN/api-reference/rtc/electron/play/mediaplayer/mediaplayer-initialize#api_irtcengine_destroymediaplayer)
- [`registerPlayerObserver`](/zh-CN/api-reference/rtc/electron/play/mediaplayer/mediaplayer-observer#api_imediaplayer_registerplayersourceobserver)
- [`unRegisterPlayerObserver`](/zh-CN/api-reference/rtc/electron/play/mediaplayer/mediaplayer-observer#api_imediaplayer_unregisterplayersourceobserver)
- [`getMediaPlayerId`](/zh-CN/api-reference/rtc/electron/play/mediaplayer/mediaplayer-info#api_imediaplayer_getmediaplayerid)
- [`open`](/zh-CN/api-reference/rtc/electron/play/mediaplayer/mediaplayer-open#api_imediaplayer_open)
- [`play`](/zh-CN/api-reference/rtc/electron/play/mediaplayer/mediaplayer-control#api_imediaplayer_play)
- [`pause`](/zh-CN/api-reference/rtc/electron/play/mediaplayer/mediaplayer-control#api_imediaplayer_pause)
- [`stop`](/zh-CN/api-reference/rtc/electron/play/mediaplayer/mediaplayer-control#api_imediaplayer_stop)
- [`onPlayerEvent`](/zh-CN/api-reference/rtc/electron/play/mediaplayer/mediaplayer-observer#callback_imediaplayersourceobserver_onplayerevent)
- [`onPlayerSourceStateChanged`](/zh-CN/api-reference/rtc/electron/play/mediaplayer/mediaplayer-observer#callback_imediaplayersourceobserver_onplayersourcestatechanged)
- [`onPositionChanged`](/zh-CN/api-reference/rtc/electron/play/mediaplayer/mediaplayer-observer#callback_imediaplayersourceobserver_onpositionchanged)
<_PlatformProcessedMarker close="true" />

<_PlatformProcessedMarker groupMode="structured" canonicalPlatform="android" platform="unity" />
媒体播放器是 RTC SDK 内置的一个播放器，支持播放多种格式的媒体资源。本文介绍如何调用媒体播放器相关的 API 播放本地或在线媒体资源，并将媒体资源分享给声网频道内的远端用户观看或收听。

## 前提条件 [#前提条件-5]

在进行操作之前，请确保你已经在项目中实现了基本的实时音视频功能。有关详细信息，请参考[实现音视频互动](/zh-CN/realtime-media/rtc/get-started/quick-start)。

## 实现方法 [#实现方法-5]

参考如下步骤，在你的项目中使用媒体播放器：

### 创建媒体播放器对象 [#创建媒体播放器对象]

初始化 `IRtcEngine` 后，调用 `CreateMediaPlayer` 创建一个 `IMediaPlayer` 对象。

:::warning[注意]
如果你需要创建多个媒体播放器对象，可以多次调用 `CreateMediaPlayer`。
:::

```csharp
MediaPlayer = RtcEngine.CreateMediaPlayer();
if (MediaPlayer == null)
{
    this.Log.UpdateLog("CreateMediaPlayer failed!");
    return;
}
```

### 注册回调事件并实现回调 [#注册回调事件并实现回调]

1. 调用 `IMediaPlayer` 类下的 `InitEventHandler` 方法添加媒体播放器的回调事件。

   ```csharp
   MpkEventHandler handler = new MpkEventHandler(this);
   MediaPlayer.InitEventHandler(handler);
   this.Log.UpdateLog("playerId id: " + MediaPlayer.GetId());
   ```

2. 根据你的需求，实现媒体播放器观测器的回调。

    ```csharp
    class MpkEventHandler : IMediaPlayerSourceObserver
    {   // 报告播放器状态改变
        public override void OnPlayerSourceStateChanged(MEDIA_PLAYER_STATE state, MEDIA_PLAYER_REASON reason)
        {

        }

        // 报告播放器的事件
        public override void OnPlayerEvent(MEDIA_PLAYER_EVENT @event, Int64 elapsedTime, string message)
        {
            Debug.Log(string.Format("OnPlayerEvent state: {0}", @event));
        }

        // 报告预加载媒体资源的事件
        public override void OnPreloadEvent(string src, PLAYER_PRELOAD_EVENT @event)
        {
            Debug.Log(string.Format("OnPreloadEvent src: {0}, @event: {1}", src, @event));
        }
        // 报告当前媒体资源的播放进度
        public override void OnPositionChanged(long positionMs, long timestampMs)
        {

        }
    }
    ```

### 设置视频渲染窗口 [#设置视频渲染窗口]

如果你需要播放视频资源，在媒体资源打开后，设置视频渲染。当播放器停止播放时，销毁对应的视频视图。在渲染视图时，你可以通过 `GetId` 获取媒体播放器的 ID，并需要将 `VIDEO_SOURCE_TYPE` 设为 `VIDEO_SOURCE_MEDIA_PLAYER`。

```csharp
// 报告播放器状态改变
public override void OnPlayerSourceStateChanged(MEDIA_PLAYER_STATE state, MEDIA_PLAYER_REASON reason)
{
    Debug.Log(string.Format(
        "OnPlayerSourceStateChanged state: {0}, ec: {1}, playId: {2}", state, reason, _sample.MediaPlayer.GetId()));
    Debug.Log("OnPlayerSourceStateChanged");
    if (state == MEDIA_PLAYER_STATE.PLAYER_STATE_OPEN_COMPLETED)
    {
        // 成功打开媒体资源后，创建一个视图用于显示媒体播放器的视频流
        MakeVideoView((uint)_sample.MediaPlayer.GetId(), "", VIDEO_SOURCE_TYPE.VIDEO_SOURCE_MEDIA_PLAYER);
    }
    else if (state == MEDIA_PLAYER_STATE.PLAYER_STATE_STOPPED)
    {
        // 播放停止后，销毁视频视图
        DestroyVideoView((uint)_sample.MediaPlayer.GetId());
    }
}
```

调用 `SetForUser` 设置视频显示，调用 `SetEnable` 开始视频渲染。

```csharp
// 创建一个视频视图
static void MakeVideoView(uint uid, string channelId = "", VIDEO_SOURCE_TYPE videoSourceType = VIDEO_SOURCE_TYPE.VIDEO_SOURCE_CAMERA)
{
    var go = GameObject.Find(uid.ToString());
    if (!ReferenceEquals(go, null))
    {
        return;
    }

    // 创建一个新的 GameObject 用于渲染视频
    var videoSurface = MakeImageSurface(uid.ToString());
    if (ReferenceEquals(videoSurface, null)) return;
    // 设置视频显示
    videoSurface.SetForUser(uid, channelId, videoSourceType);
    // 开始视频渲染
    videoSurface.SetEnable(true);

    // Texture 的宽高发生改变回调
    videoSurface.OnTextureSizeModify += (int width, int height) =>
    {
        var transform = videoSurface.GetComponent<RectTransform>();
        if (transform)
        {
            // 如果在 RawImage 中渲染，只需设置 RawImage 的大小
            transform.sizeDelta = new Vector2(width / 2, height / 2);
            transform.localScale = Vector3.one;
        }
        else
        {
            // 如果在 MeshRenderer 中渲染，只需设置 MeshRenderer 的本地大小
            float scale = (float)height / (float)width;
            videoSurface.transform.localScale = new Vector3(-1, 1, scale);
        }
        Debug.Log("OnTextureSizeModify: " + width + "  " + height);
    };
}

// 销毁视频视图
static void DestroyVideoView(uint uid)
{
    var go = GameObject.Find(uid.ToString());
    if (!ReferenceEquals(go, null))
    {
        Destroy(go);
    }
}

// 创建一个新的视频视图，包含一个 RawImage 组件，用于显示视频
private static VideoSurface MakeImageSurface(string goName)
{
    // 创建一个新的 GameObject
    GameObject go = new GameObject();
    go.name = goName;
    // 添加 RawImage 组件，用于渲染视频
    go.AddComponent<RawImage>();
    go.AddComponent<UIElementDrag>();
    var canvas = GameObject.Find("VideoCanvas");
    if (canvas != null)
    {
        go.transform.parent = canvas.transform;
        Debug.Log("add video view");
    }
    else
    {
        Debug.Log("Canvas is null video view");
    }

    // 设置 GameObject 的变换
    go.transform.Rotate(0f, 0.0f, 180.0f);
    go.transform.localPosition = Vector3.zero;
    go.transform.localScale = new Vector3(4.5f, 3f, 1f);

    // 添加 VideoSurface 组件
    var videoSurface = go.AddComponent<VideoSurface>();
    return videoSurface;
}

```

### 打开媒体资源 [#打开媒体资源]

调用 `Open` 打开本地或在线媒体文件并设置起始播放位置。支持打开的媒体资源格式见[支持的格式](#支持的格式-4)。

```csharp
public void OnOpenButtonPress()
{
    var ret = MediaPlayer.Open("Your File Path", 0);
    Debug.Log("Open returns: " + ret);
}
```

声网还提供 `OpenWithMediaSource` 方法打开媒体资源，同时可以进行播放设置，例如设置是否开启自动播放、实时缓存等功能。

### 发布媒体播放器的音视频流 [#发布媒体播放器的音视频流]

调用 `JoinChannel` 加入频道时，在 `ChannelMediaOptions` 中进行如下设置：

- 设置用户角色为主播（`CLIENT_ROLE_BROADCASTER`)。
- 将 `autoSubscribeAudio` 和 `autoSubscribeVideo` 设为 `true`，自动订阅所有音视频流。
- 将 `publishMediaPlayerAudioTrack` 和 `publishMediaPlayerVideoTrack` 设为 `true`，发布媒体播放器的音视频流。
- 将 `publishMediaPlayerId` 设为你的媒体播放器的 ID。
- 将 `enableAudioRecordingOrPlayout` 设为 `true`，开启音频播放。

```csharp
ChannelMediaOptions options = new ChannelMediaOptions();
// 自动订阅远端的音频流
options.autoSubscribeAudio.SetValue(true);
// 自动订阅远端的视频流
options.autoSubscribeVideo.SetValue(true);
options.publishCustomAudioTrack.SetValue(false);
options.publishCameraTrack.SetValue(false);
// 设置发布视频播放器的音频流
options.publishMediaPlayerAudioTrack.SetValue(true);
// 设置发布视频播放器的视频流
options.publishMediaPlayerVideoTrack.SetValue(true);
// 待发布的媒体播放器的 ID
options.publishMediaPlayerId.SetValue(MediaPlayer.GetId());
// 开启音频录制或播放
options.enableAudioRecordingOrPlayout.SetValue(true);
// 设置用户角色为主播
options.clientRoleType.SetValue(CLIENT_ROLE_TYPE.CLIENT_ROLE_BROADCASTER);
// 加入频道
var ret = RtcEngine.JoinChannel(_token, _channelName, 0, options);
this.Log.UpdateLog("RtcEngineController JoinChannel_MPK returns: " + ret);
```

### 播放控制 [#播放控制]

本节介绍如何实现播放控制，包括暂停、恢复播放、停止播放等功能。

#### 播放 [#播放]

调用 `Play` 方法播放本地或在线媒体资源。

:::warning[注意]
- 如果你通过 `Open` 打开媒体资源，你需要在收到 `OnPlayerSourceStateChanged` 回调报告状态为 `PLAYER_STATE_OPEN_COMPLETED` 后再调用 `Play` 进行播放。
- 如果你通过 `OpenWithMediaSource` 打开媒体资源，且 `autoPlay` 为 `true` 时，媒体资源打开后会自动播放，无需再额外调用 `Play` 方法。
:::

```csharp
public void OnPlayButtonPress()
{
    var ret = MediaPlayer.Play();
    Debug.Log("Play return" + ret);
}
```

**循环播放**

如果你需要循环播放，可以调用 `SetLoopCount` 方法并通过 `loopCount` 参数设置循环播放的次数，默认为 `0`，表示不循环播放。如需无限循环播放，将该参数设为 `-1`。

```csharp
public void OnPlayButtonPress()
{
    if (this.IsLoop())
    {
        MediaPlayer.SetLoopCount(-1);
    }
    else
    {
        MediaPlayer.SetLoopCount(0);
    }
    var ret = MediaPlayer.Play();
    this.Log.UpdateLog("Play return" + ret);
}
```

**定位指定位置播放**

如果你需要定位到媒体资源的指定位置再播放，可以调用 `Seek` 方法定位到指定位置。

:::warning[注意]
- 请确保在成功打开媒体文件后（即收到 `OnPlayerSourceStateChanged` 回调报告状态为 `PLAYER_STATE_OPEN_COMPLETED`）再调用 `Seek`。成功调用后，媒体播放器会自动从指定位置开始播放，并报告状态为 `PLAYER_STATE_PLAYING`。
- 如果你在暂停播放的情况下调用 `Seek`，成功调用后，媒体资源仍然会是暂停播放的状态。如需播放，请调用 `Resume` 或 `Play`。
:::

**设置播放速度**

调用 `SetPlaybackSpeed` 方法来设置当前媒体文件的播放速度。

```csharp
public void OnSetPlaybackSpeedButtonPress()
{
    var ret = MediaPlayer.SetPlaybackSpeed(2);
    this.Log.UpdateLog("SetPlaybackSpeed return" + ret);
}
```

#### 暂停播放 [#暂停播放]

调用 `Pause` 方法暂停当前播放。

```csharp
public void OnPauseButtonPress()
{
    var ret = MediaPlayer.Pause();
    this.Log.UpdateLog("Pause return" + ret);
}
```

#### 恢复播放 [#恢复播放]

暂停播放后，如需恢复播放，调用 `Resume` 方法。

```csharp
public void OnResumeButtonPress()
{
    var ret = MediaPlayer.Resume()
    this.Log.UpdateLog("Resume returns: " + ret);
}
```

#### 停止播放 [#停止播放]

调用 `Stop` 方法停止播放。停止播放后，如果你需要再次播放，需要重新打开该媒体资源。

```csharp
public void OnStopButtonPress()
{
    var ret = MediaPlayer.Stop();
    this.Log.UpdateLog("Stop return" + ret);
}
```

### 调整音量 [#调整音量]

如果你需要调整媒体播放器本地播放的音量，调用 `AdjustPlayoutVolume`。如果要调整所播放的媒体资源发布到远端的音量，调用 `AdjustPublishSignalVolume`。

```csharp
var ret = MediaPlayer.AdjustPlayoutVolume(30);
this.Log.UpdateLog("AdjustPlayoutVolume return" + ret);

ret = MediaPlayer.AdjustPublishSignalVolume(50);
this.Log.UpdateLog("AdjustPublishSignalVolume return" + ret);
```

### 预加载媒体资源 [#预加载媒体资源]

如果你需要连续播放多个不同的媒体资源，可以预先加载待播放的媒体资源以保证资源切换时的观众体验。

1. 调用 `PreloadSrc` 预加载媒体资源。如需加载多个资源，你可以多次调用该方法。预加载的相关事件可以通过监听 `OnPreloadEvent` 回调得知。

   ```csharp
   public void OnPreloadSrcButtonClick()
   {

       var nRet = MediaPlayer.PreloadSrc(PRELOAD_URL, 0);
       this.Log.UpdateLog("PreloadSrc: " + nRet);
   }
   ```

2. 调用 `PlayPreloadedSrc` 播放预加载的媒体资源。调用该方法后，如果你收到 `OnPlayerSourceStateChanged` 回调报告状态 `PLAYER_STATE_PLAYING`，则表示播放成功。

   ```csharp
   public void OnPlayPreloadButtonClick()
   {
       var nRet = MediaPlayer.PlayPreloadedSrc(PRELOAD_URL);
       this.Log.UpdateLog("PlayPreloadedSrc: " + nRet);
   }
   ```

3. 如果不再需要已加载的媒体资源，可以调用 `UnloadSrc` 释放预加载的资源。

   ```csharp
   var nRet =  MediaPlayer.UnloadSrc(PRELOAD_URL);
   this.Log.UpdateLog("UnloadSrc: " + nRet);
   ```

### 离开频道 [#离开频道]

参考下列步骤离开频道：

1. 调用 `DestroyMediaPlayer` 销毁媒体播放器对象。
2. 调用 `InitEventHandler` 取消注册播放器事件观测器。
3. 调用 `LeaveChannel` 离开频道。
4. 调用 `Dispose` 销毁 `IRtcEngine` 对象并释放 SDK 使用的资源。

```csharp
public void OnLeaveChannelButtonPress()
{
    if (RtcEngine == null) return;
    // 销毁媒体播放器对象
    if (MediaPlayer != null) RtcEngine.DestroyMediaPlayer(MediaPlayer);
    // 取消注册播放器事件观测器
    RtcEngine.InitEventHandler(null);
    // 离开频道
    RtcEngine.LeaveChannel();
    // 销毁引擎并释放资源
    RtcEngine.Dispose();
    RtcEngine = null;
    MediaPlayer = null;
}
```

## 参考信息 [#参考信息-5]

### 示例项目 [#示例项目-5]

声网提供了开源的音视频互动示例项目供你参考，你可以前往下载或查看其中的源代码。

<Cards>
  <Card title={<RepositoryCardTitle provider="gitee">MediaPlayer</RepositoryCardTitle>} href="https://gitee.com/agoraio-community/Agora-Unity-Quickstart/blob/main/API-Example-Unity/Assets/API-Example/Examples/Advanced/MediaPlayer/MediaPlayerExample.cs" />
  <Card title={<RepositoryCardTitle provider="github">MediaPlayer</RepositoryCardTitle>} href="https://github.com/AgoraIO-Extensions/Agora-Unity-Quickstart/blob/main/API-Example-Unity/Assets/API-Example/Examples/Advanced/MediaPlayer/MediaPlayerExample.cs" />
</Cards>

### 支持的格式 [#支持的格式-4]

声网的媒体播放器支持下列格式及协议：

**视频编码格式**

- H.263、H.264、H.265、MPEG4、MPEG2、RMVB、Theora、VP3、VP8、AVS、WMV

**音频编码格式**

- WAV、MP2、MP3、AAC、OPUS、FLAC、Vorbis、AMR-NB、AMR-WB、WMA v1、WMA v2

**容器格式**

- WAV、FLAC、OGG、MOV、ASF、FLV、MP3、MP4、MPEG-TS、Matroska (MKV)、AVI、ASS、CONCAT、DTS、AVS

**支持的协议**

- HTTP、HTTPS、RTMP、HLS、RTP、RTSP

### API 参考 [#api-参考-5]

- [`IMediaPlayer`](/zh-CN/api-reference/rtc/unity/rtc-interface-class#class_imediaplayer)
- [`IMediaPlayerSourceObserver`](/zh-CN/api-reference/rtc/unity/rtc-interface-class#class_imediaplayersourceobserver)
- [`IMediaPlayerCacheManager`](/zh-CN/api-reference/rtc/unity/rtc-interface-class#class_imediaplayercachemanager)
<_PlatformProcessedMarker close="true" />

<_PlatformProcessedMarker groupMode="structured" canonicalPlatform="android" platform="react-native" />
本文介绍如何调用媒体播放器相关的 API 播放本地或在线媒体资源，或将媒体资源分享给声网频道内的远端用户。
## 前提条件 [#前提条件-6]

在进行操作之前，请确保你已经在项目中实现了基本的实时音视频功能。有关详细信息，请参考[实现音视频互动](/zh-CN/realtime-media/rtc/get-started/quick-start)。

## 实现方法 [#实现方法-6]

参考如下步骤，在你的项目中使用媒体播放器：

1. 初始化 `IRtcEngine` 后，创建一个 `IMediaPlayer` 对象。

    ```typescript
    // 创建并初始化引擎
    let rtcEngine = createAgoraRtcEngine();
    rtcEngine.initialize({
      appId,
    });
    // 创建媒体播放器对象
    let mediaPlayer = rtcEngine.createMediaPlayer();
    ```

2. 调用 `registerPlayerSourceObserver` 方法注册播放观测器。

    ```typescript
    // 注册播放观测器
    mediaPlayer.registerPlayerSourceObserver(this);
    ```

3. 根据你的需求，你可以注册以下媒体播放器观测器的回调：
    -  `onPlayerSourceStateChanged`：报告播放器状态改变。
    -  `onPositionChanged`：报告当前媒体文件的播放进度。
    -  `onPlayerEvent`：报告播放器事件。

    ```typescript
    const EventHandles = {
        // 报告播放器状态改变
        onPlayerSourceStateChanged: (state, ec) {
            console.log(`state:${state}, ec:${ec}`);
        };
        
        // 报告当前媒体文件的播放进度
        onPositionChanged: (position) {
            console.log(`position:${position}`);
        };
        
        // 报告播放器事件
        onPlayerEvent: (
            eventCode,
            elapsedTime,
            message
        ) {
            console.log(
            `eventCode:${eventCode},
            elapsedTime:${elapsedTime},
            message:${message}`
            );
        };
        };
    // 添加主回调事件
    rtcEngine.registerEventHandler(EventHandles);
    ```

4. 调用 `open` 打开本地或在线媒体文件。

    ```typescript
    open = () => {
    const url = 'https://example/video.mov';
    if (!url) {
        this.error("url is invalid");
    }
    mediaPlayer.open(url, 0);
    };
    ```

5. 调用 `play` 播放媒体文件。

    ```typescript
    // 播放媒体文件
    play = () => {
    const { position, duration } = this.state;
    if (position === duration && duration !== 0) {
        mediaPlayer.seek(0);
    } else {
        mediaPlayer.play();
    }
    };
    // 暂停播放媒体文件
    pause = () => {
    mediaPlayer.pause();
    };
    // 恢复播放媒体文件
    resume = () => {
    mediaPlayer.resume();
    };
    ```

6. 停止播放并释放资源。

    ```typescript
    // 停止播放
    mediaPlayer.stop();
    // 销毁媒体播放器
    rtcEngine.destroyMediaPlayer(this.player);
    // 取消注册播放观测器
    rtcEngine.unregisterEventHandler(this);
    ```

## 参考信息 [#参考信息-6]

### 示例项目 [#示例项目-6]

声网提供了开源的实现媒体播放器示例项目供你参考，你可以前往下载或查看其中的源代码。

<Cards>
  <Card title={<RepositoryCardTitle provider="gitee">MediaPlayer</RepositoryCardTitle>} href="https://gitee.com/agoraio-community/react-native-agora/tree/main/example/src/examples/advanced/MediaPlayer/MediaPlayer.tsx" />
  <Card title={<RepositoryCardTitle provider="github">MediaPlayer</RepositoryCardTitle>} href="https://github.com/AgoraIO-Extensions/react-native-agora/blob/main/examples/legacy/src/examples/advanced/MediaPlayer/MediaPlayer.tsx" />
</Cards>

### API 参考 [#api-参考-6]

- [`createMediaPlayer`](/zh-CN/api-reference/rtc/react-native/play/mediaplayer/mediaplayer-initialize#api_irtcengine_createmediaplayer)
- [`destroy`](/zh-CN/api-reference/rtc/react-native/play/mediaplayer/mediaplayer-initialize#api_irtcengine_destroymediaplayer)
- [`registerPlayerObserver`](/zh-CN/api-reference/rtc/react-native/play/mediaplayer/mediaplayer-observer#api_imediaplayer_registerplayersourceobserver)
- [`unRegisterPlayerObserver`](/zh-CN/api-reference/rtc/react-native/play/mediaplayer/mediaplayer-observer#api_imediaplayer_unregisterplayersourceobserver)
- [`getMediaPlayerId`](/zh-CN/api-reference/rtc/react-native/play/mediaplayer/mediaplayer-info#api_imediaplayer_getmediaplayerid)
- [`open`](/zh-CN/api-reference/rtc/react-native/play/mediaplayer/mediaplayer-open#api_imediaplayer_open)
- [`play`](/zh-CN/api-reference/rtc/react-native/play/mediaplayer/mediaplayer-control#api_imediaplayer_play)
- [`pause`](/zh-CN/api-reference/rtc/react-native/play/mediaplayer/mediaplayer-control#api_imediaplayer_pause)
- [`stop`](/zh-CN/api-reference/rtc/react-native/play/mediaplayer/mediaplayer-control#api_imediaplayer_stop)
- [`onPlayerEvent`](/zh-CN/api-reference/rtc/react-native/play/mediaplayer/mediaplayer-observer#callback_imediaplayersourceobserver_onplayerevent)
- [`onPlayerSourceStateChanged`](/zh-CN/api-reference/rtc/react-native/play/mediaplayer/mediaplayer-observer#callback_imediaplayersourceobserver_onplayersourcestatechanged)
- [`onPositionChanged`](/zh-CN/api-reference/rtc/react-native/play/mediaplayer/mediaplayer-observer#callback_imediaplayersourceobserver_onpositionchanged)
<_PlatformProcessedMarker close="true" />
</_PlatformTabsGroup>
