luat_lib_i2s.c 8.9 KB

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