luat_lib_airtalk.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332
  1. /*
  2. @module airtalk
  3. @summary 设备之间,设备与PC、手机,对讲处理
  4. @catalog 综合应用API
  5. @version 1.0
  6. @date 2025.07.1
  7. @demo airtalk
  8. @tag LUAT_USE_AIRTALK
  9. @usage
  10. -- 本库仅部分BSP支持
  11. -- 主要是 Air8000 和 Air780EXX 系列
  12. -- 详细用法请参考demo
  13. */
  14. #include "luat_base.h"
  15. #include "libemqtt.h"
  16. #include "luat_airtalk.h"
  17. #include "luat_malloc.h"
  18. #include "luat_mqtt.h"
  19. #include "luat_audio.h"
  20. #include "airtalk_api.h"
  21. #define LUAT_LOG_TAG "airtalk"
  22. #include "luat_log.h"
  23. #include "rotable.h"
  24. #define LUAT_MQTT_CTRL_TYPE "MQTTCTRL*"
  25. static int l_airtalk_cb;
  26. static int l_airtalk_handler(lua_State *L, void* ptr) {
  27. (void)ptr;
  28. rtos_msg_t* msg = (rtos_msg_t*)lua_topointer(L, -1);
  29. lua_pop(L, 1);
  30. if (l_airtalk_cb) {
  31. lua_geti(L, LUA_REGISTRYINDEX, l_airtalk_cb);
  32. if (lua_isfunction(L, -1)) {
  33. lua_pushinteger(L, msg->arg1);
  34. lua_pushinteger(L, msg->arg2);
  35. lua_call(L, 2, 0);
  36. }
  37. }
  38. // 给rtos.recv方法返回个空数据
  39. lua_pushinteger(L, 0);
  40. return 1;
  41. }
  42. /*
  43. 配置airtalk参数
  44. @api airtalk.config(protocol,netc,cache_time,encode_cnt,decode_cnt,audio_pm_mode_when_stop,no_data_to)
  45. @int 语音数据传输协议类型,见airtalk.PROTOCOL_XXX
  46. @userdata network_ctrl或者mqtt客户端,如果协议是mqtt类型,传入mqtt.create返回值,如果是其他类型,传入socket.create的返回值
  47. @int 缓冲时间,单位ms,默认500ms,值越小,delay越小,抗网络波动能力越差
  48. @int 单次编码帧数,默认值5,不能低于2,不能高于5
  49. @int 单次解码帧数,如果缓冲没有足够的帧数,自动补0,默认值5,不能低于2,不能高于10,不能低于encode_cnt, decode_cnt * 4 必须是 encode_cnt的整数倍
  50. @int 对讲停止后,audio的pm状态,默认是audio.SHUTDOWN
  51. @int 多长时间判定对端长时间无数据发送,超过这个时间会上报event_error,用户决定接下来的操作。默认5000ms,单位ms
  52. @return nil 无返回值
  53. @usage
  54. mqttc = mqtt.create(nil,"120.55.137.106", 1884)
  55. airtalk.config(airtalk.PROTOCOL_MQTT, mqttc)
  56. */
  57. static int l_airtalk_config(lua_State *L)
  58. {
  59. int airtalk_protocol = luaL_optinteger(L, 1, LUAT_AIRTALK_PROTOCOL_MQTT);
  60. int cache_time = luaL_optinteger(L, 3, 500);
  61. int encode_cnt = luaL_optinteger(L, 4, 5);
  62. int decode_cnt = luaL_optinteger(L, 5, 5);
  63. int audio_pm_mode_when_stop = luaL_optinteger(L, 6, LUAT_AUDIO_PM_SHUTDOWN);
  64. int to = luaL_optinteger(L, 7, 5000);
  65. luat_mqtt_ctrl_t * mqtt_ctrl;
  66. switch (airtalk_protocol)
  67. {
  68. case LUAT_AIRTALK_PROTOCOL_MQTT:
  69. if (luaL_testudata(L, 2, LUAT_MQTT_CTRL_TYPE)){
  70. mqtt_ctrl = ((luat_mqtt_ctrl_t *)luaL_checkudata(L, 2, LUAT_MQTT_CTRL_TYPE));
  71. }else{
  72. mqtt_ctrl = ((luat_mqtt_ctrl_t *)lua_touserdata(L, 2));
  73. }
  74. if (!mqtt_ctrl)
  75. {
  76. LLOGE("protocol %d no mqttc", airtalk_protocol);
  77. return 0;
  78. }
  79. luat_airtalk_net_param_config(airtalk_protocol, cache_time, to);
  80. luat_airtalk_net_set_mqtt_ctrl(mqtt_ctrl);
  81. luat_airtalk_speech_audio_param_config(0, audio_pm_mode_when_stop);
  82. luat_airtalk_speech_set_one_block_frame_cnt(decode_cnt, encode_cnt);
  83. break;
  84. default:
  85. LLOGE("protocol %d no support!", airtalk_protocol);
  86. break;
  87. }
  88. return 0;
  89. }
  90. /*
  91. 注册airtalk事件回调
  92. @api airtalk.on(func)
  93. @function 回调方法
  94. @return nil 无返回值
  95. @usage
  96. airtalk.on(function(event, param)
  97. log.info("airtalk event", event, param)
  98. end)
  99. --[[
  100. event具体见EVENT_XXX
  101. param说明:
  102. 目前只有EVENT_ERROR会有param值,为ERROR_XXX
  103. ]]
  104. */
  105. static int l_airtalk_on(lua_State *L) {
  106. if (l_airtalk_cb)
  107. {
  108. luaL_unref(L, LUA_REGISTRYINDEX, l_airtalk_cb);
  109. l_airtalk_cb = 0;
  110. }
  111. if (lua_isfunction(L, 1)) {
  112. lua_pushvalue(L, 1);
  113. l_airtalk_cb = luaL_ref(L, LUA_REGISTRYINDEX);
  114. }
  115. return 0;
  116. }
  117. /*
  118. airtalk启动
  119. @api airtalk.start()
  120. @return nil 无返回值
  121. @usage
  122. mqttc = mqtt.create(nil,"120.55.137.106", 1884)
  123. airtalk.config(airtalk.PROTOCOL_MQTT, mqttc)
  124. airtalk.on(function(event, param)
  125. log.info("airtalk event", event, param)
  126. end)
  127. airtalk.start()
  128. */
  129. static int l_airtalk_start(lua_State *L)
  130. {
  131. luat_airtalk_speech_init();
  132. luat_airtalk_net_init();
  133. return 0;
  134. }
  135. /*
  136. 配置airtalk RTP协议中的SSRC
  137. @api airtalk.set_ssrc(ssrc)
  138. @int/string ssrc,可以是int也是可以8字节string
  139. @return nil 无返回值
  140. @usage
  141. */
  142. static int l_airtalk_set_ssrc(lua_State *L)
  143. {
  144. if (lua_isstring(L, 1))
  145. {
  146. size_t len;
  147. const char *id = lua_tolstring(L, 1, &len);//取出字符串数据;
  148. uint32_t ssrc = strtol(id, NULL, 16);
  149. luat_airtalk_net_set_ssrc(ssrc);
  150. }
  151. else
  152. {
  153. luat_airtalk_net_set_ssrc(lua_tointeger(L, 1));
  154. }
  155. return 0;
  156. }
  157. /*
  158. 配置airtalk mqtt类型语音数据的专用topic
  159. @api airtalk.set_topic(topic)
  160. @string topic
  161. @return nil 无返回值
  162. @usage
  163. airtalk.set_topic("xxxxxxxxxx")
  164. */
  165. static int l_airtalk_set_mqtt_topic(lua_State *L)
  166. {
  167. size_t len;
  168. const char *id = lua_tolstring(L, 1, &len);//取出字符串数据;
  169. luat_airtalk_net_set_mqtt_topic(id, len + 1);
  170. return 0;
  171. }
  172. /*
  173. airtalk对讲工作启动/停止
  174. @api airtalk.speech(on_off, mode, sample)
  175. @boolean 启停控制,true开始,false停止
  176. @int 工作模式,见airtalk.MODE_XXX
  177. @int 音频采样率,目前只有8000和16000,默认16000
  178. @return nil 无返回值
  179. @usage
  180. --1对1对讲开始
  181. airtalk.speech(true,airtalk.MODE_PERSON,16000)
  182. --作为发起方,进行1对多对讲
  183. airtalk.speech(true,airtalk.MODE_GROUP_SPEAKER,16000)
  184. --作为接收方,进行1对多对讲
  185. airtalk.speech(true,airtalk.MODE_GROUP_LISTENER,16000)
  186. --对讲停止
  187. airtalk.speech(false)
  188. */
  189. static int l_airtalk_speech(lua_State *L)
  190. {
  191. int mode = luaL_optinteger(L, 2, LUAT_AIRTALK_SPEECH_MODE_PERSON);
  192. int sample = luaL_optinteger(L, 3, 16000);
  193. int on_off = lua_toboolean(L, 1);
  194. if (on_off)
  195. {
  196. switch(mode)
  197. {
  198. case LUAT_AIRTALK_SPEECH_MODE_PERSON:
  199. luat_airtalk_use_16k(sample == 16000);
  200. //luat_airtalk_speech_start_play(sample == 16000);
  201. luat_airtalk_net_transfer_start(mode);
  202. luat_airtalk_speech_record_switch(1);
  203. break;
  204. case LUAT_AIRTALK_SPEECH_MODE_GROUP_SPEAKER:
  205. luat_airtalk_use_16k(sample == 16000);
  206. luat_airtalk_speech_record_switch(1);
  207. luat_airtalk_net_transfer_start(mode);
  208. break;
  209. case LUAT_AIRTALK_SPEECH_MODE_GROUP_LISTENER:
  210. luat_airtalk_use_16k(sample == 16000);
  211. luat_airtalk_speech_start_play(sample == 16000);
  212. luat_airtalk_net_transfer_start(mode);
  213. break;
  214. }
  215. }
  216. else
  217. {
  218. luat_airtalk_net_transfer_stop();
  219. luat_airtalk_speech_record_switch(0);
  220. }
  221. return 0;
  222. }
  223. ///*
  224. //airtalk上行控制
  225. //@api airtalk.uplink(on_off)
  226. //@boolean 录音上行控制,true开始,false停止
  227. //@return nil 无返回值
  228. //@usage
  229. //--开始录音
  230. //airtalk.uplink(true)
  231. //--停止录音
  232. //airtalk.uplink(false)
  233. //*/
  234. //static int l_airtalk_uplink(lua_State *L)
  235. //{
  236. // luat_airtalk_speech_record_switch(lua_toboolean(L, 1));
  237. // return 0;
  238. //}
  239. /*
  240. airtalk的详细调试信息开关
  241. @api airtalk.debug(on_off)
  242. @boolean 调试信息开关,true打开,false关闭
  243. @return nil 无返回值
  244. */
  245. static int l_airtalk_debug(lua_State *L)
  246. {
  247. uint8_t on_off = lua_toboolean(L, 1);
  248. luat_airtalk_net_debug_switch(on_off);
  249. luat_airtalk_speech_debug_switch(on_off);
  250. return 0;
  251. }
  252. #include "rotable2.h"
  253. static const rotable_Reg_t reg_airtalk[] =
  254. {
  255. { "speech", ROREG_FUNC(l_airtalk_speech)},
  256. { "config", ROREG_FUNC(l_airtalk_config)},
  257. { "on", ROREG_FUNC(l_airtalk_on)},
  258. { "start", ROREG_FUNC(l_airtalk_start)},
  259. { "set_ssrc", ROREG_FUNC(l_airtalk_set_ssrc)},
  260. { "set_topic", ROREG_FUNC(l_airtalk_set_mqtt_topic)},
  261. // { "uplink", ROREG_FUNC(l_airtalk_uplink)},
  262. { "debug", ROREG_FUNC(l_airtalk_debug)},
  263. //@const PROTOCOL_MQTT number 语音数据用MQTT传输
  264. { "PROTOCOL_MQTT", ROREG_INT(LUAT_AIRTALK_PROTOCOL_MQTT)},
  265. //@const MODE_PERSON number 对讲工作模式1对1
  266. { "MODE_PERSON", ROREG_INT(LUAT_AIRTALK_SPEECH_MODE_PERSON)},
  267. //@const MODE_GROUP_SPEAKER number 对讲工作模式1对多的发起者,录音上行,不播放
  268. { "MODE_GROUP_SPEAKER", ROREG_INT(LUAT_AIRTALK_SPEECH_MODE_GROUP_SPEAKER)},
  269. //@const MODE_GROUP_LISTENER number 对讲工作模式1对多的接收者,下行播放,不录音
  270. { "MODE_GROUP_LISTENER", ROREG_INT(LUAT_AIRTALK_SPEECH_MODE_GROUP_LISTENER)},
  271. //@const EVENT_OFF_LINE number airtalk离线
  272. { "EVENT_OFF_LINE", ROREG_INT(LUAT_AIRTALK_CB_OFF_LINE)},
  273. //@const EVENT_ON_LINE_IDLE number airtalk在线处于空闲状态
  274. { "EVENT_ON_LINE_IDLE", ROREG_INT(LUAT_AIRTALK_CB_ON_LINE_IDLE)},
  275. //@const EVENT_PLAY_START number airtalk下行播放开始
  276. { "EVENT_PLAY_START", ROREG_INT(LUAT_AIRTALK_CB_PLAY_START)},
  277. //@const EVENT_PLAY_END number airtalk下行播放结束
  278. { "EVENT_PLAY_END", ROREG_INT(LUAT_AIRTALK_CB_PLAY_END)},
  279. //@const EVENT_RECORD_START number airtalk录音上行开始
  280. { "EVENT_RECORD_START", ROREG_INT(LUAT_AIRTALK_CB_RECORD_START)},
  281. //@const EVENT_RECORD_END number airtalk录音上行结束
  282. { "EVENT_RECORD_END", ROREG_INT(LUAT_AIRTALK_CB_RECORD_END)},
  283. //@const EVENT_AUDIO_START number airtalk audio启动,只要上行和下行有一个开始就启动
  284. { "EVENT_AUDIO_START", ROREG_INT(LUAT_AIRTALK_CB_AUDIO_START)},
  285. //@const EVENT_AUDIO_END number airtalk audio停止,上行和下行都结束才停止
  286. { "EVENT_AUDIO_END", ROREG_INT(LUAT_AIRTALK_CB_AUDIO_END)},
  287. //@const EVENT_ERROR number airtalk发生异常,后续param为异常值
  288. { "EVENT_ERROR", ROREG_INT(LUAT_AIRTALK_CB_ERROR)},
  289. //@const EVENT_ERROR number airtalk发生异常,长时间没有收到音频数据
  290. { "ERROR_NO_DATA", ROREG_INT(LUAT_AIRTALL_ERR_LONG_TIME_NO_DATA)},
  291. { NULL, ROREG_INT(0) }
  292. };
  293. LUAMOD_API int luaopen_airtalk(lua_State *L)
  294. {
  295. luat_newlib2(L, reg_airtalk);
  296. return 1;
  297. }
  298. LUAT_WEAK void luat_airtalk_callback(uint32_t event, void *param, uint32_t param_len)
  299. {
  300. rtos_msg_t msg = {0};
  301. msg.handler = l_airtalk_handler;
  302. msg.ptr = param;
  303. msg.arg1 = event;
  304. msg.arg2 = param_len;
  305. luat_msgbus_put(&msg, 0);
  306. }