wuyanan

ref |> 评论输入面板集成语音识别

Showing 20 changed files with 1059 additions and 5 deletions
@@ -888,4 +888,11 @@ export class HttpUrlUtils { @@ -888,4 +888,11 @@ export class HttpUrlUtils {
888 let url = HttpUrlUtils.getHost() + HttpUrlUtils.VISITOR_COMMENT_LIST_DATA_PATH 888 let url = HttpUrlUtils.getHost() + HttpUrlUtils.VISITOR_COMMENT_LIST_DATA_PATH
889 return url 889 return url
890 } 890 }
  891 +
  892 + ///获取语音识别授权token
  893 + static getVoiceRecognizerSDKAuthToken() {
  894 + let url = HttpUrlUtils.getHost() + "/api/rmrb-search-api/zh/c/display/search/token"
  895 + return url
  896 + }
  897 +
891 } 898 }
@@ -181,4 +181,6 @@ export { TopicDetailData,GroupItem } from './src/main/ets/bean/content/TopicDeta @@ -181,4 +181,6 @@ export { TopicDetailData,GroupItem } from './src/main/ets/bean/content/TopicDeta
181 export { FeedbackTypeBean } from './src/main/ets/bean/detail/FeedbackTypeBean'; 181 export { FeedbackTypeBean } from './src/main/ets/bean/detail/FeedbackTypeBean';
182 export { FeedBackParams } from './src/main/ets/bean/content/FeedBackParams'; 182 export { FeedBackParams } from './src/main/ets/bean/content/FeedBackParams';
183 183
  184 +export { NetLayerVoiceRecoginizerToken } from './src/main/ets/bean/voicerecoginizer/NetLayerVoiceRecoginizerToken';
  185 +
184 186
  1 +export interface NetLayerVoiceRecoginizerToken {
  2 + accessToken: string
  3 + ///过期时间,到毫秒
  4 + expireTime: number
  5 +
  6 +}
1 import { inputMethodEngine } from '@kit.IMEKit' 1 import { inputMethodEngine } from '@kit.IMEKit'
2 import { commentInfo } from 'wdBean/Index' 2 import { commentInfo } from 'wdBean/Index'
  3 +import { VoiceRecoginizer } from 'wdHwAbility'
3 import { ToastUtils } from 'wdKit/Index' 4 import { ToastUtils } from 'wdKit/Index'
4 import { HttpUtils } from 'wdNetwork/Index' 5 import { HttpUtils } from 'wdNetwork/Index'
5 import { commentItemModel } from '../model/CommentModel' 6 import { commentItemModel } from '../model/CommentModel'
6 import { publishCommentModel } from '../model/PublishCommentModel' 7 import { publishCommentModel } from '../model/PublishCommentModel'
7 import commentViewModel from '../viewmodel/CommentViewModel' 8 import commentViewModel from '../viewmodel/CommentViewModel'
8 import { VoiceInputView } from './VoiceInputView' 9 import { VoiceInputView } from './VoiceInputView'
  10 +import { common, UIAbility } from '@kit.AbilityKit'
9 11
10 export interface CommentDialogInputContent { 12 export interface CommentDialogInputContent {
11 comment?: string 13 comment?: string
@@ -126,6 +128,7 @@ export struct CommentCustomDialog { @@ -126,6 +128,7 @@ export struct CommentCustomDialog {
126 .width(30) 128 .width(30)
127 .height(30) 129 .height(30)
128 .onClick(() => { 130 .onClick(() => {
  131 + VoiceRecoginizer.checkPemmission(getContext(this) as common.UIAbilityContext)
129 this.positionInfo = this.textInputController.getCaretOffset() 132 this.positionInfo = this.textInputController.getCaretOffset()
130 this.voiceSwitch = !this.voiceSwitch 133 this.voiceSwitch = !this.voiceSwitch
131 this.emojiSwitch = false 134 this.emojiSwitch = false
@@ -193,7 +196,7 @@ export struct CommentCustomDialog { @@ -193,7 +196,7 @@ export struct CommentCustomDialog {
193 } 196 }
194 if (this.voiceSwitch) { 197 if (this.voiceSwitch) {
195 VoiceInputView({voiceRecoginizerResult:(result: string) => { 198 VoiceInputView({voiceRecoginizerResult:(result: string) => {
196 - this.publishCommentModel.commentContent += result; 199 + this.publishCommentModel.commentContent = result;
197 }}).height(150) 200 }}).height(150)
198 201
199 } 202 }
  1 +import Lottie from '@ohos/lottie'
1 import { LottieView } from '../../lottie/LottieView' 2 import { LottieView } from '../../lottie/LottieView'
2 import lottie from '@ohos/lottie'; 3 import lottie from '@ohos/lottie';
  4 +import { CommonConstants } from 'wdConstant';
  5 +import { common} from '@kit.AbilityKit';
  6 +import { VoiceRecoginizer } from 'wdHwAbility/src/main/ets/voiceRecognizer/VoiceRecoginizer';
3 7
4 @Component 8 @Component
5 export struct VoiceInputView { 9 export struct VoiceInputView {
@@ -10,8 +14,19 @@ export struct VoiceInputView { @@ -10,8 +14,19 @@ export struct VoiceInputView {
10 14
11 @State private tips:string = "长按开始语音输入" 15 @State private tips:string = "长按开始语音输入"
12 16
  17 + voiceRe: VoiceRecoginizer = VoiceRecoginizer.sharedManager()
  18 +
13 voiceRecoginizerResult?:(result: string) => void 19 voiceRecoginizerResult?:(result: string) => void
14 20
  21 + aboutToAppear(): void {
  22 + this.initVoiceRecoigzer()
  23 + }
  24 +
  25 + aboutToDisappear(): void {
  26 + this.voiceRe.stop()
  27 + this.voiceRe.voiceRecoginizerResult = undefined
  28 + }
  29 +
15 build() { 30 build() {
16 Column() { 31 Column() {
17 Stack() { 32 Stack() {
@@ -39,17 +54,18 @@ export struct VoiceInputView { @@ -39,17 +54,18 @@ export struct VoiceInputView {
39 .gesture( 54 .gesture(
40 LongPressGesture() 55 LongPressGesture()
41 .onAction((event: GestureEvent) => { 56 .onAction((event: GestureEvent) => {
  57 + // this
42 this.playAnimationOne = true 58 this.playAnimationOne = true
43 this.tips = "" 59 this.tips = ""
  60 + this.voiceRe.startDialog()
44 }) 61 })
45 62
46 .onActionEnd((event: GestureEvent) => { 63 .onActionEnd((event: GestureEvent) => {
47 this.tips = "长按开始语音输入" 64 this.tips = "长按开始语音输入"
48 - if (this.voiceRecoginizerResult) {  
49 - this.voiceRecoginizerResult!(this.tips)  
50 - }  
51 - // lottie.destroy("voice_input_one")  
52 this.playAnimationOne = false 65 this.playAnimationOne = false
  66 + this.voiceRe.stop()
  67 + // this.voiceRe.voiceRecoginizerResult = undefined
  68 +
53 }) 69 })
54 ) 70 )
55 } 71 }
@@ -59,4 +75,18 @@ export struct VoiceInputView { @@ -59,4 +75,18 @@ export struct VoiceInputView {
59 .fontColor("#222222") 75 .fontColor("#222222")
60 } 76 }
61 } 77 }
  78 +
  79 + initVoiceRecoigzer() {
  80 + let context = getContext(this) as common.UIAbilityContext
  81 + let resoureDir = context.resourceDir
  82 +
  83 + this.voiceRe.AsrInit(context.resourceDir, context.filesDir)
  84 +
  85 + this.voiceRe.voiceRecoginizerResult = (result: string) => {
  86 + if (this.voiceRecoginizerResult) {
  87 + this.voiceRecoginizerResult(result)
  88 + }
  89 + }
  90 +
  91 + }
62 } 92 }
@@ -4,3 +4,5 @@ export { HWLocationUtils } from './src/main/ets/location/HWLocationUtils' @@ -4,3 +4,5 @@ export { HWLocationUtils } from './src/main/ets/location/HWLocationUtils'
4 4
5 // export { WDPushNotificationManager } from "./src/main/ets/notification/WDPushNotificationManager" 5 // export { WDPushNotificationManager } from "./src/main/ets/notification/WDPushNotificationManager"
6 export { GetuiPush } from "./src/main/ets/getuiPush/GetuiPush" 6 export { GetuiPush } from "./src/main/ets/getuiPush/GetuiPush"
  7 +
  8 +export {VoiceRecoginizer} from './src/main/ets/voiceRecognizer/VoiceRecoginizer'
@@ -8,6 +8,7 @@ @@ -8,6 +8,7 @@
8 "packageType": "InterfaceHar", 8 "packageType": "InterfaceHar",
9 "dependencies": { 9 "dependencies": {
10 "library": "file:./src/main/ets/getuiPush/GT-HM-1.0.4.har", 10 "library": "file:./src/main/ets/getuiPush/GT-HM-1.0.4.har",
  11 + "neonui":"file:./src/main/ets/voiceRecognizer/neonui.har",
11 "wdConstant": "file:../../commons/wdConstant", 12 "wdConstant": "file:../../commons/wdConstant",
12 "wdLogin": "file:../../features/wdLogin", 13 "wdLogin": "file:../../features/wdLogin",
13 "wdKit": "file:../../commons/wdKit", 14 "wdKit": "file:../../commons/wdKit",
  1 +import { audio } from '@kit.AudioKit'
  2 +import { ArkTSUtils } from '@kit.ArkTS'
  3 +import {getVoicebufferDataLengthByte} from 'neonui'
  4 +import process from '@ohos.process'
  5 +import { NativeNui } from 'neonui'
  6 +
  7 +let TAG:string = "AudioCapturer"
  8 +//音频采集器类,主要用于采集音频,写入文件
  9 +export default class AudioCapturer{
  10 + static lock_:ArkTSUtils.locks.AsyncLock = new ArkTSUtils.locks.AsyncLock()
  11 + //static voiceBuffer2:Int16Array=new Int16Array(0);
  12 + static voiceBuffer1:ArrayBuffer[] = [];
  13 + //static voiceBuffer:ArrayBuffer[] =[];
  14 + static async clearVoiceArrayBuffer(){
  15 + await AudioCapturer.lock_.lockAsync( ()=>{
  16 + if (AudioCapturer.voiceBuffer1!==undefined){
  17 + AudioCapturer.voiceBuffer1= []
  18 + }
  19 + console.info(`AudioCapturer clearVoiceArrayBuffer, then voiceBuffer1 size ${AudioCapturer.voiceBuffer1.length}`);
  20 + })
  21 + }
  22 + static async setVoiceArrayBuffer(voice:ArrayBuffer){
  23 + console.info(`AudioCapturer setVoiceArrayBuffer, 1 voiceBuffer1 size ${AudioCapturer.voiceBuffer1.length}`);
  24 + AudioCapturer.lock_.lockAsync( ()=>{
  25 + if (AudioCapturer.voiceBuffer1==undefined){
  26 + AudioCapturer.voiceBuffer1= []
  27 + }
  28 + AudioCapturer.voiceBuffer1.push(voice)
  29 + console.info(`AudioCapturer setVoiceArrayBuffer, 3 voiceBuffer1 size ${AudioCapturer.voiceBuffer1.length}`);
  30 + })
  31 + console.info(`AudioCapturer setVoiceArrayBuffer, 2 voiceBuffer1 size ${AudioCapturer.voiceBuffer1.length}`);
  32 + }
  33 + static async getVoiceArrayBuffer(buffer:ArrayBuffer):Promise<number>{
  34 + let ret:number;
  35 + let outbuferleng=buffer.byteLength;
  36 + let buffer_out_typedarray = new Int8Array(buffer)
  37 + let offset = 0
  38 + console.log("AudioCapturer enter getVoiceArrayBuffer");
  39 +
  40 + return await AudioCapturer.lock_.lockAsync( ()=>{
  41 + console.info(`AudioCapturer womx getVoiceArrayBuffer, outbuferleng ${buffer.byteLength}.with length ${AudioCapturer.voiceBuffer1.length}`);
  42 + // while(AudioRenderer.voiceBuffer1.length <= 0){
  43 + // if(AudioRenderer.flagVoiceEnd==true) {
  44 + // }
  45 + // }
  46 + if (AudioCapturer.voiceBuffer1.length > 0) {
  47 + let voice_length = getVoicebufferDataLengthByte(AudioCapturer.voiceBuffer1)
  48 + if (voice_length>=outbuferleng) {
  49 + let bytes_need = outbuferleng
  50 + while(bytes_need>0){
  51 + let voice1st = AudioCapturer.voiceBuffer1.shift()
  52 + if (voice1st==undefined ){
  53 + } else {
  54 + let out_typedbuffer:Int8Array;
  55 + console.info(`AudioCapturer womx voice1st.byteLength=${voice1st.byteLength} vs bytes_need=${bytes_need}`);
  56 +
  57 + if (voice1st.byteLength > bytes_need) {
  58 + let out_buffer = voice1st.slice(0,bytes_need)
  59 + out_typedbuffer = new Int8Array(out_buffer)
  60 +
  61 + let save_buffer = voice1st.slice(bytes_need)
  62 + AudioCapturer.voiceBuffer1.unshift(save_buffer)
  63 + } else {
  64 + out_typedbuffer = new Int8Array(voice1st)
  65 + }
  66 +
  67 + for (let i = 0; i < out_typedbuffer.byteLength; i++) {
  68 + buffer_out_typedarray[offset + i] = out_typedbuffer[i]
  69 + }
  70 + bytes_need -= out_typedbuffer.byteLength
  71 + offset += out_typedbuffer.byteLength
  72 +
  73 + console.info(`AudioCapturer womx bytes_need=${bytes_need}`);
  74 + }
  75 + }
  76 + } else {
  77 + ret = 0
  78 + console.error(`AudioCapturer error getVoiceArrayBuffer, outbuferleng 0.with ringbuffer voicebytes length ${voice_length}`);
  79 + }
  80 + } else {
  81 + ret = 0;
  82 + console.error(`AudioCapturer error getVoiceArrayBuffer, outbuferleng 0.with ringbuffer.length ${AudioCapturer.voiceBuffer1.length}<=0`);
  83 + }
  84 + return ret
  85 + })
  86 + }
  87 + static getVoiceArrayBuffer1(buffer:ArrayBuffer):number{
  88 + let ret:number=0;
  89 + let outbuferleng=buffer.byteLength;
  90 + let buffer_out_typedarray = new Int8Array(buffer)
  91 + let offset = 0
  92 + console.log("AudioCapturer enter getVoiceArrayBuffer");
  93 +
  94 + console.info(`AudioCapturer womx getVoiceArrayBuffer, outbuferleng ${buffer.byteLength}.with length ${AudioCapturer.voiceBuffer1.length}`);
  95 + // while(AudioRenderer.voiceBuffer1.length <= 0){
  96 + // if(AudioRenderer.flagVoiceEnd==true) {
  97 + // }
  98 + // }
  99 + if (AudioCapturer.voiceBuffer1.length > 0) {
  100 + let voice_length = getVoicebufferDataLengthByte(AudioCapturer.voiceBuffer1)
  101 + if (voice_length>=outbuferleng) {
  102 + let bytes_need = outbuferleng
  103 + while(bytes_need>0){
  104 + let voice1st = AudioCapturer.voiceBuffer1.shift()
  105 + if (voice1st==undefined ){
  106 + break
  107 + } else {
  108 + let out_typedbuffer:Int8Array;
  109 + console.info(`AudioCapturer womx voice1st.byteLength=${voice1st.byteLength} vs bytes_need=${bytes_need}`);
  110 +
  111 + if (voice1st.byteLength > bytes_need) {
  112 + let out_buffer = voice1st.slice(0,bytes_need)
  113 + out_typedbuffer = new Int8Array(out_buffer)
  114 +
  115 + let save_buffer = voice1st.slice(bytes_need)
  116 + AudioCapturer.voiceBuffer1.unshift(save_buffer)
  117 + } else {
  118 + out_typedbuffer = new Int8Array(voice1st)
  119 + }
  120 +
  121 + for (let i = 0; i < out_typedbuffer.byteLength; i++) {
  122 + buffer_out_typedarray[offset + i] = out_typedbuffer[i]
  123 + }
  124 + bytes_need -= out_typedbuffer.byteLength
  125 + offset += out_typedbuffer.byteLength
  126 +
  127 + console.info(`AudioCapturer womx bytes_need=${bytes_need}`);
  128 + }
  129 + }
  130 +
  131 + ret = outbuferleng - bytes_need
  132 + } else {
  133 + ret = 0
  134 + console.error(`AudioCapturer error getVoiceArrayBuffer, outbuferleng 0.with ringbuffer voicebytes length ${voice_length}`);
  135 + }
  136 + } else {
  137 + ret = 0;
  138 + console.error(`AudioCapturer error getVoiceArrayBuffer, outbuferleng 0.with ringbuffer.length ${AudioCapturer.voiceBuffer1.length}<=0`);
  139 + }
  140 + return ret;
  141 + }
  142 + //定义音频流信息
  143 + static audioStreamInfo:audio.AudioStreamInfo = {
  144 + //彩样率
  145 + samplingRate:audio.AudioSamplingRate.SAMPLE_RATE_16000,
  146 + //通道数
  147 + channels:audio.AudioChannel.CHANNEL_1,
  148 + //采样格式
  149 + sampleFormat:audio.AudioSampleFormat.SAMPLE_FORMAT_S16LE,
  150 + //编码格式
  151 + encodingType:audio.AudioEncodingType.ENCODING_TYPE_RAW
  152 + }
  153 + //定义音频采集器信息
  154 + static audioCapturerInfo:audio.AudioCapturerInfo={
  155 + //音源类型
  156 + source:audio.SourceType.SOURCE_TYPE_MIC,
  157 + //音频采集器标志
  158 + capturerFlags:0
  159 + }
  160 + //定义音频采集器
  161 + static audioCapturer:audio.AudioCapturer
  162 + static g_asrinstance:NativeNui
  163 + //初始化音频采集器
  164 + static async init(asrinstance:NativeNui){
  165 + AudioCapturer.g_asrinstance = asrinstance
  166 + AudioCapturer.audioCapturer = await audio.createAudioCapturer({
  167 + //需要音频流信息和音频采集器信息
  168 + streamInfo:AudioCapturer.audioStreamInfo,
  169 + capturerInfo:AudioCapturer.audioCapturerInfo
  170 + })
  171 + if (AudioCapturer.audioCapturer !== undefined) {
  172 + await AudioCapturer.audioCapturer.on('readData', AudioCapturer.readDataCallback);
  173 + }
  174 +
  175 + }
  176 +
  177 + static readDataCallback = (buffer: ArrayBuffer) => {
  178 + console.log(`${TAG} read data bytelength is ${buffer.byteLength}. uid[${process.uid}] pid[${process.pid}] tid[${process.tid}]`);
  179 + //AudioCapturer.setVoiceArrayBuffer(buffer)
  180 + AudioCapturer.g_asrinstance.updateAudio(buffer,false)
  181 + }
  182 +
  183 + //开始采集音频
  184 + static async start(){
  185 + await AudioCapturer.clearVoiceArrayBuffer()
  186 + if (AudioCapturer.audioCapturer) {
  187 + let stateGroup = [audio.AudioState.STATE_PREPARED,
  188 + audio.AudioState.STATE_PAUSED,
  189 + audio.AudioState.STATE_STOPPED];
  190 + if (stateGroup.indexOf(AudioCapturer.audioCapturer.state.valueOf()) === -1) {
  191 + // 当且仅当状态为STATE_PREPARED、STATE_PAUSED和STATE_STOPPED之一时才能启动采集
  192 + console.error(`${TAG}: start failed`);
  193 + console.error('Capturer is not STATE_PREPARED or STATE_PAUSED or STATE_STOPPED');
  194 + return;
  195 + }
  196 +
  197 + //开始录音
  198 + await AudioCapturer.audioCapturer.start()
  199 + console.log(`${TAG} start done`);
  200 + } else {
  201 + console.log(`${TAG} start with AudioCapturer.audioCapturer is null`);
  202 + return
  203 + }
  204 + }
  205 +
  206 + //停止采集音频
  207 + static async stop(){
  208 + if (AudioCapturer.audioCapturer) {
  209 + // 只有采集器状态为STATE_RUNNING或STATE_PAUSED的时候才可以停止
  210 + if (AudioCapturer.audioCapturer.state === audio.AudioState.STATE_RUNNING ||
  211 + AudioCapturer.audioCapturer.state === audio.AudioState.STATE_PAUSED
  212 + ) {
  213 + console.error(`Capturer state is ${AudioCapturer.audioCapturer.state}`);
  214 + await AudioCapturer.audioCapturer.stop()/*.then( (value)=>{
  215 + console.log("result of Capturer stop is " + value);
  216 + }); // 停止采集*/
  217 + console.error('Capturer stop done');
  218 + } else {
  219 + console.error('Capturer is not running or paused');
  220 + return;
  221 + }
  222 + } else {
  223 + console.log(`${TAG} stop with AudioCapturer.audioCapturer is null`);
  224 + return
  225 + }
  226 + await AudioCapturer.clearVoiceArrayBuffer()
  227 + }
  228 + // 释放资源
  229 + static async release() {
  230 + if (AudioCapturer.audioCapturer) {
  231 +
  232 + // 采集器状态不是STATE_RELEASED或STATE_NEW状态,才能release
  233 + if (AudioCapturer.audioCapturer.state === audio.AudioState.STATE_RELEASED ||
  234 + AudioCapturer.audioCapturer.state === audio.AudioState.STATE_NEW) {
  235 + console.info('Capturer already released');
  236 + return;
  237 + }
  238 +
  239 + await AudioCapturer.audioCapturer.release()
  240 + }
  241 + }
  242 +}
  1 +
  2 +import {NativeNui,Constants,MapToJson,INativeNuiCallback, AsrResult, KwsResult} from 'neonui'
  3 +import { PermissionUtils,DeviceUtil, Logger, DateTimeUtils } from 'wdKit';
  4 +import AudioCapturer from './AudioCapture';
  5 +import { common, Permissions } from '@kit.AbilityKit';
  6 +import { NetLayerVoiceRecoginizerToken } from 'wdBean';
  7 +import { HttpUrlUtils,ResponseDTO } from 'wdNetwork'
  8 +import { HttpRequest } from 'wdNetwork/src/main/ets/http/HttpRequest'
  9 +
  10 +
  11 +class NativeNuiCallbackHandle implements INativeNuiCallback {
  12 + asrspeechrealtimeResultOld:string=""
  13 + asrmessage:string;
  14 + message:string;
  15 + nuiCallback?:(result: string) => void
  16 + constructor() {
  17 + this.asrmessage=""
  18 + this.message=""
  19 + }
  20 + onNuiEventCallback(event:Constants.NuiEvent, resultCode:number, arg2:number, kwsResult:KwsResult,
  21 + asrResult:AsrResult):void {
  22 + let asrinfo:string = ""
  23 + // console.log("onUsrNuiEventCallback last this.asrmessage is " + this.asrmessage)
  24 + // console.log("onUsrNuiEventCallback this is " + JSON.stringify(this))
  25 + // console.log("onUsrNuiEventCallback event is " + event)
  26 +
  27 + if (event === Constants.NuiEvent.EVENT_ASR_RESULT){
  28 + this.message = "EVENT_ASR_RESULT"
  29 + this.asrspeechrealtimeResultOld=""
  30 + } else if (event === Constants.NuiEvent.EVENT_ASR_PARTIAL_RESULT || event === Constants.NuiEvent.EVENT_SENTENCE_END){
  31 + if (event === Constants.NuiEvent.EVENT_ASR_PARTIAL_RESULT ) {
  32 + this.message = "EVENT_ASR_PARTIAL_RESULT"
  33 + } else if(event === Constants.NuiEvent.EVENT_SENTENCE_END){
  34 + this.message = "EVENT_SENTENCE_END"
  35 + }
  36 + } else if (event === Constants.NuiEvent.EVENT_ASR_ERROR){
  37 + this.message = "EVENT_ASR_ERROR"
  38 + } else if (event === Constants.NuiEvent.EVENT_MIC_ERROR){
  39 + this.message = "EVENT_MIC_ERROR"
  40 + } else if (event === Constants.NuiEvent.EVENT_DIALOG_EX){
  41 + this.message = "EVENT_DIALOG_EX"
  42 + }
  43 + if (asrResult) {
  44 + asrinfo = asrResult.asrResult
  45 + //console.log(`asrinfo string is ${asrinfo}`)
  46 + if (asrinfo) {
  47 + try {
  48 + let asrresult_json:object|null = JSON.parse(asrResult.asrResult)
  49 + //console.log(JSON.stringify(asrresult_json))
  50 + if (asrresult_json) {
  51 + let payload:object|null = asrresult_json["payload"];
  52 + if (payload) {
  53 + //console.log(JSON.stringify(payload))
  54 + this.asrmessage = this.asrspeechrealtimeResultOld + payload["result"];
  55 +
  56 + if(event === Constants.NuiEvent.EVENT_SENTENCE_END){
  57 + // console.info("onUsrNuiEventCallback EVENT_SENTENCE_END")
  58 + this.asrspeechrealtimeResultOld = this.asrmessage
  59 + }
  60 + if (this.nuiCallback) {
  61 + this.nuiCallback(this.asrmessage)
  62 + }
  63 + }
  64 + }
  65 + } catch (e){
  66 + // console.error("got asrinfo not json, so donot fresh asrinfo." + JSON.stringify(e))
  67 + }
  68 + }
  69 + }
  70 + // console.info(`womx onUsrNuiEventCallback(${event}, ${resultCode},${arg2}, kwsResult:${kwsResult},asrResult:"${this.asrmessage}") done`)
  71 + }
  72 +
  73 + onNuiNeedAudioData(buffer:ArrayBuffer):number {
  74 + // console.info(`womx onUsrNuiNeedAudioData(buffer length = ${buffer.byteLength})`)
  75 + // console.log(`womx onUsrNuiNeedAudioData uid[${process.uid}] pid[${process.pid}] tid[${process.tid}]`);
  76 + let num:number = 0;
  77 +
  78 + if (true){
  79 + if (true){
  80 + //由于录音回调是异步的,所以此处获取共享数据需要加锁/并保持同步 是较难的,需要修改asr回调为用户主动推送方式
  81 + num = AudioCapturer.getVoiceArrayBuffer1(buffer)
  82 + } else {
  83 +
  84 + let flag_returned:boolean = false
  85 + try {
  86 + AudioCapturer.getVoiceArrayBuffer(buffer).then( (result:number)=>{
  87 + console.log("womx onUsrNuiNeedAudioData getVoiceArrayBuffer done, result="+result)
  88 + num = result
  89 + flag_returned=true
  90 + })
  91 + } catch(e ){
  92 + flag_returned=true
  93 +
  94 + }
  95 + while(flag_returned==false){
  96 + console.log("womx onUsrNuiNeedAudioData waiting ... num="+num)
  97 +
  98 + }
  99 + }
  100 + }
  101 +
  102 +
  103 + // console.info(`womx onUsrNuiNeedAudioData(buffer length = ${buffer.byteLength}) return ${num}}`)
  104 + return num;//buffer.byteLength;
  105 + }
  106 +
  107 + onNuiAudioStateChanged(state:Constants.AudioState):void {
  108 + // console.info(`womx onUsrNuiAudioStateChanged(${state})`)
  109 + if (state === Constants.AudioState.STATE_OPEN){
  110 + // console.info(`womx onUsrNuiAudioStateChanged(${state}) audio recorder start`)
  111 + //AudioCapturer.init(g_asrinstance)
  112 + AudioCapturer.start()
  113 + // console.info(`womx onUsrNuiAudioStateChanged(${state}) audio recorder start done`)
  114 + } else if (state === Constants.AudioState.STATE_CLOSE){
  115 + // console.info(`womx onUsrNuiAudioStateChanged(${state}) audio recorder close`)
  116 + AudioCapturer.stop()
  117 + //AudioCapturer.release()
  118 + // console.info(`womx onUsrNuiAudioStateChanged(${state}) audio recorder close done`)
  119 + } else if (state === Constants.AudioState.STATE_PAUSE){
  120 + // console.info(`womx onUsrNuiAudioStateChanged(${state}) audio recorder pause`)
  121 + AudioCapturer.stop()
  122 + //AudioCapturer.release()
  123 + // console.info(`womx onUsrNuiAudioStateChanged(${state}) audio recorder pause done`)
  124 + }
  125 + }
  126 + onNuiAudioRMSChanged(val:number):number{
  127 + // console.info(`womx onNuiAudioRMSChanged(${val})`)
  128 + return 0;
  129 + }
  130 + clearAsrInfo(){
  131 + this.asrmessage = ""
  132 + }
  133 +}
  134 +
  135 +const TAG = 'VoiceRecoginizer'
  136 +
  137 +export class VoiceRecoginizer {
  138 + private static MICROPHONEMISSION: Permissions = 'ohos.permission.MICROPHONE'
  139 + private static READMEDIA: Permissions = 'ohos.permission.READ_MEDIA'
  140 + private static INTENT: Permissions = "ohos.permission.INTERNET"
  141 + private static WRITE_MEDIA: Permissions = "ohos.permission.WRITE_MEDIA"
  142 +
  143 + private static appKey = "EospGmM6mdPljjjm"
  144 + private static url = "wss://nls-gateway.cn-shanghai.aliyuncs.com:443/ws/v1"
  145 + private authToken?: NetLayerVoiceRecoginizerToken
  146 +
  147 + private vadMode: boolean = false
  148 +
  149 + private cbhandle: NativeNuiCallbackHandle = new NativeNuiCallbackHandle()
  150 +
  151 + private g_asrinstance: NativeNui = new NativeNui(Constants.ModeType.MODE_DIALOG, "asr1")
  152 +
  153 + private static manager: VoiceRecoginizer
  154 +
  155 + public static sharedManager(): VoiceRecoginizer {
  156 + if (!VoiceRecoginizer.manager) {
  157 + VoiceRecoginizer.manager = new VoiceRecoginizer()
  158 + }
  159 + return VoiceRecoginizer.manager
  160 + }
  161 +
  162 + voiceRecoginizerResult?:(result: string) => void
  163 + // public voiceRecoginzerResult:(result: string) => void
  164 + genParams():string {
  165 + let params:string = "";
  166 + let nls_config:Map<string, string|number|boolean|object> = new Map();
  167 + nls_config.set("enable_intermediate_result", true);
  168 +
  169 + //参数可根据实际业务进行配置
  170 + //接口说明可见: https://help.aliyun.com/document_detail/173298.html
  171 + //查看 2.开始识别
  172 +
  173 + //由于对外的SDK不带有本地VAD模块(仅带有唤醒功能的SDK具有VAD模块),
  174 + //若要使用VAD模式,则需要设置nls_config参数启动在线VAD模式(见genParams())
  175 + if (this.vadMode) {
  176 + nls_config.set("enable_voice_detection", true);
  177 + nls_config.set("max_start_silence", 10000);
  178 + nls_config.set("max_end_silence", 800);
  179 + } else {
  180 + nls_config.set("enable_voice_detection", false);
  181 + }
  182 +
  183 + nls_config.set("enable_punctuation_prediction", true);
  184 + nls_config.set("enable_inverse_text_normalization", true);
  185 + // nls_config.set("customization_id", "test_id");
  186 + // nls_config.set("vocabulary_id", "test_id");
  187 + // nls_config.set("sample_rate", 16000);
  188 + // nls_config.set("sr_format", "opus");
  189 +
  190 + let parameters:Map<string, string|number|boolean|object> = new Map();
  191 + parameters.set("nls_config", Object( JSON.parse(MapToJson(nls_config)) ) );
  192 +
  193 + //一句话识别
  194 + // console.log("start asr for 一句话识别")
  195 + parameters.set("service_type", Constants.kServiceTypeASR); // 必填
  196 + //如果有HttpDns则可进行设置
  197 + //parameters.put("direct_ip", Utils.getDirectIp());
  198 +
  199 + params = MapToJson(parameters);//parameters.toString();
  200 + console.log("configinfo genParams" + params)
  201 + return params;
  202 + }
  203 + genInitParams(workpath:string, debugpath:string):string {
  204 + let str:string = "";
  205 + //获取token方式:
  206 +
  207 + let object:Map<string, string|number|boolean|object> = new Map();
  208 +
  209 + //账号和项目创建
  210 + // ak_id ak_secret app_key如何获得,请查看https://help.aliyun.com/document_detail/72138.html
  211 + object.set("app_key",VoiceRecoginizer.appKey); // 必填
  212 +
  213 + //方法1:
  214 + // 首先ak_id ak_secret app_key如何获得,请查看https://help.aliyun.com/document_detail/72138.html
  215 + // 然后请看 https://help.aliyun.com/document_detail/466615.html 使用其中方案一获取临时凭证
  216 + // 此方案简介: 远端服务器生成具有有效时限的临时凭证, 下发给移动端进行使用, 保证账号信息ak_id和ak_secret不被泄露
  217 + // 获得Token方法(运行在APP服务端): https://help.aliyun.com/document_detail/450255.html?spm=a2c4g.72153.0.0.79176297EyBj4k
  218 +
  219 + if (this.authToken) {
  220 + object.set("token", this.authToken.accessToken)
  221 + }
  222 + //方法2:
  223 + // STS获取临时凭证方法暂不支持
  224 +
  225 + //方法3:(强烈不推荐,存在阿里云账号泄露风险)
  226 + // 参考Auth类的实现在端上访问阿里云Token服务获取SDK进行获取。请勿将ak/sk存在本地或端侧环境。
  227 + // 此方法优点: 端侧获得Token, 无需搭建APP服务器。
  228 + // 此方法缺点: 端侧获得ak/sk账号信息, 极易泄露。
  229 + // JSONObject object = Auth.getAliYunTicket();
  230 +
  231 + object.set("device_id", DeviceUtil.clientId()/*Utils.getDeviceId()*/); // 必填, 推荐填入具有唯一性的id, 方便定位问题
  232 + object.set("url", VoiceRecoginizer.url); // 默认
  233 + object.set("workspace", workpath); // 必填, 且需要有读写权限
  234 + // object.set("sample_rate", "16000");
  235 + // object.set("format", "pcm");
  236 +
  237 + //当初始化SDK时的save_log参数取值为true时,该参数生效。表示是否保存音频debug,该数据保存在debug目录中,需要确保debug_path有效可写。
  238 + // object.put("save_wav", "true");
  239 + //debug目录,当初始化SDK时的save_log参数取值为true时,该目录用于保存中间音频文件。
  240 + object.set("debug_path", debugpath);
  241 +
  242 + // FullMix = 0 // 选用此模式开启本地功能并需要进行鉴权注册
  243 + // FullCloud = 1
  244 + // FullLocal = 2 // 选用此模式开启本地功能并需要进行鉴权注册
  245 + // AsrMix = 3 // 选用此模式开启本地功能并需要进行鉴权注册
  246 + // AsrCloud = 4
  247 + // AsrLocal = 5 // 选用此模式开启本地功能并需要进行鉴权注册
  248 + //一句话识别
  249 + // console.log("init asr for 一句话识别")
  250 + object.set("service_mode", Constants.ModeAsrCloud); // 必填
  251 +
  252 + str = MapToJson(object)
  253 +
  254 + // console.info("configinfo genInitParams:" + str);
  255 + return str;
  256 + }
  257 +
  258 + async AsrInit(path:string, filePath:string): Promise<number> {
  259 + //console.log("AsrInit this is " + JSON.stringify(this))
  260 + // console.info("AsrInit path: " + path);
  261 + //获取工作路径, 这里获得当前nuisdk.aar中assets路径
  262 +
  263 + let asset_path:string = path+"/resources_cloud"
  264 + // fs.stat(asset_path).catch((error: BusinessError) => {
  265 + // if (error.code = 13900002) {
  266 + // fs.mkdirSync(asset_path)
  267 + // }
  268 + // })
  269 + // fs.mkdirSync(asset_path)
  270 + // try {
  271 + // await this.checkPath(asset_path)
  272 + this.cbhandle.nuiCallback = (result: string) => {
  273 + if (this.voiceRecoginizerResult) {
  274 + this.voiceRecoginizerResult(result)
  275 + }
  276 + }
  277 +
  278 + let parameters: string = ""
  279 + // this.genInitParams(asset_path,filePath)
  280 + // .then(parameters) {
  281 + //
  282 + // }
  283 + await this.getToken()
  284 +
  285 + let ret:number = this.g_asrinstance.initialize(this.cbhandle, this.genInitParams(asset_path,filePath), Constants.LogLevel.LOG_LEVEL_NONE, false);
  286 + // console.info("result = " + ret);
  287 + if (ret == Constants.NuiResultCode.SUCCESS) {
  288 +
  289 + } else {
  290 + // Logger.debug(TAG,"语音识别初始化失败")
  291 + //final String msg_text = Utils.getMsgWithErrorCode(ret, "init");
  292 + //抛出错误异常信息。
  293 + /*
  294 + runOnUiThread(new Runnable() {
  295 + @Override
  296 + public void run() {
  297 + Toast.makeText(SpeechRecognizerActivity.this, msg_text, Toast.LENGTH_LONG).show();
  298 + }
  299 + });
  300 + */
  301 + }
  302 + // return ret
  303 + // }
  304 + // catch {
  305 + // return -1;
  306 + // }
  307 + //初始化SDK,注意用户需要在Auth.getAliYunTicket中填入相关ID信息才可以使用。
  308 + return ret
  309 + }
  310 +
  311 + // checkPath(asset_path:string):Promise<void> {
  312 + // return new Promise<void> ((success,fail) => {
  313 + // fs.stat(asset_path).catch((error: BusinessError) => {
  314 + // if (error.code = 13900002) {
  315 + // fs.mkdirSync(asset_path)
  316 + // success()
  317 + // return
  318 + // }
  319 + // success()
  320 + // })
  321 + // })
  322 + // }
  323 + startDialog():number {
  324 + // console.log(`womx startDialog uid[${process.uid}] pid[${process.pid}] tid[${process.tid}]`);
  325 + this.cbhandle.clearAsrInfo()
  326 + //由于对外的SDK不带有本地VAD模块(仅带有唤醒功能的SDK具有VAD模块),
  327 + //若要使用VAD模式,则需要设置nls_config参数启动在线VAD模式(见genParams())
  328 + let vad_mode:Constants.VadMode = Constants.VadMode.TYPE_P2T;
  329 + if (this.vadMode) {
  330 + //TYPE_VAD: SDK自动判断句尾结束识别。(此功能仅存在于<029>带唤醒功能的SDK)
  331 + //vad_mode = Constants.VadMode.TYPE_VAD;
  332 + // console.info("使用Voice Active Detection模式");
  333 + } else {
  334 + //TYPE_P2T: 有用户主动stop()以告知识别完成
  335 + //vad_mode = Constants.VadMode.TYPE_P2T;
  336 + // console.info("使用Push To Talk模式");
  337 + }
  338 +
  339 + //设置相关识别参数,具体参考API文档
  340 + // initialize()之后startDialog之前调用
  341 + this.g_asrinstance.setParams(this.genParams());
  342 + AudioCapturer.init(this.g_asrinstance)
  343 + let ret:number = this.g_asrinstance.startDialog(vad_mode, "");
  344 + // console.info("start done . ret = ", ret);
  345 + if (ret != 0) {
  346 + // console.info("call startDialog return error. ", ret);
  347 + }
  348 + return ret
  349 + }
  350 +
  351 + stop() {
  352 + this.cbhandle.clearAsrInfo()
  353 + AudioCapturer.stop()
  354 + }
  355 +
  356 + static async checkPemmission (context: common.UIAbilityContext) {
  357 +
  358 + let grant = await PermissionUtils.checkPermissions(VoiceRecoginizer.WRITE_MEDIA)
  359 +
  360 + if (grant) {
  361 + ///初始化SDK
  362 + // Logger.debug("已申请过权限")
  363 + return
  364 + }
  365 + // let context = getContext()
  366 + let requestGrant = await PermissionUtils.reqPermissionsFromUser([VoiceRecoginizer.MICROPHONEMISSION
  367 + ,VoiceRecoginizer.READMEDIA
  368 + ,VoiceRecoginizer.WRITE_MEDIA
  369 + ,VoiceRecoginizer.INTENT],context)
  370 + if (requestGrant) {
  371 + ///初始化SDK
  372 + }
  373 + // return false
  374 + }
  375 +
  376 +
  377 + private async getToken():Promise<NetLayerVoiceRecoginizerToken | undefined> {
  378 + return new Promise<NetLayerVoiceRecoginizerToken|undefined>((success,fail) => {
  379 + if (this.authToken && this.authToken.accessToken.length > 0) {
  380 + if (Date.now() < this.authToken.expireTime - 60 * 1000) {
  381 + success(this.authToken)
  382 + return
  383 + }
  384 + }
  385 +
  386 + HttpRequest.get<ResponseDTO<NetLayerVoiceRecoginizerToken>>(
  387 + HttpUrlUtils.getVoiceRecognizerSDKAuthToken()
  388 + ).then((res: ResponseDTO<NetLayerVoiceRecoginizerToken>) => {
  389 + if (res.code != 0) {
  390 + fail(res.message)
  391 + return
  392 + }
  393 + this.authToken = res.data
  394 + success(res.data)
  395 + })
  396 + })
  397 +
  398 + }
  399 +
  400 +
  401 +}
  1 +{
  2 + "cei":{
  3 + "cei_param_version":"2.2.0",
  4 + "cei_param_device_type":"car",
  5 + "cei_param_reco_mode":0,
  6 + "cei_param_log_level":2,
  7 + "cei_param_debug_path":"asr_debug",
  8 + "cei_param_is_debug_enable":false,
  9 + "cei_param_resource_path":"",
  10 + "cei_param_resource_is_multi_language":false,
  11 + "cei_param_audio_format_str":"16k16bitmono",
  12 + "cei_param_mcs_mode":0,
  13 + "cei_param_work_mode":0,
  14 + "cei_param_max_cache_frames":1000,
  15 + "cei_param_is_aec_bf_active":false,
  16 + "cei_param_is_agc_active":false,
  17 + "cei_param_is_vad_active":true,
  18 + "cei_param_is_kws_active":true,
  19 + "cei_param_is_sr_active":true
  20 + },
  21 + "asp":{
  22 + "asp_param_is_process_parallel":false,
  23 + "asp_param_is_input_debug_enable":false,
  24 + "asp_param_is_output_debug_enable":false,
  25 + "asp_param_debug_path":"asr_debug",
  26 + "asp_param_is_callback_enable":false,
  27 + "asp_param_callback_period_frames":5
  28 + },
  29 + "vad":{
  30 + "vad_param_is_input_debug_enable":false,
  31 + "vad_param_is_output_debug_enable":false,
  32 + "vad_param_debug_path":"asr_debug",
  33 + "vad_param_asleep_speech_noise_thres":-0.8,
  34 + "vad_param_awake_speech_noise_thres":-0.5,
  35 + "vad_param_asleep_max_speech_segment_time":300000,
  36 + "vad_param_awake_max_speech_segment_time":60000,
  37 + "vad_param_asleep_block_size":3,
  38 + "vad_param_awake_block_size":3,
  39 + "vad_param_front_timeout_interval":8000,
  40 + "vad_param_tail_timeout_interval":800,
  41 + "vad_param_is_detect_start":true,
  42 + "vad_param_is_detect_end":true
  43 + },
  44 + "kws":{
  45 + "kws_param_is_input_debug_enable":false,
  46 + "kws_param_is_output_debug_enable":false,
  47 + "kws_param_debug_path":"asr_debug",
  48 + "kws_param_is_process_parallel":false,
  49 + "kws_param_front_extend_frames":10,
  50 + "kws_param_tail_extend_frames":5,
  51 + "kws_param_encoder_type_str":"opu",
  52 + "kws_param_encoder_bitrate":16000,
  53 + "kws_param_encoder_complexity":2,
  54 + "kws_param_callback_period_ms":100,
  55 + "kws_param_max_frames_per_callback":25,
  56 + "kws_param_max_bytes_per_callback":16000
  57 + },
  58 + "sr":{
  59 + "sr_param_is_input_debug_enable":false,
  60 + "sr_param_is_output_debug_enable":false,
  61 + "sr_param_debug_path":"asr_debug",
  62 + "sr_param_is_itn_enable":true,
  63 + "sr_param_is_do_conf_filter":false,
  64 + "sr_param_is_process_parallel":true,
  65 + "sr_param_is_need_result":false,
  66 + "sr_param_is_need_voice":true,
  67 + "sr_param_ngram_conf_thres":65.0,
  68 + "sr_param_jsgf_conf_thres":65.0,
  69 + "sr_param_encoder_type_str":"opu",
  70 + "sr_param_encoder_bitrate":16000,
  71 + "sr_param_encoder_complexity":2,
  72 + "sr_param_callback_period_ms":100,
  73 + "sr_param_max_frames_per_callback":25,
  74 + "sr_param_max_bytes_per_callback":16000
  75 + },
  76 + "ou":{
  77 + "oss_upload_param_is_enable":false,
  78 + "oss_upload_param_asp_in":false,
  79 + "oss_upload_param_asp_out":false,
  80 + "oss_upload_param_vad_in":false,
  81 + "oss_upload_param_vad_out":false,
  82 + "oss_upload_param_kws_in":false,
  83 + "oss_upload_param_kws_susp_in":false,
  84 + "oss_upload_param_kws_out":false,
  85 + "oss_upload_param_kws_susp_out":false,
  86 + "oss_upload_param_sr_in":false
  87 + }
  88 +}
  1 +{
  2 + "device_type":"phone",
  3 + "assets_version":"1.1.20190902",
  4 + "nui_config":{
  5 + "service_mode":"kModeFullCloud",
  6 + "log_level":"kLogLevelVerbose",
  7 + "enable_recorder_by_user":true,
  8 + "enable_callback_recording":false,
  9 + "enable_dialog":false
  10 + },
  11 + "nls_config":{
  12 + "debug_level":4,
  13 + "sr_format":"opus",
  14 + "sample_rate":16000,
  15 + "dns_timeout":5000,
  16 + "vocab_default_weight":2
  17 + },
  18 + "audio_config":{
  19 + "debug":"none",
  20 + "16k_audio":{
  21 + "name":"16kmono16bit",
  22 + "id":0,
  23 + "mic":{
  24 + "name":"16kmono16bit",
  25 + "debug_heap_pollution":false,
  26 + "read_cnt":0,
  27 + "sample_rate":16000,
  28 + "bits_per_sample":16,
  29 + "channels":1,
  30 + "recording_interval":10,
  31 + "cei_frame_time_len":20,
  32 + "channel_mask":"kAMChannalMaskNone",
  33 + "format_type":"kAMDataFormatPcmInterleaved",
  34 + "endianness":"kAMByteOrderLittleEndian"
  35 + }
  36 + },
  37 + "8k_audio":{
  38 + "name":"8kmono16bit",
  39 + "id":0,
  40 + "mic":{
  41 + "name":"8kmono16bit",
  42 + "debug_heap_pollution":false,
  43 + "read_cnt":0,
  44 + "sample_rate":8000,
  45 + "bits_per_sample":16,
  46 + "channels":1,
  47 + "recording_interval":10,
  48 + "cei_frame_time_len":20,
  49 + "channel_mask":"kAMChannalMaskNone",
  50 + "format_type":"kAMDataFormatPcmInterleaved",
  51 + "endianness":"kAMByteOrderLittleEndian"
  52 + }
  53 + }
  54 + }
  55 +}
  1 +{
  2 + "device_type":"car",
  3 + "mode_type":2,
  4 + "smart_engine":3,
  5 + "encode_type":"pcm",
  6 + "debug_info":{
  7 + "debug_level":0,
  8 + "debug_path":"/sdcard/tmp"
  9 + },
  10 + "common_info":{
  11 + "pitch_level":0,
  12 + "speed_level":1.0,
  13 + "volume":1.0,
  14 + "play_audio":0,
  15 + "callback_raw_data":1,
  16 + "sample_rate":16000,
  17 + "font_name":"xiaoyun",
  18 + "wait_time":2000
  19 + },
  20 + "cache":{
  21 + "on":true,
  22 + "max_cache_size":2000000,
  23 + "save_path":"/sdcard/mit/"
  24 + },
  25 + "font":{
  26 + "on":false,
  27 + "mode":"cmd",
  28 + "save_path":"/sdcard/mit"
  29 + }
  30 +}
  31 +
  1 +{
  2 + "cei":{
  3 + "cei_param_version":"2.2.0",
  4 + "cei_param_device_type":"car",
  5 + "cei_param_reco_mode":0,
  6 + "cei_param_log_level":2,
  7 + "cei_param_debug_path":"asr_debug",
  8 + "cei_param_is_debug_enable":false,
  9 + "cei_param_resource_path":"",
  10 + "cei_param_resource_is_multi_language":false,
  11 + "cei_param_audio_format_str":"16k16bitmono",
  12 + "cei_param_mcs_mode":0,
  13 + "cei_param_work_mode":0,
  14 + "cei_param_max_cache_frames":1000,
  15 + "cei_param_is_aec_bf_active":false,
  16 + "cei_param_is_agc_active":false,
  17 + "cei_param_is_vad_active":true,
  18 + "cei_param_is_kws_active":true,
  19 + "cei_param_is_sr_active":true
  20 + },
  21 + "asp":{
  22 + "asp_param_is_process_parallel":false,
  23 + "asp_param_is_input_debug_enable":false,
  24 + "asp_param_is_output_debug_enable":false,
  25 + "asp_param_debug_path":"asr_debug",
  26 + "asp_param_is_callback_enable":false,
  27 + "asp_param_callback_period_frames":5
  28 + },
  29 + "vad":{
  30 + "vad_param_is_input_debug_enable":false,
  31 + "vad_param_is_output_debug_enable":false,
  32 + "vad_param_debug_path":"asr_debug",
  33 + "vad_param_asleep_speech_noise_thres":-0.8,
  34 + "vad_param_awake_speech_noise_thres":-0.5,
  35 + "vad_param_asleep_max_speech_segment_time":300000,
  36 + "vad_param_awake_max_speech_segment_time":60000,
  37 + "vad_param_asleep_block_size":3,
  38 + "vad_param_awake_block_size":3,
  39 + "vad_param_front_timeout_interval":8000,
  40 + "vad_param_tail_timeout_interval":800,
  41 + "vad_param_is_detect_start":true,
  42 + "vad_param_is_detect_end":true
  43 + },
  44 + "kws":{
  45 + "kws_param_is_input_debug_enable":false,
  46 + "kws_param_is_output_debug_enable":false,
  47 + "kws_param_debug_path":"asr_debug",
  48 + "kws_param_is_process_parallel":false,
  49 + "kws_param_front_extend_frames":10,
  50 + "kws_param_tail_extend_frames":5,
  51 + "kws_param_encoder_type_str":"opu",
  52 + "kws_param_encoder_bitrate":16000,
  53 + "kws_param_encoder_complexity":2,
  54 + "kws_param_callback_period_ms":100,
  55 + "kws_param_max_frames_per_callback":25,
  56 + "kws_param_max_bytes_per_callback":16000
  57 + },
  58 + "sr":{
  59 + "sr_param_is_input_debug_enable":false,
  60 + "sr_param_is_output_debug_enable":false,
  61 + "sr_param_debug_path":"asr_debug",
  62 + "sr_param_is_itn_enable":true,
  63 + "sr_param_is_do_conf_filter":false,
  64 + "sr_param_is_process_parallel":true,
  65 + "sr_param_is_need_result":false,
  66 + "sr_param_is_need_voice":true,
  67 + "sr_param_ngram_conf_thres":65.0,
  68 + "sr_param_jsgf_conf_thres":65.0,
  69 + "sr_param_encoder_type_str":"opu",
  70 + "sr_param_encoder_bitrate":16000,
  71 + "sr_param_encoder_complexity":2,
  72 + "sr_param_callback_period_ms":100,
  73 + "sr_param_max_frames_per_callback":25,
  74 + "sr_param_max_bytes_per_callback":16000
  75 + },
  76 + "ou":{
  77 + "oss_upload_param_is_enable":false,
  78 + "oss_upload_param_asp_in":false,
  79 + "oss_upload_param_asp_out":false,
  80 + "oss_upload_param_vad_in":false,
  81 + "oss_upload_param_vad_out":false,
  82 + "oss_upload_param_kws_in":false,
  83 + "oss_upload_param_kws_susp_in":false,
  84 + "oss_upload_param_kws_out":false,
  85 + "oss_upload_param_kws_susp_out":false,
  86 + "oss_upload_param_sr_in":false
  87 + }
  88 +}
  1 +{
  2 + "device_type":"phone",
  3 + "assets_version":"1.1.20190902",
  4 + "nui_config":{
  5 + "service_mode":"kModeFullCloud",
  6 + "log_level":"kLogLevelVerbose",
  7 + "enable_recorder_by_user":true,
  8 + "enable_callback_recording":false,
  9 + "enable_dialog":false
  10 + },
  11 + "nls_config":{
  12 + "debug_level":4,
  13 + "sr_format":"opus",
  14 + "sample_rate":16000,
  15 + "dns_timeout":5000,
  16 + "vocab_default_weight":2
  17 + },
  18 + "audio_config":{
  19 + "debug":"none",
  20 + "16k_audio":{
  21 + "name":"16kmono16bit",
  22 + "id":0,
  23 + "mic":{
  24 + "name":"16kmono16bit",
  25 + "debug_heap_pollution":false,
  26 + "read_cnt":0,
  27 + "sample_rate":16000,
  28 + "bits_per_sample":16,
  29 + "channels":1,
  30 + "recording_interval":10,
  31 + "cei_frame_time_len":20,
  32 + "channel_mask":"kAMChannalMaskNone",
  33 + "format_type":"kAMDataFormatPcmInterleaved",
  34 + "endianness":"kAMByteOrderLittleEndian"
  35 + }
  36 + },
  37 + "8k_audio":{
  38 + "name":"8kmono16bit",
  39 + "id":0,
  40 + "mic":{
  41 + "name":"8kmono16bit",
  42 + "debug_heap_pollution":false,
  43 + "read_cnt":0,
  44 + "sample_rate":8000,
  45 + "bits_per_sample":16,
  46 + "channels":1,
  47 + "recording_interval":10,
  48 + "cei_frame_time_len":20,
  49 + "channel_mask":"kAMChannalMaskNone",
  50 + "format_type":"kAMDataFormatPcmInterleaved",
  51 + "endianness":"kAMByteOrderLittleEndian"
  52 + }
  53 + }
  54 + }
  55 +}
  1 +{
  2 + "device_type":"car",
  3 + "mode_type":2,
  4 + "smart_engine":3,
  5 + "encode_type":"pcm",
  6 + "debug_info":{
  7 + "debug_level":0,
  8 + "debug_path":"/sdcard/tmp"
  9 + },
  10 + "common_info":{
  11 + "pitch_level":0,
  12 + "speed_level":1.0,
  13 + "volume":1.0,
  14 + "play_audio":0,
  15 + "callback_raw_data":1,
  16 + "sample_rate":16000,
  17 + "font_name":"xiaoyun",
  18 + "wait_time":2000
  19 + },
  20 + "cache":{
  21 + "on":true,
  22 + "max_cache_size":2000000,
  23 + "save_path":"/sdcard/mit/"
  24 + },
  25 + "font":{
  26 + "on":false,
  27 + "mode":"cmd",
  28 + "save_path":"/sdcard/mit"
  29 + }
  30 +}
  31 +