| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343 |
- /*
- @module i2s
- @summary 数字音频
- @version core V0007
- @date 2022.05.26
- @tag LUAT_USE_I2S
- @demo multimedia
- @usage
- -- 这个库属于底层适配库, 具体用法请查阅示例
- -- demo/multimedia
- -- demo/tts
- -- demo/record
- */
- #include "luat_base.h"
- #include "luat_mem.h"
- #include "luat_i2s.h"
- #include "luat_zbuff.h"
- #ifdef LUAT_USE_I2S
- #include "c_common.h"
- #define LUAT_LOG_TAG "i2s"
- #include "luat_log.h"
- #ifndef I2S_DEVICE_MAX_CNT
- #define I2S_DEVICE_MAX_CNT 2
- #endif
- static int i2s_cbs[I2S_DEVICE_MAX_CNT];
- static luat_zbuff_t *i2s_rx_buffer[I2S_DEVICE_MAX_CNT];
- int l_i2s_handler(lua_State *L, void* ptr) {
- (void)ptr;
- //LLOGD("l_uart_handler");
- rtos_msg_t* msg = (rtos_msg_t*)lua_topointer(L, -1);
- lua_pop(L, 1);
- int i2s_id = msg->arg1;
- lua_geti(L, LUA_REGISTRYINDEX, i2s_cbs[i2s_id]);
- if (lua_isfunction(L, -1)) {
- if (msg->arg2 == 0) {
- //LLOGD("uart%ld sent callback", i2s_id);
- lua_pushinteger(L, i2s_id);
- lua_pushnil(L);
- lua_call(L, 2, 0);
- }
- else {
- lua_pushinteger(L, i2s_id);
- lua_pushlightuserdata(L, i2s_rx_buffer[i2s_id]);
- lua_call(L, 2, 0);
- }
- }
- // 给rtos.recv方法返回个空数据
- lua_pushinteger(L, 0);
- return 1;
- }
- int luat_i2s_event_cb(uint8_t id ,luat_i2s_event_t event, uint8_t *rx_data, uint32_t rx_len, void *param){
- uint32_t len;
- rtos_msg_t msg;
- switch (event){
- case LUAT_I2S_EVENT_RX_DONE:
- if (!i2s_rx_buffer[id] || !i2s_cbs[id]){
- return -1;
- }
- len = (rx_len > i2s_rx_buffer[id]->len)?i2s_rx_buffer[id]->len:rx_len;
- memcpy(i2s_rx_buffer[id]->addr, rx_data, rx_len);
- i2s_rx_buffer[id]->used = len;
- msg.handler = l_i2s_handler;
- msg.ptr = NULL;
- msg.arg1 = id;
- msg.arg2 = len;
- luat_msgbus_put(&msg, 0);
- break;
- default:
- break;
- }
- return 0;
- }
- /*
- 初始化i2s
- @api i2s.setup(id, mode, sample, bitw, channel, format, framebit)
- @int i2s通道号,与具体设备有关
- @int 模式, 0 主机 1 从机
- @int 采样率,默认44100. 可选
- @int 数据位数,默认16, 可以是8的倍数
- @int 声道, 0 左声道, 1 右声道, 2 立体声. 可选
- @int 格式, 可选MODE_I2S, MODE_LSB, MODE_MSB
- @int 1个声道的BCLK数量, 可选16和32
- @return boolean 成功与否
- @return int 底层返回值
- @usage
- -- 以默认参数初始化i2s
- i2s.setup(0)
- -- 以详细参数初始化i2s, 示例为默认值
- i2s.setup(0, 0, 44100, 16, 0, 0, 16)
- */
- static int l_i2s_setup(lua_State *L) {
- luat_i2s_conf_t conf = {0};
- conf.id = luaL_checkinteger(L, 1);
- conf.mode = luaL_optinteger(L, 2, LUAT_I2S_MODE_MASTER);
- conf.sample_rate = luaL_optinteger(L, 3, LUAT_I2S_HZ_44k);
- conf.data_bits = luaL_optinteger(L, 4, LUAT_I2S_BITS_16);
- conf.channel_format = luaL_optinteger(L, 5, LUAT_I2S_CHANNEL_STEREO);
- conf.standard = luaL_optinteger(L, 6, LUAT_I2S_MODE_I2S);
- conf.channel_bits = luaL_optinteger(L, 7, LUAT_I2S_BITS_16);
- conf.luat_i2s_event_callback = luat_i2s_event_cb;
- int ret = luat_i2s_setup(&conf);
- lua_pushboolean(L, ret == 0 ? 1 : 0);
- lua_pushinteger(L, ret);
- return 2;
- }
- /*
- 发送i2s数据
- @api i2s.send(id, data, len)
- @int 通道id
- @string 数据, 可以是字符串或zbuff
- @int 数据长度,单位字节, 字符串默认为字符串全长, zbuff默认为指针位置
- @return boolean 成功与否
- @return int 底层返回值,供调试用
- @usage
- local f = io.open("/luadb/abc.wav")
- while 1 do
- local data = f:read(4096)
- if not data or #data == 0 then
- break
- end
- i2s.send(0, data)
- sys.wait(100)
- end
- */
- static int l_i2s_send(lua_State *L) {
- char* buff;
- size_t len;
- int id = luaL_checkinteger(L, 1);
- if (lua_isuserdata(L, 2)) {
- luat_zbuff_t* zbuff = ((luat_zbuff_t *)luaL_checkudata(L, 2, LUAT_ZBUFF_TYPE));
- buff = (char*)zbuff->addr;
- len = zbuff->cursor;
- }
- else {
- buff = (char*)luaL_checklstring(L, 2, &len);
- }
- if (lua_type(L, 3) == LUA_TNUMBER) {
- len = luaL_checkinteger(L, 3);
- }
- int ret = luat_i2s_send(id, buff, len);
- lua_pushboolean(L, ret == len ? 1 : 0);
- lua_pushinteger(L, ret);
- return 2;
- }
- /*
- 接收i2s数据,注意在数据在回调时已经存放在zbuff里,目前只有air780exxx系列支持
- @api i2s.recv(id, buffer, len)
- @int 通道id
- @zbuff 数据缓存区
- @int 单次返回的数据长度,单位字节,必须与传入的zbuff的大小一致
- @return boolean 成功与否
- @usage
- local buffer = zbuff.create(3200)
- local succ = i2s.recv(0, buffer, 3200);
- */
- static int l_i2s_recv(lua_State *L) {
- int id = luaL_checkinteger(L, 1);
- if (id >= I2S_DEVICE_MAX_CNT)
- {
- lua_pushboolean(L, 0);
- return 1;
- }
- if (lua_isuserdata(L, 2)) {
- luat_zbuff_t* zbuff = ((luat_zbuff_t *)luaL_checkudata(L, 2, LUAT_ZBUFF_TYPE));
- i2s_rx_buffer[id] = zbuff;
- }
- else {
- i2s_rx_buffer[id] = NULL;
- }
- size_t len = luaL_checkinteger(L, 3);
- lua_pushboolean(L, !luat_i2s_recv(id, NULL, len));
- return 1;
- }
- /*
- 关闭i2s
- @api i2s.close(id)
- @int 通道id
- @return nil 无返回值
- @usage
- i2s.close(0)
- */
- static int l_i2s_close(lua_State *L) {
- int id = luaL_checkinteger(L, 1);
- luat_i2s_close(id);
- return 0;
- }
- /*
- 注册I2S事件回调
- @api i2s.on(id, func)
- @int i2s id, i2s0写0, i2s1写1
- @function 回调方法
- @return nil 无返回值
- @usage
- i2s.on(0, function(id, buff)
- if buff then
- log.info("i2s get data in zbuff")
- else
- log.info("i2s tx one block done")
- end
- end)
- */
- static int l_i2s_on(lua_State *L) {
- int i2s_id = luaL_checkinteger(L, 1);
- if (i2s_id >= I2S_DEVICE_MAX_CNT)
- {
- lua_pushliteral(L, "no such i2s id");
- return 1;
- }
- if (i2s_cbs[i2s_id] != 0)
- {
- luaL_unref(L, LUA_REGISTRYINDEX, i2s_cbs[i2s_id]);
- }
- if (lua_isfunction(L, 2)) {
- lua_pushvalue(L, 2);
- i2s_cbs[i2s_id] = luaL_ref(L, LUA_REGISTRYINDEX);
- }
- return 0;
- }
- /*
- 获取i2s的发送缓冲区状态
- @api i2s.txStat(id)
- @int i2s id, i2s0写0, i2s1写1
- @return 底层缓冲区的总大小
- @return 底层缓冲区的剩余待发送数据
- @usage
- -- 读取发送缓冲区的状态, 从而判断是否需要继续传入音频数据
- local max, remain = i2s.txStat(0)
- log.info("i2s发送缓冲区状态", max, remain)
- */
- static int l_i2s_tx_stat(lua_State *L) {
- int i2s_id = luaL_checkinteger(L, 1);
- size_t buffsize = 0, remain = 0;
- luat_i2s_txbuff_info(i2s_id, &buffsize, &remain);
- lua_pushinteger(L, buffsize);
- lua_pushinteger(L, remain);
- return 2;
- }
- #if 0
- /*
- 获取I2S参数,参数具体参考setup
- @api i2s.getPara(id)
- @int 通道id
- @return boolean 是否在工作状态 true是
- @return int 模式, 0 主机 1 从机
- @return int 采样率
- @return int 数据位数
- @return int 声道
- @return int 格式
- @return int 1个声道的BCLK数量
- */
- static int l_i2s_get_param(lua_State *L) {
- int id = luaL_checkinteger(L, 1);
- luat_i2s_conf_t *config = luat_i2s_get_config(id);
- lua_pushboolean(L, config->state);
- lua_pushinteger(L, config->mode);
- lua_pushinteger(L, config->sample_rate);
- lua_pushinteger(L, config->data_bits);
- lua_pushinteger(L, config->channel_format);
- lua_pushinteger(L, config->standard);
- lua_pushinteger(L, config->channel_bits);
- return 7;
- }
- #endif
- int l_i2s_play(lua_State *L);
- int l_i2s_pause(lua_State *L);
- int l_i2s_stop(lua_State *L);
- #ifndef LUAT_COMPILER_NOWEAK
- LUAT_WEAK int luat_i2s_txbuff_info(uint8_t id, size_t *buffsize, size_t* remain) {
- (void)id;
- (void)buffsize;
- (void)remain;
- return -1;
- }
- LUAT_WEAK int l_i2s_play(lua_State *L) {
- LLOGE("not support yet");
- return 0;
- }
- LUAT_WEAK int l_i2s_pause(lua_State *L) {
- LLOGE("not support yet");
- return 0;
- }
- LUAT_WEAK int l_i2s_stop(lua_State *L) {
- LLOGE("not support yet");
- return 0;
- }
- #endif
- #include "rotable2.h"
- static const rotable_Reg_t reg_i2s[] =
- {
- { "setup", ROREG_FUNC(l_i2s_setup)},
- { "send", ROREG_FUNC(l_i2s_send)},
- { "recv", ROREG_FUNC(l_i2s_recv)},
- { "close", ROREG_FUNC(l_i2s_close)},
- { "on", ROREG_FUNC(l_i2s_on)},
- { "txStat", ROREG_FUNC(l_i2s_tx_stat)},
- #if 0
- { "getPara", ROREG_FUNC(l_i2s_get_param)},
- #endif
- // 以下为兼容扩展功能,待定
- { "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)},
- //@const MONO_L number 左声道
- { "MONO_L", ROREG_INT(0)},
- //@const MONO_R number 右声道
- { "MONO_R", ROREG_INT(1)},
- //@const STEREO number 立体声
- { "STEREO", ROREG_INT(2)},
- { NULL, ROREG_INT(0) }
- };
- LUAMOD_API int luaopen_i2s(lua_State *L)
- {
- luat_newlib2(L, reg_i2s);
- return 1;
- }
- #endif
|