record.lua 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183
  1. --- 模块功能:录音处理
  2. -- @module record
  3. -- @author openLuat
  4. -- @license MIT
  5. -- @copyright openLuat
  6. -- @release 2017.11.23
  7. require "log"
  8. require "ril"
  9. module(..., package.seeall)
  10. local FILE = '/record.amr'
  11. local recordType = "FILE"
  12. local recording,stoping,recordCb,stopCbFnc
  13. --- 开始录音
  14. -- @number seconds 录音时长,单位:秒
  15. -- 流录音模式下,如果想长时间录音,可以将此参数设置为0x7FFFFFFF,相当于录音2147483647秒=24855天
  16. -- @function[opt=nil] cbFnc 录音回调函数:
  17. -- 当type参数为"FILE"时,回调函数的调用形式为:
  18. -- cbFnc(result,size)
  19. -- result:录音结果,true表示成功,false或者nil表示失败
  20. -- size:number类型,录音文件的大小,单位是字节,在result为true时才有意义
  21. -- 当type参数为"STREAM"时,回调函数的调用形式为:
  22. -- cbFnc(result,size,tag)
  23. -- result:录音结果,true表示成功,false或者nil表示失败
  24. -- size:number类型,每次上报的录音数据流的大小,单位是字节,在result为true时才有意义
  25. -- tag:string类型,"STREAM"表示录音数据流通知,"END"表示录音结束
  26. -- @string[opt="FILE"] type 录音模式
  27. -- "FILE"表示文件录音模式,录音数据自动保存在文件中,录音结束后,执行一次cbFnc函数
  28. -- "STREAM"表示流录音模式,录音数据保存在内存中,每隔一段时间执行一次cbFnc函数去读取录音数据流,录音结束后再执行一次cbFnc函数
  29. -- @number[opt=1] quality 录音质量,0:一般质量,1:中等质量,2:高质量,3:无损质量
  30. -- @number[opt=2] rcdType 录音类型,n:1:mic(从麦克风录制),2:voice(录制语音通话,录制的流与上下行通道),3:voice_dual(在poc模式下从麦克风录制)
  31. -- @number[opt=3] format 录音格式,1:pcm,2:wav,3:amrnb,4:speex
  32. -- pcm格式:录音质量参数无效,采样率:8000,单声道,采样精度:16 bit,5秒钟录音80KB左右
  33. -- wav格式:录音质量参数无效,比特率:128kbps,5秒钟录音80KB左右
  34. -- amrnb格式:录音质量参数有效
  35. -- 录音质量为0时:比特率:5.15kbps,5秒钟录音3KB多
  36. -- 录音质量为1时:比特率:6.70kbps,5秒钟录音4KB多
  37. -- 录音质量为2时:比特率:7.95kbps,5秒钟录音4KB多
  38. -- 录音质量为3时:比特率:12.2kbps,5秒钟录音7KB多
  39. -- speex格式:录音质量参数无效,pcm格式128kbps后的压缩格式,5秒钟6KB左右
  40. -- @number[opt=nil] streamRptLen 流录音时,每次上报的字节阀值
  41. -- @usage
  42. -- 文件录音模式,录音5秒,一般质量,amrnb格式,录音结束后执行cbFnc函数:
  43. -- record.start(5,cbFnc)
  44. -- 流录音模式,录音5秒,一般质量,amrnb格式,每隔一段时间执行一次cbFnc函数,录音结束后再执行一次cbFnc函数:
  45. -- record.start(5,cbFnc,"STREAM")
  46. -- 流录音模式,录音5秒,一般质量,amrnb格式,每产生500字节的录音数据执行一次cbFnc函数,录音结束后再执行一次cbFnc函数:
  47. -- record.start(5,cbFnc,"STREAM",nil,nil,500)
  48. function start(seconds, cbFnc, type, quality, rcdType,format, streamRptLen)
  49. if recording or stoping or seconds <= 0 or ((type~="STREAM") and seconds>50) then
  50. log.error('record.start', recording, stoping, seconds)
  51. if cbFnc then cbFnc() end
  52. return
  53. end
  54. delete()
  55. recordType = type or "FILE"
  56. if type=="STREAM" then
  57. --param1: 录音时长 n:单位秒
  58. --param2: 录音质量 n:0:一般质量 1:中等质量 2:高质量 3:无损质量
  59. --param3:录音类型 n:1:mic 2:voice 3:voice_dual
  60. --param4:录音文件类型 n: 1:pcm 2:wav 3:amrnb
  61. audiocore.streamrecord(seconds,quality or 1,rcdType or 1,format or 3,streamRptLen)
  62. else
  63. --param1: 录音保存文件
  64. --param2: 录音时长 n:单位秒
  65. --param3: 录音质量 n:0:一般质量 1:中等质量 2:高质量 3:无损质量
  66. --param4:录音类型 n:1:mic 2:voice 3:voice_dual
  67. --param5:录音文件类型 n: 1:pcm 2:wav 3:amrnb
  68. audiocore.record(FILE,seconds,quality or 1,rcdType or 1,format or 3)
  69. end
  70. log.info("record.start",seconds,recordType,format or 3)
  71. recording = true
  72. recordCb = cbFnc
  73. return true
  74. end
  75. --- 停止录音
  76. -- @function[opt=nil] cbFnc 停止录音的回调函数(停止结果通过此函数通知用户),回调函数的调用形式为:
  77. -- cbFnc(result)
  78. -- result:number类型
  79. -- 0表示停止成功
  80. -- 1表示之前已经发送了停止动作,请耐心等待停止结果的回调
  81. -- @usage record.stop(cb)
  82. function stop(cbFnc)
  83. if not recording then
  84. if cbFnc then cbFnc(0) end
  85. return
  86. end
  87. if stoping then
  88. if cbFnc then cbFnc(1) end
  89. return
  90. end
  91. stopCbFnc = cbFnc
  92. log.info("record.stop")
  93. audiocore.stoprecord()
  94. stoping = true
  95. end
  96. --- 读取录音文件的完整路径
  97. -- @return string 录音文件的完整路径
  98. -- @usage filePath = record.getFilePath()
  99. function getFilePath()
  100. return FILE
  101. end
  102. --- 读取录音数据
  103. -- @param offset 偏移位置
  104. -- @param len 长度
  105. -- @return data 录音数据
  106. -- @usage data = record.getData(0, 1024)
  107. function getData(offset, len)
  108. local f = io.open(FILE, "rb")
  109. if not f then log.error('record.getData', 'open failed') return "" end
  110. if not f:seek("set", offset) then log.error('record.getData', 'seek failed') f:close() return "" end
  111. local data = f:read(len)
  112. f:close()
  113. log.info("record.getData", data and data:len() or 0)
  114. return data or ""
  115. end
  116. --- 读取录音文件总长度,录音时长
  117. -- @return fileSize 录音文件大小
  118. -- @return duration 录音时长
  119. -- @usage fileSize, duration = record.getSize()
  120. function getSize()
  121. local size,duration = io.fileSize(FILE),0
  122. if size>6 then
  123. duration = ((size-6)-((size-6)%1600))/1600
  124. end
  125. return size, duration
  126. end
  127. --- 删除录音
  128. -- @usage record.delete()
  129. function delete()
  130. log.info("record.delete")
  131. audiocore.deleterecord()
  132. os.remove(FILE)
  133. end
  134. --- 判断是否存在录音
  135. -- @return result true - 有录音 false - 无录音
  136. -- @usage result = record.exists()
  137. function exists()
  138. return io.exists(FILE)
  139. end
  140. --- 是否正在处理录音
  141. -- @return result true - 正在处理 false - 空闲
  142. -- @usage result = record.isBusy()
  143. function isBusy()
  144. return recording or stoping
  145. end
  146. rtos.on(rtos.MSG_RECORD,function(msg)
  147. log.info("record.MSG_RECORD",msg.record_end_ind,msg.record_error_ind,recordType)
  148. --文件录音,在回调时可以删除录音buf;但是流录音,一定要等buf读取完成后,再删除
  149. if recordType=="FILE" then audiocore.deleterecord() end
  150. if msg.record_error_ind then
  151. delete()
  152. if recordCb then recordCb(false,0,"END") recordCb = nil end
  153. recording = false
  154. stoping = false
  155. if stopCbFnc then stopCbFnc(0) stopCbFnc=nil end
  156. end
  157. if msg.record_end_ind then
  158. if recordCb then recordCb(true,recordType=="FILE" and io.fileSize(FILE) or 0,"END") recordCb = nil end
  159. recording = false
  160. stoping = false
  161. if stopCbFnc then stopCbFnc(0) stopCbFnc=nil end
  162. end
  163. end)
  164. rtos.on(rtos.MSG_STREAM_RECORD,function(msg)
  165. log.info("record.MSG_STREAM_RECORD",msg.wait_read_len)
  166. if recordCb then recordCb(true,msg.wait_read_len,"STREAM") end
  167. end)