luat_lib_i2s.c 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344
  1. /*
  2. @module i2s
  3. @summary 数字音频
  4. @version core V0007
  5. @date 2022.05.26
  6. @tag LUAT_USE_I2S
  7. @demo multimedia
  8. @usage
  9. -- 这个库属于底层适配库, 具体用法请查阅示例
  10. -- demo/multimedia
  11. -- demo/tts
  12. -- demo/record
  13. */
  14. #include "luat_base.h"
  15. #include "luat_mem.h"
  16. #include "luat_i2s.h"
  17. #include "luat_zbuff.h"
  18. #ifdef LUAT_USE_I2S
  19. #include "c_common.h"
  20. #define LUAT_LOG_TAG "i2s"
  21. #include "luat_log.h"
  22. #ifndef I2S_DEVICE_MAX_CNT
  23. #define I2S_DEVICE_MAX_CNT 2
  24. #endif
  25. static int i2s_cbs[I2S_DEVICE_MAX_CNT];
  26. static luat_zbuff_t *i2s_rx_buffer[I2S_DEVICE_MAX_CNT];
  27. int l_i2s_handler(lua_State *L, void* ptr) {
  28. (void)ptr;
  29. //LLOGD("l_uart_handler");
  30. rtos_msg_t* msg = (rtos_msg_t*)lua_topointer(L, -1);
  31. lua_pop(L, 1);
  32. int i2s_id = msg->arg1;
  33. lua_geti(L, LUA_REGISTRYINDEX, i2s_cbs[i2s_id]);
  34. if (lua_isfunction(L, -1)) {
  35. if (msg->arg2 == 0) {
  36. //LLOGD("uart%ld sent callback", i2s_id);
  37. lua_pushinteger(L, i2s_id);
  38. lua_pushnil(L);
  39. lua_call(L, 2, 0);
  40. }
  41. else {
  42. lua_pushinteger(L, i2s_id);
  43. lua_pushlightuserdata(L, i2s_rx_buffer[i2s_id]);
  44. lua_call(L, 2, 0);
  45. }
  46. }
  47. // 给rtos.recv方法返回个空数据
  48. lua_pushinteger(L, 0);
  49. return 1;
  50. }
  51. int luat_i2s_event_cb(uint8_t id ,luat_i2s_event_t event, uint8_t *rx_data, uint32_t rx_len, void *param){
  52. uint32_t len;
  53. rtos_msg_t msg;
  54. switch (event){
  55. case LUAT_I2S_EVENT_RX_DONE:
  56. if (!i2s_rx_buffer[id] || !i2s_cbs[id])
  57. return -1;
  58. len = (rx_len > i2s_rx_buffer[id]->len)?i2s_rx_buffer[id]->len:rx_len;
  59. memcpy(i2s_rx_buffer[id]->addr, rx_data, rx_len);
  60. i2s_rx_buffer[id]->used = len;
  61. msg.handler = l_i2s_handler;
  62. msg.ptr = NULL;
  63. msg.arg1 = id;
  64. msg.arg2 = len;
  65. luat_msgbus_put(&msg, 0);
  66. break;
  67. default:
  68. break;
  69. }
  70. return 0;
  71. }
  72. /*
  73. 初始化i2s
  74. @api i2s.setup(id, mode, sample, bitw, channel, format, framebit)
  75. @int i2s通道号,与具体设备有关
  76. @int 模式, 0 主机 1 从机
  77. @int 采样率,默认44100. 可选
  78. @int 数据位数,默认16, 可以是8的倍数
  79. @int 声道, 0 左声道, 1 右声道, 2 立体声. 可选
  80. @int 格式, 可选MODE_I2S, MODE_LSB, MODE_MSB
  81. @int 1个声道的BCLK数量, 可选16和32
  82. @return boolean 成功与否
  83. @return int 底层返回值
  84. @usage
  85. -- 以默认参数初始化i2s
  86. i2s.setup(0)
  87. -- 以详细参数初始化i2s, 示例为默认值
  88. i2s.setup(0, 0, 44100, 16, 0, 0, 16)
  89. */
  90. static int l_i2s_setup(lua_State *L) {
  91. luat_i2s_conf_t conf = {0};
  92. conf.id = luaL_checkinteger(L, 1);
  93. conf.mode = luaL_optinteger(L, 2, LUAT_I2S_MODE_MASTER);
  94. conf.sample_rate = luaL_optinteger(L, 3, LUAT_I2S_HZ_44k);
  95. conf.data_bits = luaL_optinteger(L, 4, LUAT_I2S_BITS_16);
  96. conf.channel_format = luaL_optinteger(L, 5, LUAT_I2S_CHANNEL_STEREO);
  97. conf.standard = luaL_optinteger(L, 6, LUAT_I2S_MODE_I2S);
  98. conf.channel_bits = luaL_optinteger(L, 7, LUAT_I2S_BITS_16);
  99. conf.luat_i2s_event_callback = luat_i2s_event_cb;
  100. int ret = luat_i2s_setup(&conf);
  101. lua_pushboolean(L, ret == 0 ? 1 : 0);
  102. lua_pushinteger(L, ret);
  103. return 2;
  104. }
  105. /*
  106. 发送i2s数据
  107. @api i2s.send(id, data, len)
  108. @int 通道id
  109. @string 数据, 可以是字符串或zbuff
  110. @int 数据长度,单位字节, 字符串默认为字符串全长, zbuff默认为指针位置
  111. @return boolean 成功与否
  112. @return int 底层返回值,供调试用
  113. @usage
  114. local f = io.open("/luadb/abc.wav")
  115. while 1 do
  116. local data = f:read(4096)
  117. if not data or #data == 0 then
  118. break
  119. end
  120. i2s.send(0, data)
  121. sys.wait(100)
  122. end
  123. */
  124. static int l_i2s_send(lua_State *L) {
  125. char* buff;
  126. size_t len;
  127. int id = luaL_checkinteger(L, 1);
  128. if (lua_isuserdata(L, 2)) {
  129. luat_zbuff_t* zbuff = ((luat_zbuff_t *)luaL_checkudata(L, 2, LUAT_ZBUFF_TYPE));
  130. buff = (char*)zbuff->addr;
  131. len = zbuff->cursor;
  132. }
  133. else {
  134. buff = (char*)luaL_checklstring(L, 2, &len);
  135. }
  136. if (lua_type(L, 3) == LUA_TNUMBER) {
  137. len = luaL_checkinteger(L, 3);
  138. }
  139. int ret = luat_i2s_send(id, buff, len);
  140. lua_pushboolean(L, ret == len ? 1 : 0);
  141. lua_pushinteger(L, ret);
  142. return 2;
  143. }
  144. /*
  145. 接收i2s数据,注意在数据在回调时已经存放在zbuff里,目前只有air780e系列支持
  146. @api i2s.recv(id, buffer, len)
  147. @int 通道id
  148. @zbuff 数据缓存区
  149. @int 单次返回的数据长度,单位字节,必须与传入的zbuff的大小一致
  150. @return boolean 成功与否
  151. @usage
  152. local buffer = zbuff.create(3200)
  153. local succ = i2s.recv(0, buffer, 3200);
  154. */
  155. static int l_i2s_recv(lua_State *L) {
  156. int id = luaL_checkinteger(L, 1);
  157. if (id >= I2S_DEVICE_MAX_CNT)
  158. {
  159. lua_pushboolean(L, 0);
  160. return 1;
  161. }
  162. if (lua_isuserdata(L, 2)) {
  163. luat_zbuff_t* zbuff = ((luat_zbuff_t *)luaL_checkudata(L, 2, LUAT_ZBUFF_TYPE));
  164. i2s_rx_buffer[id] = zbuff;
  165. }
  166. else {
  167. i2s_rx_buffer[id] = NULL;
  168. }
  169. size_t len = luaL_checkinteger(L, 3);
  170. lua_pushboolean(L, !luat_i2s_recv(id, NULL, len));
  171. return 1;
  172. }
  173. /*
  174. 关闭i2s
  175. @api i2s.close(id)
  176. @int 通道id
  177. @return nil 无返回值
  178. @usage
  179. i2s.close(0)
  180. */
  181. static int l_i2s_close(lua_State *L) {
  182. int id = luaL_checkinteger(L, 1);
  183. luat_i2s_close(id);
  184. return 0;
  185. }
  186. /*
  187. 注册I2S事件回调
  188. @api i2s.on(id, func)
  189. @int i2s id, i2s0写0, i2s1写1
  190. @function 回调方法
  191. @return nil 无返回值
  192. @usage
  193. i2s.on(0, function(id, buff)
  194. if buff then
  195. log.info("i2s get data in zbuff")
  196. else
  197. log.info("i2s tx one block done")
  198. end
  199. end)
  200. */
  201. static int l_i2s_on(lua_State *L) {
  202. int i2s_id = luaL_checkinteger(L, 1);
  203. if (i2s_id >= I2S_DEVICE_MAX_CNT)
  204. {
  205. lua_pushliteral(L, "no such i2s id");
  206. return 1;
  207. }
  208. if (i2s_cbs[i2s_id] != 0)
  209. {
  210. luaL_unref(L, LUA_REGISTRYINDEX, i2s_cbs[i2s_id]);
  211. }
  212. if (lua_isfunction(L, 2)) {
  213. lua_pushvalue(L, 2);
  214. i2s_cbs[i2s_id] = luaL_ref(L, LUA_REGISTRYINDEX);
  215. }
  216. return 0;
  217. }
  218. /*
  219. 获取i2s的发送缓冲区状态
  220. @api i2s.txStat(id)
  221. @int i2s id, i2s0写0, i2s1写1
  222. @return 底层缓冲区的总大小
  223. @return 底层缓冲区的剩余待发送数据
  224. @usage
  225. -- 读取发送缓冲区的状态, 从而判断是否需要继续传入音频数据
  226. local max, remain = i2s.txStat(0)
  227. log.info("i2s发送缓冲区状态", max, remain)
  228. */
  229. static int l_i2s_tx_stat(lua_State *L) {
  230. int i2s_id = luaL_checkinteger(L, 1);
  231. size_t buffsize = 0, remain = 0;
  232. luat_i2s_txbuff_info(i2s_id, &buffsize, &remain);
  233. lua_pushinteger(L, buffsize);
  234. lua_pushinteger(L, remain);
  235. return 2;
  236. }
  237. #if 0
  238. /*
  239. 获取I2S参数,参数具体参考setup
  240. @api i2s.getPara(id)
  241. @int 通道id
  242. @return boolean 是否在工作状态 true是
  243. @return int 模式, 0 主机 1 从机
  244. @return int 采样率
  245. @return int 数据位数
  246. @return int 声道
  247. @return int 格式
  248. @return int 1个声道的BCLK数量
  249. */
  250. static int l_i2s_get_param(lua_State *L) {
  251. int id = luaL_checkinteger(L, 1);
  252. luat_i2s_conf_t *config = luat_i2s_get_config(id);
  253. lua_pushboolean(L, config->state);
  254. lua_pushinteger(L, config->mode);
  255. lua_pushinteger(L, config->sample_rate);
  256. lua_pushinteger(L, config->data_bits);
  257. lua_pushinteger(L, config->channel_format);
  258. lua_pushinteger(L, config->standard);
  259. lua_pushinteger(L, config->channel_bits);
  260. return 7;
  261. }
  262. #endif
  263. int l_i2s_play(lua_State *L);
  264. int l_i2s_pause(lua_State *L);
  265. int l_i2s_stop(lua_State *L);
  266. #ifndef LUAT_COMPILER_NOWEAK
  267. LUAT_WEAK int luat_i2s_txbuff_info(uint8_t id, size_t *buffsize, size_t* remain) {
  268. (void)id;
  269. (void)buffsize;
  270. (void)remain;
  271. return -1;
  272. }
  273. LUAT_WEAK int l_i2s_play(lua_State *L) {
  274. LLOGE("not support yet");
  275. return 0;
  276. }
  277. LUAT_WEAK int l_i2s_pause(lua_State *L) {
  278. LLOGE("not support yet");
  279. return 0;
  280. }
  281. LUAT_WEAK int l_i2s_stop(lua_State *L) {
  282. LLOGE("not support yet");
  283. return 0;
  284. }
  285. #endif
  286. #include "rotable2.h"
  287. static const rotable_Reg_t reg_i2s[] =
  288. {
  289. { "setup", ROREG_FUNC(l_i2s_setup)},
  290. { "send", ROREG_FUNC(l_i2s_send)},
  291. { "recv", ROREG_FUNC(l_i2s_recv)},
  292. { "close", ROREG_FUNC(l_i2s_close)},
  293. { "on", ROREG_FUNC(l_i2s_on)},
  294. { "txStat", ROREG_FUNC(l_i2s_tx_stat)},
  295. #if 0
  296. { "getPara", ROREG_FUNC(l_i2s_get_param)},
  297. #endif
  298. // 以下为兼容扩展功能,待定
  299. { "play", ROREG_FUNC(l_i2s_play)},
  300. { "pause", ROREG_FUNC(l_i2s_pause)},
  301. { "stop", ROREG_FUNC(l_i2s_stop)},
  302. //@const MODE_I2S number I2S标准,比如ES7149
  303. { "MODE_I2S", ROREG_INT(0)},
  304. //@const MODE_LSB number LSB格式
  305. { "MODE_LSB", ROREG_INT(1)},
  306. //@const MODE_MSB number MSB格式,比如TM8211
  307. { "MODE_MSB", ROREG_INT(2)},
  308. //@const MONO_L number 左声道
  309. { "MONO_L", ROREG_INT(0)},
  310. //@const MONO_R number 右声道
  311. { "MONO_R", ROREG_INT(1)},
  312. //@const STEREO number 立体声
  313. { "STEREO", ROREG_INT(2)},
  314. { NULL, ROREG_INT(0) }
  315. };
  316. LUAMOD_API int luaopen_i2s(lua_State *L)
  317. {
  318. luat_newlib2(L, reg_i2s);
  319. return 1;
  320. }
  321. #endif