国产片侵犯亲女视频播放_亚洲精品二区_在线免费国产视频_欧美精品一区二区三区在线_少妇久久久_在线观看av不卡

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務器之家 - 編程語言 - 編程技術 - 鴻蒙AI能力之語音識別

鴻蒙AI能力之語音識別

2021-12-24 19:32鴻蒙社區panda_coder 編程技術

文章旨在幫助大家開發錄音及語音識別時少踩一點坑。AI語音識別不需要任何權限,但此處使用到麥克風錄制音頻,就需要申請麥克風權限。

鴻蒙AI能力之語音識別

文章旨在幫助大家開發錄音及語音識別時少踩一點坑。

效果

鴻蒙AI能力之語音識別

左側為簡易UI布局及識別成果,右側為網易云播放的測試音頻。

開發步驟

IDE安裝、項目創建等在此略過。App采用SDK版本為API 6,使用JS UI。

1.權限申請

AI語音識別不需要任何權限,但此處使用到麥克風錄制音頻,就需要申請麥克風權限。

在config.json配置文件中添加權限:

  1. "reqPermissions": [
  2. {
  3. "name": "ohos.permission.MICROPHONE"
  4. }
  5. ]

在MainAbility中顯示申明麥克風權限:

  1. @Override
  2. public void onStart(Intent intent) {
  3. super.onStart(intent);
  4. requestPermission();
  5. }
  6. //獲取權限
  7. private void requestPermission() {
  8. String[] permission = {
  9. "ohos.permission.MICROPHONE",
  10. };
  11. List applyPermissions = new ArrayList<>();
  12. for (String element : permission) {
  13. if (verifySelfPermission(element) != 0) {
  14. if (canRequestPermission(element)) {
  15. applyPermissions.add(element);
  16. }
  17. }
  18. }
  19. requestPermissionsFromUser(applyPermissions.toArray(new String[0]), 0);
  20. }

2.創建音頻錄制的工具類

首先創建音頻錄制的工具類AudioCaptureUtils。

而音頻錄制需要用到AudioCapturer類,而在創建AudioCapture類時又會用到AudioStreamInfo類及AudioCapturerInfo類,所以我們分別申明以上3個類的變量。

  1. private AudioStreamInfo audioStreamInfo;
  2. private AudioCapturer audioCapturer;
  3. private AudioCapturerInfo audioCapturerInfo;

在語音識別時對音頻的錄制是由限制的,限制如下:

鴻蒙AI能力之語音識別

所以我們在錄制音頻時需要注意:

1.采樣率16000HZ

2.聲道為單聲道

3.僅支持普通話

作為工具類,為了使AudioCaptureUtils能多處使用,我們在創建構造函數時,提供聲道與頻率的參數重載,并在構造函數中初始化AudioStreamInfo類及AudioCapturerInfo類。

  1. //channelMask 聲道
  2. //SampleRate 頻率
  3. public AudioCaptureUtils(AudioStreamInfo.ChannelMask channelMask, int SampleRate) {
  4. this.audioStreamInfo = new AudioStreamInfo.Builder()
  5. .encodingFormat(AudioStreamInfo.EncodingFormat.ENCODING_PCM_16BIT)
  6. .channelMask(channelMask)
  7. .sampleRate(SampleRate)
  8. .build();
  9. this.audioCapturerInfo = new AudioCapturerInfo.Builder().audioStreamInfo(audioStreamInfo).build();
  10. }

在init函數中進行audioCapturer的初始化,在初始化時對音效進行設置,默認為降噪模式。

  1. //packageName 包名
  2. public void init(String packageName) {
  3. this.init(SoundEffect.SOUND_EFFECT_TYPE_NS,packageName );
  4. }
  5. //soundEffect 音效uuid
  6. //packageName 包名
  7. public void init(UUID soundEffect, String packageName) {
  8. if (audioCapturer == null || audioCapturer.getState() == AudioCapturer.State.STATE_UNINITIALIZED)
  9. audioCapturer = new AudioCapturer(this.audioCapturerInfo);
  10. audioCapturer.addSoundEffect(soundEffect, packageName);
  11. }

初始化后提供start、stop和destory方法,分別開啟音頻錄制、停止音頻錄制和銷毀,此處都是調用AudioCapturer類中對應函數。

  1. public void stop(){
  2. this.audioCapturer.stop();
  3. }
  4. public void destory(){
  5. this.audioCapturer.stop();
  6. this.audioCapturer.release();
  7. }
  8. public Boolean start() {
  9. if (audioCapturer == null)
  10. return false;
  11. return audioCapturer.start();
  12. }

提供一個讀取音頻流的方法及獲取AudioCapturer實例的方法。

  1. //buffers 需要寫入的數據流
  2. //offset 數據流的偏移量
  3. //byteslength 數據流的長度
  4. public int read(byte[] buffers, int offset, int bytesLength){
  5. return audioCapturer.read(buffers,offset,bytesLength);
  6. }
  7. //獲取AudioCapturer的實例audioCapturer
  8. public AudioCapturer get(){
  9. return this.audioCapturer;
  10. }

3.創建語音識別的工具類

在上面我們已經創建好一個音頻錄制的工具類,接下來在創建一個語音識別的工具類 AsrUtils。

我們再回顧一下語音識別的約束與限制:

鴻蒙AI能力之語音識別

在此補充一個隱藏限制,PCM流的長度只允許640與1280兩種長度,也就是我們音頻讀取流時只能使用640與1280兩種長度。

接下來我們定義一些基本常量:

  1. //采樣率限定16000HZ
  2. private static final int VIDEO_SAMPLE_RATE = 16000;
  3. //VAD結束時間 默認2000ms
  4. private static final int VAD_END_WAIT_MS = 2000;
  5. //VAD起始時間 默認4800ms
  6. //這兩參數與識別準確率有關,相關信息可百度查看,在此使用系統默認
  7. private static final int VAD_FRONT_WAIT_MS = 4800;
  8. //輸入時常 20000ms
  9. private static final int TIMEOUT_DURATION = 20000;
  10. //PCM流長度僅限640或1280
  11. private static final int BYTES_LENGTH = 1280;
  12. //線程池相關參數
  13. private static final int CAPACITY = 6;
  14. private static final int ALIVE_TIME = 3;
  15. private static final int POOL_SIZE = 3;

因為要在后臺持續錄制音頻,所以需要開辟一個新的線程。此處用到java的ThreadPoolExecutor類進行線程操作。

定義一個線程池實例以及其它相關屬性如下:

  1. //錄音線程
  2. private ThreadPoolExecutor poolExecutor;
  3. /* 自定義狀態信息
  4. ** 錯誤:-1
  5. ** 初始:0
  6. ** init:1
  7. ** 開始輸入:2
  8. ** 結束輸入:3
  9. ** 識別結束:5
  10. ** 中途出識別結果:9
  11. ** 最終識別結果:10
  12. */
  13. public int state = 0;
  14. //識別結果
  15. public String result;
  16. //是否開啟語音識別
  17. //當開啟時才寫入PCM流
  18. boolean isStarted = false;
  19. //ASR客戶端
  20. private AsrClient asrClient;
  21. //ASR監聽對象
  22. private AsrListener listener;
  23. AsrIntent asrIntent;
  24. //音頻錄制工具類
  25. private AudioCaptureUtils audioCaptureUtils;

在構造函數中初始化相關屬性:

  1. public AsrUtils(Context context) {
  2. //實例化一個單聲道,采集頻率16000HZ的音頻錄制工具類實例
  3. this.audioCaptureUtils = new AudioCaptureUtils(AudioStreamInfo.ChannelMask.CHANNEL_IN_MONO, VIDEO_SAMPLE_RATE);
  4. //初始化降噪音效
  5. this.audioCaptureUtils.init("com.panda_coder.liedetector");
  6. //結果值設為空
  7. this.result = "";
  8. //給錄音控件初始化一個新的線程池
  9. poolExecutor = new ThreadPoolExecutor(
  10. POOL_SIZE,
  11. POOL_SIZE,
  12. ALIVE_TIME,
  13. TimeUnit.SECONDS,
  14. new LinkedBlockingQueue<>(CAPACITY),
  15. new ThreadPoolExecutor.DiscardOldestPolicy());
  16. if (asrIntent == null) {
  17. asrIntent = new AsrIntent();
  18. //設置音頻來源為PCM流
  19. //此處也可設置為文件
  20. asrIntent.setAudioSourceType(AsrIntent.AsrAudioSrcType.ASR_SRC_TYPE_PCM);
  21. asrIntent.setVadEndWaitMs(VAD_END_WAIT_MS);
  22. asrIntent.setVadFrontWaitMs(VAD_FRONT_WAIT_MS);
  23. asrIntent.setTimeoutThresholdMs(TIMEOUT_DURATION);
  24. }
  25. if (asrClient == null) {
  26. //實例化AsrClient
  27. asrClient = AsrClient.createAsrClient(context).orElse(null);
  28. }
  29. if (listener == null) {
  30. //實例化MyAsrListener
  31. listener = new MyAsrListener();
  32. //初始化AsrClient
  33. this.asrClient.init(asrIntent, listener);
  34. }
  35. }
  36. //夠建一個實現AsrListener接口的類MyAsrListener
  37. class MyAsrListener implements AsrListener {
  38. @Override
  39. public void onInit(PacMap pacMap) {
  40. HiLog.info(TAG, "====== init");
  41. state = 1;
  42. }
  43. @Override
  44. public void onBeginningOfSpeech() {
  45. state = 2;
  46. }
  47. @Override
  48. public void onRmsChanged(float v) {
  49. }
  50. @Override
  51. public void onBufferReceived(byte[] bytes) {
  52. }
  53. @Override
  54. public void onEndOfSpeech() {
  55. state = 3;
  56. }
  57. @Override
  58. public void onError(int i) {
  59. state = -1;
  60. if (i == AsrError.ERROR_SPEECH_TIMEOUT) {
  61. //當超時時重新監聽
  62. asrClient.startListening(asrIntent);
  63. } else {
  64. HiLog.info(TAG, "======error code:" + i);
  65. asrClient.stopListening();
  66. }
  67. }
  68. //注意與onIntermediateResults獲取結果值的區別
  69. //pacMap.getString(AsrResultKey.RESULTS_RECOGNITION);
  70. @Override
  71. public void onResults(PacMap pacMap) {
  72. state = 10;
  73. //獲取最終結果
  74. //{"result":[{"confidence":0,"ori_word":"你 好 ","pinyin":"NI3 HAO3 ","word":"你好。"}]}
  75. String results = pacMap.getString(AsrResultKey.RESULTS_RECOGNITION);
  76. ZSONObject zsonObject = ZSONObject.stringToZSON(results);
  77. ZSONObject infoObject;
  78. if (zsonObject.getZSONArray("result").getZSONObject(0) instanceof ZSONObject) {
  79. infoObject = zsonObject.getZSONArray("result").getZSONObject(0);
  80. String resultWord = infoObject.getString("ori_word").replace(" ", "");
  81. result += resultWord;
  82. }
  83. }
  84. //中途識別結果
  85. //pacMap.getString(AsrResultKey.RESULTS_INTERMEDIATE)
  86. @Override
  87. public void onIntermediateResults(PacMap pacMap) {
  88. state = 9;
  89. // String result = pacMap.getString(AsrResultKey.RESULTS_INTERMEDIATE);
  90. // if (result == null)
  91. // return;
  92. // ZSONObject zsonObject = ZSONObject.stringToZSON(result);
  93. // ZSONObject infoObject;
  94. // if (zsonObject.getZSONArray("result").getZSONObject(0) instanceof ZSONObject) {
  95. // infoObject = zsonObject.getZSONArray("result").getZSONObject(0);
  96. // String resultWord = infoObject.getString("ori_word").replace(" ", "");
  97. // HiLog.info(TAG, "=========== 9 " + resultWord);
  98. // }
  99. }
  100. @Override
  101. public void onEnd() {
  102. state = 5;
  103. //當還在錄音時,重新監聽
  104. if (isStarted)
  105. asrClient.startListening(asrIntent);
  106. }
  107. @Override
  108. public void onEvent(int i, PacMap pacMap) {
  109. }
  110. @Override
  111. public void onAudioStart() {
  112. state = 2;
  113. }
  114. @Override
  115. public void onAudioEnd() {
  116. state = 3;
  117. }
  118. }

開啟識別與停止識別的函數:

  1. public void start() {
  2. if (!this.isStarted) {
  3. this.isStarted = true;
  4. asrClient.startListening(asrIntent);
  5. poolExecutor.submit(new AudioCaptureRunnable());
  6. }
  7. }
  8. public void stop() {
  9. this.isStarted = false;
  10. asrClient.stopListening();
  11. audioCaptureUtils.stop();
  12. }
  13. //音頻錄制的線程
  14. private class AudioCaptureRunnable implements Runnable {
  15. @Override
  16. public void run() {
  17. byte[] buffers = new byte[BYTES_LENGTH];
  18. //開啟錄音
  19. audioCaptureUtils.start();
  20. while (isStarted) {
  21. //讀取錄音的PCM流
  22. int ret = audioCaptureUtils.read(buffers, 0, BYTES_LENGTH);
  23. if (ret <= 0) {
  24. HiLog.error(TAG, "======Error read data");
  25. } else {
  26. //將錄音的PCM流寫入到語音識別服務中
  27. //若buffer的長度不為1280或640時,則需要手動處理成1280或640
  28. asrClient.writePcm(buffers, BYTES_LENGTH);
  29. }
  30. }
  31. }
  32. }

識別結果是通過listener的回調獲取的結果,所以我們在處理時是將結果賦值給result,通過getresult或getResultAndClear函數獲取結果。

  1. public String getResult() {
  2. return result;
  3. }
  4. public String getResultAndClear() {
  5. if (this.result == "")
  6. return "";
  7. String results = getResult();
  8. this.result = "";
  9. return results;
  10. }

4.創建一個簡易的JS UI,并通過JS調ServerAbility的能力調用Java

hml代碼:

  1. "container">
  2. "title">
  3. 語音識別內容: {{ text }}

樣式代碼:

  1. .container {
  2. flex-direction: column;
  3. justify-content: flex-start;
  4. align-items: center;
  5. width: 100%;
  6. height: 100%;
  7. padding: 10%;
  8. }
  9. .title {
  10. font-size: 20px;
  11. color: #000000;
  12. opacity: 0.9;
  13. text-align: left;
  14. width: 100%;
  15. margin: 3% 0;
  16. }
  17. .btn{
  18. padding: 10px 20px;
  19. margin:3px;
  20. border-radius: 6px;
  21. }

js邏輯控制代碼:

  1. //js調Java ServiceAbility的工具類
  2. import { jsCallJavaAbility } from '../../common/JsCallJavaAbilityUtils.js';
  3. export default {
  4. data: {
  5. text: ""
  6. },
  7. //開啟事件
  8. start() {
  9. jsCallJavaAbility.callAbility("ControllerAbility",100,{}).then(result=>{
  10. console.log(result)
  11. })
  12. },
  13. //關閉事件
  14. stop() {
  15. jsCallJavaAbility.callAbility("ControllerAbility",101,{}).then(result=>{
  16. console.log(result)
  17. })
  18. jsCallJavaAbility.unSubAbility("ControllerAbility",201).then(result=>{
  19. if (result.code == 200) {
  20. console.log("取消訂閱成功");
  21. }
  22. })
  23. },
  24. //訂閱Java端結果事件
  25. sub() {
  26. jsCallJavaAbility.subAbility("ControllerAbility", 200, (data) => {
  27. let text = data.data.text
  28. text && (this.text += text)
  29. }).then(result => {
  30. if (result.code == 200) {
  31. console.log("訂閱成功");
  32. }
  33. })
  34. }
  35. }

ServerAbility:

  1. public class ControllerAbility extends Ability {
  2. AnswerRemote remote = new AnswerRemote();
  3. AsrUtils asrUtils;
  4. //訂閱事件的委托
  5. private static HashMap<Integer, IRemoteObject> remoteObjectHandlers = new HashMap<Integer, IRemoteObject>();
  6. @Override
  7. public void onStart(Intent intent) {
  8. HiLog.error(LABEL_LOG, "ControllerAbility::onStart");
  9. super.onStart(intent);
  10. //初始化語音識別工具類
  11. asrUtils = new AsrUtils(this);
  12. }
  13. @Override
  14. public void onCommand(Intent intent, boolean restart, int startId) {
  15. }
  16. @Override
  17. public IRemoteObject onConnect(Intent intent) {
  18. super.onConnect(intent);
  19. return remote.asObject();
  20. }
  21. class AnswerRemote extends RemoteObject implements IRemoteBroker {
  22. AnswerRemote() {
  23. super("");
  24. }
  25. @Override
  26. public boolean onRemoteRequest(int code, MessageParcel data, MessageParcel reply, MessageOption option) {
  27. Map zsonResult = new HashMap();
  28. String zsonStr = data.readString();
  29. ZSONObject zson = ZSONObject.stringToZSON(zsonStr);
  30. switch (code) {
  31. case 100: {
  32. //當js發送code為100時,開啟語音識別
  33. asrUtils.start();
  34. break;
  35. }
  36. case 101: {
  37. //當js發送code為101時,關閉語音識別
  38. asrUtils.stop();
  39. break;
  40. }
  41. case 200: {
  42. //當js發送code為200時,訂閱獲取識別結果事件
  43. remoteObjectHandlers.put(200 ,data.readRemoteObject());
  44. //定時獲取語音識別結果并返回JS UI
  45. getAsrText();
  46. break;
  47. }
  48. default: {
  49. reply.writeString("service not defined");
  50. return false;
  51. }
  52. }
  53. reply.writeString(ZSONObject.toZSONString(zsonResult));
  54. return true;
  55. }
  56. @Override
  57. public IRemoteObject asObject() {
  58. return this;
  59. }
  60. }
  61. public void getAsrText() {
  62. new Thread(() -> {
  63. while (true) {
  64. try {
  65. Thread.sleep(1 * 500);
  66. Map zsonResult = new HashMap();
  67. zsonResult.put("text",asrUtils.getResultAndClear());
  68. ReportEvent(200, zsonResult);
  69. } catch (RemoteException | InterruptedException e) {
  70. break;
  71. }
  72. }
  73. }).start();
  74. }
  75. private void ReportEvent(int remoteHandler, Object backData) throws RemoteException {
  76. MessageParcel data = MessageParcel.obtain();
  77. MessageParcel reply = MessageParcel.obtain();
  78. MessageOption option = new MessageOption();
  79. data.writeString(ZSONObject.toZSONString(backData));
  80. IRemoteObject remoteObject = remoteObjectHandlers.get(remoteHandler);
  81. remoteObject.sendRequest(100, data, reply, option);
  82. reply.reclaim();
  83. data.reclaim();
  84. }
  85. }

至此簡易的語音識別功能完畢。

相關演示:https://www.bilibili.com/video/BV1E44y177hv/

完整代碼開源:https://gitee.com/panda-coder/harmonyos-apps/tree/master/AsrDemo

原文鏈接:https://harmonyos.51cto.com

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 天天操综合网 | 日韩美女视频 | av一区二区三区四区 | 中文字幕第一区 | 国产露脸国语对白在线 | 亚洲高清视频一区二区 | 精久久久 | 亚洲福利在线观看 | 亚洲精品天堂 | 97国产资源 | 亚洲成年人影院 | 91中文在线 | 欧美日韩精品一区二区三区蜜桃 | 欧美日韩一区精品 | 亚洲欧美国产日韩综合 | 欧美精品久久一区 | 亚洲精品国产剧情久久9191 | 国产在线乱 | 久久人人爽人人爽人人片亚洲 | caoporn最新地址 | 日本中文字幕一区 | 成人在线视频免费 | 亚洲精品午夜视频 | 国产精品免费视频观看 | 国产精品成人一区二区三区 | 精品无码久久久久国产 | 一区二区精品视频 | 欧美精品一区二区三区四区 | 国产一级视频免费观看 | 午夜成人在线视频 | 中文字幕国产一区 | 中文字幕视频免费 | 日韩精品一区二 | 成人免费一区二区三区视频网站 | 国产精品久久精品 | 毛片免费电影 | www.亚色网.com| 黄色在线免费看 | 国产中文字幕网 | 91精品国产一区二区三区四区在线 | 欧美福利在线 |