# Custom audio source (/en/realtime-media/video/build/customize-audio-processing/custom-audio/ios)

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

The default audio module of Video SDK meets the need of using basic audio functions in your app. For adding advanced audio functions, Video SDK supports using custom audio sources and custom audio rendering modules.

    Video SDK uses the basic audio module on the device your app runs on by default. However, there are certain use-cases where you want to integrate a custom audio source into your app, such as:

    * Your app has its own audio module.
    * You need to process the captured audio with a pre-processing library for audio enhancement.
    * You need flexible device resource allocation to avoid conflicts with other services.

    This page shows you how to capture and render audio from custom sources.

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

    To set an external audio source, you configure the Agora Engine before joining a channel. To manage the capture and processing of audio frames, you use methods from outside the Video SDK that are specific to your custom source. Video SDK enables you to push processed audio data to the subscribers in a channel.

    #### Capture custom audio [#capture-custom-audio-1]

    The following figure illustrates the process of custom audio capture.

    ![Audio data transmission](https://assets-docs.agora.io/images/video-sdk/audio-data-transmission.svg)

    * You implement the capture module using external methods provided by the SDK.

    * You call `pushExternalAudioFrame` to send the captured audio frames to the SDK.

    #### Render custom audio [#render-custom-audio-1]

    The following figure illustrates the process of custom audio rendering.

    ![Audio Data Transmission](https://assets-docs.agora.io/images/video-sdk/custom-audio-rendering-sdk.svg)

    * You implement the rendering module using external methods provided by the SDK.

    * You call `pullPlaybackAudioFrame` to retrieve the audio data sent by remote users.

    ## Prerequisites [#prerequisites-1]

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

    ## Implementation [#implementation-1]

    This section shows you how to implement custom audio capture and render audio from a custom source.

    ### Customize the audio source [#customize-the-audio-source]

    Refer to the following call sequence diagram to implement custom audio capture in your app:

    **Custom audio capture**

    ![Custom audio capture](https://assets-docs.agora.io/images/video-sdk/custom-audio-capture-with-custom-track.svg)

    Follow these steps to implement custom audio capture in your project:

    1. After initializing `AgoraRtcEngineKit`, call `createCustomAudioTrack` to create a custom audio track and retrieve the audio track ID.

       ```swift
       let audioTrack = AgoraAudioTrackConfig()
       audioTrack.enableLocalPlayback = true
       trackId = agoraKit.createCustomAudioTrack(.mixable, config: audioTrack)
       ```

    2. Use `joinChannelByToken` to join the channel. In `AgoraRtcChannelMediaOptions`, set the `publishCustomAudioTrackId` parameter to the audio track ID you obtained. Set `publishCustomAudioTrack` to `YES` to publish the custom audio track in the channel.

       <CalloutContainer type="warning">
         <CalloutDescription>
           To play an external audio source locally using `enableCustomAudioLocalPlayback`, or to adjust the local playback volume of a custom audio track using `adjustCustomAudioPlayoutVolume`, set `enableAudioRecordingOrPlayout` to `YES` in `AgoraRtcChannelMediaOptions`.
         </CalloutDescription>
       </CalloutContainer>

    ```swift
    let option = AgoraRtcChannelMediaOptions()
    // Disable microphone track
    option.publishMicrophoneTrack = false
    // Enable the custom audio track
    option.publishCustomAudioTrack = true
    // Set the custom audio track ID
    option.publishCustomAudioTrackId = Int(trackId)
    option.clientRoleType = GlobalSettings.shared.getUserRole()
    NetworkManager.shared.generateToken(channelName: channelName, success: { token in
      // Join the channel
      let result = self.agoraKit.joinChannel(byToken: token, channelId: channelName, uid: 0, mediaOptions: option)
      if result != 0 {
        self.showAlert(title: "Error", message: "Failed to join the channel: \(result). Check your parameters.")
      }
    })
    ```

    3. Implement the custom audio acquisition module

    Agora provides a sample project [CustomAudioSource.swift](https://github.com/AgoraIO/API-Examples/tree/main/iOS/APIExample/APIExample/Examples/Advanced/CustomAudioSource) to demonstrate how to read PCM audio data from a local file. In production, create a custom audio acquisition module tailored to your business needs.

    4. Call `pushExternalAudioFrameRawData` to send captured audio frames to the SDK via the custom audio track. Ensure `trackId` matches the one used when joining the channel in step 2. Set `sampleRate`, `channels`, and `samples` to configure the external audio frame.

       <CalloutContainer type="info">
         <CalloutDescription>
           * For audio-video synchronization, Agora recommends using `getCurrentMonotonicTimeInMs` to obtain the system’s monotonic time and set the `timestamp`.
           * To push audio frames in `CMSampleBuffer` format, use `pushExternalAudioFrameSampleBuffer`.
         </CalloutDescription>
       </CalloutContainer>

    ```swift
    extension CustomAudioSource: AgoraPcmSourcePushDelegate {
      func onAudioFrame(data: UnsafeMutablePointer<UInt8>) {
        agoraKit.pushExternalAudioFrameRawData(data,
                          samples: samples,
                          sampleRate: Int(sampleRate),
                          channels: Int(audioChannel),
                          trackId: Int(trackId),
                          timestamp: 0)
      }
    }
    ```

    5. To stop publishing custom audio, call `destroyCustomAudioTrack` to remove the custom audio track.

       ```swift
       agoraKit.destroyCustomAudioTrack(Int(trackId))
       ```

    ### Custom audio rendering [#custom-audio-rendering-1]

    This section shows you how to implement custom audio rendering.

    To retrieve audio data for playback, implement collection and processing of raw audio data. Refer to [Raw audio processing](stream-raw-audio.mdx).

    Follow these steps to call the raw audio data API in your project for custom audio rendering:

    1. Retrieve the audio data to be played from `onRecordAudioFrame`, `onPlaybackAudioFrame`, `onMixedAudioFrame`, or `onPlaybackAudioFrameBeforeMixing`.

    2. Independently render and play the audio data.

    ## Reference [#reference-1]

    This section explains how to implement different sound effects and audio mixing in your app, covering essential steps and code snippets.

    ### Sample projects [#sample-projects-1]

    Agora provides the following open-source sample projects for audio self-capture and audio self-rendering for your reference:

    * [CustomAudioSource](https://github.com/AgoraIO/API-Examples/tree/main/iOS/APIExample/APIExample/Examples/Advanced/CustomAudioSource)
    * [CustomAudioRender](https://github.com/AgoraIO/API-Examples/tree/main/iOS/APIExample/APIExample/Examples/Advanced/CustomAudioRender)

    ### API reference [#api-reference-1]

    * [`createCustomAudioTrack`](https://api-ref.agora.io/en/video-sdk/ios/4.x/documentation/agorartckit/agorartcenginekit/createcustomaudiotrack\(_\:config:\))
    * [`destroyCustomAudioTrack`](https://api-ref.agora.io/en/video-sdk/ios/4.x/documentation/agorartckit/agorartcenginekit/destroycustomaudiotrack\(_:\))
    * [`pushExternalAudioFrameSampleBuffer`](https://api-ref.agora.io/en/video-sdk/ios/4.x/documentation/agorartckit/agorartcmediaplayerprotocol/play\(\))
    * [`pushExternalAudioFrameRawData`](https://api-ref.agora.io/en/video-sdk/ios/4.x/documentation/agorartckit/agorartcenginekit/pushexternalaudioframesamplebuffer\(_:\))
    * [`enableExternalAudioSink`](https://api-ref.agora.io/en/video-sdk/ios/4.x/documentation/agorartckit/agorartcenginekit/enableexternalaudiosink\(_\:samplerate\:channels:\))
    * [`pullPlaybackAudioFrameRawData`](https://api-ref.agora.io/en/video-sdk/ios/4.x/documentation/agorartckit/agorartcenginekit/pullplaybackaudioframerawdata\(_\:lengthinbyte:\))

    
  
      
  
      
  
      
  
      
  
