AudioRenderer播放音频异常
===================

#### 问题现象

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

#### 背景知识

[AudioRenderer](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/arkts-apis-audio-audiorenderer)是音频渲染器，用于播放PCM音频数据，需要应用持续写入音频数据进行工作。应用可以在输入前添加数据预处理，如设定音频文件的采样率、位宽等，适用于更专业、更多样化的媒体播放应用开发，详情可以参考[AudioRenderer开发指导](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/using-audiorenderer-for-playback#开发指导)。

#### 解决方案

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

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

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

*   **现象描述**：播放音频时会出现部分杂音、卡顿，有时甚至会大段出现。
*   **分析原因**：
    
    AudioRenderer会调用[AudioRendererWriteDataCallback](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/arkts-apis-audio-t#audiorendererwritedatacallback12)方法来写入音频数据，如果数据未能填满回调buffer的长度就放入队列里播放，则会导致杂音、卡顿等现象。如下图所示，因为部分buffer未填满导致存在脏数据影响播放：
    
    ![](https://contentcenter-vali-drcn.dbankcdn.cn/pvt_2/DeveloperAlliance_scene_100_1/b3/v3/yImVb8kjRKmzKPHnJ2z83A/zh-cn_image_0000002658911947.png?HW-CC-KV=V1&HW-CC-Date=20260709T134246Z&HW-CC-Expire=86400&HW-CC-Sign=7D849CD644F8A7A6EC1A1CFA7715D13FF27C44F10C3FC8B87358306B3F15BA4D "点击放大")
    
    此时可以将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开发音频播放功能完整示例](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/using-audiorenderer-for-playback#完整示例)。
    

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

*   **现象描述**：
    
    停止写入音频数据后，播放没有停止，还会一直输出杂音。
    
*   **分析原因**：
    
    在没有写入新的音频数据也没有停止AudioRenderer的情况下，则会循环播放缓冲区的历史数据，导致不断输出杂音，影响播放效果，如下图所示：
    
    ![](https://contentcenter-vali-drcn.dbankcdn.cn/pvt_2/DeveloperAlliance_scene_100_1/cc/v3/CttIZ8W6RESeVHEaAFB9GA/zh-cn_image_0000002628392738.png?HW-CC-KV=V1&HW-CC-Date=20260709T134246Z&HW-CC-Expire=86400&HW-CC-Sign=FF10AA8C3D1894BC58CBB2A22186D7B72988319A9BC7040BCD600D72B9AEFF8E "点击放大")
    
    打印出日志如下图所示，在没有新数据写入也没有停止的情况下，会不断循环播放缓冲区数据：
    
    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开发音频播放功能完整示例](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/using-audiorenderer-for-playback#完整示例)。