luat_lib_cc.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437
  1. /*
  2. @module cc
  3. @summary VoLTE通话功能
  4. @version 1.0
  5. @date 2024.1.17
  6. @demo cc
  7. @tag LUAT_USE_VOLTE
  8. @usage
  9. -- 选型手册上支持VoLTE通话功能的模组支持
  10. */
  11. #include "luat_base.h"
  12. #include "luat_mem.h"
  13. #include "luat_rtos.h"
  14. #include "luat_msgbus.h"
  15. #include "luat_zbuff.h"
  16. #include "luat_mobile.h"
  17. #include "luat_network_adapter.h"
  18. #include "luat_i2s.h"
  19. #include "luat_audio.h"
  20. #define LUAT_LOG_TAG "cc"
  21. #include "luat_log.h"
  22. enum{
  23. VOLTE_EVENT_PLAY_TONE = 1,
  24. VOLTE_EVENT_RECORD_VOICE_START,
  25. VOLTE_EVENT_RECORD_VOICE_UPLOAD,
  26. VOLTE_EVENT_PLAY_VOICE,
  27. VOLTE_EVENT_HANGUP,
  28. VOLTE_EVENT_CALL_READY,
  29. };
  30. //播放控制
  31. typedef struct
  32. {
  33. luat_rtos_task_handle task_handle;
  34. luat_zbuff_t *up_buff[2];
  35. luat_zbuff_t *down_buff[2];
  36. int record_cb;
  37. HANDLE record_timer;
  38. uint32_t bak_sample_rate; // i2s采样率备份
  39. int (*bak_luat_i2s_event_callback)(uint8_t id ,luat_i2s_event_t event, uint8_t *rx_data, uint32_t rx_len, void *param); // i2s回调函数备份
  40. uint8_t bak_is_full_duplex; // 是否全双工备份
  41. uint32_t next_download_point;
  42. uint8_t *download_buffer;
  43. uint8_t total_download_cnt;
  44. uint8_t play_type;
  45. uint8_t record_type;
  46. uint8_t is_call_uplink_on;
  47. uint8_t record_on_off;
  48. uint8_t record_start;
  49. uint8_t upload_need_stop;
  50. volatile uint8_t record_down_zbuff_point;
  51. volatile uint8_t record_up_zbuff_point;
  52. }luat_cc_ctrl_t;
  53. static luat_cc_ctrl_t luat_cc;
  54. static int l_cc_handler(lua_State *L, void* ptr) {
  55. (void)ptr;
  56. //LLOGD("l_uart_handler");
  57. rtos_msg_t* msg = (rtos_msg_t*)lua_topointer(L, -1);
  58. lua_pop(L, 1);
  59. if (luat_cc.record_on_off && luat_cc.record_cb)
  60. {
  61. lua_geti(L, LUA_REGISTRYINDEX, luat_cc.record_cb);
  62. if (lua_isfunction(L, -1)) {
  63. lua_pushboolean(L, msg->arg1);
  64. lua_pushinteger(L, msg->arg2);
  65. lua_call(L, 2, 0);
  66. }
  67. }
  68. // 给rtos.recv方法返回个空数据
  69. lua_pushinteger(L, 0);
  70. return 1;
  71. }
  72. static void mobile_voice_data_input(uint8_t *input, uint32_t len, uint32_t sample_rate, uint8_t bits){
  73. if (luat_cc.record_on_off) {
  74. luat_cc.record_down_zbuff_point = 0;
  75. luat_cc.download_buffer = (uint8_t *)input;
  76. if (1 == sample_rate)
  77. {
  78. luat_cc.total_download_cnt = 6;
  79. }
  80. else
  81. {
  82. luat_cc.total_download_cnt = 3;
  83. }
  84. memcpy(luat_cc.down_buff[0]->addr, luat_cc.download_buffer, sample_rate * 320);
  85. luat_cc.down_buff[0]->used = sample_rate * 320;
  86. luat_cc.next_download_point = 1;
  87. luat_start_rtos_timer(luat_cc.record_timer, 20, 1);
  88. if (luat_cc.down_buff[0]->used >= luat_cc.down_buff[0]->len) {
  89. rtos_msg_t msg;
  90. msg.handler = l_cc_handler;
  91. msg.arg1 = 1;
  92. msg.arg2 = 0;
  93. luat_msgbus_put(&msg, 0);
  94. luat_cc.record_down_zbuff_point = !luat_cc.record_down_zbuff_point;
  95. luat_cc.down_buff[luat_cc.record_down_zbuff_point]->used = 0;
  96. }
  97. }
  98. luat_rtos_event_send(luat_cc.task_handle, VOLTE_EVENT_PLAY_VOICE, (uint32_t)input, len, sample_rate, 0);
  99. }
  100. static int record_cb(uint8_t id ,luat_i2s_event_t event, uint8_t *rx_data, uint32_t rx_len, void *param){
  101. if (luat_cc.upload_need_stop) return 0;
  102. switch(event){
  103. case LUAT_I2S_EVENT_RX_DONE:
  104. luat_rtos_event_send(luat_cc.task_handle, VOLTE_EVENT_RECORD_VOICE_UPLOAD, (uint32_t)rx_data, rx_len, 0, 0);
  105. break;
  106. case LUAT_I2S_EVENT_TX_DONE:
  107. case LUAT_I2S_EVENT_TRANSFER_DONE:
  108. break;
  109. default:
  110. break;
  111. }
  112. return 0;
  113. }
  114. static LUAT_RT_RET_TYPE download_data_callback(LUAT_RT_CB_PARAM)
  115. {
  116. if (luat_cc.record_type && luat_cc.record_on_off) {
  117. luat_zbuff_t *buff = luat_cc.down_buff[luat_cc.record_down_zbuff_point];
  118. memcpy(buff->addr + buff->used, luat_cc.download_buffer + luat_cc.next_download_point * luat_cc.record_type * 320, luat_cc.record_type * 320);//20ms录音完成
  119. luat_cc.next_download_point = (luat_cc.next_download_point + 1) % luat_cc.total_download_cnt;
  120. buff->used += luat_cc.record_type * 320;
  121. if (buff->used >= buff->len) {
  122. rtos_msg_t msg;
  123. msg.handler = l_cc_handler;
  124. msg.arg2 = luat_cc.record_down_zbuff_point;
  125. msg.arg1 = 1;
  126. luat_msgbus_put(&msg, 0);
  127. luat_cc.record_down_zbuff_point = !luat_cc.record_down_zbuff_point;
  128. luat_cc.down_buff[luat_cc.record_down_zbuff_point]->used = 0;
  129. }
  130. }
  131. }
  132. static void luat_volte_task(void *param){
  133. luat_zbuff_t *zbuff = NULL;
  134. luat_event_t event;
  135. uint8_t multimedia_id = (int)param;
  136. uint8_t speech_on_off = 0;
  137. luat_audio_conf_t* audio_conf = luat_audio_get_config(multimedia_id);
  138. luat_i2s_conf_t *i2s = luat_i2s_get_config(multimedia_id);
  139. luat_cc.bak_luat_i2s_event_callback = i2s->luat_i2s_event_callback;
  140. luat_cc.bak_sample_rate = i2s->sample_rate;
  141. luat_cc.bak_is_full_duplex = i2s->is_full_duplex;
  142. while (1){
  143. luat_rtos_event_recv(luat_cc.task_handle, 0, &event, NULL, LUAT_WAIT_FOREVER);
  144. switch(event.id)
  145. {
  146. case VOLTE_EVENT_PLAY_TONE:
  147. if (LUAT_MOBILE_CC_PLAY_STOP == event.param1){
  148. luat_cc.record_type = 0;
  149. luat_cc.play_type = 0;
  150. if (luat_rtos_timer_is_active(luat_cc.record_timer))
  151. {
  152. luat_rtos_timer_stop(luat_cc.record_timer);
  153. rtos_msg_t msg;
  154. msg.handler = l_cc_handler;
  155. msg.arg2 = luat_cc.record_up_zbuff_point;
  156. msg.arg1 = 0;
  157. luat_msgbus_put(&msg, 0);
  158. msg.arg2 = luat_cc.record_down_zbuff_point;
  159. msg.arg1 = 1;
  160. luat_msgbus_put(&msg, 0);
  161. }
  162. luat_cc.is_call_uplink_on = 0;
  163. luat_audio_speech_stop(multimedia_id);
  164. i2s->is_full_duplex = luat_cc.bak_is_full_duplex;
  165. i2s->luat_i2s_event_callback = luat_cc.bak_luat_i2s_event_callback;
  166. i2s->sample_rate = luat_cc.bak_sample_rate;
  167. LLOGD("VOLTE_EVENT_PLAY_STOP");
  168. LLOGD("load old i2s param");
  169. speech_on_off = 0;
  170. break;
  171. }
  172. break;
  173. case VOLTE_EVENT_RECORD_VOICE_START:
  174. luat_cc.record_type = event.param1;
  175. luat_cc.is_call_uplink_on = 1;
  176. if (!speech_on_off)
  177. {
  178. luat_cc.bak_luat_i2s_event_callback = i2s->luat_i2s_event_callback;
  179. luat_cc.bak_sample_rate = i2s->sample_rate;
  180. luat_cc.bak_is_full_duplex = i2s->is_full_duplex;
  181. i2s->is_full_duplex = 1;
  182. i2s->luat_i2s_event_callback = record_cb;
  183. speech_on_off = 1;
  184. LLOGD("save old i2s param");
  185. }
  186. luat_audio_speech(multimedia_id, 0, event.param1, NULL, 0, 1);
  187. luat_cc.record_up_zbuff_point = 0;
  188. if (luat_cc.record_on_off) {
  189. luat_cc.up_buff[0]->used = 0;
  190. }
  191. LLOGD("VOLTE_EVENT_RECORD_VOICE_START");
  192. break;
  193. case VOLTE_EVENT_RECORD_VOICE_UPLOAD:
  194. if (!luat_cc.is_call_uplink_on) break;
  195. if (luat_cc.upload_need_stop) {
  196. LLOGD("VOLTE RECORD VOICE ALREADY STOP");
  197. break;
  198. }
  199. if (luat_cc.record_on_off && luat_cc.record_type) {
  200. zbuff = luat_cc.up_buff[luat_cc.record_up_zbuff_point];
  201. memcpy(zbuff->addr + zbuff->used, (uint8_t *)event.param1, event.param2);
  202. zbuff->used += event.param2;
  203. }
  204. if (luat_cc.record_type) {
  205. luat_mobile_speech_upload((uint8_t *)event.param1, event.param2);
  206. }
  207. if (luat_cc.record_on_off && luat_cc.record_type) {
  208. if (zbuff->used >= zbuff->len) {
  209. rtos_msg_t msg;
  210. msg.handler = l_cc_handler;
  211. msg.arg2 = luat_cc.record_up_zbuff_point;
  212. msg.arg1 = 0;
  213. luat_msgbus_put(&msg, 0);
  214. luat_cc.record_up_zbuff_point = !luat_cc.record_up_zbuff_point;
  215. luat_cc.up_buff[luat_cc.record_up_zbuff_point]->used = 0;
  216. }
  217. }
  218. break;
  219. case VOLTE_EVENT_PLAY_VOICE:
  220. luat_cc.play_type = event.param3; //1 = 8K 2 = 16K
  221. if (!speech_on_off)
  222. {
  223. luat_cc.bak_luat_i2s_event_callback = i2s->luat_i2s_event_callback;
  224. luat_cc.bak_sample_rate = i2s->sample_rate;
  225. luat_cc.bak_is_full_duplex = i2s->is_full_duplex;
  226. i2s->is_full_duplex = 1;
  227. i2s->luat_i2s_event_callback = record_cb;
  228. speech_on_off = 1;
  229. LLOGD("save old i2s param");
  230. }
  231. luat_audio_speech(multimedia_id, 1, event.param3, (uint8_t *)event.param1, event.param2, 1);
  232. LLOGD("VOLTE PLAY VOICE");
  233. break;
  234. case VOLTE_EVENT_HANGUP:
  235. luat_mobile_hangup_call(event.param1);
  236. break;
  237. }
  238. }
  239. }
  240. /**
  241. 获取最后一次通话的号码
  242. @api cc.lastNum()
  243. @return string 获取最后一次通话的号码
  244. */
  245. static int l_cc_get_last_call_num(lua_State* L) {
  246. char number[64] = {0};
  247. luat_mobile_get_last_call_num(number, sizeof(number));
  248. lua_pushlstring(L, (const char*)(number),strlen(number));
  249. return 1;
  250. }
  251. /**
  252. 拨打电话
  253. @api cc.dial(sim_id, number)
  254. @number sim_id
  255. @string 电话号码
  256. @return bool 拨打电话成功与否
  257. */
  258. static int l_cc_make_call(lua_State* L) {
  259. uint8_t sim_id = luaL_optinteger(L, 1, 0);
  260. size_t len = 0;
  261. char* number = luaL_checklstring(L, 2, &len);
  262. lua_pushboolean(L, !luat_mobile_make_call(sim_id,number, len));
  263. return 1;
  264. }
  265. /**
  266. 挂断电话
  267. @api cc.hangUp(sim_id)
  268. @number sim_id
  269. */
  270. static int l_cc_hangup_call(lua_State* L) {
  271. uint8_t sim_id = luaL_optinteger(L, 1, 0);
  272. luat_rtos_event_send(luat_cc.task_handle, VOLTE_EVENT_HANGUP, sim_id, 0, 0, 0);
  273. return 0;
  274. }
  275. /**
  276. 接听电话
  277. @api cc.accept(sim_id)
  278. @number sim_id
  279. @return bool 接听电话成功与否
  280. */
  281. static int l_cc_answer_call(lua_State* L) {
  282. uint8_t sim_id = luaL_optinteger(L, 1, 0);
  283. lua_pushboolean(L, !luat_mobile_answer_call(sim_id));
  284. return 1;
  285. }
  286. /**
  287. 初始化电话功能
  288. @api cc.init(multimedia_id)
  289. @number multimedia_id 多媒体id
  290. @return bool 成功与否
  291. */
  292. static int l_cc_speech_init(lua_State* L) {
  293. uint8_t multimedia_id = luaL_optinteger(L, 1, 0);
  294. if (luat_mobile_speech_init(multimedia_id,mobile_voice_data_input)){
  295. lua_pushboolean(L, 0);
  296. return 1;
  297. }
  298. luat_cc.record_timer = luat_create_rtos_timer(download_data_callback, NULL, NULL);
  299. luat_rtos_task_create(&luat_cc.task_handle, 4*1024, 100, "volte", luat_volte_task, multimedia_id, 64);
  300. lua_pushboolean(L, 1);
  301. return 1;
  302. }
  303. /**
  304. 录音通话
  305. @api cc.record(on_off,upload_zbuff1, upload_zbuff2, download_zbuff1, download_zbuff2)
  306. @boolean 开启关闭通话录音功能,false或者nil关闭,其他开启
  307. @zbuff 上行数据保存区1,zbuff创建时的空间容量必须是640的倍数,下同
  308. @zbuff 上行数据保存区2,和上行数据保存区1组成双缓冲区
  309. @zbuff 下行数据保存区1
  310. @zbuff 下行数据保存区2,和下行数据保存区1组成双缓冲区
  311. @return bool 成功与否,如果处于通话状态,会失败
  312. @usage
  313. buff1 = zbuff.create(6400,0,zbuff.HEAP_AUTO)
  314. buff2 = zbuff.create(6400,0,zbuff.HEAP_AUTO)
  315. buff3 = zbuff.create(6400,0,zbuff.HEAP_AUTO)
  316. buff4 = zbuff.create(6400,0,zbuff.HEAP_AUTO)
  317. cc.on("record", function(type, buff_point)
  318. log.info(type, buff_point) -- type==true是下行数据,false是上行数据 buff_point指示双缓存中返回了哪一个
  319. end)
  320. cc.record(true, buff1, buff2, buff3, buff4)
  321. */
  322. static int l_cc_record_call(lua_State* L) {
  323. if (luat_cc.record_type)
  324. {
  325. lua_pushboolean(L, 0);
  326. return 1;
  327. }
  328. luat_cc.record_on_off = lua_toboolean(L, 1);
  329. if (luat_cc.record_on_off)
  330. {
  331. luat_cc.up_buff[0] = (luat_zbuff_t *)luaL_checkudata(L, 2, LUAT_ZBUFF_TYPE);
  332. luat_cc.up_buff[1] = (luat_zbuff_t *)luaL_checkudata(L, 3, LUAT_ZBUFF_TYPE);
  333. luat_cc.down_buff[0] = (luat_zbuff_t *)luaL_checkudata(L, 4, LUAT_ZBUFF_TYPE);
  334. luat_cc.down_buff[1] = (luat_zbuff_t *)luaL_checkudata(L, 5, LUAT_ZBUFF_TYPE);
  335. }
  336. else
  337. {
  338. luat_cc.up_buff[0] = NULL;
  339. luat_cc.up_buff[1] = NULL;
  340. luat_cc.down_buff[0] = NULL;
  341. luat_cc.down_buff[1] = NULL;
  342. }
  343. lua_pushboolean(L, 1);
  344. return 1;
  345. }
  346. /**
  347. 获取当前通话质量
  348. @api cc.quality()
  349. @return int 1为低音质(8K),2为高音质(16k),0没有在通话
  350. */
  351. static int l_cc_get_quality(lua_State* L) {
  352. lua_pushinteger(L, luat_cc.record_type);
  353. return 1;
  354. }
  355. /**
  356. 注册通话回调
  357. @api cc.on(event, func)
  358. @string 事件名称 音频录音数据为"record"
  359. @function 回调方法
  360. @return nil 无返回值
  361. @usage
  362. cc.on("record", function(type, buff_point)
  363. log.info(type, buff_point) -- type==true是下行数据,false是上行数据 buff_point指示双缓存中返回了哪一个
  364. end)
  365. */
  366. static int l_cc_on(lua_State *L) {
  367. const char* event = luaL_checkstring(L, 1);
  368. if (!strcmp("record", event)) {
  369. if (luat_cc.record_cb != 0) {
  370. luaL_unref(L, LUA_REGISTRYINDEX, luat_cc.record_cb);
  371. luat_cc.record_cb = 0;
  372. }
  373. if (lua_isfunction(L, 2)) {
  374. lua_pushvalue(L, 2);
  375. luat_cc.record_cb = luaL_ref(L, LUA_REGISTRYINDEX);
  376. }
  377. }
  378. return 0;
  379. }
  380. #include "rotable2.h"
  381. static const rotable_Reg_t reg_cc[] =
  382. {
  383. { "init" , ROREG_FUNC(l_cc_speech_init)},
  384. { "dial" , ROREG_FUNC(l_cc_make_call)},
  385. { "accept" , ROREG_FUNC(l_cc_answer_call)},
  386. { "hangUp" , ROREG_FUNC(l_cc_hangup_call)},
  387. { "lastNum" , ROREG_FUNC(l_cc_get_last_call_num)},
  388. { "quality" , ROREG_FUNC(l_cc_get_quality)},
  389. { "on" , ROREG_FUNC(l_cc_on)},
  390. { "record", ROREG_FUNC(l_cc_record_call)},
  391. { NULL, ROREG_INT(0)}
  392. };
  393. LUAMOD_API int luaopen_cc( lua_State *L ) {
  394. luat_newlib2(L, reg_cc);
  395. return 1;
  396. }
  397. void luat_cc_start_speech(uint32_t param)
  398. {
  399. luat_cc.upload_need_stop = 0;
  400. luat_rtos_event_send(luat_cc.task_handle, VOLTE_EVENT_RECORD_VOICE_START, param, 0, 0, 0);
  401. }
  402. void luat_cc_play_tone(uint32_t param)
  403. {
  404. if (!param) luat_cc.upload_need_stop = 1;
  405. luat_rtos_event_send(luat_cc.task_handle, VOLTE_EVENT_PLAY_TONE, param, 0, 0, 0);
  406. }