# Raw audio processing (/en/realtime-media/broadcast-streaming/build/process-raw-and-custom-media/stream-raw-audio)

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

In some use-cases, raw audio captured through the microphone must be processed to enhance the user experience or achieve the desired functionality Video SDK enables you to pre-process and post-process the captured audio for implementation of custom playback effects.

<_PlatformTabsGroup groupMode="structured" canonicalPlatform="web" platforms="[&#x22;android&#x22;,&#x22;ios&#x22;,&#x22;macos&#x22;,&#x22;windows&#x22;,&#x22;web&#x22;,&#x22;electron&#x22;,&#x22;flutter&#x22;,&#x22;react-native&#x22;,&#x22;unity&#x22;]" showTabs="true">
  <_PlatformPanel platform="android">
    <_PlatformProcessedMarker groupMode="structured" canonicalPlatform="web" platform="android" />

    This article shows you how to pre-process and post-process collected raw audio data.

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

    For use-cases that require self-processing of audio data, Agora Video SDK provides raw data processing functionality. You can perform pre-processing to modify the captured audio signal before sending the data to the encoder, or post-process data to modify the received audio signal after sending the data to the decoder.

    To implement processing of raw audio data in your app, take the following steps.

    * Register an instance of the audio frame observer before joining a channel.
    * Set the format of audio frames captured by each callback.
    * Implement callbacks in the frame observers to process raw audio data.
    * Unregister the frame observers before you leave a channel.

    The following figure shows the basic processing of raw audio data:

    **Process raw audio**

    ![Raw Audio Processing](https://assets-docs.agora.io/images/video-sdk/process-raw-audio.svg)

    ## Prerequisites [#prerequisites]

    Ensure that you have implemented the [SDK quickstart](../../index) in your project.

    ## Implement raw audio processing [#implement-raw-audio-processing]

    Follow these steps to implement raw audio data processing functionality in your app:

    1. Before joining a channel, create an `IAudioFrameObserver` instance and call the `registerAudioFrameObserver` method to register the audio observer.
    2. Call `setRecordingAudioFrameParameters`, `setPlaybackAudioFrameParameters`, and `setMixedAudioFrameParameters` to configure the audio frame format.
    3. Implement `onRecordAudioFrame`, `onPlaybackAudioFrame`, `onPlaybackAudioFrameBeforeMixing`, and `onMixedAudioFrame` callbacks. These callbacks receive and process audio frames. If the return value of these callbacks is `false`, it indicates that the processing of the audio frames is invalid.

    Refer to the following sample code to implement this logic:

    <CodeBlockTabs defaultValue="java">
      <CodeBlockTabsList>
        <CodeBlockTabsTrigger value="java">
          Java
        </CodeBlockTabsTrigger>

        <CodeBlockTabsTrigger value="kotlin">
          Kotlin
        </CodeBlockTabsTrigger>
      </CodeBlockTabsList>

      <CodeBlockTab value="java">
        ```java
        // Call registerAudioFrameObserver to register an audio observer and pass in an IAudioFrameObserver instance
        engine.registerAudioFrameObserver(new IAudioFrameObserver() {
          // Implement the onRecordAudioFrame callback
          @Override
          public boolean onRecordAudioFrame(byte[] samples, int numOfSamples, int bytesPerSample, int channels, int samplesPerSec) {
            if(isEnableLoopBack){
              mAudioPlayer.play(samples, 0, numOfSamples * bytesPerSample);
            }

            return false;
          }

          // Implement the onPlaybackAudioFrame callback
          @Override
          public boolean onPlaybackAudioFrame(byte[] samples, int numOfSamples, int bytesPerSample, int channels, int samplesPerSec) {
            return false;
          }

          // Implement the onPlaybackAudioFrameBeforeMixing callback
          @Override
          public boolean onPlaybackAudioFrameBeforeMixing(byte[] samples, int numOfSamples, int bytesPerSample, int channels, int samplesPerSec, int uid) {
            return false;
          }

          // Implement the onMixedAudioFrame callback
          @Override
          public boolean onMixedAudioFrame(byte[] samples, int numOfSamples, int bytesPerSample, int channels, int samplesPerSec) {
            return false;
          }

          // Call methods with 'set' prefix to configure the audio frames captured by each callback
          engine.setRecordingAudioFrameParameters(SAMPLE_RATE, SAMPLE_NUM_OF_CHANNEL, Constants.RAW_AUDIO_FRAME_OP_MODE_READ_WRITE, SAMPLES_PER_CALL);
          engine.setMixedAudioFrameParameters(SAMPLE_RATE, SAMPLES_PER_CALL);
          engine.setPlaybackAudioFrameParameters(SAMPLE_RATE, SAMPLE_NUM_OF_CHANNEL, Constants.RAW_AUDIO_FRAME_OP_MODE_READ_WRITE, SAMPLES_PER_CALL);
        });
        ```
      </CodeBlockTab>

      <CodeBlockTab value="kotlin">
        ```kotlin
        // Register an audio frame observer using registerAudioFrameObserver with an IAudioFrameObserver instance
        engine.registerAudioFrameObserver(object : IAudioFrameObserver {

          // Implement the onRecordAudioFrame callback
          override fun onRecordAudioFrame(
            samples: ByteArray,
            numOfSamples: Int,
            bytesPerSample: Int,
            channels: Int,
            samplesPerSec: Int
          ): Boolean {
            if (isEnableLoopBack) {
              mAudioPlayer.play(samples, 0, numOfSamples * bytesPerSample)
            }
            return false
          }

          // Implement the onPlaybackAudioFrame callback
          override fun onPlaybackAudioFrame(
            samples: ByteArray,
            numOfSamples: Int,
            bytesPerSample: Int,
            channels: Int,
            samplesPerSec: Int
          ): Boolean {
            return false
          }

          // Implement the onPlaybackAudioFrameBeforeMixing callback
          override fun onPlaybackAudioFrameBeforeMixing(
            samples: ByteArray,
            numOfSamples: Int,
            bytesPerSample: Int,
            channels: Int,
            samplesPerSec: Int,
            uid: Int
          ): Boolean {
            return false
          }

          // Implement the onMixedAudioFrame callback
          override fun onMixedAudioFrame(
            samples: ByteArray,
            numOfSamples: Int,
            bytesPerSample: Int,
            channels: Int,
            samplesPerSec: Int
          ): Boolean {
            return false
          }
        })

        // Call methods with 'set' prefix to configure the audio frames captured by each callback
        engine.setRecordingAudioFrameParameters(SAMPLE_RATE, SAMPLE_NUM_OF_CHANNEL, Constants.RAW_AUDIO_FRAME_OP_MODE_READ_WRITE, SAMPLES_PER_CALL)
        engine.setMixedAudioFrameParameters(SAMPLE_RATE, SAMPLES_PER_CALL)
        engine.setPlaybackAudioFrameParameters(SAMPLE_RATE, SAMPLE_NUM_OF_CHANNEL, Constants.RAW_AUDIO_FRAME_OP_MODE_READ_WRITE, SAMPLES_PER_CALL)
        ```
      </CodeBlockTab>
    </CodeBlockTabs>

    <CalloutContainer type="info">
      <CalloutDescription>
        Video SDK uses a synchronous callback mechanism for processing raw audio data. When you save or rewrite data using the callbacks, consider the following best practices:

        * To ensure continuity of the audio stream, do not block the SDK thread by processing data directly in the callback function. Instead, make a deep copy of the received audio data and transfer the copied data to another thread for processing.
        * If you choose to process the audio data synchronously within the callback function, you must strictly control the processing time. For example, if the callback function is triggered every 10 milliseconds, then the processing time within the callback must be less than 10 milliseconds to prevent delays or interruptions in the audio stream.
      </CalloutDescription>
    </CalloutContainer>

    ## Reference [#reference]

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

    * [Audio module](../../core-concepts)

    ### Sample project [#sample-project]

    Agora provides an open-source example project [ProcessAudioRawData](https://github.com/AgoraIO/API-Examples/blob/main/Android/APIExample/app/src/main/java/io/agora/api/example/examples/advanced/ProcessAudioRawData.java) for your reference. Download or view the project for a more detailed example.

    ### API reference [#api-reference]

    * [`registerAudioFrameObserver`](https://api-ref.agora.io/en/video-sdk/android/4.x/API/class_irtcengine.html#api_imediaengine_registeraudioframeobserver)
    * [`setRecordingAudioFrameParameters`](https://api-ref.agora.io/en/video-sdk/android/4.x/API/class_irtcengine.html#api_irtcengine_setrecordingaudioframeparameters)
    * [`setPlaybackAudioFrameParameters`](https://api-ref.agora.io/en/video-sdk/android/4.x/API/class_irtcengine.html#api_irtcengine_setplaybackaudioframeparameters)
    * [`setMixedAudioFrameParameters`](https://api-ref.agora.io/en/video-sdk/android/4.x/API/class_irtcengine.html#api_irtcengine_setmixedaudioframeparameters)
    * [`onRecordAudioFrame`](https://api-ref.agora.io/en/video-sdk/android/4.x/API/class_iaudioframeobserver_2.html#callback_iaudioframeobserverbase_onrecordaudioframe)
    * [`onPlaybackAudioFrame`](https://api-ref.agora.io/en/video-sdk/android/4.x/API/class_iaudioframeobserver_2.html#callback_iaudioframeobserverbase_onplaybackaudioframe)
    * [`onplaybackaudioframebeforemixing`](https://api-ref.agora.io/en/video-sdk/android/4.x/API/class_iaudioframeobserver_2.html#callback_iaudioframeobserver_onplaybackaudioframebeforemixing)
    * [`onMixedAudioFrame`](https://api-ref.agora.io/en/video-sdk/android/4.x/API/class_iaudioframeobserver_2.html#callback_iaudioframeobserverbase_onmixedaudioframe)

    <_PlatformProcessedMarker close="true" />
  </_PlatformPanel>

  <_PlatformPanel platform="ios">
    <_PlatformProcessedMarker groupMode="structured" canonicalPlatform="web" platform="ios" />

    This article shows you how to pre-process and post-process collected raw audio data.

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

    For use-cases that require self-processing of audio data, Agora Video SDK provides raw data processing functionality. You can perform pre-processing to modify the captured audio signal before sending the data to the encoder, or post-process data to modify the received audio signal after sending the data to the decoder.

    To implement processing of raw audio data in your app, take the following steps.

    * Register an instance of the audio frame observer before joining a channel.
    * Set the format of audio frames captured by each callback.
    * Implement callbacks in the frame observers to process raw audio data.
    * Unregister the frame observers before you leave a channel.

    The following figure shows the basic processing of raw audio data:

    **Process raw audio**

    ![Raw Audio Processing](https://assets-docs.agora.io/images/video-sdk/process-raw-audio.svg)

    ## Prerequisites [#prerequisites-1]

    Ensure that you have implemented the [SDK quickstart](../../index) in your project.

    ## Implement raw audio processing [#implement-raw-audio-processing-1]

    Follow these steps to implement raw audio data processing functionality in your app:

    1. Before joining a channel, call `setAudioFrameDelegate` to set the audio frame delegate.
    2. Call `setRecordingAudioFrameParameters`, `setPlaybackAudioFrameParameters`, and `setMixedAudioFrameParameters` to configure the audio frame format.
    3. Implement `onRecordAudioFrame`, `onPlaybackAudioFrame`, `onPlaybackAudioFrameBeforeMixing`, and `onMixedAudioFrame` callbacks. These callbacks receive and process audio frames. If the return value of these callbacks is `false`, it indicates that the processing of the audio frames is invalid.

    Refer to the following sample code to implement this logic:

    ```swift
    class RawAudioDataMain: BaseViewController {
      var localVideo = Bundle.loadVideoView(type: .local, audioOnly: true)
      var remoteVideo = Bundle.loadVideoView(type: .remote, audioOnly: true)

      @IBOutlet weak var container: AGEVideoContainer!
      // Define agoraKit variable
      var agoraKit: AgoraRtcEngineKit!

      // ...
      // Initialize agoraKit and register the corresponding callbacks
      agoraKit = AgoraRtcEngineKit.sharedEngine(with: config, delegate: self)

      // Set the audio frame delegate.
      // You need to implement the AgoraAudioFrameDelegate protocol in this method
      agoraKit.setAudioFrameDelegate(self)

      // Configure the audio frames captured by each callback
      agoraKit.setRecordingAudioFrameParametersWithSampleRate(44100, channel: 1, mode: .readWrite, samplesPerCall: 4410)
      agoraKit.setMixedAudioFrameParametersWithSampleRate(44100, samplesPerCall: 4410)
      agoraKit.setPlaybackAudioFrameParametersWithSampleRate(44100, channel: 1, mode: .readWrite, samplesPerCall: 4410)

      // ...

      // Under the current class, implement the extension of the AgoraAudioFrameDelegat protocol
      extension RawAudioDataMain: AgoraAudioFrameDelegate {

        // Implement the onRecordAudioFrame callback
        func onRecordAudioFrame(_ frame: AgoraAudioFrame, channelId: String) -> Bool {
          return true
        }
        // Implement the onPlaybackAudioFrame callback
        func onPlaybackAudioFrame(_ frame: AgoraAudioFrame, channelId: String) -> Bool {
          return true
        }
        // Implement the onMixedAudioFrame callback
        func onMixedAudioFrame(_ frame: AgoraAudioFrame, channelId: String) -> Bool {
          return true
        }
        // Implement the onPlaybackAudioFrameBeforeMixing callback
        func onPlaybackAudioFrame(beforeMixing frame: AgoraAudioFrame, channelId: String, uid: UInt) -> Bool {
          return true
        }
      }
    }
    ```

    <CalloutContainer type="info">
      <CalloutDescription>
        Video SDK uses a synchronous callback mechanism for processing raw audio data. When you save or rewrite data using the callbacks, consider the following best practices:

        * To ensure continuity of the audio stream, do not block the SDK thread by processing data directly in the callback function. Instead, make a deep copy of the received audio data and transfer the copied data to another thread for processing.
        * If you choose to process the audio data synchronously within the callback function, you must strictly control the processing time. For example, if the callback function is triggered every 10 milliseconds, then the processing time within the callback must be less than 10 milliseconds to prevent delays or interruptions in the audio stream.
      </CalloutDescription>
    </CalloutContainer>

    ## Reference [#reference-1]

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

    * [Audio module](../../core-concepts)

    ### Sample project [#sample-project-1]

    Agora provides an open-source example project [RawAudioData](https://github.com/AgoraIO/API-Examples/blob/main/iOS/APIExample/APIExample/Examples/Advanced/RawAudioData/RawAudioData.swift) for your reference. Download or view the project for a more detailed example.

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

    * [`setAudioFrameDelegate`](https://api-ref.agora.io/en/video-sdk/ios/4.x/documentation/agorartckit/agorartcenginekit/setaudioframedelegate\(_:\))
    * [`setRecordingAudioFrameParametersWithSampleRate`](https://api-ref.agora.io/en/video-sdk/ios/4.x/documentation/agorartckit/agorartcenginekit/setrecordingaudioframeparameterswithsamplerate\(_\:channel\:mode\:samplespercall:\))
    * [`setPlaybackAudioFrameParametersWithSampleRate`](https://api-ref.agora.io/en/video-sdk/ios/4.x/documentation/agorartckit/agorartcenginekit/setplaybackaudioframeparameterswithsamplerate\(_\:channel\:mode\:samplespercall:\))
    * [`setMixedAudioFrameParametersWithSampleRate`](https://api-ref.agora.io/en/video-sdk/ios/4.x/documentation/agorartckit/agorartcenginekit/setmixedaudioframeparameterswithsamplerate\(_\:channel\:samplespercall:\))
    * [`onRecordAudioFrame`](https://api-ref.agora.io/en/video-sdk/ios/4.x/documentation/agorartckit/agoraaudioframedelegate/onrecordaudioframe\(_\:channelid:\))
    * [`onPlaybackAudioFrame`](https://api-ref.agora.io/en/video-sdk/ios/4.x/documentation/agorartckit/agoraaudioframedelegate/onplaybackaudioframe\(_\:channelid:\))
    * [`onPlaybackAudioFrameBeforeMixing`](https://api-ref.agora.io/en/video-sdk/ios/4.x/documentation/agorartckit/agoraaudioframedelegate/onplaybackaudioframe\(beforemixing\:channelid\:uid:\))
    * [`onMixedAudioFrame`](https://api-ref.agora.io/en/video-sdk/ios/4.x/documentation/agorartckit/agoraaudioframedelegate/onmixedaudioframe\(_\:channelid:\))

    <_PlatformProcessedMarker close="true" />
  </_PlatformPanel>

  <_PlatformPanel platform="macos">
    <_PlatformProcessedMarker groupMode="structured" canonicalPlatform="web" platform="macos" />

    This article shows you how to pre-process and post-process collected raw audio data.

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

    For use-cases that require self-processing of audio data, Agora Video SDK provides raw data processing functionality. You can perform pre-processing to modify the captured audio signal before sending the data to the encoder, or post-process data to modify the received audio signal after sending the data to the decoder.

    To implement processing of raw audio data in your app, take the following steps.

    * Register an instance of the audio frame observer before joining a channel.
    * Set the format of audio frames captured by each callback.
    * Implement callbacks in the frame observers to process raw audio data.
    * Unregister the frame observers before you leave a channel.

    The following figure shows the basic processing of raw audio data:

    **Process raw audio**

    ![Raw Audio Processing](https://assets-docs.agora.io/images/video-sdk/process-raw-audio.svg)

    ## Prerequisites [#prerequisites-2]

    Ensure that you have implemented the [SDK quickstart](../../index) in your project.

    ## Implement raw audio processing [#implement-raw-audio-processing-2]

    Follow these steps to implement raw audio data processing functionality in your app:

    1. Before joining a channel, call `setAudioFrameDelegate` to set the audio frame delegate.
    2. Call `setRecordingAudioFrameParameters`, `setPlaybackAudioFrameParameters`, and `setMixedAudioFrameParameters` to configure the audio frame format.
    3. Implement `onRecordAudioFrame`, `onPlaybackAudioFrame`, `onPlaybackAudioFrameBeforeMixing`, and `onMixedAudioFrame` callbacks. These callbacks receive and process audio frames. If the return value of these callbacks is `false`, it indicates that the processing of the audio frames is invalid.

    Refer to the following sample code to implement this logic:

    ```swift

    class RawAudioDataMain: BaseViewController
    {
      var localVideo = Bundle.loadVideoView(type: .local, audioOnly: true)
      var remoteVideo = Bundle.loadVideoView(type: .remote, audioOnly: true)

      @IBOutlet weak var container: AGEVideoContainer!
      // Define the agoraKit variable
      var agoraKit: AgoraRtcEngineKit!

      // ...
      // Initialize agoraKit and register the corresponding callbacks
      agoraKit = AgoraRtcEngineKit.sharedEngine(with: config, delegate: self)

      // Set the audio frame delegate.
      // You need to implement the AgoraAudioFrameDelegate protocol in this method
      agoraKit.setAudioFrameDelegate(self)

      // Configure the audio frames captured by each callback
      agoraKit.setRecordingAudioFrameParametersWithSampleRate(44100, channel: 1, mode: .readWrite, samplesPerCall: 4410)
      agoraKit.setMixedAudioFrameParametersWithSampleRate(44100, samplesPerCall: 4410)
      agoraKit.setPlaybackAudioFrameParametersWithSampleRate(44100, channel: 1, mode: .readWrite, samplesPerCall: 4410)

      // ...

      // In the current class, implement an extension for the AgoraAudioFrameDelegate protocol
      extension RawAudioDataMain: AgoraAudioFrameDelegate {

        // Implement the onRecordAudioFrame callback
        func onRecordAudioFrame(_ frame: AgoraAudioFrame, channelId: String) -> Bool {
          return true
        }
        // Implement the onPlaybackAudioFrame callback
        func onPlaybackAudioFrame(_ frame: AgoraAudioFrame, channelId: String) -> Bool {
          return true
        }
        // Implement the onMixedAudioFrame callback
        func onMixedAudioFrame(_ frame: AgoraAudioFrame, channelId: String) -> Bool {
          return true
        }
        // Implement the onPlaybackAudioFrameBeforeMixing callback
      func onPlaybackAudioFrame(beforeMixing frame: AgoraAudioFrame, channelId: String, uid: UInt) -> Bool {
          return true
        }
      }
    }
    ```

    <CalloutContainer type="info">
      <CalloutDescription>
        Video SDK uses a synchronous callback mechanism for processing raw audio data. When you save or rewrite data using the callbacks, consider the following best practices:

        * To ensure continuity of the audio stream, do not block the SDK thread by processing data directly in the callback function. Instead, make a deep copy of the received audio data and transfer the copied data to another thread for processing.
        * If you choose to process the audio data synchronously within the callback function, you must strictly control the processing time. For example, if the callback function is triggered every 10 milliseconds, then the processing time within the callback must be less than 10 milliseconds to prevent delays or interruptions in the audio stream.
      </CalloutDescription>
    </CalloutContainer>

    ## 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.

    * [Audio module](../../core-concepts)

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

    Agora provides an open-source example project [RawAudioData](https://github.com/AgoraIO/API-Examples/blob/main/iOS/APIExample/APIExample/Examples/Advanced/RawAudioData/RawAudioData.swift) for your reference. Download or view the project for a more detailed example.

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

    * [`setAudioFrameDelegate`](https://api-ref.agora.io/en/video-sdk/macos/4.x/documentation/agorartckit/agorartcenginekit/setaudioframedelegate\(_:\))
    * [`setRecordingAudioFrameParametersWithSampleRate`](https://api-ref.agora.io/en/video-sdk/macos/4.x/documentation/agorartckit/agorartcenginekit/setrecordingaudioframeparameterswithsamplerate\(_\:channel\:mode\:samplespercall:\))
    * [`setPlaybackAudioFrameParametersWithSampleRate`](https://api-ref.agora.io/en/video-sdk/macos/4.x/documentation/agorartckit/agorartcenginekit/setplaybackaudioframeparameterswithsamplerate\(_\:channel\:mode\:samplespercall:\))
    * [`setMixedAudioFrameParametersWithSampleRate`](https://api-ref.agora.io/en/video-sdk/macos/4.x/documentation/agorartckit/agorartcenginekit/setmixedaudioframeparameterswithsamplerate\(_\:channel\:samplespercall:\))
    * [`onRecordAudioFrame`](https://api-ref.agora.io/en/video-sdk/macos/4.x/documentation/agorartckit/agoraaudioframedelegate/onrecordaudioframe\(_\:channelid:\))
    * [`onPlaybackAudioFrame`](https://api-ref.agora.io/en/video-sdk/macos/4.x/documentation/agorartckit/agoraaudioframedelegate/onplaybackaudioframe\(_\:channelid:\))
    * [`onPlaybackAudioframeBeforeMixing`](https://api-ref.agora.io/en/video-sdk/macos/4.x/documentation/agorartckit/agoraaudioframedelegate/onplaybackaudioframe\(beforemixing\:channelid\:uid:\))
    * [`onMixedAudioFrame`](https://api-ref.agora.io/en/video-sdk/macos/4.x/documentation/agorartckit/agoraaudioframedelegate/onmixedaudioframe\(_\:channelid:\))

    <_PlatformProcessedMarker close="true" />
  </_PlatformPanel>

  <_PlatformPanel platform="windows">
    <_PlatformProcessedMarker groupMode="structured" canonicalPlatform="web" platform="windows" />

    This article shows you how to pre-process and post-process collected raw audio data.

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

    For use-cases that require self-processing of audio data, Agora Video SDK provides raw data processing functionality. You can perform pre-processing to modify the captured audio signal before sending the data to the encoder, or post-process data to modify the received audio signal after sending the data to the decoder.

    To implement processing of raw audio data in your app, take the following steps.

    * Register an instance of the audio frame observer before joining a channel.
    * Set the format of audio frames captured by each callback.
    * Implement callbacks in the frame observers to process raw audio data.
    * Unregister the frame observers before you leave a channel.

    The following figure shows the basic processing of raw audio data:

    **Process raw audio**

    ![Raw Audio Processing](https://assets-docs.agora.io/images/video-sdk/process-raw-audio.svg)

    ## Prerequisites [#prerequisites-3]

    Ensure that you have implemented the [SDK quickstart](../../index) in your project.

    ## Implement raw audio processing [#implement-raw-audio-processing-3]

    Follow these steps to implement raw audio data processing functionality in your app:

    1. Before joining a channel, create an `IAudioFrameObserver` instance and call the `registerAudioFrameObserver` method to register the audio frame observer.
    2. Call `setRecordingAudioFrameParameters`, `setPlaybackAudioFrameParameters`, and `setMixedAudioFrameParameters` methods to configure the audio frame format.
    3. Implement `onRecordAudioFrame`, `onPlaybackAudioFrame`, `onPlaybackAudioFrameBeforeMixing`, and `onMixedAudioFrame` callbacks. These callbacks receive and process audio frames. If the return value of these callbacks is `false`, it indicates that the processing of the audio frames is invalid.

    Refer to the following sample code to implement this logic:

    ```cpp
    BOOL CAgoraOriginalAudioDlg::RegisterAudioFrameObserver(
      BOOL bEnable, IAudioFrameObserver *audioFrameObserver) {

      agora::util::AutoPtr<agora::media::IMediaEngine> mediaEngine;
      // Query AGORA_IID_MEDIA_ENGINE interface
      mediaEngine.queryInterface(m_rtcEngine, agora::rtc::AGORA_IID_MEDIA_ENGINE);
      int nRet = 0;

      if (mediaEngine.get() == NULL) return FALSE;

      if (bEnable) {
        // Register the audio observer
        nRet = mediaEngine->registerAudioFrameObserver(audioFrameObserver);
      } else {
        // Unregister the audio observer
        nRet = mediaEngine->registerAudioFrameObserver(NULL);
      }

      return nRet == 0 ? TRUE : FALSE;
    }

    // Implement the onRecordAudioFrame callback
    bool COriginalAudioProcFrameObserver::onRecordAudioFrame(const char* channelId,
                                 AudioFrame& audioFrame) {
      SIZE_T nSize = audioFrame.channels * audioFrame.samplesPerChannel * 2;
      unsigned int readByte = 0;
      int timestamp = GetTickCount();
      short *pBuffer = (short *)audioFrame.buffer;

      for (SIZE_T i = 0; i < nSize / 2; i++) {
        if (pBuffer[i] * 2 > 32767) {
          pBuffer[i] = 32767;
        } else if (pBuffer[i] * 2 < -32768) {
          pBuffer[i] = -32768;
        } else {
          pBuffer[i] *= 2;
        }
      }

    #ifdef _DEBUG
      CString strInfo;
      strInfo.Format(_T("audio Frame buffer size:%d, timestamp:%d \n"), nSize, timestamp);
      OutputDebugString(strInfo);
      audioFrame.renderTimeMs = timestamp;
    #endif

      return true;
    }

    // Implement the onPlaybackAudioFrame callback
    bool COriginalAudioProcFrameObserver::onPlaybackAudioFrame(
      const char* channelId, AudioFrame& audioFrame) {
      return true;
    }

    // Implement the onMixedAudioFrame callback
    bool COriginalAudioProcFrameObserver::onMixedAudioFrame(const char* channelId, AudioFrame& audioFrame) {
      return true;
    }

    // Implement the onPlaybackAudioFrameBeforeMixing callback
    bool COriginalAudioProcFrameObserver::onPlaybackAudioFrameBeforeMixing(const char* channelId, rtc::uid_t uid, AudioFrame& audioFrame) {
      return true;
    }

    // Configure the audio frames captured by each callback
    m_rtcEngine->setRecordingAudioFrameParameters(44100, 2, RAW_AUDIO_FRAME_OP_MODE_READ_WRITE, 1024);
    m_rtcEngine->setPlaybackAudioFrameParameters(44100, 2, RAW_AUDIO_FRAME_OP_MODE_READ_WRITE, 1024);
    m_rtcEngine->setPlaybackAudioFrameBeforeMixingParameters(44100, 2);
    m_rtcEngine->setMixedAudioFrameParameters(44100, 2, 1024);
    ```

    <CalloutContainer type="info">
      <CalloutDescription>
        Video SDK uses a synchronous callback mechanism for processing raw audio data. When you save or rewrite data using the callbacks, consider the following best practices:

        * To ensure continuity of the audio stream, do not block the SDK thread by processing data directly in the callback function. Instead, make a deep copy of the received audio data and transfer the copied data to another thread for processing.
        * If you choose to process the audio data synchronously within the callback function, you must strictly control the processing time. For example, if the callback function is triggered every 10 milliseconds, then the processing time within the callback must be less than 10 milliseconds to prevent delays or interruptions in the audio stream.
      </CalloutDescription>
    </CalloutContainer>

    ## Reference [#reference-3]

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

    * [Audio module](../../core-concepts)

    ### Sample project [#sample-project-3]

    Agora provides an open-source example project [ProcessRawAudioData](https://gitee.com/agoraio-community/API-Examples/tree/main/windows/APIExample/APIExample/Advanced/OriginalAudio) for your reference. Download or view the project for a more detailed example.

    ### API reference [#api-reference-3]

    * [`registerAudioFrameObserver`](https://api-ref.agora.io/en/video-sdk/cpp/4.x/API/class_imediaengine.html#api_imediaengine_registeraudioframeobserver)
    * [`setRecordingAudioFrameParameters`](https://api-ref.agora.io/en/video-sdk/cpp/4.x/API/class_irtcengine.html#api_irtcengine_setrecordingaudioframeparameters)
    * [`setPlaybackAudioFrameParameters`](https://api-ref.agora.io/en/video-sdk/cpp/4.x/API/class_irtcengine.html#api_irtcengine_setplaybackaudioframeparameters)
    * [`setMixedAudioFrameParameters`](https://api-ref.agora.io/en/video-sdk/cpp/4.x/API/class_irtcengine.html#api_irtcengine_setmixedaudioframeparameters)
    * [`setPlaybackAudioFrameBeforeMixingParameters`](https://api-ref.agora.io/en/video-sdk/cpp/4.x/API/class_irtcengine.html#api_irtcengine_setplaybackaudioframebeforemixingparameters)
    * [`onRecordAudioFrame`](https://api-ref.agora.io/en/video-sdk/cpp/4.x/API/class_iaudioframeobserverbase.html#callback_iaudioframeobserverbase_onrecordaudioframe)
    * [`onPlaybackAudioFrame`](https://api-ref.agora.io/en/video-sdk/cpp/4.x/API/class_iaudioframeobserverbase.html#callback_iaudioframeobserverbase_onplaybackaudioframe)
    * [`onPlaybackAudioFrameBeforeMixing`](https://api-ref.agora.io/en/video-sdk/cpp/4.x/API/callback_iaudioframeobserver_onplaybackaudioframebeforemixing.html)
    * [`onMixedAudioFrame`](https://api-ref.agora.io/en/video-sdk/cpp/4.x/API/class_iaudioframeobserverbase.html#callback_iaudioframeobserverbase_onmixedaudioframe)

    <_PlatformProcessedMarker close="true" />
  </_PlatformPanel>

  <_PlatformPanel platform="web">
    <_PlatformProcessedMarker groupMode="structured" canonicalPlatform="web" platform="web" />

    This article shows you how to pre-process and post-process collected raw audio data.

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

    For use-cases that require self-processing of audio data, use the [Web Audio API](https://developer.mozilla.org/en-US/docs/Web/API/Web_Audio_API) with Agora Video SDK to enable raw audio data processing. The Web Audio API allows you to modify the captured audio signal before transmitting it to the channel.

    The following figure shows the basic processing of raw audio data:

    **Process raw audio**

    ![Raw Audio Processing](https://assets-docs.agora.io/images/video-sdk/process-raw-audio-web.svg)

    ## Prerequisites [#prerequisites-4]

    Ensure that you have implemented the [SDK quickstart](../../index) in your project.

    ## Implement raw audio processing [#implement-raw-audio-processing-4]

    To modify raw audio frames before publishing, follow these steps:

    1. Create a local audio track and publish it to the channel.
    2. Use the Web Audio API to create an `AudioContext` and connect the audio track to an `AnalyserNode`.
    3. Extract audio data using an `AnalyserNode` and process it.

    The following example extracts the audio data and logs it to the console.

    ```js
    async function createAndProcessAudioTrack() {
      try {
        // Create a microphone audio track
        localAudioTrack = await AgoraRTC.createMicrophoneAudioTrack();

        // Publish the audio track to the RTC client
        await client.publish([localAudioTrack]);

        // Initialize the Web Audio API context for audio processing
        audioContext = new AudioContext();

        // Create a media stream source from the microphone track
        const source = audioContext.createMediaStreamSource(
          new MediaStream([localAudioTrack.getMediaStreamTrack()])
        );

        // Create an AnalyserNode to extract real-time audio frequency data
        analyser = audioContext.createAnalyser();
        analyser.fftSize = 2048;

        // Create a buffer to store the frequency data
        dataArray = new Uint8Array(analyser.frequencyBinCount);

        // Connect the audio source to the analyser
        source.connect(analyser);

        // Start continuously processing audio frames
        processAudioFrames();
      } catch (error) {
        console.error('Error creating or processing audio track:', error);
      }
    }

    function processAudioFrames() {
      if (!analyser) {
        console.warn('Analyser not initialized.');
        return;
      }

      // Retrieve frequency data from the analyser node
      analyser.getByteFrequencyData(dataArray);
      console.log('Audio Data:', dataArray);

      // Schedule the next frame for continuous audio analysis
      animationFrameId = requestAnimationFrame(processAudioFrames);
    }
    ```

    ## Reference [#reference-4]

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

    ### API reference [#api-reference-4]

    * [`createMicrophoneAudioTrack`](https://api-ref.agora.io/en/video-sdk/web/4.x/interfaces/iagorartc.html#createcustomvideotrack)
    * [`publish`](https://api-ref.agora.io/en/video-sdk/web/4.x/interfaces/iagorartcclient.html#publish)

    <_PlatformProcessedMarker close="true" />
  </_PlatformPanel>

  <_PlatformPanel platform="electron">
    <_PlatformProcessedMarker groupMode="structured" canonicalPlatform="web" platform="electron" />

    **This feature implementation is not yet available for Electron.**

    <_PlatformProcessedMarker close="true" />
  </_PlatformPanel>

  <_PlatformPanel platform="flutter">
    <_PlatformProcessedMarker groupMode="structured" canonicalPlatform="web" platform="flutter" />

    **This feature implementation is not yet available for Flutter.**

    <_PlatformProcessedMarker close="true" />
  </_PlatformPanel>

  <_PlatformPanel platform="react-native">
    <_PlatformProcessedMarker groupMode="structured" canonicalPlatform="web" platform="react-native" />

    **This feature implementation is not yet available for React Native.**

    <_PlatformProcessedMarker close="true" />
  </_PlatformPanel>

  <_PlatformPanel platform="unity">
    <_PlatformProcessedMarker groupMode="structured" canonicalPlatform="web" platform="unity" />

    This article shows you how to pre-process and post-process collected raw audio data.

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

    For use-cases that require self-processing of audio data, Agora Video SDK provides raw data processing functionality. You can perform pre-processing to modify the captured audio signal before sending the data to the encoder, or post-process data to modify the received audio signal after sending the data to the decoder.

    To implement processing of raw audio data in your game, take the following steps.

    * Register an instance of the audio frame observer before joining a channel.
    * Set the format of audio frames captured by each callback.
    * Implement callbacks in the frame observers to process raw audio data.
    * Unregister the frame observers before you leave a channel.

    The following figure shows the basic processing of raw audio data:

    **Process raw audio**

    ![Raw Audio Processing](https://assets-docs.agora.io/images/video-sdk/process-raw-audio.svg)

    ## Prerequisites [#prerequisites-5]

    Ensure that you have implemented the [SDK quickstart](../../index) in your project.

    ## Implement raw audio processing [#implement-raw-audio-processing-5]

    Follow these steps to implement raw audio data processing functionality in your game:

    1. Before joining a channel, create an `IAudioFrameObserver` instance and call `RegisterAudioFrameObserver` to register the audio observer. To process and write back the audio data, set `mode` to `INTPTR`.
    2. Call `SetRecordingAudioFrameParameters`, `SetPlaybackAudioFrameParameters`, and `SetMixedAudioFrameParameters` to configure the desired audio frame format.
    3. Implement the following callbacks to collect and process audio frames:

       * `OnRecordAudioFrame`
       * `OnPlaybackAudioFrame`
       * `OnPlaybackAudioFrameBeforeMixing`
       * `OnMixedAudioFrame`

    Refer to the following sample code to implement this logic:

    ```csharp
    // Register the audio observer
    // Set the mode to INTPTR to process and write back audio data
    RtcEngine.RegisterAudioFrameObserver(new AudioFrameObserver(this),
      AUDIO_FRAME_POSITION.AUDIO_FRAME_POSITION_PLAYBACK |
      AUDIO_FRAME_POSITION.AUDIO_FRAME_POSITION_RECORD |
      AUDIO_FRAME_POSITION.AUDIO_FRAME_POSITION_MIXED |
      AUDIO_FRAME_POSITION.AUDIO_FRAME_POSITION_BEFORE_MIXING |
      AUDIO_FRAME_POSITION.AUDIO_FRAME_POSITION_EAR_MONITORING,
      OBSERVER_MODE.INTPTR);

    int CHANNEL = 2;
    int SAMPLE_RATE = 48000;

    // Configure the playback audio frame format
    RtcEngine.SetPlaybackAudioFrameParameters(SAMPLE_RATE, CHANNEL, RAW_AUDIO_FRAME_OP_MODE_TYPE.RAW_AUDIO_FRAME_OP_MODE_READ_WRITE, 1024);

    // Configure the recording audio frame format
    RtcEngine.SetRecordingAudioFrameParameters(SAMPLE_RATE, CHANNEL, RAW_AUDIO_FRAME_OP_MODE_TYPE.RAW_AUDIO_FRAME_OP_MODE_READ_WRITE, 1024);

    // Configure the mixed audio frame format
    RtcEngine.SetMixedAudioFrameParameters(SAMPLE_RATE, CHANNEL, 1024);

    internal class AudioFrameObserver : IAudioFrameObserver
    {
      // Callback for recording audio frames
      public override bool OnRecordAudioFrame(string channelId, AudioFrame audioFrame)
      {
        ProcessAudioData(audioFrame);
        return true;
      }

      // Callback for playback audio frames
      public override bool OnPlaybackAudioFrame(string channelId, AudioFrame audioFrame)
      {
        ProcessAudioData(audioFrame);
        return true;
      }

      // Callback for playback audio frames before mixing
      public override bool OnPlaybackAudioFrameBeforeMixing(string channelId, uint uid, AudioFrame audioFrame)
      {
        ProcessAudioData(audioFrame);
        return true;
      }

      // Callback for mixed audio frames
      public override bool OnMixedAudioFrame(string channelId, AudioFrame audioFrame)
      {
        ProcessAudioData(audioFrame);
        return true;
      }

      // Process and modify the audio data from audioFrame.buffer
      public void ProcessAudioData(AudioFrame audioFrame)
      {
        long length = (long)audioFrame.bytesPerSample * audioFrame.channels * audioFrame.samplesPerChannel;
        for (long i = 0; i < length; i += (long)audioFrame.bytesPerSample)
        {
          IntPtr pos = (IntPtr)(i + (long)audioFrame.buffer);
          System.Runtime.InteropServices.Marshal.WriteByte(pos, 0);
        }
      }
    }
    ```

    <CalloutContainer type="info">
      <CalloutDescription>
        Video SDK uses a synchronous callback mechanism for processing raw audio data. When you save or rewrite data using the callbacks, consider the following best practices:

        * To ensure continuity of the audio stream, do not block the SDK thread by processing data directly in the callback function. Instead, make a deep copy of the received audio data and transfer the copied data to another thread for processing.
        * If you choose to process the audio data synchronously within the callback function, you must strictly control the processing time. For example, if the callback function is triggered every 10 milliseconds, then the processing time within the callback must be less than 10 milliseconds to prevent delays or interruptions in the audio stream.
      </CalloutDescription>
    </CalloutContainer>

    ## Reference [#reference-5]

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

    * [Audio module](../../core-concepts)

    ### Sample project [#sample-project-4]

    Agora provides an open-source example project [ProcessAudioRawData](https://github.com/AgoraIO-Extensions/Agora-Unity-Quickstart/blob/main/API-Example-Unity/Assets/API-Example/Examples/Advanced/ProcessAudioRawData/ProcessAudioRawData.cs) for your reference. Download or view the project for a more detailed example.

    ### API reference [#api-reference-5]

    * [`RegisterAudioFrameObserver`](https://api-ref.agora.io/en/video-sdk/unity/4.x/API/class_irtcengine.html#api_imediaengine_registeraudioframeobserver)
    * [`SetRecordingAudioFrameParameters`](https://api-ref.agora.io/en/video-sdk/unity/4.x/API/class_irtcengine.html#api_irtcengine_setrecordingaudioframeparameters)
    * [`SetPlaybackAudioFrameParameters`](https://api-ref.agora.io/en/video-sdk/unity/4.x/API/class_irtcengine.html#ariaid-title209)
    * [`SetMixedAudioFrameParameters`](https://api-ref.agora.io/en/video-sdk/unity/4.x/API/class_irtcengine.html#api_irtcengine_setmixedaudioframeparameters)
    * [`SetPlaybackAudioFrameBeforeMixingParameters`](https://api-ref.agora.io/en/video-sdk/unity/4.x/API/class_irtcengine.html#api_irtcengine_setplaybackaudioframebeforemixingparameters)
    * [`OnRecordAudioFrame`](https://api-ref.agora.io/en/video-sdk/unity/4.x/API/class_iaudioframeobserver.html#callback_iaudioframeobserverbase_onmixedaudioframe)
    * [`OnPlaybackAudioFrame`](https://api-ref.agora.io/en/video-sdk/unity/4.x/API/class_iaudioframeobserver.html#callback_iaudioframeobserverbase_onplaybackaudioframe)
    * [`OnPlaybackAudioFrameBeforeMixing`](https://api-ref.agora.io/en/video-sdk/unity/4.x/API/class_iaudioframeobserver.html#callback_iaudioframeobserver_onplaybackaudioframebeforemixing)
    * [`OnMixedAudioFrame`](https://api-ref.agora.io/en/video-sdk/unity/4.x/API/class_iaudioframeobserver.html#callback_iaudioframeobserverbase_onmixedaudioframe)

    <_PlatformProcessedMarker close="true" />
  </_PlatformPanel>
</_PlatformTabsGroup>
