文档管理中心

如何使用Web播放16进制数据流格式的音频

问题现象

接口返回的是mp3音频转化的16进制数据流,要如何通过Web页面嵌入的方式播放这段音频。

背景知识

  • Webview:@ohos.web.webview提供Web控制能力,Web组件提供网页显示的能力。
  • runJavaScript:注入JavaScript脚本。

解决方案

通过Web注入JavaScript脚本的方式来动态把要播放的音频文件传给H5,再通过H5的audioPlayer进行音频播放。

收起
自动换行
深色代码主题
复制
  1. import { webview } from '@kit.ArkWeb';
  2. import { http } from '@kit.NetworkKit';
  3. import { BusinessError } from '@kit.BasicServicesKit';
  4. import { fileIo as fs } from '@kit.CoreFileKit';
  5. import { filePreview } from '@kit.PreviewKit';
  6. @Entry
  7. @Component
  8. struct WebText {
  9. @State musics: Array<string> = [];
  10. private context: Context = this.getUIContext().getHostContext() as Context;
  11. // 在线链接,返回音频的16进制数据流
  12. private url: string = 'www.example.com';
  13. private sandbox: string = this.context.cacheDir + '/new.text';
  14. controller: webview.WebviewController = new webview.WebviewController();
  15. aboutToAppear(): void {
  16. filePreview.canPreview(this.context, this.sandbox).then((result) => {
  17. if (!result) {
  18. let file = fs.openSync(this.sandbox, fs.OpenMode.CREATE);
  19. fs.close(file, (err: BusinessError) => {
  20. if (err) {
  21. console.error('close file failed with error message: ' + err.message + ', error code: ' + err.code);
  22. } else {
  23. console.info('close file succeed');
  24. }
  25. });
  26. }
  27. }).catch((err: BusinessError) => {
  28. console.error('close file failed with error message: ' + err.message + ', error code: ' + err.code);
  29. });
  30. }
  31. build() {
  32. Column() {
  33. Column() {
  34. Web({ src: $rawfile('audio.html'), controller: this.controller })
  35. .domStorageAccess(true)
  36. .javaScriptAccess(true)
  37. .fileAccess(false)
  38. .geolocationAccess(false);
  39. }
  40. .height('20%')
  41. .width('100%');
  42. Column() {
  43. ForEach(this.musics, (item: string) => {
  44. ListItem() {
  45. Text('点击"' + item.toString().substring(0, 10) + '"播放该音频')
  46. .fontSize(16)
  47. .textAlign(TextAlign.Start)
  48. .size({ height: 10, width: '100%' })
  49. .onClick(() => {
  50. try {
  51. this.controller.runJavaScript(
  52. 'playAudio("' + item + '")',
  53. (error, result) => {
  54. if (error) {
  55. console.error(`ErrorCode: ${(error as BusinessError).code}, Message: ${(error as BusinessError).message}`);
  56. console.info(`result is: ${result}`);
  57. return;
  58. }
  59. });
  60. } catch (error) {
  61. console.error(`ErrorCode: ${(error as BusinessError).code}, Message: ${(error as BusinessError).message}`);
  62. }
  63. });
  64. }.margin(10)
  65. .borderRadius(10)
  66. .backgroundColor($r('sys.color.navigation_drag_bar_item_default'));
  67. }, (item: string) => item);
  68. }.height('60%')
  69. .width('100%');
  70. Column() {
  71. Button('获取在线音频并存到沙箱').onClick(() => {
  72. this.readText();
  73. if (!this.musics || this.musics.length === 0) {
  74. this.postHttp();
  75. }
  76. });
  77. }.height('10%')
  78. .width('100%');
  79. }.height('100%')
  80. .width('100%');
  81. }
  82. private postHttp() {
  83. let httpRequest = http.createHttp();
  84. httpRequest.on('headersReceive', (header) => {
  85. console.info(`header:${header}`);
  86. });
  87. httpRequest.request(
  88. this.url,
  89. {
  90. method: http.RequestMethod.POST,
  91. header: {
  92. 'contentType': 'application/json'
  93. },
  94. extraData: 'data to send',
  95. expectDataType: http.HttpDataType.STRING,
  96. usingCache: true,
  97. priority: 1,
  98. connectTimeout: 60000,
  99. readTimeout: 60000,
  100. usingProtocol: http.HttpProtocol.HTTP1_1,
  101. usingProxy: false
  102. }, async (err: BusinessError, data: http.HttpResponse) => {
  103. if (!err) {
  104. let strr = data.result as string;
  105. let lines = strr.split('\n');
  106. this.musics = [];
  107. for (let i = 0; i < lines.length; i++) {
  108. if (lines[i] && lines[i] !== '' && lines[i].startsWith('data:')) {
  109. let linei = lines[i].slice(5);
  110. let dataEntry: DataEntry = JSON.parse(linei) as DataEntry;
  111. let resultData: ResultData = dataEntry.data;
  112. let music = resultData.audio;
  113. if (music && music !== '') {
  114. this.musics.push(music);
  115. this.createText(music);
  116. }
  117. }
  118. }
  119. httpRequest.destroy();
  120. } else {
  121. httpRequest.off('headersReceive');
  122. httpRequest.destroy();
  123. }
  124. }
  125. );
  126. }
  127. private createText(music: string) {
  128. let file = fs.openSync(this.sandbox, fs.OpenMode.READ_WRITE | fs.OpenMode.APPEND);
  129. fs.writeSync(file.fd, music + '\n');
  130. fs.close(file, (err: BusinessError) => {
  131. if (err) {
  132. console.error('close file failed with error message: ' + err.message + ', error code: ' + err.code);
  133. } else {
  134. console.info('close file succeed');
  135. }
  136. });
  137. }
  138. private readText() {
  139. fs.readText(this.sandbox).then((str: string) => {
  140. let lines = str.split('\n');
  141. this.musics = [];
  142. for (let i = 0; i < lines.length; i++) {
  143. let music = lines[i];
  144. if (music && music !== '') {
  145. this.musics.push(music);
  146. }
  147. }
  148. }).catch((err: BusinessError) => {
  149. console.error('readText failed with error message: ' + err.message + ', error code: ' + err.code);
  150. });
  151. }
  152. }
  153. class DataEntry {
  154. data: ResultData = new ResultData;
  155. }
  156. class ResultData {
  157. audio: string = '';
  158. }

html:

收起
自动换行
深色代码主题
复制
  1. <!DOCTYPE html>
  2. <html lang="zh-CN">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>播放音频</title>
  6. <style>
  7. body {
  8. font-family: Arial, sans-serif;
  9. margin: 20px;
  10. }
  11. textarea {
  12. width: 100%;
  13. height: 100px;
  14. }
  15. button {
  16. margin-top: 10px;
  17. }
  18. audio {
  19. margin-top: 10px;
  20. }
  21. </style>
  22. </head>
  23. <body onload='playAudio()'>
  24. <audio id="audioPlayer" muted="" controls></audio>
  25. <script>
  26. function playAudio(hexInput) {
  27. // 将16进制字符串转换为二进制字节数组
  28. const binaryData = Uint8Array.from(hexInput.match(/.{1,2}/g), byte => parseInt(byte, 16));
  29. // 创建一个Blob对象
  30. const blob = new Blob([binaryData], { type: 'audio/mpeg' });
  31. // 创建一个URL对应于该Blob
  32. const url = URL.createObjectURL(blob);
  33. // 设置音频元素的src属性
  34. const audioPlayer = document.getElementById('audioPlayer');
  35. audioPlayer.src = url;
  36. // 播放音频
  37. audioPlayer.play().catch(error => {
  38. });
  39. }
  40. </script>
  41. </body>
  42. </html>
在 FAQ 中进行搜索
请输入您想要搜索的关键词