# AudioRenderer播放音频异常

#### 问题现象

使用AudioRenderer播放音频时会出现杂音或没有声音等现象。

#### 背景知识

AudioRenderer是音频渲染器，用于播放PCM音频数据，需要应用持续写入音频数据进行工作。应用可以在输入前添加数据预处理，如设定音频文件的采样率、位宽等，适用于更专业、更多样化的媒体播放应用开发，详情可以参考AudioRenderer开发指导。

#### 解决方案

**场景一**：**播放音频时没声音或者整段杂音。**

*   **现象描述**：播放音频时不显示播放失败，但是完全没有声音，或者整段都是杂音。
*   **分析原因**：
    *   AudioRenderer仅支持播放PCM格式的音频文件，播放其他音频格式的文件就只能听到杂音。
    *   当同优先级或高优先级音频流要使用输出设备时，当前音频流可能被中断，导致无法继续播放。
*   **解决方案**：
    1.  **选择合适的音频播放开发工具**。
        
        AudioRenderer只能播放PCM格式的音频文件，非PCM格式的音频文件可以使用其他支持该格式的播放器进行播放，例如WAV等格式的文件就可以使用AVPlayer来进行播放，详情可以参考音频播放的开发方式。
        
    2.  **设置合适的焦点管理策略**。
        
        多音频播放涉及音频抢占问题，需要设置正确的焦点策略来处理，详情可以参考音频焦点管理解决方案。
        

**场景二**：**播放音频时有部分杂音、卡顿。**

*   **现象描述**：播放音频时会出现部分杂音、卡顿，有时甚至会大段出现。
*   **分析原因**：
    
    AudioRenderer会调用AudioRendererWriteDataCallback方法来写入音频数据，如果数据未能填满回调buffer的长度就放入队列里播放，则会导致杂音、卡顿等现象。如下图所示，因为部分buffer未填满导致存在脏数据影响播放：
    
    此时可以将buffer长度和写入数据长度打印出来，比较大小，相关日志如下：
    
    ```
    06-12 10:51:56.358   3224-3224  A03d00/JSAPP com.examp...rrebuild  I  Read from file: 5988bytes, buffer length: 8916bytes
    ```
    
    可以看出，写入的数据小于buffer的大小，因此会有杂音、卡顿等现象的出现。
    

*   **解决方案**：
    
    在无法填满回调所需长度数据的情况下，需要返回audio.AudioDataCallbackResult.INVALID，此时系统不会处理该段音频数据，然后会再次向应用请求数据，在确认数据填满后再返回audio.AudioDataCallbackResult.VALID进行播放，参考如下代码，可以判断写入数据是否已填满buffer，如果未填满就可以返回INVALID：
    
    ```
    // 如果开发者不希望播放某段buffer，返回audio.AudioDataCallbackResult.INVALID即可。
    if (bufferLength < buffer.byteLength) {
      return audio.AudioDataCallbackResult.INVALID;
    }
    ```
    
    完整示例代码可以参考使用AudioRenderer开发音频播放功能完整示例。
    

**场景三**：**播放完音频后会一直输出杂音。**

*   **现象描述**：
    
    停止写入音频数据后，播放没有停止，还会一直输出杂音。
    
*   **分析原因**：
    
    在没有写入新的音频数据也没有停止AudioRenderer的情况下，则会循环播放缓冲区的历史数据，导致不断输出杂音，影响播放效果，如下图所示：
    
    打印出日志如下图所示，在没有新数据写入也没有停止的情况下，会不断循环播放缓冲区数据：
    
    ```
    06-16 15:07:45.322   13899-13899   A03d00/JSAPP com.examp...rrebuild  I     Read from file: 5988bytes, buffer length: 8916bytes
    06-16 15:07:45.322   13899-13899   A03d00/JSAPP com.examp...rrebuild  I     Read from file: 5988bytes, buffer length: 8916bytes
    06-16 15:07:45.329   13899-13899   A03d00/JSAPP com.examp...rrebuild  I     Read from file: 5988bytes, buffer length: 8916bytes
    06-16 15:07:45.329   13899-13899   A03d00/JSAPP com.examp...rrebuild  I     Read from file: 5988bytes, buffer length: 8916bytes
    ```
    

*   **解决方案**：
    
    对于最后一帧，如果数据不够填满缓冲长度，开发者需要使用剩余数据拼接空数据的方式，将缓冲填满，不够的时候可以用0将数据填满，没有音频数据写入时返回INVALID，或停止AudioRenderer。参考示例代码如下：
    
    ```
    // 如果当前回调传入的数据不足一帧，空白区域需要使用静音数据填充，否则会导致播放出现杂音。
    if (bufferLength < buffer.byteLength) {
      let view = new DataView(buffer);
      for (let i = bufferLength; i < buffer.byteLength; i++) {
        // 空白区域填充静音数据。当使用音频采样格式为SAMPLE_FORMAT_U8时0x7F为静音数据，使用其他采样格式时0为静音数据。
        view.setUint8(i, 0);
      }
    }
    ```
    
    完整示例代码可以参考使用AudioRenderer开发音频播放功能完整示例。