HarmonyOS SDK的Audio Kit闭源开放能力具体有哪些?

摘要:1.问题描述: 如何实现自定义音量调节? 解决方案: 设置系统音量 应用无法直接调节系统音量,系统提供了ArkTS组件AVVolumePanel音量面板,应用可以创建该组件,让用户通过界面操作来调节音量。 设置应用音量 管理应用音量的接口由
1.问题描述: 如何实现自定义音量调节? 解决方案: 设置系统音量 应用无法直接调节系统音量,系统提供了ArkTS组件AVVolumePanel音量面板,应用可以创建该组件,让用户通过界面操作来调节音量。 设置应用音量 管理应用音量的接口由AudioVolumeManager提供,在使用之前,需要使用getVolumeManager()获取AudioVolumeManager实例,示例代码如下: import { audio } from '@kit.AudioKit'; let audioManager = audio.getAudioManager(); let audioVolumeManager = audioManager.getVolumeManager(); 设置应用音量。 当音量模式设置为APP_INDIVIDUAL时,可通过下面示例接口设置应用音量。 // 设置应用的音量(范围为0到100)。 audioVolumeManager.setAppVolumePercentage(20).then(() => { console.info(`set app volume success.`); }); 设置音频流音量 在ArkTS API端和Native API端分别有对应的API用来设置音频流音量。 使用ArkTS API时,开发者可以使用AVPlayer或AudioRenderer的setVolume()方法。 使用AVPlayer设置音频流音量的示例代码如下: let volume = 1.0; // 指定的音量大小,取值范围为[0.00-1.00],1表示最大音量 avPlayer.setVolume(volume); 使用AudioRenderer设置音频流音量的示例代码如下: 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接口设置当前音频流音量值,示例代码如下: // 要设置的音量值,音量值的范围是[0.0, 1.0]。 float volume = 0.5f; // 设置当前音频流音量值。 OH_AudioStream_Result OH_AudioRenderer_SetVolume(audioRenderer, volume); 请注意: setVolume接口调整的是音频流本身的音量,不是系统音量,音量条本身不会发生变化,而且音频流本身的音量默认值是1,即以系统音量来播放,应用只可以在系统音量的基础上调到0~1倍,不会超过系统音量,也不会影响系统音量的值(即音量条)。 为确保用户能感知音量变化,应用后台不能调节音量,否则系统会做出对应的控制措施,因此音量面板设置volumeLevel初始值是不生效的,只有改变volumeLevel值触发音量面板,才会改变当前系统音量;并且音量面板调节具体音量由系统控制,当前播放什么音频就调节什么音量,没有播放时就会调节媒体音量。 2.问题描述: 如何实现支持滑动的视频音量调节功能? 解决方案: Slider组件结合音频流音量管理AVPlayer或AudioRenderer实现。Slider组件用于支持用户滑动获取音量值,将获取到的值通过setVolume接口传递给音频音量管理实现音量滑动控制调节。 3.问题描述: 集成腾讯云点播实现视频播放,自定义声音按钮实现音量滑动调节有什么比较好的策略? 解决方案: 使用Slider组件实现音量控制滑动条,结合腾讯云点播SDK的setAudioPlayoutVolume方法进行实现。实现时,建议默认音量100,即默认系统当前音量播放。 4.问题描述: 音乐播放器的音频输出如何增加PCM输出模式,支持数字耳放小尾巴usb独占? 解决方案: 方案一:使用AudioRenderer直接播放PCM格式的音频数据。 AudioRenderer可以直接播放PCM数据,还可以通过数据预处理来实现更灵活的播放,关键代码如下: 配置文件路径: 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); 读取文件数据: 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; } 调用start()方法进行音频渲染 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播放,参考代码如下: 定义PCM转WAV的方法,获取源文件路径和目标文件路径,分别写入WAV文件头和PCM数据,参考代码如下: 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) } 定义写入WAV头部信息的方法,创建一个大小为44字节的缓冲区,用于存储WAV文件的头部信息,再将其写入输出文件,参考代码如下: 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 }) } 定义读取pcm数据的方法,将PCM数据从输入文件写入输出文件,使用fs.readSync读取输入文件的数据,并写入输出文件,直到读取完毕,参考代码如下: 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) } 完成转码后让AVPlayer使用fs文件系统打开沙箱地址获取媒体文件地址并通过dataSrc属性进行播放,AVPlayer的具体开发流程可以参考AVPlayer播放音频完整示例。