AirUI 可视化方案仍在优化中,其轻量化、低成本、高可靠的特性在工业场景具备一定应用价值。针对用户对通话录音功能的需求,本文提供一套可直接落地的实现方案,支持自动接听与自动录音,适用于暂无需可视化 UI 的场景参考。
一、方案功能
基于LuatOS开发,适配多种型号核心板,可实现低成本通话留痕,适用于客服系统、会议记录、远程问诊、话务工单追溯等场景。
主要功能特色如下:
自动接听: 来电响铃2声后自动接听,无需手动操作。
自动录音: 通话接通后自动开始录音,对方挂断后自动停止。
SD卡存储: 录音文件以PCM格式保存到SD卡,支持自动挂载和空间检测。
数据优化: 只保存上行数据,避免下行数据造成的回声问题。
跨模组兼容: Air780EHM、Air780EGH、Air780EHV、Air8000系列核心板,均可通过外挂音频配件板和SD卡存储配件板实现。
简而言之:一套方案搞定多个硬件型号,极大提升开发效率。
二、主要硬件准备
方案一:Air8000/Air780EHV开发板
开发板提供了丰富的音频接口资源,可通过开发板上的音频接口进行连接和测试。
如Air8000/Air780EHV开发板:

方案二:核心板+配件板
如果没有Air780EHV和Air8000系列Turnkey开发板,那么可使用Air780EHM、Air780EGH、Air780EHV、Air8000系列核心板,通过外挂音频配件板和存储配件板来实现通话录音功能。
AirAUDIO_1010音频配件板: 负责音频输入输出;
AirMICROSD_1010存储配件板: 提供SD卡存储功能。
连接小贴士: 如果搭配AirAUDIO_1010扩展板测试,需将扩展板中PA开关拨到OFF,让软件控制PA,避免pop音。
本文以Air780EGH为例:
接线方式参照下方图表对应连接(注意不同型号核心板具体引脚号差异):


三、开源示例与教程
基于LuatOS开发的通话录音示例已上传Gitee开源仓库,即便是新接触LuatOS开发的朋友,也可以根据合宙资料中心提供配套实操教程快速上手。
核心功能模块包括SD卡挂载、通话状态机、录音数据回调等,完整示例代码详见源码仓库最新文件。
--[[ 录音功能特性: - 录音文件保存为PCM格式:/sd/record_call.pcm - 只保存上行数据(包含本地声音和网络回声) - 下行数据自动跳过,避免重复存储 - 支持SD卡自动挂载和空间检测 -- ====================== 录音功能 ====================== -- 创建音频数据缓冲区 local up1 = zbuff.create(BUFFER_SIZE,0) -- 上行数据保存区1 local up2 = zbuff.create(BUFFER_SIZE,0) -- 上行数据保存区2 local down1 = zbuff.create(BUFFER_SIZE,0) -- 下行数据保存区1 local down2 = zbuff.create(BUFFER_SIZE,0) -- 下行数据保存区2 -- 打开录音文件 local function open_record_file() -- 先挂载SD卡 if not mount_sd_card() then log.error("录音文件", "SD卡挂载失败,无法进行录音") return false end log.info("录音文件", "SD卡挂载成功,录音文件将保存到SD卡") -- 关闭已打开的文件 if record_file then record_file:close() record_file = nil end -- 删除旧录音文件 if io.exists(RECORD_FILE_PATH) then os.remove(RECORD_FILE_PATH) log.info("录音文件", "删除旧录音文件:", RECORD_FILE_PATH) end -- 创建录音文件 record_file = io.open(RECORD_FILE_PATH, "wb") if record_file then log.info("录音文件", "创建录音文件成功:", RECORD_FILE_PATH) record_start_time = mcu.ticks() is_recording_to_file = true return true else log.error("录音文件", "创建录音文件失败:", RECORD_FILE_PATH) return false end end -- 关闭录音文件 local function close_record_file() if record_file then record_file:close() record_file = nil local file_size = io.fileSize(RECORD_FILE_PATH) record_duration = (mcu.ticks() - record_start_time) / 1000 -- 转换为秒 log.info("录音文件", "录音完成", "文件大小:", file_size, "字节", "录音时长:", string.format("%.1f", record_duration), "秒", "路径:", RECORD_FILE_PATH) is_recording_to_file = false record_start_time = 0 record_duration = 0 end end -- 写入录音数据到文件 local function write_record_data(buff, is_downlink) if not record_file or not is_recording_to_file then return false end -- 保存数据 if not is_downlink then local data_size = buff:used() if data_size > 0 then local start_time = mcu.ticks() -- 写入数据到文件 record_file:write(buff:query()) local end_time = mcu.ticks() local write_time = end_time - start_time local write_speed = data_size / (write_time / 1000) -- 字节/秒 log.info("录音写入", "数据大小:", data_size, "字节,", "写入耗时:", string.format("%.2f", write_time), "ms,", "写入速度:", string.format("%.2f", write_speed / 1024), "KB/s") return true end else -- 下行数据不保存,只记录日志 -- 写入下行数据会导致文件内有回声 local data_size = buff:used() if data_size > 0 then log.info("录音写入", "下行数据跳过", "数据大小:", data_size, "字节") end end return false end -- 音频数据回调函数 local function recordCallback(is_dl, point) if is_dl then log.info("录音", "下行数据,位于缓存", point+1, "缓存1数据量", down1:used(), "缓存2数据量", down2:used()) -- 处理下行数据 if point == 0 then write_record_data(down1, true) down1:del() -- 清空缓冲区 else write_record_data(down2, true) down2:del() -- 清空缓冲区 end else log.info("录音", "上行数据,位于缓存", point+1, "缓存1数据量", up1:used(), "缓存2数据量", up2:used()) -- 处理上行数据 if point == 0 then write_record_data(up1, false) up1:del() -- 清空缓冲区 else write_record_data(up2, false) up2:del() -- 清空缓冲区 end end log.info("通话质量", cc.quality()) end -- 启用通话录音 local function enableRecording() cc.record(true, up1, up2, down1, down2) cc.on("record", recordCallback) log.info("cc_app", "通话录音已启用") end -- 开始通话录音到文件 local function start_call_recording() if open_record_file() then log.info("通话录音", "开始录音到文件:", RECORD_FILE_PATH) return true else log.error("通话录音", "无法开始录音到文件,请检查SD卡") return false end end -- 停止通话录音到文件 local function stop_call_recording() close_record_file() log.info("通话录音", "停止录音到文件") end -- 获取所有缓冲区 local function getRecordingBuffers() return { up1 = up1, up2 = up2, down1 = down1, down2 = down2 } end -- 获取录音文件信息 local function get_record_file_info() if io.exists(RECORD_FILE_PATH) then local file_size = io.fileSize(RECORD_FILE_PATH) return { path = RECORD_FILE_PATH, size = file_size, duration = record_duration, exists = true } else return { path = RECORD_FILE_PATH, size = 0, duration = 0, exists = false } end end -- 呼入自动接听,等待对方挂断 local function handle_scenario(status) if status == "INCOMINGCALL" then -- 获取来电号码 caller_number = cc.lastNum() or "未知号码" call_counter = call_counter + 1 log.info("收到来电,号码:", caller_number, "响铃次数:", call_counter) -- 响铃2声后自动接听 if call_counter >= 2 then log.info("自动接听来电") cc.accept(0) call_counter = 0 -- 重置计数器 end elseif status == "SPEECH_START" then -- 语音通话真正开始 log.info("电话已接通,电话号码:", caller_number) -- 开始通话录音到文件 start_call_recording() elseif status == "DISCONNECTED" then -- 对方挂断通话 log.info("通话结束对方挂断") -- 停止通话录音到文件 stop_call_recording() call_counter = 0 -- 重置计数器 end end -- ====================== 主事件处理器 ====================== sys.subscribe("CC_IND", function(status) log.info("CC状态", status) handle_scenario(status) -- 需要处理的通用状态 if status == "READY" then sys.publish("CC_READY") -- 发布系统就绪事件 elseif status == "HANGUP_CALL_DONE" or status == "MAKE_CALL_FAILED" or status == "DISCONNECTED" then exaudio.pm(audio.SHUTDOWN) --主动进入低功耗模式 end end) -- ====================== 电话系统初始化 ====================== local function init_cc() -- 先尝试挂载SD卡 mount_sd_card() -- 初始化音频设备 audio_drv.initAudioDevice() -- 等待电话系统就绪 sys.waitUntil("CC_READY") -- 初始化电话功能 cc.init(audio_drv.getMultimediaId()) -- 启用通话录音(录音功能在cc_app中) enableRecording() log.info("cc_app", "电话系统初始化完成") end -- 启动初始化任务 sys.taskInit(init_cc) 四、使用注意事项 必须插入SD卡才能使用录音功能,因为录音文件较大无法存入内存;缓冲区大小必须是640的倍数,否则可能导致录音异常。
四、使用注意事项
必须插入SD卡才能使用录音功能,因为录音文件较大无法存入内存;缓冲区大小必须是640的倍数,否则可能导致录音异常。
录音文件保存在SD卡的/sd/record_call.pcm路径下,可以通过读卡器在电脑上查看;录音文件为原始PCM格式,需要使用专用播放器(如Audacity)播放。

-
Lua
+关注
关注
0文章
90浏览量
11507 -
通话录音
+关注
关注
0文章
3浏览量
1125 -
物联网开发
+关注
关注
0文章
12浏览量
1936 -
LuatOS
+关注
关注
0文章
169浏览量
2745
发布评论请先 登录
解决苹果手机通话不能录音的问题
iPhone6手机通话时怎么录音?,完美攻略get起来吧~
电话录音,电话录音系统,电话录音卡,电话录音盒
做好通话录音设备,要考量这几个方面
电脑版本的通话录音软件有哪些
谷歌Android Pie系统正式推出,除了添加一些新特性外通话录音功能遭遇封杀
ios15支持通话录音功能吗 苹果如何设置通话录音
ios15出通话录音,ios15有通话录音吗
电销自动外呼系统的主要功能都有哪些
苹果13有通话录音功能吗
【苹果神器来袭】录音宝,让你的通话录音so easy!
工业场景通话录音:LuatOS 开源方案
通话录音功能实现:自动接听 + 自动录音开源方案
评论