harmony 鸿蒙使用SoundPool开发音频播放功能

  • 2023-10-30
  • 浏览 (429)

使用SoundPool开发音频播放功能

使用SoundPool(音频池)提供的接口,可以实现低时延短音播放。

当应用开发时,经常需要使用一些急促简短的音效(如相机快门音效、系统通知音效等),此时建议调用SoundPool,实现一次加载,多次低时延播放。

SoundPool当前支持播放1MB以下的音频资源,大小超过1MB的长音频将截取1MB大小数据进行播放。

本开发指导将以SoundPool进行一次低时延播放音频的过程为例,向开发者讲解如何使用SoundPool。详细的API声明请参考SoundPool API参考

过程包括:创建SoundPool实例,加载音频资源(包括资源的解封装与解码:解码格式参考音频解码支持),设置播放参数(循环模式/播放优先级等),播放控制(播放/停止),释放资源。

在应用开发过程中,开发者应通过监听方法检查当前播放状态并按照一定顺序调用接口,执行对应操作,否则系统可能会抛出异常或生成其他未定义的行为。具体顺序可参考下列开发步骤及对应说明。

开发步骤及注意事项

  1. 调用createSoundPool方法创建SoundPool实例。

    let soundPool: media.SoundPool;
    let audioRendererInfo: audio.AudioRendererInfo = {
        content : audio.StreamUsage.STREAM_USAGE_VOICE_COMMUNICATION
        usage : audio.StreamUsage.STREAM_USAGE_MUSIC,
        rendererFlags : 1
    }
    
    
    media.createSoundPool(5, audioRendererInfo).then((soundpool_: media.SoundPool) => {
      if (soundpool_ != null) {
        soundPool = soundpool_;
        console.info('create SoundPool success');
      } else {
        console.error('create SoundPool fail');
      }
    }).catch((error: BusinessError) => {
      console.error(`soundpool catchCallback, error message:${error.message}`);
    });
    
  2. 调用load方法进行音频资源加载。 可以传入uri或fd加载资源,此处使用传入uri的方式为例,更多方法请参考API文档

    let soundID: number;
    await fs.open('/test_01.mp3', fs.OpenMode.READ_ONLY).then((file: fs.File) => {
      console.info("file fd: " + file.fd);
      uri = 'fd://' + (file.fd).toString()
    }); // '/test_01.mp3' 作为样例,使用时需要传入文件对应路径。
    soundPool.load(uri).then((soundId: number) => {
      console.info('soundPool load uri success');
      soundID = soundId;
    }).catch((err) => {
      console.error('soundPool load failed and catch error is ' + err.message);
    });
    
  3. 调用on(‘loadComplete’)方法,用于监听“资源加载完成”。

    soundPool.on('loadComplete', (soundId_: number) => {
      console.info('loadComplete, soundId: ' + soundId_);
    });
    
  4. 调用on(‘playFinished’)方法,用于监听“播放完成”。

    soundPool.on('playFinished', () => {
      console.info("recive play finished message");
    });
    
  5. 调用on(‘error’)方法,设置错误类型监听。

    soundPool.on('error', (error) => {
      console.info('error happened,message is :' + error.message);
    });
    
  6. 配置播放参数PlayParameters,并调用play方法播放音频。多次调用play播放同一个soundID,只会播放一次。

    let soundID: number;
    let streamID: number;
    let playParameters: media.PlayParameters = {
        loop = 0, // 循环0次
        rate = 2, // 2倍速
        leftVolume = 0.5, // range = 0.0-1.0
        rightVolume = 0.5, // range = 0.0-1.0
        priority = 0, // 最低优先级
        parallelPlayFlag: boolean = false // 不和其它正在播放的音频并行播放
      }
    soundPool.play(soundID, playParameters, (error: BusinessError, streamId: number) => {
      if (error) {
        console.info(`play sound Error: errCode is ${error.code}, errMessage is ${error.message}`)
      } else {
        streamID = streamId;
        console.info('play success soundid:' + streamId);
      }
    });
    
  7. 调用setLoop方法设置循环次数。

    let streamID: number;
    soundPool.setLoop(streamID, 1).then(() => {
      console.info('setLoop success streamID:' + streamID);
    }).catch((err: BusinessError) => {
      console.error('soundpool setLoop failed and catch error is ' + err.message);
    });
    
  8. 调用setPriority方法设置优先级。

    let streamID: number;
    soundPool.setPriority(streamID, 1);
    
  9. 调用setVolume方法设置音量。

    let streamID: number;
    // 先调用play方法获取到对应资源的streamID
    
    
    soundPool.setVolume(streamID, 0.5, 0.5).then(() => {
      console.info('setVolume success');
    }).catch((err: BusinessError) => {
      console.error('soundpool setVolume failed and catch error is ' + err.message);
    });
    
  10. 调用stop方法终止指定流的播放。

    let streamID: number;
    //先调用play方法给拿到对应的streamID
    
    
    soundPool.stop(streamID).then(() => {
      console.info('stop success');
    }).catch((err: BusinessError) => {
      console.error('soundpool load stop and catch error is ' + err.message);
    });
    
  11. 调用unload方法卸载音频资源。

    let soundID: number;
    // 先调用load方法获取到对应资源的soundID
    
    
    soundPool.unload(soundID).then(() => {
      console.info('unload success');
    }).catch((err: BusinessError) => {
      console.error('soundpool unload failed and catch error is ' + err.message);
    });
    
  12. 调用off(‘loadComplete’)方法注销加载完成监听。

    soundPool.off('loadComplete');
    
  13. 调用off(‘playFinished’)方法注销播放完成监听。

    soundPool.off('playFinished');
    
  14. 调用off(‘error’)方法注销错误错误类型监听。

    soundPool.off('error');
    
  15. 调用release方法释放SoundPool实例。

    soundPool.release().then(() => {
      console.info('release success');
    }).catch((err: BusinessError) => {
      console.error('soundpool release failed and catch error is ' + err.message);
    });
    

完整示例

下面展示了使用SoundPool进行低时延播放的完整示例代码。


import audio from '@ohos.multimedia.audio';
import media from '@ohos.multimedia.media';
import fs from '@ohos.file.fs'
struct Soundpool {
  private soundPool: media.SoundPool;
  private streamId: number = 0;
  private soundId: number = 0;
  private audioRendererInfo: audio.AudioRendererInfo = {
    content: audio.ContentType.CONTENT_TYPE_SPEECH,
    usage: audio.StreamUsage.STREAM_USAGE_MEDIA,
    rendererFlags: 1
  }
  private PlayParameters: media.PlayParameters = {
    loop: number = 3, // 循环4次
    rate: audio.AudioRendererRate = audio.AudioRendererRate.RENDER_RATE_NORMAL, // 正常倍速
    leftVolume: number = 0.5, // range = 0.0-1.0
    rightVolume: number = 0.5, // range = 0.0-1.0
    priority: number = 0, // 最低优先级
    parallelPlayFlag: boolean = false // 不和其它正在播放的音频并行播放
  }
  private uri: string = "";
  async create(): Promise<void> {
    //创建soundPool实例
    this.soundPool = await media.createSoundPool(5, this.audioRendererInfo);
    //注册监听
    this.loadCallback();
    this.finishPlayCallback();
    this.setErrorCallback();
    // 加载音频资源
    await fs.open('/test_01.mp3', fs.OpenMode.READ_ONLY).then((file: fs.File) => {
      console.info("file fd: " + file.fd);
      this.uri = 'fd://' + (file.fd).toString()
    }); // '/test_01.mp3' 作为样例,使用时需要传入文件对应路径。
    this.soundId = await this.soundPool.load(this.uri);
  }
  async loadCallback(): Promise<void> {
    // 加载完成回调
    this.soundPool.on('loadComplete', (soundId_: number) => {
      console.info('loadComplete, soundId: ' + soundId_);
    })
  }
  //设置播放完成监听
  async finishPlayCallback(): Promise<void> {
    // 播放完成回调
    this.soundPool.on('playFinished', () => {
      console.info("recive play finished message");
      // 可进行下次播放
    })
  }
  //设置错误类型监听
  setErrorCallback(): void {
    this.soundPool.on('error', (error) => {
      console.info('error happened,message is :' + error.message);
    })
  }
  async PlaySoundPool(): Promise<void> {
    // 开始播放,这边play也可带播放播放的参数PlayParameters
    this.streamId = await this.soundPool.play(this.soundId);
    // 设置循环播放次数
    this.soundPool.setLoop(this.streamId, 2); // 播放3次
    // 设置对应流的优先级
    this.soundPool.setPriority(this.streamId, 1);
    // 设置音量
    this.soundPool.setVolume(this.streamId, 0.5, 0.5);
  }
  async release(): Promise<void> {
    // 终止指定流的播放
    this.soundPool.stop(this.streamId);
    // 卸载音频资源
    await this.soundPool.unload(this.soundId);
    //关闭监听
    this.setOffCallback();
    // 释放SoundPool
    await this.soundPool.release();
  }
  //关闭监听
  setOffCallback() {
    this.soundPool.off('loadComplete');
    this.soundPool.off('playFinished');
    this.soundPool.off('error');
  }
}

你可能感兴趣的鸿蒙文章

harmony 鸿蒙媒体

harmony 鸿蒙开发音频通话功能

harmony 鸿蒙音频通话开发概述

harmony 鸿蒙音频解码

harmony 鸿蒙音效管理

harmony 鸿蒙音频编码

harmony 鸿蒙音频输入设备管理

harmony 鸿蒙音频输出设备管理

harmony 鸿蒙多音频播放的并发策略

harmony 鸿蒙音频播放开发概述

0  赞