1/* 2 * Copyright (c) 2023 Hunan OpenValley Digital Industry Development Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16import audio from '@ohos.multimedia.audio'; 17import Logger from '../utils/Logger'; 18 19const TAG = 'mAudioRenderer'; 20 21// 与使用AudioRenderer开发音频播放功能过程相似,关键区别在于audioRenderInfo参数和音频数据来源 22export default class AudioRendererHelper { 23 private renderModel: audio.AudioRenderer | null = null; 24 private audioStreamInfo: audio.AudioStreamInfo = { 25 samplingRate: audio.AudioSamplingRate.SAMPLE_RATE_16000, // 采样率 26 channels: audio.AudioChannel.CHANNEL_2, // 通道数 27 sampleFormat: audio.AudioSampleFormat.SAMPLE_FORMAT_S16LE, // 采样格式 28 encodingType: audio.AudioEncodingType.ENCODING_TYPE_RAW // 编码格式 29 }; 30 private audioRendererInfo: audio.AudioRendererInfo = { 31 // 需使用通话场景相应的参数 32 content: audio.ContentType.CONTENT_TYPE_SPEECH, // 音频内容类型:语音 33 usage: audio.StreamUsage.STREAM_USAGE_VOICE_COMMUNICATION, // 音频流使用类型:语音通信 34 rendererFlags: 0 // 音频渲染器标志:默认为0即可 35 }; 36 private audioRendererOptions: audio.AudioRendererOptions = { 37 streamInfo: this.audioStreamInfo, 38 rendererInfo: this.audioRendererInfo 39 }; 40 41 // 初始化,创建实例 42 async init(): Promise<void> { 43 try { 44 this.renderModel = await audio.createAudioRenderer(this.audioRendererOptions); 45 Logger.info(TAG,`creating AudioRenderer success`); 46 } catch (err) { 47 Logger.error(TAG,`creating AudioRenderer failed ${JSON.stringify(err)}`); 48 } 49 } 50 51 // 开始一次音频渲染 52 async start(): Promise<void> { 53 if (!this.renderModel) { 54 Logger.info(TAG,`start failed AudioRenderer is null`); 55 return; 56 } 57 try { 58 let stateGroup = [audio.AudioState.STATE_PREPARED, audio.AudioState.STATE_PAUSED, audio.AudioState.STATE_STOPPED]; 59 if (stateGroup.indexOf(this.renderModel.state) === -1) { // 当且仅当状态为prepared、paused和stopped之一时才能启动渲染 60 Logger.info(TAG,`start failed`); 61 return; 62 } 63 await this.renderModel.start(); // 启动渲染 64 await this.renderModel.setVolume(1.0); //调节音量 65 Logger.info(TAG,`start AudioRenderer success`); 66 } catch (err) { 67 Logger.error(TAG,`start AudioRenderer failed ${JSON.stringify(err)}`); 68 } 69 } 70 71 72 async write(buffer: ArrayBuffer): Promise<number> { 73 try { 74 let len: number = await this.renderModel.write(buffer); 75 return len; 76 } catch (err) { 77 Logger.error(TAG,`AudioRenderer write failed, error: ${JSON.stringify(err)}`); 78 } 79 return 0; 80 } 81 82 // 停止渲染 83 async stop(): Promise<void> { 84 try { 85 // 只有渲染器状态为running或paused的时候才可以停止 86 if (this.renderModel.state !== audio.AudioState.STATE_RUNNING && this.renderModel.state !== audio.AudioState.STATE_PAUSED) { 87 Logger.info(TAG,`Renderer is not running or paused.`); 88 return; 89 } 90 await this.renderModel.stop(); // 停止渲染 91 } catch (err) { 92 Logger.error(TAG,`AudioRenderer stop failed, error: ${JSON.stringify(err)}`); 93 } 94 } 95 96 // 销毁实例,释放资源 97 async release(): Promise<void> { 98 Logger.info(TAG,`Renderer release`); 99 try { 100 // 渲染器状态不是released状态,才能release 101 if (this.renderModel.state === audio.AudioState.STATE_RELEASED) { 102 Logger.info(TAG,`Renderer already released`); 103 return; 104 } 105 await this.renderModel.release(); // 释放资源 106 } catch (err) { 107 Logger.error(TAG,`AudioRenderer release failed, error: ${JSON.stringify(err)}`); 108 } 109 } 110} 111