【FAQ】HarmonyOS SDK 闭源开放能力 — Audio Kit

1.问题描述:

如何实现自定义音量调节?

解决方案:

设置系统音量

应用无法直接调节系统音量,系统提供了ArkTS组件AVVolumePanel音量面板,应用可以创建该组件,让用户通过界面操作来调节音量。

设置应用音量

  1. 管理应用音量的接口由AudioVolumeManager提供,在使用之前,需要使用getVolumeManager()获取AudioVolumeManager实例,示例代码如下:

    TS 复制代码
    import { audio } from '@kit.AudioKit';
    
    
    
    let audioManager = audio.getAudioManager();
    
    let audioVolumeManager = audioManager.getVolumeManager();
  2. 设置应用音量。

    音量模式设置为APP_INDIVIDUAL时,可通过下面示例接口设置应用音量。

    ts 复制代码
    // 设置应用的音量(范围为0到100)。
    
    audioVolumeManager.setAppVolumePercentage(20).then(() => {
    
      console.info(`set app volume success.`);
    
    });

设置音频流音量

在ArkTS API端和Native API端分别有对应的API用来设置音频流音量。

使用ArkTS API时,开发者可以使用AVPlayer或AudioRenderer的setVolume()方法。

  • 使用AVPlayer设置音频流音量的示例代码如下:

    ts 复制代码
    let volume = 1.0;  // 指定的音量大小,取值范围为[0.00-1.00],1表示最大音量
    
    avPlayer.setVolume(volume);
  • 使用AudioRenderer设置音频流音量的示例代码如下:

    ts 复制代码
    import { BusinessError } from '@kit.BasicServicesKit';
    
    
    
    audioRenderer.setVolume(0.5).then(() => {  // 音量范围为[0.0-1.0]
    
      console.info('Invoke setVolume succeeded.');
    
    }).catch((err: BusinessError) => {  
    
      console.error(`Invoke setVolume failed, code is ${err.code}, message is ${err.message}`);
    
    });
  • 使用Native API时开发者可使用OH_AudioRenderer_SetVolume接口设置当前音频流音量值,示例代码如下:

    C++ 复制代码
    // 要设置的音量值,音量值的范围是[0.0, 1.0]。
    
    float volume = 0.5f;
    
    
    
    // 设置当前音频流音量值。
    
    OH_AudioStream_Result OH_AudioRenderer_SetVolume(audioRenderer, volume);

请注意:

  • setVolume接口调整的是音频流本身的音量,不是系统音量,音量条本身不会发生变化,而且音频流本身的音量默认值是1,即以系统音量来播放,应用只可以在系统音量的基础上调到0~1倍,不会超过系统音量,也不会影响系统音量的值(即音量条)。

  • 为确保用户能感知音量变化,应用后台不能调节音量,否则系统会做出对应的控制措施,因此音量面板设置volumeLevel初始值是不生效的,只有改变volumeLevel值触发音量面板,才会改变当前系统音量;并且音量面板调节具体音量由系统控制,当前播放什么音频就调节什么音量,没有播放时就会调节媒体音量。

2.问题描述:

如何实现支持滑动的视频音量调节功能?

解决方案:

Slider组件结合音频流音量管理AVPlayerAudioRenderer实现。Slider组件用于支持用户滑动获取音量值,将获取到的值通过setVolume接口传递给音频音量管理实现音量滑动控制调节。

3.问题描述:

集成腾讯云点播实现视频播放,自定义声音按钮实现音量滑动调节有什么比较好的策略?

解决方案:

使用Slider组件实现音量控制滑动条,结合腾讯云点播SDK的setAudioPlayoutVolume方法进行实现。实现时,建议默认音量100,即默认系统当前音量播放。

4.问题描述:

音乐播放器的音频输出如何增加PCM输出模式,支持数字耳放小尾巴usb独占?

解决方案:

方案一:使用AudioRenderer直接播放PCM格式的音频数据。

AudioRenderer可以直接播放PCM数据,还可以通过数据预处理来实现更灵活的播放,关键代码如下:

  1. 配置文件路径:
TS 复制代码
let bufferSize: number = 0;

let path = getContext().cacheDir;

let filePath = path + '/StarWars10s-2C-48000-4SW.wav';

let file: fs.File = fs.openSync(filePath, fs.OpenMode.READ_ONLY);
  1. 读取文件数据:
TS 复制代码
try {

  fs.readSync(file.fd, buffer, options);

  bufferSize += buffer.byteLength;

  // 系统会判定buffer有效,正常播放。

  return audio.AudioDataCallbackResult.VALID;

} catch (error) {

  console.error('Error reading file:', error);

  // 系统会判定buffer无效,不播放。

  return audio.AudioDataCallbackResult.INVALID;

}
  1. 调用start()方法进行音频渲染
TS 复制代码
audioRenderer.start((err: BusinessError) => {

  if (err) {

    console.error(`Renderer start failed, code is ${err.code}, message is ${err.message}`);

  } else {

    console.info('Renderer start success.');

  }

});

具体开发步骤以及完整代码可以参考AudioRenderer的开发步骤

方案二:对PCM数据进行音频转码后使用AVPlayer播放。

AVPlayer无法直接播放PCM格式的音频数据,需要将音频数据转码封装成AVPlayer支持的格式。PCM格式数据是裸流,播放占用内存大,使用AVPlayer播放封装后的音频数据会占用更小的内存。

这里以WAV格式为例,WAV格式是一种无损的格式,可以最好地保存音频质量,如果对音频大小或者格式有其他要求,可以参考音频编码媒体数据封装进行其他的音频编码格式转化。

现在将PCM数据转码封装成完整的WAV文件再用AVPlayer播放,参考代码如下:

  1. 定义PCM转WAV的方法,获取源文件路径和目标文件路径,分别写入WAV文件头和PCM数据,参考代码如下:
TS 复制代码
public pcmToWav(src:string, dest:string){

  const inFile: fs.File = fs.openSync(src, fs.OpenMode.READ_ONLY);

  const outFile: fs.File = fs.openSync(dest, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE);

  let byteRate = 16 * sampleRate * channel / 8;

  const inFileStat = fs.statSync(inFile.fd)

  // 获取源文件信息,包括文件大小等

  let audioDataSize = inFileStat.size;

  let totalDataLen = audioDataSize + 36;

  console.log('audioDataSize= ', audioDataSize)

  // 1.wav文件头编写

  this.writeWavFileHeader(outFile, audioDataSize, totalDataLen, byteRate);

  // 2.写入pcm数据

  this.writePcmData(inFile, outFile, audioDataSize)

}
  1. 定义写入WAV头部信息的方法,创建一个大小为44字节的缓冲区,用于存储WAV文件的头部信息,再将其写入输出文件,参考代码如下:
TS 复制代码
private writeString(dv:DataView, offset:number, str:string){

  for (let i = 0; i < str.length; i++) {

    dv.setUint8(offset + i, str.charCodeAt(i));

  }

}

// 定义写入WAV头文件信息的方法

private writeWavFileHeader(out:fs.File, audioDataSize:number, totalDataLen:number, byteRate:number){

  const header = new ArrayBuffer(44);

  const dv = new DataView(header);

  const bitsPerSample = 16; // 当前位深是16

  // 写入RIFF块

  this.writeString(dv, 0, 'RIFF');

  dv.setUint32(4, totalDataLen, true);

  this.writeString(dv, 8, 'WAVE');

  // 写入fmt块

  this.writeString(dv, 12, 'fmt ');

  dv.setUint32(16, 16, true); // fmt块大小

  dv.setUint16(20, 1, true); // 格式类别(PCM)

  dv.setUint16(22, channel, true); // 通道数

  dv.setUint32(24, sampleRate, true); // 采样率

  dv.setUint32(28, byteRate, true); // 比特率

  dv.setUint16(32, channel * bitsPerSample / 8, true); // 每个采样点的字节数

  dv.setUint16(34, bitsPerSample, true); // 位深

  // 写入data块

  this.writeString(dv, 36, 'data');

  dv.setUint32(40, audioDataSize, true); // 数据块大小

  console.log('audioDataSize= ', audioDataSize)

  // 将头文件信息写入输出文件

  fs.writeSync(out.fd, new Uint8Array(header).buffer, {

    length: 44

  })

}

 
  1. 定义读取pcm数据的方法,将PCM数据从输入文件写入输出文件,使用fs.readSync读取输入文件的数据,并写入输出文件,直到读取完毕,参考代码如下:
TS 复制代码
private writePcmData(inFile:fs.File, outFile:fs.File, audioDataSize:number){

  // 写入PCM数据

  let readSize = 0

  let data = new ArrayBuffer(audioDataSize);

  let readOptions: ReadOptions = {

    offset: readSize,

    length: audioDataSize

  };

  let readLen = fs.readSync(inFile.fd, data, readOptions);

  while (readLen > 0) {

    readSize += readLen;

    fs.writeSync(outFile.fd, data, { length: readLen });

    readOptions.offset = readSize;

    readLen = fs.readSync(inFile.fd, data, readOptions);

  }

  fs.closeSync(inFile.fd)

  fs.closeSync(outFile.fd)

}

 
  1. 完成转码后让AVPlayer使用fs文件系统打开沙箱地址获取媒体文件地址并通过dataSrc属性进行播放,AVPlayer的具体开发流程可以参考AVPlayer播放音频完整示例
相关推荐
哈哈你是真的厉害2 小时前
小白基础入门 React Native 鸿蒙跨平台开发:实现一个简单的个人所得税计算器
react native·react.js·harmonyos
小白阿龙3 小时前
鸿蒙+flutter 跨平台开发——汇率查询器开发实战
flutter·华为·harmonyos·鸿蒙
小学生波波3 小时前
HarmonyOS6 - 鸿蒙ArkUI动画详解
华为·arkts·鸿蒙·arkui·鸿蒙开发·harmonyos6
哈哈你是真的厉害3 小时前
小白基础入门 React Native 鸿蒙跨平台开发:二维码生成工具(通过生成网址生成)
react native·react.js·harmonyos
HMS Core4 小时前
【FAQ】HarmonyOS SDK 闭源开放能力 — Media Kit
华为·harmonyos
2501_944526424 小时前
Flutter for OpenHarmony 万能游戏库App实战 - 设置功能实现
android·javascript·flutter·游戏·harmonyos
IT陈图图5 小时前
Flutter × OpenHarmony 音乐播放器应用 - 构建录音控制区域
flutter·华为·鸿蒙·openharmony
2501_944424125 小时前
Flutter for OpenHarmony游戏集合App实战之记忆翻牌表情图案
开发语言·javascript·flutter·游戏·harmonyos
2501_944424125 小时前
Flutter for OpenHarmony游戏集合App实战之数字拼图打乱排列
android·开发语言·flutter·游戏·harmonyos