07 通话中播放音频
作者:拓毅恒 | 最后修改:2026-07-08
一、通话中播放音频概述
- 通话中播放外部音频:在 VoLTE 通话建立后,给对方播放音频文件或 TTS 文本的功能,可用于呼叫中心语音播报、通话中信息提示等场景。
- 文件播放:支持播放 MP3、AMR 等格式的音频文件,框架自动从文件头解析采样率、位宽、声道数等参数。
- TTS 播放:支持将文本转为语音播放,当前 V2046 固件 TTS 仅支持 16K 通话质量播放。
- 通话模式:支持两种模式——呼入自动接听后播放(IS_DIAL=false)和主动拨出后播放(IS_DIAL=true)。
二、演示功能概述
本章节将演示如何使用 Air8000 实现在 VoLTE 通话中给对方播放外部音频:
- 呼入自动接听播放:来电响铃 2 声后自动接听,音频通道建立后播放预设音频
- 主动拨出播放:设备自动拨打预设号码,对方接通后播放预设音频
- 文件播放模式:根据通话质量(8K/16K)自动选择对应采样率的 MP3 文件播放
- TTS 播放模式:将文本转为语音在通话中播放给对方
三、准备硬件环境
参考:Air8000 硬件环境清单,准备好硬件环境,下面 3.1 和 3.2 两种环境二选一即可。
3.1 Air8000 整机开发板
Air8000 开发板提供了丰富的音频接口资源,可通过开发板上的音频接口进行连接和测试。
具备 volte 功能的电话卡插入开发板/核心板的 sim 卡槽。

3.2 Air8000 核心板 + AirAUDIO_1010 配件板
Air8000 核心板集成了移动网络通信功能。

注意:如果搭配 AirAUDIO_1010 扩展板测试,需将 AirAUDIO_1010 扩展板中 PA 开关拨到 OFF,让软件控制 PA,避免 pop 音
Air8000 核心板和 AirAUDIO_1010 配件板的硬件接线方式为:
| Air8000核心板 | AirAUDIO_1010配件板 |
| 22/I2S_MCLK | I2S_MCLK |
| 18/I2S_BCK | I2S_BCK |
| 19/I2S_LRCK | I2S_LRCK |
| 20/I2S_DIN | I2S_DIN |
| 21/I2S_DOUT | I2S_DOUT |
| 80/I2C_SCL | I2C_SCL |
| 81/I2C_SDA | I2C_SDA |
| 82/GPIO17 | PA_EN |
| 83/GPIO16 | 8311_EN |
| VDD_EXT | VCC |
| GND | GND |
四、准备软件环境
4.1 工具 + 内核固件 + 脚本
1、烧录工具 Luatools;
2、本 demo 仅支持 Air8000 V2046 及以上版本的 13/113 号固件使用。https://docs.openluat.com/air8000/luatos/firmware/
3、 luatos 需要的脚本和资源文件
- 脚本和资源文件点我浏览所有文件
- 准备好软件环境之后,接下来查看如何使用 LuaTools 烧录软件,将本篇文章中演示使用的项目文件烧录到 Air8000 核心板中,或者查看 Air8000 系列整机开发板使用手册 V2.0,将本篇文章中演示使用的项目文件烧录到 Air8000 开发板中。
4、lib 脚本文件:使用 Luatools 烧录时,勾选 添加默认 lib 选项,使用默认 lib 脚本文件;
4.2 API 介绍
这里仅介绍本篇文档所使用的 API,详情请查看:API - cc
cc.extern_source(source, is_add_record, is_error_stop, codec_id, sample_rate, data_bits, channel_nums, is_signed)
通话中附加额外的音频数据播放,可在通话中向对方播放音频文件或 TTS 文本。
cc.quality()
获取当前通话质量(采样率),返回值:1=8K 低音质,2=16K 高音质。用于根据通话质量选择对应采样率的音频文件。
cc.on(event, callback)
注册通话事件回调函数。
cc.lastNum()
获取来电号码。
cc.accept(id)
接听来电。
cc.dial(id, number)
拨打电话。
五、代码演示
5.1 通话播放外部音频应用
--[[
@module play_audio_during_cc
@summary 通话中播放音频(文件/TTS)
@version 1.0
@date 2026.07.08
@author 拓毅恒
@usage
本模块演示在VoLTE通话中给对方播放音频文件或TTS文本。
通话接通后在AUDIO_START事件中自动触发播放。
工作流程:
- 系统启动后初始化音频设备和CC
- 由宏IS_DIAL决定是主动拨号还是等待来电接听
- 通话建立(AUDIO_START)后,播放预设音频
注意事项:
1. 本demo使用新音频框架,固件需要V2046及以上的13/113号固件才能播放
2. 使用本demo时需要确认audio_drv.lua中初始化配置的音频框架audio_mode = "new" 才能播放
3. 传入音频文件时(如{"/luadb/test_16k.mp3"}),框架自动从文件头解析
采样率、位宽、声道数等参数,并与当前通话参数自动校验
4. 校验不匹配会静默失败
5. 准备音频文件时需注意:
- 确保文件是16bit、单声道的MP3文件
- 最好准备两种采样率的文件(8K和16K各一份),运行时通过cc.quality()判断后选择
6. 当前V2046固件 TTS 仅支持16K通话质量播放,8K时会静默失败
常用cc.extern_source调用示例:
1. 播放文件: cc.extern_source({"/luadb/test_16k.mp3"}) -- 框架自动识别
2. 播放TTS: cc.extern_source("你好,测试一下")
3. 裸PCM数据: cc.extern_source(pcm_zbuff, nil, audio_v2.DATA_CODEC_TYPE_RAW, 8000, 16, 1, true)
4. 停止播放: cc.extern_source(nil)
]]
-- 引入音频设备模块
local exaudio = require "exaudio"
local audio_drv = require "audio_drv"
-- ====================== 配置区域 ======================
-- 通话模式选择(二选一):
-- true = 主动拨出,false = 等待来电自动接听
local IS_DIAL = false
-- 主动拨出时的目标号码(IS_DIAL=true时有效)
local DIAL_NUMBER = "10000"
-- 播放模式选择(二选一):
local PLAY_MODE = "FILE" -- "FILE"播放文件, "TTS"播放文本
-- 文件播放模式(PLAY_MODE="FILE"时生效):
local PLAY_FILE_8K = "/luadb/test_8k.mp3" -- 8K通话时播放的文件
local PLAY_FILE_16K = "/luadb/test_16k.mp3" -- 16K通话时播放的文件
-- TTS播放模式(PLAY_MODE="TTS"时生效):
local PLAY_TTS_TEXT = "你好,测试一下,123456789"
-- ====================== 全局状态变量 ======================
local call_counter = 0 -- 响铃计数器
local caller_number = "" -- 来电号码
local is_connected = false -- 通话连接状态
-- ====================== 通话事件处理 ======================
-- 来电自动接听模式
local function handle_incoming_call(status)
if status == "INCOMINGCALL" then
-- 获取来电号码
caller_number = cc.lastNum() or "未知号码"
call_counter = call_counter + 1
log.info("play_audio_during_cc", "收到来电,号码:", caller_number, "响铃次数:", call_counter)
-- 响铃2声后自动接听
if call_counter >= 2 then
log.info("play_audio_during_cc", "自动接听来电")
cc.accept(0)
call_counter = 0
end
end
end
-- 主动拨号模式
local function handle_outgoing_call(status)
if status == "MAKE_CALL_OK" then
log.info("play_audio_during_cc", "拨号请求成功")
elseif status == "CONNECTED" then
log.info("play_audio_during_cc", "电话已接通")
elseif status == "MAKE_CALL_FAILED" then
log.info("play_audio_during_cc", "拨号失败")
end
end
-- 根据模式和通话质量获取播放源
local function get_play_source_by_quality(cc_quality)
if PLAY_MODE == "TTS" then
return PLAY_TTS_TEXT
end
-- 文件模式:根据通话质量选择对应的音频文件
if cc_quality == 1 then
return {PLAY_FILE_8K}
elseif cc_quality == 2 then
return {PLAY_FILE_16K}
end
return {PLAY_FILE_16K}
end
-- 通话中播放外部音频(接通音频通道后触发)
local function play_extern_source()
local quality = cc.quality()
log.info("play_audio_during_cc", "通话质量:", quality, "(1=8K低音质, 2=16K高音质)")
-- 先清理上一次通话可能残留的extern_source状态,确保第二次也能播放
cc.extern_source()
-- 根据模式获取播放源
local play_source = get_play_source_by_quality(quality)
-- 播放音频
local ok = cc.extern_source(play_source)
if ok then
if type(play_source) == "table" then
log.info("play_audio_during_cc", "开始播放文件:", play_source[1])
elseif type(play_source) == "string" then
log.info("play_audio_during_cc", "开始播放TTS:", play_source)
end
else
log.error("play_audio_during_cc", "播放失败,可能音频参数与通话不匹配")
end
end
-- 主动拨号模式的定时拨号处理
local function handle_dial_timer()
log.info("play_audio_during_cc", "开始拨号:", DIAL_NUMBER)
cc.dial(0, DIAL_NUMBER)
end
-- CC_IND事件处理器
local function handle_cc_ind(status)
log.info("CC状态", status)
-- 根据模式分发事件
if IS_DIAL then
handle_outgoing_call(status)
else
handle_incoming_call(status)
end
-- AUDIO_START:音频通道已建立,可以播放外部音频
if status == "AUDIO_START" then
play_extern_source()
end
-- SPEECH_START:通话开始
if status == "SPEECH_START" then
is_connected = true
log.info("play_audio_during_cc", "通话已建立")
end
-- 需要处理的通用状态
if status == "READY" then
sys.publish("CC_READY") -- 发布系统就绪事件
-- 主动拨号模式:电话系统就绪后自动拨号
if IS_DIAL then
sys.timerStart(handle_dial_timer, 1000)
end
elseif status == "HANGUP_CALL_DONE" or status == "MAKE_CALL_FAILED" or status == "DISCONNECTED" then
-- 通话结束,关闭PA节省功耗,保留driver下次通话时快速恢复
exaudio.pm(audio.SHUTDOWN)
is_connected = false
call_counter = 0
log.info("play_audio_during_cc", "通话结束")
end
end
-- ====================== 主事件处理器 ======================
sys.subscribe("CC_IND", handle_cc_ind)
-- ====================== 电话系统初始化 ======================
local function init_cc()
-- 初始化音频设备
audio_drv.initAudioDevice()
-- 等待电话系统就绪
sys.waitUntil("CC_READY")
-- 初始化电话功能
cc.init(audio_drv.getMultimediaId())
log.info("play_audio_during_cc", IS_DIAL and "主动拨号模式" or "来电接听模式")
log.info("play_audio_during_cc", "播放模式: ", PLAY_MODE)
log.info("play_audio_during_cc", "电话系统初始化完成")
end
-- 启动初始化任务
sys.taskInit(init_cc)
log.info("play_audio_during_cc", "通话外部音频播放模块加载完成")
六、功能演示
6.1 选择功能
首先注释掉 main.lua 中默认通话功能模块,打开通话中播放外部音频功能模块:

6.2 配置播放参数
在 audio_drv.lua 文件中,将音频框架改为 new

6.3 烧录代码
使用 Luatools 将代码烧录到 Air8000 开发板或核心板中。

6.4 电话系统初始化完成
烧录完毕后,系统会自动初始化音频设备和电话系统。日志中会显示模块加载和初始化完成信息。

6.5 来电响铃(呼入模式)
当有来电时,日志会显示来电号码和响铃次数。响铃 2 声后自动接听。

6.5.1 启动拨号(主动拨出模式)
如果在开头设置为 IS_DIAL = true,设备将自动拨打预设号码,日志显示拨号请求。


6.7 通话建立并播放音频
对方接通后,显示 SPEECH_START 和 AUDIO_START 状态,自动触发播放外部音频。

6.8 播放完成
音频播放完成后,显示 EXT_SRC_DONE 事件。通话继续,等待对方挂断。

6.9 通话结束
对方挂断后,通话结束,显示 DISCONNECTED 状态,系统自动关闭 PA 节省功耗。

七、总结
至此,我们演示了使用 Air8000 在 VoLTE 通话中播放外部音频的全过程:
- 呼入自动播放:来电响铃 2 声后自动接听,音频通道建立后自动播放预设音频
- 主动拨出播放:设备自动拨打预设号码,对方接通后播放预设音频
- 文件播放模式:根据通话质量自动选择对应采样率的音频文件,支持 MP3/AMR 格式
- TTS 播放模式:将文本转为语音在通话中播放给对方
注意事项:
- 本 demo 使用新音频框架,需确认
audio_drv.lua中audio_mode = "new" - 固件需要 V2046 及以上的 13/113 号固件才能播放
- 音频文件准备好 8K 和 16K 两种采样率,运行时通过
cc.quality()判断后选择 - 当前 V2046 固件 TTS 仅支持 16K 通话质量播放,8K 时会静默失败