Bläddra i källkod

update:audio统一API

alienwalker 3 år sedan
förälder
incheckning
a559b672e5
3 ändrade filer med 169 tillägg och 8 borttagningar
  1. 52 7
      components/multimedia/luat_lib_multimedia.c
  2. 110 0
      luat/include/luat_audio.h
  3. 7 1
      luat/modules/luat_lib_i2s.c

+ 52 - 7
components/multimedia/luat_lib_multimedia.c

@@ -15,6 +15,11 @@
 
 #include <stddef.h>
 #include "mp3_decode/minimp3.h"
+#ifndef __BSP_COMMON_H__
+#include "c_common.h"
+#endif
+
+
 #define LUAT_M_CODE_TYPE "MCODER*"
 #define MP3_FRAME_LEN 4 * 1152
 
@@ -165,9 +170,10 @@ static int l_audio_raw_on(lua_State *L) {
 
 /*
 播放或者停止播放一个文件,播放完成后,会回调一个audio.DONE消息,可以用pause来暂停或者恢复,其他API不可用。考虑到读SD卡速度比较慢而拖累luavm进程的速度,所以尽量使用本API
-@api audio.play(id, path)
+@api audio.play(id, path, errStop)
 @int 音频通道
-@string 文件名,如果为空,则表示停止播放
+@string/table 文件名,如果为空,则表示停止播放,如果是table,则表示连续播放多个文件,并且会用到errStop参数
+@boolean 是否在文件解码失败后停止解码,只有在连续播放多个文件时才有用,默认true,遇到解码错误自动停止
 @return boolean 成功返回true,否则返回false
 @usage
 audio.play(0, "xxxxxx")		--开始播放某个文件
@@ -178,7 +184,27 @@ static int l_audio_play(lua_State *L) {
     size_t len, i;
     int result = 0;
     const uint8_t *buf;
-    if (lua_isstring(L, 2))
+    uint8_t is_error_stop = 1;
+    if (lua_istable(L, 2))
+    {
+    	size_t len = lua_rawlen(L, 2); //返回数组的长度
+        uData_t *info = (uData_t *)luat_heap_malloc(len * sizeof(uData_t));
+        for (size_t i = 0; i < len; i++)
+        {
+            lua_rawgeti(L, 2, 1 + i);
+            info[i].value.asBuffer.buffer = lua_tolstring(L, -1, &info[i].value.asBuffer.length);
+            info[i].Type = UDATA_TYPE_OPAQUE;
+            lua_pop(L, 1); //将刚刚获取的元素值从栈中弹出
+        }
+    	if (lua_isboolean(L, 3))
+    	{
+    		is_error_stop = lua_toboolean(L, 3);
+    	}
+        result = luat_audio_play_multi_files(multimedia_id, info, len, is_error_stop);
+    	lua_pushboolean(L, !result);
+    	luat_heap_free(info);
+    }
+    else if (LUA_TSTRING == (lua_type(L, (2))))
     {
         buf = lua_tolstring(L, 2, &len);//取出字符串数据
         char *path = luat_heap_malloc(len + 1);
@@ -197,6 +223,20 @@ static int l_audio_play(lua_State *L) {
     return 1;
 }
 
+/**
+停止播放文件
+@api audio.playStop(id)
+@int audio id,例如0
+@return boolean 成功返回true,否则返回false
+@usage
+audio.playStop(0)
+*/
+static int l_audio_play_stop(lua_State *L) {
+    lua_pushboolean(L, !luat_audio_play_stop(luaL_checkinteger(L, 1)));
+    return 1;
+}
+
+
 /**
 检查当前文件是否已经播放结束
 @api audio.isEnd(id, path)
@@ -215,18 +255,22 @@ static int l_audio_play_wait_end(lua_State *L) {
 
 /*
 配置一个音频通道的特性,比如实现自动控制PA开关。注意这个不是必须的,一般在调用play的时候才需要自动控制,其他情况比如你手动控制播放时,就可以自己控制PA开关
-@api audio.config(id, paPin, onLevel)
+@api audio.config(id, paPin, onLevel, dacDelay, paDelay, dacPin, dacLevel)
 @int 音频通道
 @int PA控制IO
 @int PA打开时的电平
-@int 在DAC启动后插入的冗余时间,单位100ms
+@int 在DAC启动前插入的冗余时间,单位100ms,一般用于外部DAC
 @int 在DAC启动后,延迟多长时间打开PA,单位1ms
+@int 外部dac电源控制IO,如果不填,则表示使用平台默认IO,比如Air780E使用DACEN脚,air105则不启用
+@int 外部dac打开时,电源控制IO的电平,默认拉高
 @return 无
 @usage
-audio.config(0, pin.PC0, 1)	--PA控制脚是PC0,高电平打开
+audio.config(0, pin.PC0, 1)	--PA控制脚是PC0,高电平打开,air105用这个配置就可以用了
+audio.config(0, 25, 1, 6, 200)	--PA控制脚是GPIO25,高电平打开,Air780E云喇叭板用这个配置就可以用了
 */
 static int l_audio_config(lua_State *L) {
-    luat_audio_config_pa(luaL_checkinteger(L, 1), luaL_optinteger(L, 2, 255), luaL_optinteger(L, 3, 1), luaL_optinteger(L, 3, 5), luaL_optinteger(L, 3, 200));
+    luat_audio_config_pa(luaL_checkinteger(L, 1), luaL_optinteger(L, 2, 255), luaL_optinteger(L, 3, 1), luaL_optinteger(L, 4, 5), luaL_optinteger(L, 5, 200));
+    luat_audio_config_dac(luaL_checkinteger(L, 1), luaL_optinteger(L, 6, -1), luaL_optinteger(L, 7, 1));
     return 0;
 }
 
@@ -552,6 +596,7 @@ static const rotable_Reg_t reg_audio[] =
 	{ "stop",		   ROREG_FUNC(l_audio_stop_raw)},
     { "on",            ROREG_FUNC(l_audio_raw_on)},
 	{ "play",		   ROREG_FUNC(l_audio_play)},
+	{ "playStop",	   ROREG_FUNC(l_audio_play_stop)},
 	{ "isEnd",		   ROREG_FUNC(l_audio_play_wait_end)},
 	{ "config",			ROREG_FUNC(l_audio_config)},
     { "PCM",           ROREG_INT(MULTIMEDIA_DATA_TYPE_PCM)},

+ 110 - 0
luat/include/luat_audio.h

@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 2022 OpenLuat & AirM2M
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+ * the Software, and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef __LUAT_AUDIO_H__
+#define __LUAT_AUDIO_H__
+#include "luat_base.h"
+#ifndef __BSP_COMMON_H__
+#include "c_common.h"
+#endif
+/**
+ * @brief 播放指定数量的文件或者ROM数组(文件数据直接写成数组形式)
+ *
+ * @param multimedia_id 多媒体通道,目前只有0
+ * @param info 文件信息,文件路径信息
+ * @param files_num 文件数量
+ * @return int =0成功,其他失败
+ */
+int luat_audio_play_multi_files(uint8_t multimedia_id, uData_t *info, uint32_t files_num, uint8_t error_stop);
+
+/**
+ * @brief 播放指定的文件或
+ *
+ * @param multimedia_id 多媒体通道,目前只有0
+ * @param path 文件路径
+ * @return int =0成功,其他失败
+ */
+int luat_audio_play_file(uint8_t multimedia_id, const char *path);
+/**
+ * @brief 是否播放完全部数据
+ *
+ * @param multimedia_id multimedia_id 多媒体通道,目前只有0
+ * @return uint8_t =1是,=0没有
+ */
+uint8_t luat_audio_is_finish(uint8_t multimedia_id);
+
+/**
+ * @brief 强制停止播放文件,但是不会停止已经输出到底层驱动的数据播放
+ *
+ * @param multimedia_id multimedia_id 多媒体通道,目前只有0
+ * @return int =0成功,其他失败
+ */
+int luat_audio_play_stop(uint8_t multimedia_id);
+
+/**
+ * @brief 获取上一次播放结果,在MULTIMEDIA_CB_AUDIO_DONE回调时调用最佳
+ *
+ * @param multimedia_id multimedia_id 多媒体通道,目前只有0
+ * @return int =0完整的播放完成,<0被用户停止了,>0 TTS失败,或者第几个音频文件解码失败(用户在play_info未设置了解码失败后继续,文件位置+1)
+ */
+int luat_audio_play_get_last_error(uint8_t multimedia_id);
+
+
+/**
+ * @brief 立刻初始化播放未编码的原始音频数据流
+ *
+ * @param multimedia_id multimedia_id 多媒体通道,目前只有0
+ * @param audio_format 音频数据格式,目前只支持PCM,即需要手动解码
+ * @param num_channels 声道数,目前只能1或2
+ * @param sample_rate 采样率,注意只有8K,16K,32K,48K,96K,22.05K,44.1K这些能被支持
+ * @param bits_per_sample 量化bit,只能是16
+ * @param is_signed 量化数据是否带符号,只能是1
+ * @return int =0成功,其他失败
+ */
+int luat_audio_start_raw(uint8_t multimedia_id, uint8_t audio_format, uint8_t num_channels, uint32_t sample_rate, uint8_t bits_per_sample, uint8_t is_signed);
+/**
+ * @brief 向底层驱动传入一段原始音频数据
+ *
+ * @param multimedia_id multimedia_id 多媒体通道,目前只有0
+ * @param data 原始音频数据
+ * @param len 原始音频数据长度
+ * @return int =0成功,其他失败
+ */
+int luat_audio_write_raw(uint8_t multimedia_id, uint8_t *data, uint32_t len);
+/**
+ * @brief 强制停止所有播放,同时底层驱动也会停止输出,不要用于播放文件的结束
+ *
+ * @param multimedia_id multimedia_id 多媒体通道,目前只有0
+ * @return int =0成功,其他失败
+ */
+int luat_audio_stop_raw(uint8_t multimedia_id);
+/**
+ * @brief 暂停/恢复播放
+ *
+ * @param multimedia_id multimedia_id 多媒体通道,目前只有0
+ * @param is_pause 0恢复,其他暂停
+ * @return int =0成功,其他失败
+ */
+int luat_audio_pause_raw(uint8_t multimedia_id, uint8_t is_pause);
+
+void luat_audio_config_pa(uint8_t multimedia_id, uint32_t pin, int level, uint32_t dummy_time_len, uint32_t pa_delay_time);
+void luat_audio_config_dac(uint8_t multimedia_id, int pin, int level);
+#endif

+ 7 - 1
luat/modules/luat_lib_i2s.c

@@ -19,7 +19,7 @@
 @int 模式, 当前仅支持0, MASTER|TX|RX 模式, 暂不支持slave. 可选
 @int 采样率,默认44100. 可选
 @int 声道, 0 左声道, 1 右声道, 2 双声道. 可选
-@int 格式, 当前仅支持i2s标准格式. 可选
+@int 格式, 可选MODE_I2S, MODE_LSB, MODE_MSB
 @int mclk频率, 默认 8M. 可选
 @return boolean 成功与否
 @return int 底层返回值
@@ -148,6 +148,12 @@ static const rotable_Reg_t reg_i2s[] =
     { "play",       ROREG_FUNC(l_i2s_play)},
     { "pause",      ROREG_FUNC(l_i2s_pause)},
     { "stop",       ROREG_FUNC(l_i2s_stop)},
+	//@const MODE_I2S number I2S标准,比如ES7149
+	{ "MODE_I2S", 	ROREG_INT(0)},
+	//@const MODE_LSB number LSB格式
+	{ "MODE_LSB", 	ROREG_INT(1)},
+	//@const MODE_MSB number MSB格式,比如TM8211
+	{ "MODE_MSB", 	ROREG_INT(2)},
 	{ NULL,         ROREG_INT(0) }
 };