Просмотр исходного кода

fix:优化8000 的audio 文件

梁健 6 месяцев назад
Родитель
Сommit
2b8fb9214b

+ 26 - 28
module/Air8000/demo/audio/exaudio.lua

@@ -12,11 +12,11 @@ local exaudio = {}
 local I2S_ID = 0
 local I2S_MODE = 0          -- 0:主机 1:从机
 local I2S_SAMPLE_RATE = 16000
-local I2S_CHANNEL_FORMAT = i2s.MONO_R  -- 0:左声道, 1:右声道, 2:立体声
+local I2S_CHANNEL_FORMAT = i2s.MONO_R  
 local I2S_COMM_FORMAT = i2s.MODE_LSB   -- 可选MODE_I2S, MODE_LSB, MODE_MSB
 local I2S_CHANNEL_BITS = 16
 local MULTIMEDIA_ID = 0
-local MSG_PLAY_DONE = "playDone"
+local EX_MSG_PLAY_DONE = "playDone"
 local ES8311_ADDR = 0x18    -- 7位地址
 local CHIP_ID_REG = 0x00    -- 芯片ID寄存器地址
 
@@ -85,14 +85,16 @@ local function audio_callback(id, event, point)
 
     if event == audio.MORE_DATA then
         if type(audio_play_param.content) == "function" then
-            audio_play_param.content()
+            local data = audio_play_param.content() 
+            if data ~= nil and  type(data) == "string" then
+                audio.write(MULTIMEDIA_ID,data)
+            end
         end
-        
     elseif event == audio.DONE then
         if type(audio_play_param.cbFnc) == "function" then
             audio_play_param.cbFnc(exaudio.PLAY_DONE)
         end
-        sys.publish(MSG_PLAY_DONE)
+        sys.publish(EX_MSG_PLAY_DONE)
         
     elseif event == audio.RECORD_DATA then
         if type(audio_record_param.path) == "function" then
@@ -131,8 +133,6 @@ end
 
 -- 音频硬件初始化
 local function audio_setup()
-    sys.wait(100)
-
     -- I2C配置
     if not i2c.setup(audio_setup_param.i2c_id, i2c.FAST) then
         log.error("I2C初始化失败")
@@ -182,7 +182,6 @@ local function audio_setup()
     audio.micVol(MULTIMEDIA_ID, mic_vol)
     audio.pm(MULTIMEDIA_ID, audio.RESUME)
     
-    sys.wait(100)
     -- 检查芯片连接
     if audio_setup_param.model == "es8311" and not read_es8311_id() then
         log.error("ES8311通讯失败,请检查硬件")
@@ -248,15 +247,6 @@ function exaudio.setup(audioConfigs)
     return audio_setup()
 end
 
--- 模块接口:写入音频数据块
-function exaudio.write_datablock(data)
-    if not data or type(data) ~= "string" then
-        log.error("写入的数据必须为字符串类型")
-        return false
-    end
-    return audio.write(MULTIMEDIA_ID, data)
-end
-
 -- 模块接口:开始播放
 function exaudio.play_start(playConfigs)
     if not playConfigs or type(playConfigs) ~= "table" then
@@ -274,9 +264,11 @@ function exaudio.play_start(playConfigs)
     -- 处理优先级
     if playConfigs.priority ~= nil then
         if check_param(playConfigs.priority, "number", "priority") then
-            if playConfigs.priority >= audio_play_param.priority then
-                audio.play(MULTIMEDIA_ID)
-                sys.waitUntil(MSG_PLAY_DONE)
+            if playConfigs.priority > audio_play_param.priority then
+                if audio.play(MULTIMEDIA_ID) ~= true then
+                    return false
+                end
+                sys.waitUntil(EX_MSG_PLAY_DONE)
                 audio_play_param.priority = playConfigs.priority
             end
         else
@@ -306,7 +298,9 @@ function exaudio.play_start(playConfigs)
         end
 
         audio_play_param.content = playConfigs.content
-        audio.play(MULTIMEDIA_ID, audio_play_param.content)
+        if audio.play(MULTIMEDIA_ID, audio_play_param.content) ~= true then
+            return false
+        end
 
     elseif play_type == 1 then  -- TTS播放
         if not check_param(playConfigs.content, "string", "content") then
@@ -314,7 +308,9 @@ function exaudio.play_start(playConfigs)
             return false
         end
         audio_play_param.content = playConfigs.content
-        audio.tts(MULTIMEDIA_ID, audio_play_param.content)
+        if audio.tts(MULTIMEDIA_ID, audio_play_param.content)  ~= true  then
+            return false
+        end
 
     elseif play_type == 2 then  -- 流式播放
         if not check_param(playConfigs.content, "function", "content") then
@@ -345,7 +341,9 @@ function exaudio.play_start(playConfigs)
             audio_play_param.signed_or_Unsigned
         )
         -- 发送初始数据
-        audio.write(MULTIMEDIA_ID, string.rep("\0", 512))
+        if audio.write(MULTIMEDIA_ID, string.rep("\0", 512)) ~= true then
+            return false
+        end
     end
 
     -- 处理回调函数
@@ -364,16 +362,16 @@ end
 
 -- 模块接口:停止播放
 function exaudio.play_stop()
-    return audio.stop(MULTIMEDIA_ID)
+    return audio.play(MULTIMEDIA_ID)
 end
 
 -- 模块接口:检查播放是否结束
-function exaudio.isEnd()
+function exaudio.is_end()
     return audio.isEnd()
 end
 
 -- 模块接口:获取错误信息
-function exaudio.getError()
+function exaudio.get_error()
     return audio.getError()
 end
 
@@ -469,7 +467,7 @@ end
 
 -- 模块接口:停止录音
 function exaudio.record_stop()
-    audio.recordStop(MULTIMEDIA_ID)
+    return audio.recordStop(MULTIMEDIA_ID)
 end
 
 -- 模块接口:设置音量
@@ -482,7 +480,7 @@ function exaudio.vol(number)
 end
 
 -- 模块接口:设置麦克风音量
-function exaudio.micVol(number)
+function exaudio.mic_vol(number)
     if check_param(number, "number", "麦克风音量值") then
         mic_vol = number
         return audio.micVol(MULTIMEDIA_ID, number)  

+ 3 - 3
module/Air8000/demo/audio/main.lua

@@ -9,11 +9,11 @@ VERSION = "1.0.0"
 
 
 
-require "play_file"     --  播放文件
+-- require "play_file"     --  播放文件
 -- require "play_tts"      -- 播放tts
--- require "play_steam"        -- 流式播放
+require "play_stream"        -- 流式播放
 -- require "record_file"        -- 录音到文件
--- require "record_steam"        -- 流式录音   
+-- require "record_stream"        -- 流式录音   
 
 
 sys.timerLoopStart(function()

+ 27 - 4
module/Air8000/demo/audio/play_file.lua

@@ -1,4 +1,5 @@
 exaudio = require("exaudio")
+local taskName = "task_audio"
 
 local audio_setup_param ={
     model= "es8311",          -- 音频编解码类型,可填入"es8311","es8211"
@@ -19,13 +20,35 @@ local audio_play_param ={
     content = "/luadb/1.mp3",          -- 如果播放类型为0时,则填入string 是播放单个音频文件,如果是表则是播放多段音频文件。
     cbFnc = play_end,            -- 播放完毕回调函数
 }
-local taskName = "task_audio"
+
+local function boot_key_cb()
+    log.info("停止播放")
+    sys.sendMsg(taskName, MSG_KEY_PRESS, "STOP_AUDIO")
+end
+--按下boot 停止播放
+gpio.setup(0, boot_key_cb, gpio.PULLDOWN, gpio.RISING)
+gpio.debounce(0, 200, 1)
+
+local function power_key_cb()
+    sys.sendMsg(taskName, MSG_KEY_PRESS, "NEXT_AUDIO")
+end
+
+--按下powerkey 打断播放,播放优先级更高的音频
+gpio.setup(gpio.PWR_KEY, power_key_cb, gpio.PULLUP, gpio.FALLING)
+gpio.debounce(gpio.PWR_KEY, 200, 1)
+
+
+
 local function audio_task()
     log.info("开始播放音频文件")
     if exaudio.setup(audio_setup_param) then
-        exaudio.play_start(audio_play_param)
-        sys.wait(2000)
-        exaudio.play_start({type= 0,content = "/luadb/1.mp3",priority = 1})     -- 高优先级播放,可对之前的播放进行打断并播放新的文件
+        exaudio.play_start(audio_play_param) -- 仅仅支持task 中运行
+         msg = sys.waitMsg(audio_task, MSG_KEY_PRESS)
+        if msg[2] ==  "NEXT_AUDIO" then  -- true powerkey false boot key
+            
+        elseif msg[2] ==  "STOP_AUDIO" then
+           exaudio.play_stop()
+        end 
     end
     
 end

+ 6 - 9
module/Air8000/demo/audio/play_steam.lua → module/Air8000/demo/audio/play_stream.lua

@@ -11,22 +11,20 @@ local audio_setup_param ={
     -- bits_per_sample = 16,  -- codec 采样位数
     -- pa_on_level = 1,           -- PA打开电平 1 高电平 0 低电平        
 }
-local  index = 4352         --  每次播放的数据长度不能小于1024,并且除去最后一包数据,数据长度都要为1024 的倍数
+local  index = 4096         --  每次播放的数据长度不能小于1024,并且除去最后一包数据,数据长度都要为1024 的倍数
 local f = io.open("/luadb/test.pcm", "rb")   -- 模拟流式播放音源,实际的音频数据来源也可以来自网络或者本地存储
 local function audio_need_more_data()
     if f then 
-        local data = f:read(index)
-        -- print("-------------")
-        if  data  then
-            exaudio.write_datablock(data)     
-        end
-        -- sys.wait(100)
+        return   f:read(index)
     end
 end 
 
 local function play_end(event)
     if event == exaudio.PLAY_DONE then
         log.info("播放完成")
+        if f then 
+            return   f:close()
+        end
     end
 end 
 
@@ -56,8 +54,7 @@ local audio_play_param ={
 
 local taskName = "task_audio"
 local function audio_task()
-    log.info("开始播报")
-
+    log.info("开始流式播报")
     if exaudio.setup(audio_setup_param) then
         exaudio.play_start(audio_play_param)
     end

+ 97 - 4
module/Air8000/demo/audio/readme.md

@@ -7,18 +7,111 @@
 
 1、main.lua:主程序入口;
 
-2、play_file.lua: 播放音频文件,可支持wav,mp3,wav 格式音频
+2、play_file.lua: 播放音频文件,可支持wav,amr,mp3 格式音频
 
-3、play_tts: 支持文字转普通话输出
+3、play_tts: 支持文字转普通话输出需要固件支持
 
-4、play_steam: 流式播放音频,仅支持PCM 格式,可以将音频推流到云端,用来对接大模型或者流式录音的应用。
+4、play_stream: 流式播放音频,仅支持PCM 格式,可以将音频推流到云端,用来对接大模型或者流式录音的应用。
 
 5、record_file: 录音到文件,仅支持PCM 格式
 
-6、record_steam:  流式录音,仅支持PCM,可以将音频流不断的拉取,可用来对接大模型
+6、record_stream:  流式录音,仅支持PCM,可以将音频流不断的拉取,可用来对接大模型
 
 7、1.mp3: 用于测试本地mp3文件播放
 
 8、test.pcm: 用于测试pcm 流式播放(实际可以云端下载)
 
 
+
+
+
+## 常量的介绍
+
+1、exaudio.PLAY_DONE : 当播放音频结束时,会在回调函数返回播放完成的时间
+2、exaudio.RECORD_DONE : 当录音结束时,会在回调函数返回播放完成的时间
+3、exaudio.AMR_NB : 仅录音时有用,表示使用AMR_NB 方式录音
+4、exaudio.AMR_WB : 仅录音时有用,表示使用AMR_WB 方式录音
+5、exaudio.PCM_8000 :  仅录音时有用,表示使用8000/秒 的速度对音频进行采样
+6、exaudio.PCM_16000 : 仅录音时有用,表示使用16000/秒 的速度对音频进行采样
+7、exaudio.PCM_24000 : 仅录音时有用,表示使用24000/秒 的速度对音频进行采样
+8、exaudio.PCM_32000 : 仅录音时有用,表示使用32000/秒 的速度对音频进行采样
+
+## 演示功能概述
+
+1、播放一个mp3,演示了
+
+
+## 演示硬件环境
+
+![](https://docs.openluat.com/air8000/luatos/app/image/netdrv_multi.jpg)
+
+1、Air8000开发板一块+可上网的sim卡一张+4g天线一根+wifi天线一根+网线一根:
+
+- sim卡插入开发板的sim卡槽
+
+- 天线装到开发板上
+
+- 网线一端插入开发板网口,另外一端连接可以上外网的路由器网口
+
+2、TYPE-C USB数据线一根 + USB转串口数据线一根,Air8000开发板和数据线的硬件接线方式为:
+
+- Air8000开发板通过TYPE-C USB口供电;(外部供电/USB供电 拨动开关 拨到 USB供电一端)
+
+- TYPE-C USB数据线直接插到核心板的TYPE-C USB座子,另外一端连接电脑USB口;
+
+- USB转串口数据线,一般来说,白线连接开发板的UART1_TX,绿线连接开发板的UART1_RX,黑线连接核心板的GND,另外一端连接电脑USB口;
+
+
+## 演示软件环境
+
+1、Luatools下载调试工具
+
+2、[Air8000 V2012版本固件](https://docs.openluat.com/air8000/luatos/firmware/)(理论上,2025年7月26日之后发布的固件都可以)
+
+3、PC端的串口工具,例如SSCOM、LLCOM等都可以
+
+4、[MQTT客户端软件MQTTX](https://docs.openluat.com/air8000/luatos/common/swenv/#27-mqttmqttx)
+
+
+## 演示核心步骤
+
+1、搭建好硬件环境
+
+2、demo脚本代码netdrv_device.lua中,按照自己的网卡需求启用对应的Lua文件
+
+- 如果需要单4G网卡,打开require "netdrv_4g",其余注释掉
+
+- 如果需要单WIFI STA网卡,打开require "netdrv_wifi",其余注释掉;同时netdrv_wifi.lua中的wlan.connect("茶室-降功耗,找合宙!", "Air123456", 1),前两个参数,修改为自己测试时wifi热点的名称和密码;注意:仅支持2.4G的wifi,不支持5G的wifi
+
+- 如果需要以太网卡,打开require "netdrv_eth_spi",其余注释掉
+
+- 如果需要多网卡,打开require "netdrv_multiple",其余注释掉;同时netdrv_multiple.lua中的ssid = "茶室-降功耗,找合宙!", password = "Air123456", 修改为自己测试时wifi热点的名称和密码;注意:仅支持2.4G的wifi,不支持5G的wifi
+
+3、Luatools烧录内核固件和修改后的demo脚本代码
+
+4、烧录成功后,自动开机运行,如果出现以下日志,表示四路mqtt连接成功
+
+``` lua
+I/user.mqtt_client_main_task_func connect success
+
+I/user.mqtts_client_main_task_func connect success
+
+I/user.mqtts_ca_client_main_task_func connect success
+
+I/user.mqtts_m_ca_client_main_task_func connect success
+```
+
+5、启动三个MQTTX工具,分别连接上mqtt client、mqtts client、mqtts mutual client对应的server,订阅$imei/timer/up$主题,imei表示设备的imei号;可以看到,每隔5秒钟,会接收到一段类似于 send from timer: 1 的数据,最后面的数字每次加1;
+
+6、打开PC端的串口工具,选择对应的端口,配置波特率115200,数据位8,停止位1,无奇偶校验位;
+
+7、PC端的串口工具输入一段数据,点击发送,在MQTTX工具订阅的$imei/uart/up$主题下可以接收到数据;
+
+8、在MQTTX工具上,在主题$imei/down$下publish一段数据,点击发送,在PC端的串口工具上可以接收到主题和数据,并且也能看到是哪一个server发送的,类似于以下效果:
+
+``` lua
+recv from mqtt server: 864793080144269/down,123456798012345678901234567830
+recv from mqtt ssl server: 864793080144269/down,123456798012345678901234567830
+recv from mqtt ssl ca server: 864793080144269/down,123456798012345678901234567830
+recv from mqtt ssl mutual ca server: 864793080144269/down,123456798012345678901234567830
+```

+ 0 - 0
module/Air8000/demo/audio/record_steam.lua → module/Air8000/demo/audio/record_stream.lua