recordAudio.ts 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. import JsRecorder from "js-audio-recorder";
  2. import Recorder from "recorder-core/recorder.mp3.min";
  3. // import Recorder from "recorder-core/recorder.wav.min";
  4. import request from "umi-request";
  5. let mediaRecorder: JsRecorder | null;
  6. let chunks: Blob[] = [];
  7. /**
  8. * 下载录音文件
  9. * @private
  10. * @param {*} blob blob数据
  11. * @param {string} name 下载的文件名
  12. * @param {string} type 下载的文件后缀
  13. */
  14. function _download(blob: Blob, name: string, type: string): void {
  15. let oA = document.createElement("a");
  16. oA.href = window.URL.createObjectURL(blob);
  17. oA.download = `${name}.${type}`;
  18. oA.click();
  19. }
  20. let rec: typeof Recorder | null;
  21. /**调用open打开录音请求好录音权限**/
  22. var recOpen = function (success?: any) {
  23. //一般在显示出录音按钮或相关的录音界面时进行此方法调用,后面用户点击开始录音时就能畅通无阻了
  24. rec = Recorder({
  25. //本配置参数请参考下面的文档,有详细介绍
  26. type: "mp3",
  27. sampleRate: 16000,
  28. bitRate: 16, //mp3格式,指定采样率hz、比特率kbps,其他参数使用默认配置;注意:是数字的参数必须提供数字,不要用字符串;需要使用的type类型,需提前把格式支持文件加载进来,比如使用wav格式需要提前加载wav.js编码引擎
  29. onProcess: function (buffers: any, powerLevel: any, bufferDuration: any, bufferSampleRate: any, newBufferIdx: any, asyncEnd: any) {
  30. console.log(buffers, powerLevel, bufferDuration, bufferSampleRate, newBufferIdx, asyncEnd);
  31. //录音实时回调,大约1秒调用12次本回调,buffers为开始到现在的所有录音pcm数据块(16位小端LE)
  32. //可实时绘制波形(extensions目录内的waveview.js、wavesurfer.view.js、frequency.histogram.view.js插件功能)
  33. //可利用extensions/sonic.js插件实时变速变调,此插件计算量巨大,onProcess需要返回true开启异步模式
  34. //可实时上传(发送)数据,配合Recorder.SampleData方法,将buffers中的新数据连续的转换成pcm上传,或使用mock方法将新数据连续的转码成其他格式上传,可以参考文档里面的:Demo片段列表 -> 实时转码并上传-通用版;基于本功能可以做到:实时转发数据、实时保存数据、实时语音识别(ASR)等
  35. },
  36. });
  37. //var dialog=createDelayDialog(); 我们可以选择性的弹一个对话框:为了防止移动端浏览器存在第三种情况:用户忽略,并且(或者国产系统UC系)浏览器没有任何回调,此处demo省略了弹窗的代码
  38. rec.open(
  39. function () {
  40. //打开麦克风授权获得相关资源
  41. //dialog&&dialog.Cancel(); 如果开启了弹框,此处需要取消
  42. //rec.start() 此处可以立即开始录音,但不建议这样编写,因为open是一个延迟漫长的操作,通过两次用户操作来分别调用open和start是推荐的最佳流程
  43. success && success();
  44. // register('recorder',)
  45. },
  46. function (msg: any, isUserNotAllow: any) {
  47. //用户拒绝未授权或不支持
  48. //dialog&&dialog.Cancel(); 如果开启了弹框,此处需要取消
  49. console.log((isUserNotAllow ? "UserNotAllow," : "") + "无法录音:" + msg);
  50. }
  51. );
  52. };
  53. /**开始录音**/
  54. function recStart() {
  55. //打开了录音后才能进行start、stop调用
  56. rec.start();
  57. }
  58. /**结束录音**/
  59. function recStop() {
  60. rec.stop(
  61. function (blob: Blob, duration: any) {
  62. //简单利用URL生成本地文件地址,注意不用了时需要revokeObjectURL,否则霸占内存
  63. //此地址只能本地使用,比如赋值给audio.src进行播放,赋值给a.href然后a.click()进行下载(a需提供download="xxx.mp3"属性)
  64. var localUrl = (window.URL || webkitURL).createObjectURL(blob);
  65. const formData = new FormData();
  66. formData.append('policy','eyJleHBpcmF0aW9uIjoiMjAyMy0wNS0yNFQxNDowMDo0Mi4wODhaIiwiY29uZGl0aW9ucyI6W1siZXEiLCIkZmlsZW5hbWUiLCJjb3Vyc2V3YXJlLzE2ODQ5MTg4Mzk0NDcubXA0Il0sWyJlcSIsIiRhY2wiLCJwdWJsaWMtcmVhZCJdLFsiZXEiLCIka2V5IiwiY291cnNld2FyZS8xNjg0OTE4ODM5NDQ3Lm1wNCJdLFsiZXEiLCIkYnVja2V0IiwiZ3l0Il0sWyJzdGFydHMtd2l0aCIsIiRuYW1lIiwiIl1dfQ==');
  67. formData.append('signature','H2fdUkZv2ydvDdtxkyrKwm33Ig4=');
  68. formData.append('key','courseware/1684918839447.mp4');
  69. formData.append('KSSAccessKeyId','AKLTtTeIbadpRG-pil4S0Q4m-Q');
  70. formData.append('acl','public-read');
  71. formData.append('name','courseware/1684918839447.mp4');
  72. formData.append('file', blob, 'test.mp3');
  73. request.post('https://gyt.ks3-cn-beijing.ksyuncs.com', {
  74. data: formData,
  75. requestType: 'form'
  76. })
  77. console.log(blob, localUrl, "时长:" + duration + "ms");
  78. _download(blob, "test", "mp3");
  79. rec.close(); //释放录音资源,当然可以不释放,后面可以连续调用start;但不释放时系统或浏览器会一直提示在录音,最佳操作是录完就close掉
  80. // rec=null;
  81. //已经拿到blob文件对象想干嘛就干嘛:立即播放、上传、下载保存
  82. /*** 【立即播放例子】 ***/
  83. var audio = document.createElement("audio");
  84. audio.controls = true;
  85. audio.style.position = "fixed";
  86. audio.style.top = "0px";
  87. audio.style.zIndex = "99999";
  88. document.body.appendChild(audio);
  89. audio.src = localUrl;
  90. audio.play();
  91. },
  92. function (msg: any) {
  93. console.log("录音失败:" + msg);
  94. // rec.close();//可以通过stop方法的第3个参数来自动调用close
  95. // rec=null;
  96. }
  97. );
  98. }
  99. //我们可以选择性的弹一个对话框:为了防止移动端浏览器存在第三种情况:用户忽略,并且(或者国产系统UC系)浏览器没有任何回调
  100. /*伪代码:
  101. function createDelayDialog(){
  102. if(Is Mobile){//只针对移动端
  103. return new Alert Dialog Component
  104. .Message("录音功能需要麦克风权限,请允许;如果未看到任何请求,请点击忽略~")
  105. .Button("忽略")
  106. .OnClick(function(){//明确是用户点击的按钮,此时代表浏览器没有发起任何权限请求
  107. //此处执行fail逻辑
  108. console.log("无法录音:权限请求被忽略");
  109. })
  110. .OnCancel(NOOP)//自动取消的对话框不需要任何处理
  111. .Delay(8000); //延迟8秒显示,这么久还没有操作基本可以判定浏览器有毛病
  112. };
  113. };
  114. */
  115. //这里假设立即运行,只录3秒,录完后立即播放,本段代码copy到控制台内可直接运行
  116. // recOpen(function(){
  117. // recStart();
  118. // setTimeout(recStop,3000);
  119. // });
  120. /**
  121. * 1. 检测是否支持录音
  122. * 2. 获取音频流
  123. * 3. 创建 MediaRecorder 对象
  124. * 4. 监听录音事件
  125. * 5. 开始录音
  126. */
  127. export function createRecordAudio() {
  128. // if (!navigator.mediaDevices || !navigator.mediaDevices.getUserMedia) {
  129. // console.log("浏览器不支持录音");
  130. // return;
  131. // }
  132. // mediaRecorder = new JsRecorder();
  133. // mediaRecorder.onprogress = (payload: any) => {
  134. // console.log(payload);
  135. // };
  136. // console.log("🚀 ~ mediaRecorder:", mediaRecorder);
  137. recOpen();
  138. }
  139. // // 开始录制
  140. export function startRecordingAudio() {
  141. // mediaRecorder?.start();
  142. recStart();
  143. }
  144. // // 停止录制
  145. export function stopRecordingAudio() {
  146. recStop();
  147. // mediaRecorder?.stop();
  148. // mediaRecorder?.downloadWAV("test.wav");
  149. // setTimeout(() => {
  150. // let wavBlob = mediaRecorder?.getWAVBlob();
  151. // console.log(wavBlob);
  152. // }, 1000);
  153. }