cc_app.lua 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246
  1. --[[
  2. @module cc_app
  3. @summary 通话业务逻辑模块,实现4种通话场景的处理和通话录音功能
  4. @version 1.0
  5. @date 2025.10.21
  6. @author 陈媛媛
  7. @usage
  8. 本模块提供以下功能:
  9. 1. 设置 ACTIVE_SCENARIO 变量选择需要的场景(1-4)
  10. 2. 其他场景自动禁用,不会影响程序运行
  11. 3. 每个场景都有独立的状态处理逻辑
  12. 4. 实现通话录音功能
  13. 支持的场景:
  14. [场景1] 呼入立即挂断(响铃3次后自动拒接)
  15. [场景2] 呼入自动接听(响2声)+10秒后主动挂断
  16. [场景3] 呼入自动接听(响2声)+等待对方挂断
  17. [场景4] 主动呼出电话+等待对方挂断
  18. 注意事项:
  19. 1. 设置ACTIVE_SCENARIO选择要启用的场景(1-4)
  20. 2. 场景4会主动拨打电话(修改为自己测试时要拨打的电话号码)
  21. 3. 所有通话都会被录音(需确保存储空间足够)
  22. ]]
  23. -- 引入音频设备模块
  24. local audio_drv = require "audio_drv"
  25. -- ====================== 配置区域 ======================
  26. -- 设置当前激活的场景(1-4),注释掉不需要的场景
  27. -- local ACTIVE_SCENARIO = 1 -- 场景1:呼入立即挂断
  28. -- local ACTIVE_SCENARIO = 2 -- 场景2:呼入自动接听,10秒后主动挂断
  29. local ACTIVE_SCENARIO = 3 -- 场景3:呼入自动接听,等待对方挂断
  30. -- local ACTIVE_SCENARIO = 4 -- 场景4:主动呼出,等待对方挂断
  31. -- 全局状态变量
  32. local call_counter = 0 -- 响铃计数器(用于场景1-3)
  33. local caller_number = "" -- 来电号码(用于场景1-3)
  34. local is_connected = false -- 通话连接状态标志(用于场景2)
  35. local outgoing_number = "10000" -- 呼出号码(用于场景4),修改为自己测试时要拨打的电话号码
  36. -- ====================== 录音功能 ======================
  37. -- 创建音频数据缓冲区
  38. local up1 = zbuff.create(6400,0) -- 上行数据保存区1
  39. local up2 = zbuff.create(6400,0) -- 上行数据保存区2
  40. local down1 = zbuff.create(6400,0) -- 下行数据保存区1
  41. local down2 = zbuff.create(6400,0) -- 下行数据保存区2
  42. -- 音频数据回调函数
  43. local function recordCallback(is_dl, point)
  44. if is_dl then
  45. log.info("录音", "下行数据,位于缓存", point+1, "缓存1数据量", down1:used(), "缓存2数据量", down2:used())
  46. else
  47. log.info("录音", "上行数据,位于缓存", point+1, "缓存1数据量", up1:used(), "缓存2数据量", up2:used())
  48. end
  49. log.info("通话质量", cc.quality())
  50. -- 可以在初始化串口后,通过uart.tx来发送走对应的zbuff即可
  51. end
  52. -- 启用通话录音
  53. local function enableRecording()
  54. cc.record(true, up1, up2, down1, down2)
  55. cc.on("record", recordCallback)
  56. log.info("cc_app", "通话录音已启用")
  57. end
  58. -- 获取所有缓冲区
  59. local function getRecordingBuffers()
  60. return {
  61. up1 = up1,
  62. up2 = up2,
  63. down1 = down1,
  64. down2 = down2
  65. }
  66. end
  67. -- ====================== 场景处理函数 ======================
  68. -- 场景1:呼入立即挂断(响铃3次后)
  69. local function handle_scenario1(status)
  70. if status == "INCOMINGCALL" then
  71. -- 获取来电号码
  72. caller_number = cc.lastNum() or "未知号码"
  73. call_counter = call_counter + 1
  74. log.info("场景1", "收到来电,号码:", caller_number, "响铃次数:", call_counter)
  75. -- 响铃3声后拒接
  76. if call_counter >= 3 then
  77. log.info("场景1", "拒接来电")
  78. cc.hangUp(0)
  79. call_counter = 0 -- 重置计数器
  80. end
  81. elseif status == "HANGUP_CALL_DONE" then
  82. log.info("场景1", "挂断完成")
  83. call_counter = 0
  84. end
  85. end
  86. -- 场景2挂断回调函数
  87. local function scenario2_hangup_callback()
  88. log.info("场景2", "10秒通话结束,主动挂断")
  89. cc.hangUp(0)
  90. is_connected = false
  91. end
  92. -- 场景2:呼入自动接听,10秒后主动挂断
  93. local function handle_scenario2(status)
  94. if status == "INCOMINGCALL" then
  95. -- 获取来电号码
  96. caller_number = cc.lastNum() or "未知号码"
  97. call_counter = call_counter + 1
  98. log.info("场景2", "收到来电,号码:", caller_number, "响铃次数:", call_counter)
  99. -- 响铃2声后自动接听
  100. if call_counter >= 2 then
  101. log.info("场景2", "自动接听来电")
  102. cc.accept(0)
  103. call_counter = 0 -- 重置计数器
  104. end
  105. elseif status == "ANSWER_CALL_DONE" then
  106. log.info("场景2", "接听完成,等待通话建立")
  107. elseif status == "SPEECH_START" then
  108. -- 语音通话真正开始
  109. if not is_connected then
  110. log.info("场景2", "通话已建立,开始计时")
  111. is_connected = true
  112. -- 创建10秒后挂断的定时器
  113. sys.timerStart(scenario2_hangup_callback, 10000) -- 10秒后执行挂断
  114. log.info("场景2", "10秒挂断定时器创建成功")
  115. end
  116. elseif status == "HANGUP_CALL_DONE" or status == "DISCONNECTED" then
  117. log.info("场景2", "通话结束")
  118. is_connected = false
  119. -- 取消挂断定时器
  120. sys.timerStop(scenario2_hangup_callback)
  121. log.info("场景2", "已取消挂断定时器")
  122. call_counter = 0 -- 重置计数器
  123. end
  124. end
  125. -- 场景3:呼入自动接听,等待对方挂断
  126. local function handle_scenario3(status)
  127. if status == "INCOMINGCALL" then
  128. -- 获取来电号码
  129. caller_number = cc.lastNum() or "未知号码"
  130. call_counter = call_counter + 1
  131. log.info("场景3", "收到来电,号码:", caller_number, "响铃次数:", call_counter)
  132. -- 响铃2声后自动接听
  133. if call_counter >= 2 then
  134. log.info("场景3", "自动接听来电")
  135. cc.accept(0)
  136. call_counter = 0 -- 重置计数器
  137. end
  138. elseif status == "SPEECH_START" then
  139. -- 语音通话真正开始
  140. log.info("场景3", "电话已接通,电话号码:", caller_number)
  141. elseif status == "DISCONNECTED" then
  142. -- 对方挂断通话
  143. log.info("场景3", "通话结束对方挂断")
  144. call_counter = 0 -- 重置计数器
  145. end
  146. end
  147. -- 场景4:主动呼出,等待对方挂断
  148. local function handle_scenario4(status)
  149. if status == "CONNECTED" then
  150. log.info("场景4", "呼叫接通")
  151. elseif status == "DISCONNECTED" then
  152. log.info("场景4", "通话结束(对方挂断)")
  153. elseif status == "MAKE_CALL_FAILED" then
  154. log.info("场景4", "呼叫失败")
  155. end
  156. end
  157. -- 场景4拨号函数
  158. local function dial_for_scenario4()
  159. log.info("场景4", "开始拨打", outgoing_number)
  160. cc.dial(0, outgoing_number)
  161. end
  162. -- ====================== 主事件处理器 ======================
  163. sys.subscribe("CC_IND", function(status)
  164. log.info("CC状态", status)
  165. -- 根据激活的场景调用对应的处理函数
  166. if ACTIVE_SCENARIO == 1 then
  167. handle_scenario1(status)
  168. elseif ACTIVE_SCENARIO == 2 then
  169. handle_scenario2(status)
  170. elseif ACTIVE_SCENARIO == 3 then
  171. handle_scenario3(status)
  172. elseif ACTIVE_SCENARIO == 4 then
  173. handle_scenario4(status)
  174. end
  175. -- 所有场景都需要处理的通用状态
  176. if status == "READY" then
  177. sys.publish("CC_READY") -- 发布系统就绪事件
  178. -- 场景4:电话系统就绪后自动拨号
  179. if ACTIVE_SCENARIO == 4 then
  180. sys.timerStart(dial_for_scenario4, 1000) -- 延迟1秒拨号
  181. end
  182. elseif status == "HANGUP_CALL_DONE" or status == "MAKE_CALL_FAILED" or status == "DISCONNECTED" then
  183. audio.pm(0,audio.STANDBY)
  184. -- audio.pm(0,audio.SHUTDOWN) --低功耗可以选择SHUTDOWN或者POWEROFF,如果codec无法断电用SHUTDOWN
  185. end
  186. end)
  187. -- ====================== 电话系统初始化 ======================
  188. local function init_cc()
  189. -- 初始化音频设备(使用exaudio)
  190. audio_drv.initAudioDevice()
  191. -- 等待电话系统就绪
  192. sys.waitUntil("CC_READY")
  193. -- 初始化电话功能
  194. cc.init(audio_drv.getMultimediaId())
  195. -- 启用通话录音(录音功能在cc_app中)
  196. enableRecording()
  197. log.info("cc_app", "电话系统初始化完成")
  198. end
  199. -- 启动初始化任务
  200. sys.taskInit(init_cc)
  201. log.info("cc_app", "通话业务逻辑模块加载完成,当前场景:", ACTIVE_SCENARIO)
  202. -- 导出录音相关功能(如果需要被其他模块使用)
  203. -- return {
  204. -- enableRecording = enableRecording,
  205. -- getRecordingBuffers = getRecordingBuffers,
  206. -- recordCallback = recordCallback
  207. -- }