wangliang_wd

Merge branch 'main' of http://192.168.1.42/developOne/harmonyPool into main

* 'main' of http://192.168.1.42/developOne/harmonyPool:
  ref |> 搜索集成语音输入
  ref |> 评论输入面板集成语音识别
  ref |> 初步写语音输入UI
  过时代码注销
Showing 28 changed files with 1284 additions and 25 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 +}
@@ -106,3 +106,7 @@ export { CustomPullToRefresh } from './src/main/ets/components/reusable/CustomPu @@ -106,3 +106,7 @@ export { CustomPullToRefresh } from './src/main/ets/components/reusable/CustomPu
106 export { MorningEveningViewModel } from './src/main/ets/viewmodel/MorningEveningViewModel' 106 export { MorningEveningViewModel } from './src/main/ets/viewmodel/MorningEveningViewModel'
107 107
108 export { GrayManageModel } from './src/main/ets/viewmodel/GrayManageModel' 108 export { GrayManageModel } from './src/main/ets/viewmodel/GrayManageModel'
  109 +
  110 +export { VoiceInputView } from './src/main/ets/components/comment/view/VoiceInputView'
  111 +
  112 +// export {voicese}
@@ -5,11 +5,11 @@ import { promptAction } from '@kit.ArkUI'; @@ -5,11 +5,11 @@ import { promptAction } from '@kit.ArkUI';
5 import { image } from '@kit.ImageKit'; 5 import { image } from '@kit.ImageKit';
6 import { photoAccessHelper } from '@kit.MediaLibraryKit'; 6 import { photoAccessHelper } from '@kit.MediaLibraryKit';
7 import fs from '@ohos.file.fs'; 7 import fs from '@ohos.file.fs';
8 -import { DateTimeUtils, NetworkUtil, PermissionUtil } from 'wdKit'; 8 +import { DateTimeUtils, NetworkUtil, PermissionUtil, PermissionUtils } from 'wdKit';
9 import { PrivacySettingModel } from '../model/PrivacySettingModel'; 9 import { PrivacySettingModel } from '../model/PrivacySettingModel';
10 import { TrackConstants, TrackingButton } from 'wdTracking'; 10 import { TrackConstants, TrackingButton } from 'wdTracking';
11 import { faceDetector } from '@kit.CoreVisionKit'; 11 import { faceDetector } from '@kit.CoreVisionKit';
12 -import mediaLibrary from '@ohos.multimedia.mediaLibrary'; 12 +// import mediaLibrary from '@ohos.multimedia.mediaLibrary';
13 import fileIo from '@ohos.file.fs'; 13 import fileIo from '@ohos.file.fs';
14 import { httpRequest } from '../utils/httpRequest'; 14 import { httpRequest } from '../utils/httpRequest';
15 import { taskpool } from '@kit.ArkTS'; 15 import { taskpool } from '@kit.ArkTS';
@@ -61,6 +61,15 @@ export struct ImageDownloadComponent { @@ -61,6 +61,15 @@ export struct ImageDownloadComponent {
61 .iconColor(Color.White) 61 .iconColor(Color.White)
62 .onClick(async () => { 62 .onClick(async () => {
63 //console.info(`cj2024 onClick ${this.imageBuffer}`) 63 //console.info(`cj2024 onClick ${this.imageBuffer}`)
  64 + // let readGrant = await PermissionUtils.checkPermissions(PERMISSIONS[0])
  65 + // let writeGrant = await PermissionUtils.checkPermissions(PERMISSIONS[1])
  66 + // console.info(`cj2024 onClick readGrant ${readGrant} writeGrant ${writeGrant}`)
  67 + // if (!readGrant && !writeGrant) {
  68 + // const context = getContext(this) as common.UIAbilityContext;
  69 + // let requestGrant = await PermissionUtils.reqPermissionsFromUser(PERMISSIONS, context);
  70 + // } else {
  71 + //
  72 + // }
64 if (this.imageBuffer !== undefined) { 73 if (this.imageBuffer !== undefined) {
65 try { 74 try {
66 await this.saveImage(this.imageBuffer); 75 await this.saveImage(this.imageBuffer);
@@ -134,7 +143,7 @@ export struct ImageDownloadComponent { @@ -134,7 +143,7 @@ export struct ImageDownloadComponent {
134 * @returns 143 * @returns
135 */ 144 */
136 async saveImage(buffer: ArrayBuffer | string): Promise<void> { 145 async saveImage(buffer: ArrayBuffer | string): Promise<void> {
137 - //console.info(`cj2024 saveImage buffer ${buffer} isGranted = ${this.isGranted}`) 146 + console.info(`cj2024 saveImage buffer ${buffer} isGranted = ${this.isGranted}`)
138 if (!this.isGranted) { 147 if (!this.isGranted) {
139 //跳转权限设置 148 //跳转权限设置
140 // const permissionUtil = new PermissionUtil(); 149 // const permissionUtil = new PermissionUtil();
@@ -154,23 +163,23 @@ export struct ImageDownloadComponent { @@ -154,23 +163,23 @@ export struct ImageDownloadComponent {
154 // const file = await fs.open(uri, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE); 163 // const file = await fs.open(uri, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE);
155 // await fs.write(file.fd, buffer); 164 // await fs.write(file.fd, buffer);
156 // await fs.close(file.fd); 165 // await fs.close(file.fd);
157 - let media = mediaLibrary.getMediaLibrary(context);  
158 - let publicPath = await media.getPublicDirectory(mediaLibrary.DirectoryType.DIR_IMAGE);  
159 - let picName = DateTimeUtils.getCurDate(DateTimeUtils.PATTERN_DATE_TIME_DEFAULT) + '.jpg'  
160 - // //console.info(`cj2024 saveImage time ${picName}`)  
161 - let asset = await media.createAsset(mediaLibrary.MediaType.IMAGE, picName, publicPath);  
162 -  
163 - if (asset) {  
164 - let fd = await asset.open('rw');  
165 - await fileIo.write(fd, buffer);  
166 - await asset.close(fd);  
167 - promptAction.showToast({ message: '已保存至相册!' });  
168 - } else {  
169 - if (this.isGranted) {  
170 - promptAction.showToast({ message: '保存图片失败!' });  
171 - }  
172 -  
173 - throw new Error('Failed to create asset');  
174 - } 166 + // let media = mediaLibrary.getMediaLibrary(context);
  167 + // let publicPath = await media.getPublicDirectory(mediaLibrary.DirectoryType.DIR_IMAGE);
  168 + // let picName = DateTimeUtils.getCurDate(DateTimeUtils.PATTERN_DATE_TIME_DEFAULT) + '.jpg'
  169 + // // //console.info(`cj2024 saveImage time ${picName}`)
  170 + // let asset = await media.createAsset(mediaLibrary.MediaType.IMAGE, picName, publicPath);
  171 + //
  172 + // if (asset) {
  173 + // let fd = await asset.open('rw');
  174 + // await fileIo.write(fd, buffer);
  175 + // await asset.close(fd);
  176 + // promptAction.showToast({ message: '已保存至相册!' });
  177 + // } else {
  178 + // if (this.isGranted) {
  179 + // promptAction.showToast({ message: '保存图片失败!' });
  180 + // }
  181 + //
  182 + // throw new Error('Failed to create asset');
  183 + // }
175 } 184 }
176 } 185 }
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'
  9 +import { VoiceInputView } from './VoiceInputView'
  10 +import { common, UIAbility } from '@kit.AbilityKit'
8 11
9 export interface CommentDialogInputContent { 12 export interface CommentDialogInputContent {
10 comment?: string 13 comment?: string
@@ -27,6 +30,7 @@ export struct CommentCustomDialog { @@ -27,6 +30,7 @@ export struct CommentCustomDialog {
27 onPublishBtnClickTrack?: () => void // 和confirm配套使用。当设置了onPublishBtnClick 则无效 30 onPublishBtnClickTrack?: () => void // 和confirm配套使用。当设置了onPublishBtnClick 则无效
28 31
29 @State private emojiSwitch: boolean = false 32 @State private emojiSwitch: boolean = false
  33 + @State private voiceSwitch: boolean = false
30 textInputController: TextAreaController = new TextAreaController() 34 textInputController: TextAreaController = new TextAreaController()
31 @State positionInfo: CaretOffset = { index: 0, x: 0, y: 0 } 35 @State positionInfo: CaretOffset = { index: 0, x: 0, y: 0 }
32 @State publishButtonOpacity: number = 0.5 36 @State publishButtonOpacity: number = 0.5
@@ -105,6 +109,9 @@ export struct CommentCustomDialog { @@ -105,6 +109,9 @@ export struct CommentCustomDialog {
105 if (this.emojiSwitch) { 109 if (this.emojiSwitch) {
106 this.emojiSwitch = false 110 this.emojiSwitch = false
107 } 111 }
  112 + if (this.voiceSwitch) {
  113 + this.voiceSwitch = false
  114 + }
108 }) 115 })
109 } 116 }
110 .backgroundColor('#F9F9F9') 117 .backgroundColor('#F9F9F9')
@@ -117,8 +124,21 @@ export struct CommentCustomDialog { @@ -117,8 +124,21 @@ export struct CommentCustomDialog {
117 Row() { 124 Row() {
118 Row({ space: 12 }) { 125 Row({ space: 12 }) {
119 //语音暂时不做,隐藏 126 //语音暂时不做,隐藏
120 - // Image($r('app.media.WDInput_voice')).width(30).height(30)  
121 - 127 + Image($r(this.voiceSwitch ? 'app.media.WDInput_keyboardImage' : 'app.media.WDInput_voice'))
  128 + .width(30)
  129 + .height(30)
  130 + .onClick(() => {
  131 + VoiceRecoginizer.checkPemmission(getContext(this) as common.UIAbilityContext)
  132 + this.positionInfo = this.textInputController.getCaretOffset()
  133 + this.voiceSwitch = !this.voiceSwitch
  134 + this.emojiSwitch = false
  135 + if (this.voiceSwitch) {
  136 + this.textInputController.stopEditing()
  137 + } else {
  138 + focusControl.requestFocus("textAreaId") // 弹起键盘
  139 + // this.textInputController.caretPosition(this.textInputController.getTextContentRect().x)
  140 + }
  141 + })
122 Image($r(this.emojiSwitch ? 'app.media.WDInput_keyboardImage' : 'app.media.WDInput_emojiImage')) 142 Image($r(this.emojiSwitch ? 'app.media.WDInput_keyboardImage' : 'app.media.WDInput_emojiImage'))
123 .width(30) 143 .width(30)
124 .height(30) 144 .height(30)
@@ -127,6 +147,7 @@ export struct CommentCustomDialog { @@ -127,6 +147,7 @@ export struct CommentCustomDialog {
127 this.positionInfo = this.textInputController.getCaretOffset() 147 this.positionInfo = this.textInputController.getCaretOffset()
128 148
129 this.emojiSwitch = !this.emojiSwitch 149 this.emojiSwitch = !this.emojiSwitch
  150 + this.voiceSwitch = false
130 if (this.emojiSwitch) { 151 if (this.emojiSwitch) {
131 this.textInputController.stopEditing() 152 this.textInputController.stopEditing()
132 } else { 153 } else {
@@ -137,6 +158,7 @@ export struct CommentCustomDialog { @@ -137,6 +158,7 @@ export struct CommentCustomDialog {
137 }) 158 })
138 } 159 }
139 160
  161 +
140 // Blank() 162 // Blank()
141 163
142 Row() { 164 Row() {
@@ -172,6 +194,12 @@ export struct CommentCustomDialog { @@ -172,6 +194,12 @@ export struct CommentCustomDialog {
172 if (this.emojiSwitch) { 194 if (this.emojiSwitch) {
173 emojiView({ publishCommentModel: this.publishCommentModel }).height(150) 195 emojiView({ publishCommentModel: this.publishCommentModel }).height(150)
174 } 196 }
  197 + if (this.voiceSwitch) {
  198 + VoiceInputView({voiceRecoginizerResult:(result: string) => {
  199 + this.publishCommentModel.commentContent = result;
  200 + }}).height(150)
  201 +
  202 + }
175 203
176 }.backgroundColor(Color.White) 204 }.backgroundColor(Color.White)
177 .width('100%') 205 .width('100%')
  1 +import Lottie from '@ohos/lottie'
  2 +import { LottieView } from '../../lottie/LottieView'
  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';
  7 +
  8 +@Component
  9 +export struct VoiceInputView {
  10 +
  11 + @State private playAnimationOne: boolean = false
  12 +
  13 + // @State private playAnimationTwo: boolean = false
  14 +
  15 + @State private tips:string = "长按开始语音输入"
  16 +
  17 + voiceRe: VoiceRecoginizer = VoiceRecoginizer.sharedManager()
  18 +
  19 + voiceRecoginizerResult?:(result: string) => void
  20 +
  21 + aboutToAppear(): void {
  22 + this.initVoiceRecoigzer()
  23 + }
  24 +
  25 + aboutToDisappear(): void {
  26 + this.voiceRe.stop()
  27 + this.voiceRe.voiceRecoginizerResult = undefined
  28 + }
  29 +
  30 + build() {
  31 + Column() {
  32 + Stack() {
  33 + Row() {
  34 + if (this.playAnimationOne) {
  35 + LottieView({
  36 + name: 'voice_input_one',
  37 + path: "lottie/search_animation_two.json",
  38 + lottieWidth: 100,
  39 + lottieHeight: 100,
  40 + autoplay: true,
  41 + loop: true,
  42 + // onComplete:() => {
  43 + // this.playAnimationOne = false
  44 + // }
  45 + })
  46 + }
  47 + }.height(100)
  48 + Button()
  49 + .type(ButtonType.Circle)
  50 + .backgroundImage($r('app.media.WDInput_voice_longPress_icon'))
  51 + .backgroundColor(Color.White)
  52 + .width(60)
  53 + .height(60)
  54 + .gesture(
  55 + LongPressGesture()
  56 + .onAction((event: GestureEvent) => {
  57 + // this
  58 + this.playAnimationOne = true
  59 + this.tips = ""
  60 + this.voiceRe.startDialog()
  61 + })
  62 +
  63 + .onActionEnd((event: GestureEvent) => {
  64 + this.tips = "长按开始语音输入"
  65 + this.playAnimationOne = false
  66 + this.voiceRe.stop()
  67 + // this.voiceRe.voiceRecoginizerResult = undefined
  68 +
  69 + })
  70 + )
  71 + }
  72 + Blank()
  73 + Text(this.tips)
  74 + .fontSize(13)
  75 + .fontColor("#222222")
  76 + }
  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 + }
  92 +}
1 import router from '@ohos.router' 1 import router from '@ohos.router'
  2 +import { VoiceRecoginizer } from 'wdHwAbility'
2 import { BreakpointSystem, DateTimeUtils, NetworkUtil, StringUtils, ToastUtils } from 'wdKit' 3 import { BreakpointSystem, DateTimeUtils, NetworkUtil, StringUtils, ToastUtils } from 'wdKit'
3 import { ParamType, TrackConstants, Tracking } from 'wdTracking/Index' 4 import { ParamType, TrackConstants, Tracking } from 'wdTracking/Index'
4 import SearcherAboutDataModel from '../../model/SearcherAboutDataModel' 5 import SearcherAboutDataModel from '../../model/SearcherAboutDataModel'
@@ -8,6 +9,8 @@ import { SearchHistoryComponent } from './SearchHistoryComponent' @@ -8,6 +9,8 @@ import { SearchHistoryComponent } from './SearchHistoryComponent'
8 import { SearchHotsComponent } from './SearchHotsComponent' 9 import { SearchHotsComponent } from './SearchHotsComponent'
9 import { SearchRelatedComponent } from './SearchRelatedComponent' 10 import { SearchRelatedComponent } from './SearchRelatedComponent'
10 import { SearchResultComponent } from './SearchResultComponent' 11 import { SearchResultComponent } from './SearchResultComponent'
  12 +import { VoiceSearchCustomDialog } from './VoiceSearchCustomDialog'
  13 +import { common } from '@kit.AbilityKit'
11 14
12 const TAG = "SearchComponent" 15 const TAG = "SearchComponent"
13 16
@@ -37,6 +40,7 @@ export struct SearchComponent { @@ -37,6 +40,7 @@ export struct SearchComponent {
37 @StorageProp('currentBreakpoint') @Watch("currentChanged") currentBreakpoint: string = 'sm'; 40 @StorageProp('currentBreakpoint') @Watch("currentChanged") currentBreakpoint: string = 'sm';
38 private breakpointSystem = new BreakpointSystem(); 41 private breakpointSystem = new BreakpointSystem();
39 @State percent: number = 1 42 @State percent: number = 1
  43 + private commentInputDialogController?: CustomDialogController
40 44
41 currentChanged() { 45 currentChanged() {
42 if (this.currentBreakpoint == "md" || this.currentBreakpoint == "lg") { 46 if (this.currentBreakpoint == "md" || this.currentBreakpoint == "lg") {
@@ -366,17 +370,22 @@ export struct SearchComponent { @@ -366,17 +370,22 @@ export struct SearchComponent {
366 } 370 }
367 }) 371 })
368 372
369 - Image($r('app.media.search_input_del_icon')) 373 + Image($r(StringUtils.isEmpty(this.searchText) ? 'app.media.search_voice_icon' : 'app.media.search_input_del_icon'))
370 .width(`${this.calcHeight(31)}lpx`) 374 .width(`${this.calcHeight(31)}lpx`)
371 .height(`${this.calcHeight(31)}lpx`) 375 .height(`${this.calcHeight(31)}lpx`)
372 .objectFit(ImageFit.Auto) 376 .objectFit(ImageFit.Auto)
373 .interpolation(ImageInterpolation.Medium) 377 .interpolation(ImageInterpolation.Medium)
374 .onClick(() => { 378 .onClick(() => {
  379 + if (StringUtils.isEmpty(this.searchText)) { ///唤起语音搜索
  380 + this.stopInput()
  381 + this.voiceSearchDialog()
  382 + }else { ///清除输入内容
375 this.searchText = "" 383 this.searchText = ""
  384 + }
376 }) 385 })
377 .offset({ x: 10 }) 386 .offset({ x: 10 })
378 .enabled(true) 387 .enabled(true)
379 - .visibility(StringUtils.isEmpty(this.searchText) ? Visibility.Hidden : Visibility.Visible) 388 + // .visibility(StringUtils.isEmpty(this.searchText) ? Visibility.Hidden : Visibility.Visible)
380 389
381 }.padding({ right: `${this.calcHeight(70)}lpx` }) 390 }.padding({ right: `${this.calcHeight(70)}lpx` })
382 .layoutWeight(1) 391 .layoutWeight(1)
@@ -406,6 +415,31 @@ export struct SearchComponent { @@ -406,6 +415,31 @@ export struct SearchComponent {
406 .alignItems(VerticalAlign.Center) 415 .alignItems(VerticalAlign.Center)
407 } 416 }
408 417
  418 + private voiceSearchDialog() {
  419 +
  420 + VoiceRecoginizer.checkPemmission(getContext(this) as common.UIAbilityContext)
  421 +
  422 + this.commentInputDialogController = new CustomDialogController({
  423 + builder: VoiceSearchCustomDialog (
  424 + { onSearchBtnClick:((content:string) => {
  425 + this.commentInputDialogController?.close()
  426 + this.searchText = content
  427 + if (StringUtils.isNotEmpty(this.searchText)) {
  428 + SearcherAboutDataModel.putSearchHistoryData(this.searchText)
  429 + this.getSearchHistoryData()
  430 + this.getSearchInputResData(this.searchText)
  431 + }
  432 + })
  433 + }
  434 + ),
  435 + autoCancel: true,
  436 + alignment: DialogAlignment.Bottom,
  437 + customStyle: true,
  438 + backgroundColor: "#50000000",
  439 + }).open()
  440 +
  441 + }
  442 +
409 getSearchResultCountData() { 443 getSearchResultCountData() {
410 SearcherAboutDataModel.getSearchResultCountData(encodeURI(this.searchText), getContext(this)).then((value) => { 444 SearcherAboutDataModel.getSearchResultCountData(encodeURI(this.searchText), getContext(this)).then((value) => {
411 if (value != null) { 445 if (value != null) {
  1 +
  2 +import { VoiceRecoginizer } from 'wdHwAbility'
  3 +import { common, UIAbility } from '@kit.AbilityKit'
  4 +import { VoiceInputView } from '../comment/view/VoiceInputView'
  5 +
  6 +@Preview
  7 +@CustomDialog
  8 +export struct VoiceSearchCustomDialog {
  9 + controller?: CustomDialogController
  10 + onSearchBtnClick?: (content: string) => void
  11 + @State voiceContent: string = ""
  12 +
  13 + build() {
  14 + Column() {
  15 + Row() {
  16 + TextArea({
  17 + placeholder: '我来说两句',
  18 + text: this.voiceContent
  19 + })
  20 + .placeholderColor("#999999")
  21 + .id("textAreaId")
  22 + .defaultFocus(false) // 获取默认焦点
  23 + .enableKeyboardOnFocus(true)
  24 + .height('100%')
  25 + .width('100%')
  26 + .backgroundColor($r('app.color.color_transparent'))
  27 + .caretColor("#ED2800")
  28 + .onFocus(() => {
  29 + this.controller?.close()
  30 + })
  31 + }
  32 + .backgroundColor('#F9F9F9')
  33 + .margin({ top: 12, right: 12, left: 12, bottom:10})
  34 + .height(80)
  35 + .borderRadius(4)
  36 + Row() {
  37 + Image($r('app.media.WDInput_keyboardImage'))
  38 + .width(30)
  39 + .height(30)
  40 + .onClick(() => {
  41 + this.controller?.close()
  42 + })
  43 + Text('搜索')
  44 + .backgroundColor("#ED2800")
  45 + .width(80)
  46 + .height(30)
  47 + .fontSize(15)
  48 + .fontColor(Color.White)
  49 + .textAlign(TextAlign.Center)
  50 + .borderRadius(4)
  51 + .opacity(this.voiceContent.length > 0 ? 1.0 : 0.5)
  52 + .enabled(this.voiceContent.length > 0)
  53 + .onClick(() => {
  54 + if (this.onSearchBtnClick) {
  55 + this.onSearchBtnClick(this.voiceContent)
  56 + }
  57 + })
  58 + }
  59 + .padding({ left: 12, right: 12 })
  60 + .width('100%')
  61 + .justifyContent(FlexAlign.SpaceBetween)
  62 + VoiceInputView({voiceRecoginizerResult:(result: string) => {
  63 + this.voiceContent = result
  64 + }}).height(150)
  65 + }.backgroundColor(Color.White)
  66 + .width('100%')
  67 +}
  68 +
  69 +}
@@ -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 +{"v":"5.6.10","fr":60,"ip":0,"op":90,"w":560,"h":560,"nm":"波纹","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"语音","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[280,280,0],"ix":2},"a":{"a":0,"k":[12.98,14.416,0],"ix":1},"s":{"a":0,"k":[300,300,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.122,-0.519],[0,0],[-4.764,-0.045],[0,0],[-1.197,4.408],[0,0],[0,0],[-0.519,-0.123],[0,0],[0.123,-0.519],[0,0],[5.457,-0.527],[0,0],[0.008,-0.042],[0.016,-0.039],[0.023,-0.035],[0.03,-0.03],[0.035,-0.023],[0.039,-0.016],[0.041,-0.009],[0.042,0],[0,0],[0.041,0.008],[0.039,0.016],[0.036,0.024],[0.03,0.03],[0.023,0.035],[0.017,0.039],[0.008,0.041],[0,0.042],[0,0],[1.37,5.161],[0,0],[0,0],[-0.52,0.122],[0,0]],"o":[[0,0],[1.08,4.582],[0,0],[4.646,-0.044],[0,0],[0,0],[0.124,-0.519],[0,0],[0.519,0.123],[0,0],[-1.272,5.357],[0,0],[0,0.042],[-0.009,0.041],[-0.016,0.039],[-0.024,0.035],[-0.029,0.03],[-0.035,0.024],[-0.039,0.016],[-0.042,0.008],[0,0],[-0.042,0],[-0.042,-0.009],[-0.039,-0.016],[-0.035,-0.023],[-0.03,-0.03],[-0.024,-0.035],[-0.016,-0.04],[-0.009,-0.042],[0,0],[-5.308,-0.547],[0,0],[0,0],[-0.122,-0.519],[0,0],[0.52,-0.122]],"v":[[-10.101,0.773],[-10.027,1.085],[-0.095,9.016],[0.098,9.016],[9.945,1.421],[10.026,1.102],[10.1,0.79],[11.263,0.072],[11.89,0.221],[12.607,1.385],[12.532,1.697],[1.248,11.531],[1.248,13.523],[1.236,13.648],[1.199,13.768],[1.14,13.88],[1.059,13.977],[0.962,14.057],[0.851,14.118],[0.73,14.154],[0.604,14.167],[-0.684,14.167],[-0.809,14.154],[-0.93,14.118],[-1.042,14.057],[-1.139,13.977],[-1.219,13.88],[-1.279,13.77],[-1.315,13.648],[-1.328,13.523],[-1.328,11.523],[-12.446,2.027],[-12.534,1.676],[-12.608,1.363],[-11.889,0.202],[-11.263,0.053]],"c":true},"ix":2},"nm":"路径 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[0,0],[2.845,0],[0,-2.845],[0,0],[-2.846,0],[0,2.845]],"o":[[0,-2.845],[-2.846,0],[0,0],[0,2.845],[2.845,0],[0,0]],"v":[[5.112,-6.439],[-0.039,-11.59],[-5.191,-6.439],[-5.191,-1.288],[-0.039,3.865],[5.112,-1.288]],"c":true},"ix":2},"nm":"路径 2","mn":"ADBE Vector Shape - Group","hd":false},{"ind":2,"ty":"sh","ix":3,"ks":{"a":0,"k":{"i":[[0,0],[-4.268,0],[0,-4.268],[0,0],[4.268,0],[0,4.267]],"o":[[0,-4.268],[4.268,0],[0,0],[0,4.267],[-4.268,0],[0,0]],"v":[[-7.767,-6.439],[-0.04,-14.167],[7.687,-6.439],[7.687,-1.288],[-0.04,6.439],[-7.767,-1.288]],"c":true},"ix":2},"nm":"路径 3","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"mm","mm":1,"nm":"合并路径 1","mn":"ADBE Vector Filter - Merge","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"填充 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[12.98,14.416],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"组 1","np":5,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":90,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"按钮","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[280,280,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":0,"s":[210,210]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":10,"s":[210,210]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":20,"s":[210,210]},{"t":30,"s":[210,210]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"椭圆路径 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":0,"k":[0.929411764706,0.156862745098,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"填充 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":0,"op":90,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"按钮 2","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[280,280,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":0,"s":[210,210]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":10,"s":[210,210]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":20,"s":[210,210]},{"i":{"x":[0.667,0.667],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":30,"s":[210,210]},{"i":{"x":[0.667,0.667],"y":[1,1]},"o":{"x":[0.333,0.333],"y":[0,0]},"t":90,"s":[210,210]},{"t":130,"s":[300,300]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"椭圆路径 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[0.929411764706,0.156862745098,0,1]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":90,"s":[1,0.683882236481,0.597104787827,1]},{"t":130,"s":[1,0.800000011921,0.745098054409,1]}],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"填充 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":0,"op":90,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"扩散圈","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.908],"y":[0]},"t":234,"s":[100]},{"t":240,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[280,280,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.59,0.59],"y":[1.003,1.003]},"o":{"x":[0.543,0.543],"y":[0,0]},"t":15,"s":[210,210]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":90,"s":[300,300]},{"t":130,"s":[390,390]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"椭圆路径 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":90,"s":[1,0.798773705959,0.745113372803,1]},{"t":130,"s":[0.992156863213,0.882352948189,0.858823537827,1]}],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"填充 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":0,"op":90,"st":0,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":"扩散圈 2","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.908],"y":[0]},"t":234,"s":[100]},{"t":240,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[280,280,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.566,0.566],"y":[0.957,0.957]},"o":{"x":[0.511,0.511],"y":[0.032,0.032]},"t":30,"s":[214.752,214.752]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":90,"s":[390,390]},{"t":130,"s":[480,480]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"椭圆路径 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":90,"s":[0.992432598039,0.884142348346,0.860077861711,1]},{"t":130,"s":[1,0.945098042488,0.933333337307,1]}],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"填充 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":30,"op":90,"st":-30,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":"扩散圈 3","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.566],"y":[1]},"o":{"x":[0.198],"y":[0]},"t":90,"s":[100]},{"i":{"x":[0.847],"y":[1]},"o":{"x":[0.362],"y":[0]},"t":130,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.908],"y":[0]},"t":235,"s":[100]},{"t":241,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[280,280,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.587,0.587],"y":[0.981,0.981]},"o":{"x":[0.526,0.526],"y":[0.103,0.103]},"t":46,"s":[233.126,233.126]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":90,"s":[480,480]},{"t":130,"s":[570,570]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"椭圆路径 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0.946208160999,0.934681372549,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"填充 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":46,"op":90,"st":-14,"bm":0}],"markers":[]}
  1 +{"v":"5.6.10","fr":60,"ip":0,"op":42,"w":560,"h":560,"nm":"波纹","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"语音","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[280,280,0],"ix":2},"a":{"a":0,"k":[12.98,14.416,0],"ix":1},"s":{"a":0,"k":[300,300,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-0.122,-0.519],[0,0],[-4.764,-0.045],[0,0],[-1.197,4.408],[0,0],[0,0],[-0.519,-0.123],[0,0],[0.123,-0.519],[0,0],[5.457,-0.527],[0,0],[0.008,-0.042],[0.016,-0.039],[0.023,-0.035],[0.03,-0.03],[0.035,-0.023],[0.039,-0.016],[0.041,-0.009],[0.042,0],[0,0],[0.041,0.008],[0.039,0.016],[0.036,0.024],[0.03,0.03],[0.023,0.035],[0.017,0.039],[0.008,0.041],[0,0.042],[0,0],[1.37,5.161],[0,0],[0,0],[-0.52,0.122],[0,0]],"o":[[0,0],[1.08,4.582],[0,0],[4.646,-0.044],[0,0],[0,0],[0.124,-0.519],[0,0],[0.519,0.123],[0,0],[-1.272,5.357],[0,0],[0,0.042],[-0.009,0.041],[-0.016,0.039],[-0.024,0.035],[-0.029,0.03],[-0.035,0.024],[-0.039,0.016],[-0.042,0.008],[0,0],[-0.042,0],[-0.042,-0.009],[-0.039,-0.016],[-0.035,-0.023],[-0.03,-0.03],[-0.024,-0.035],[-0.016,-0.04],[-0.009,-0.042],[0,0],[-5.308,-0.547],[0,0],[0,0],[-0.122,-0.519],[0,0],[0.52,-0.122]],"v":[[-10.101,0.773],[-10.027,1.085],[-0.095,9.016],[0.098,9.016],[9.945,1.421],[10.026,1.102],[10.1,0.79],[11.263,0.072],[11.89,0.221],[12.607,1.385],[12.532,1.697],[1.248,11.531],[1.248,13.523],[1.236,13.648],[1.199,13.768],[1.14,13.88],[1.059,13.977],[0.962,14.057],[0.851,14.118],[0.73,14.154],[0.604,14.167],[-0.684,14.167],[-0.809,14.154],[-0.93,14.118],[-1.042,14.057],[-1.139,13.977],[-1.219,13.88],[-1.279,13.77],[-1.315,13.648],[-1.328,13.523],[-1.328,11.523],[-12.446,2.027],[-12.534,1.676],[-12.608,1.363],[-11.889,0.202],[-11.263,0.053]],"c":true},"ix":2},"nm":"路径 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[0,0],[2.845,0],[0,-2.845],[0,0],[-2.846,0],[0,2.845]],"o":[[0,-2.845],[-2.846,0],[0,0],[0,2.845],[2.845,0],[0,0]],"v":[[5.112,-6.439],[-0.039,-11.59],[-5.191,-6.439],[-5.191,-1.288],[-0.039,3.865],[5.112,-1.288]],"c":true},"ix":2},"nm":"路径 2","mn":"ADBE Vector Shape - Group","hd":false},{"ind":2,"ty":"sh","ix":3,"ks":{"a":0,"k":{"i":[[0,0],[-4.268,0],[0,-4.268],[0,0],[4.268,0],[0,4.267]],"o":[[0,-4.268],[4.268,0],[0,0],[0,4.267],[-4.268,0],[0,0]],"v":[[-7.767,-6.439],[-0.04,-14.167],[7.687,-6.439],[7.687,-1.288],[-0.04,6.439],[-7.767,-1.288]],"c":true},"ix":2},"nm":"路径 3","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"mm","mm":1,"nm":"合并路径 1","mn":"ADBE Vector Filter - Merge","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"填充 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[12.98,14.416],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"变换"}],"nm":"组 1","np":5,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":42,"st":-90,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"按钮","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[280,280,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-90,"s":[210,210]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-80,"s":[210,210]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-70,"s":[210,210]},{"t":-60,"s":[210,210]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"椭圆路径 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":0,"k":[0.929411764706,0.156862745098,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"填充 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":0,"op":42,"st":-90,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"按钮 2","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[280,280,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-90,"s":[210,210]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-80,"s":[210,210]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-70,"s":[210,210]},{"i":{"x":[0.667,0.667],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":-60,"s":[210,210]},{"i":{"x":[0.667,0.667],"y":[1,1]},"o":{"x":[0.333,0.333],"y":[0,0]},"t":0,"s":[210,210]},{"t":40,"s":[300,300]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"椭圆路径 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":-90,"s":[0.929411764706,0.156862745098,0,1]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[1,0.683882236481,0.597104787827,1]},{"t":40,"s":[1,0.800000011921,0.745098054409,1]}],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"填充 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":0,"op":42,"st":-90,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"扩散圈","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.908],"y":[0]},"t":144,"s":[100]},{"t":150,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[280,280,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.59,0.59],"y":[1.003,1.003]},"o":{"x":[0.543,0.543],"y":[0,0]},"t":-75,"s":[210,210]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":0,"s":[300,300]},{"t":40,"s":[390,390]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"椭圆路径 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[1,0.798773705959,0.745113372803,1]},{"t":40,"s":[0.992156863213,0.882352948189,0.858823537827,1]}],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"填充 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":0,"op":42,"st":-90,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":"扩散圈 2","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.908],"y":[0]},"t":144,"s":[100]},{"t":150,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[280,280,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.566,0.566],"y":[0.957,0.957]},"o":{"x":[0.511,0.511],"y":[0.032,0.032]},"t":-60,"s":[214.752,214.752]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":0,"s":[390,390]},{"t":40,"s":[480,480]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"椭圆路径 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[0.992432598039,0.884142348346,0.860077861711,1]},{"t":40,"s":[1,0.945098042488,0.933333337307,1]}],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"填充 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":0,"op":42,"st":-120,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":"扩散圈 3","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.566],"y":[1]},"o":{"x":[0.198],"y":[0]},"t":0,"s":[100]},{"i":{"x":[0.847],"y":[1]},"o":{"x":[0.362],"y":[0]},"t":40,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.908],"y":[0]},"t":145,"s":[100]},{"t":151,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[280,280,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.587,0.587],"y":[0.981,0.981]},"o":{"x":[0.526,0.526],"y":[0.103,0.103]},"t":-44,"s":[233.126,233.126]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":0,"s":[480,480]},{"t":40,"s":[570,570]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"椭圆路径 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0.946208160999,0.934681372549,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"填充 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":0,"op":42,"st":-104,"bm":0}],"markers":[]}
  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 +