# Stream media to a channel (/en/realtime-media/video/build/capture-and-render-video/play-media/macos)

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

Playing media files during online business presentations, educational sessions, or casual meetups heightens user engagement. Video SDK enables you to add media playing functionality to your app.

    This page shows you how to use media player-related APIs to play local or online media resources with remote users in Video Calling channels.

    ## Understand the tech [#understand-the-tech-2]

    To play a media file in a channel, you open the file using a media player instance. When the file is ready to be played, you set up the local video container to display the media player output. You update channel media options to start publishing the media player stream, and stop publishing the camera and microphone streams. The remote user sees the camera and microphone streams of the media publishing user replaced by media streams.

    **Media player flow**

    ![Media player](https://assets-docs.agora.io/images/video-sdk/play-media.svg)

    ## Prerequisites [#prerequisites-2]

    Ensure that you have implemented the [SDK quickstart](/en/realtime-media/video/get-started-sdk) in your project.

    ## Implement the logic [#implement-the-logic-2]

    To implement a media player in your app, follow these steps:

    1. After initializing an instance of `AgoraRtcEngineKit`, create a `mediaPlayerKit` object.

       ```swift
       // Initialize AgoraRtcEngineKit and create a mediaPlayerKit object.
       agoraKit = AgoraRtcEngineKit.sharedEngine(with: config, delegate: self)
       // Create mediaPlayerKit object
       mediaPlayerKit = agoraKit.createMediaPlayer(with: self)
       ```

    2. Implement media player callbacks. Observe the status of the player through callbacks and obtain the playback progress of the current media file.

       ```swift
       extension MediaPlayerMain: AgoraRtcMediaPlayerDelegate {
         // Observe the state of the player
         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
             }
           }
         }
         // Observe the current playback progress
         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. Call the `setupLocalVideo` method to render the local media player view.

       ```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. When joining a channel using `joinChannelByToken`, set the media player ID, publish media player's audio and video, and share media resources with remote users in the channel through the `mediaOptions` parameter.

       ```swift
       let option1 = AgoraRtcChannelMediaOptions()
       ```

    // ...

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

    ````

    5. Use the `open` method to open a local or online media file.

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

    6. Call the `play` method to play the media file.

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

    <CalloutContainer type="warning">
      <CalloutDescription>
        Call the `play` method to play the media file only after receiving the `didChangedToState` callback reporting the player state as `AgoraMediaPlayerStateOpenCompleted`.
      </CalloutDescription>
    </CalloutContainer>

    7. When a user leaves the channel, call `stop` to stop playback, and `destroyMediaPlayer` to release resources.

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

    ## Reference [#reference-2]

    This section contains content that completes the information on this page, or points you to documentation that explains other aspects to this product.

    ### Supported formats and protocols [#supported-formats-and-protocols-2]

    The media player supports the following media formats and protocols:

    #### Video encoding formats [#video-encoding-formats-2]

    * H.263, H.264, H.265, MPEG-4, MPEG-2, RMVB, Theora, VP3, VP8, AVS, WMV

    #### Audio coding formats [#audio-coding-formats-2]

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

    #### Container formats [#container-formats-2]

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

    #### Supported protocols [#supported-protocols-2]

    * HTTP, HTTPS, RTMP, HLS, RTP, RTSP

    ### Sample project [#sample-project-2]

    Agora provides an open source sample project [MediaPlayer](https://github.com/AgoraIO/API-Examples/blob/main/macOS/APIExample/Examples/Advanced/MediaPlayer/MediaPlayer.swift) on GitHub. Download it or view the source code for a more detailed example.

    ### API reference [#api-reference-2]

    * [`createMediaPlayer(with:)`](https://api-ref.agora.io/en/video-sdk/macos/4.x/documentation/agorartckit/agorartcenginekit/createmediaplayer\(with:\))
    * [`getMediaPlayerId`](https://api-ref.agora.io/en/video-sdk/macos/4.x/documentation/agorartckit/agorartcmediaplayerprotocol/getmediaplayerid\(\))
    * [`open`](https://api-ref.agora.io/en/video-sdk/macos/4.x/documentation/agorartckit/agorartcmediaplayerprotocol/open\(_\:startpos:\))
    * [`play`](https://api-ref.agora.io/en/video-sdk/macos/4.x/documentation/agorartckit/agorartcmediaplayerprotocol/play\(\))
    * [`pause`](https://api-ref.agora.io/en/video-sdk/macos/4.x/documentation/agorartckit/agorartcmediaplayerprotocol/pause\(\))
    * [`stop`](https://api-ref.agora.io/en/video-sdk/macos/4.x/documentation/agorartckit/agorartcmediaplayerprotocol/stop\(\))
    * [`destroyMediaPlayer`](https://api-ref.agora.io/en/video-sdk/macos/4.x/documentation/agorartckit/agorartcenginekit/destroymediaplayer\(_:\))

    
  
      
  
      
  
      
  
      
  
