duerapp_alert.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609
  1. /**
  2. * Copyright (2017) Baidu Inc. All rights reserved.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. /**
  17. * File: duerapp_config.h
  18. * Auth: Renhe Zhang (v_zhangrenhe@baidu.com)
  19. * Desc: Duer Alert function file.
  20. */
  21. #include <stdio.h>
  22. #include <stdlib.h>
  23. #include <string.h>
  24. #include <time.h>
  25. #include <gst/gst.h>
  26. #include <glib.h>
  27. #include "lightduer_dcs_alert.h"
  28. #include "duerapp_media.h"
  29. #include "lightduer_net_ntp.h"
  30. #include "lightduer_types.h"
  31. #include "lightduer_timers.h"
  32. #include "lightduer_mutex.h"
  33. #include "lightduer_memory.h"
  34. #include "duerapp_config.h"
  35. #include "duerapp_alert.h"
  36. typedef struct _duerapp_alert_node {
  37. char *token;
  38. char *type;
  39. char *time;
  40. int ring_count;
  41. bool isbell;
  42. duer_timer_handler handle;
  43. char *ring_tab[0];
  44. } duerapp_alert_node;
  45. typedef struct _duer_alert_list {
  46. struct _duer_alert_list *next;
  47. duerapp_alert_node *data;
  48. } duer_alert_list_t;
  49. static duer_alert_list_t s_alert_head;
  50. static duer_mutex_t s_alert_mutex = NULL;
  51. static duer_mutex_t s_bell_mutex = NULL;
  52. static char *s_ring_path = NULL;
  53. static GMainLoop *s_loop = NULL;
  54. static bool s_is_bell = false;
  55. bool duer_alert_bell()
  56. {
  57. return s_is_bell;
  58. }
  59. void duer_set_alert_ring(char *ring)
  60. {
  61. s_ring_path = ring;
  62. }
  63. char *duer_get_alert_ring()
  64. {
  65. return s_ring_path;
  66. }
  67. static char *duer_get_json_value_str(const baidu_json *data)
  68. {
  69. char *ret = NULL;
  70. int len = 0;
  71. if(data && data->valuestring) {
  72. len = strlen(data->valuestring) + 1;
  73. ret = (char *)DUER_MALLOC(len);
  74. if(ret) {
  75. snprintf(ret, len, "%s", data->valuestring);
  76. } else {
  77. DUER_LOGE("ret malloc failed.");
  78. }
  79. }
  80. return ret;
  81. }
  82. static char *duer_get_assets_url_str(const baidu_json *assets, const char *assetid)
  83. {
  84. char *ret = NULL;
  85. baidu_json *ass_url = NULL;
  86. baidu_json *asset = NULL;
  87. baidu_json *ass_id = NULL;
  88. int ass_count = 0;
  89. if(!assets) {
  90. DUER_LOGW("assets is null.");
  91. return NULL;
  92. }
  93. ass_count = baidu_json_GetArraySize(assets);
  94. for(int i = 0; i < ass_count; i++) {
  95. asset = baidu_json_GetArrayItem(assets, i);
  96. if(!asset) {
  97. continue;
  98. }
  99. ass_id = baidu_json_GetObjectItem(asset, "assetId");
  100. if(ass_id && ass_id->valuestring
  101. && (strcmp(ass_id->valuestring, assetid) == 0)) {
  102. ass_url = baidu_json_GetObjectItem(asset, "url");
  103. break;
  104. }
  105. }
  106. ret = duer_get_json_value_str(ass_url);
  107. if(!ret) {
  108. DUER_LOGW("not find assetId(%s) of url.", assetid);
  109. }
  110. return ret;
  111. }
  112. static duer_errcode_t duer_alert_list_push(duerapp_alert_node *data)
  113. {
  114. duer_errcode_t rt = DUER_OK;
  115. duer_alert_list_t *new_node = NULL;
  116. duer_alert_list_t *tail = &s_alert_head;
  117. do {
  118. new_node = (duer_alert_list_t *)DUER_MALLOC(sizeof(duer_alert_list_t));
  119. if (!new_node) {
  120. DUER_LOGE("Memory too low");
  121. rt = DUER_ERR_MEMORY_OVERLOW;
  122. break;
  123. }
  124. new_node->next = NULL;
  125. new_node->data = data;
  126. while (tail->next) {
  127. tail = tail->next;
  128. }
  129. tail->next = new_node;
  130. } while(0);
  131. return rt;
  132. }
  133. static duer_errcode_t duer_alert_list_remove(duerapp_alert_node *data)
  134. {
  135. duer_alert_list_t *pre = &s_alert_head;
  136. duer_alert_list_t *cur = NULL;
  137. duer_errcode_t rt = DUER_ERR_FAILED;
  138. while (pre->next) {
  139. cur = pre->next;
  140. if (cur->data == data) {
  141. pre->next = cur->next;
  142. DUER_FREE(cur);
  143. rt = DUER_OK;
  144. break;
  145. }
  146. pre = pre->next;
  147. }
  148. return rt;
  149. }
  150. static duerapp_alert_node *duer_create_alert_node(const baidu_json *data)
  151. {
  152. baidu_json *payload = NULL;
  153. baidu_json *playorder = NULL;
  154. baidu_json *time = NULL;
  155. baidu_json *token = NULL;
  156. baidu_json *type = NULL;
  157. baidu_json *assets = NULL;
  158. baidu_json *playorder_id = NULL;
  159. int playorder_count = 0;
  160. int node_size = sizeof(duerapp_alert_node);
  161. duerapp_alert_node *alert = NULL;
  162. if(!data) {
  163. DUER_LOGW("data is null.");
  164. return NULL;
  165. }
  166. payload = baidu_json_GetObjectItem(data, "payload");
  167. if(!payload) {
  168. DUER_LOGW("payload is null.");
  169. return NULL;
  170. }
  171. time = baidu_json_GetObjectItem(payload, "scheduledTime");
  172. token = baidu_json_GetObjectItem(payload, "token");
  173. type = baidu_json_GetObjectItem(payload, "type");
  174. playorder = baidu_json_GetObjectItem(payload, "assetPlayOrder");
  175. assets = baidu_json_GetObjectItem(payload, "assets");
  176. if(!(time && token && type && playorder && assets)) {
  177. DUER_LOGW("Missing required parameters.");
  178. return NULL;
  179. }
  180. playorder_count = baidu_json_GetArraySize(playorder);
  181. node_size += playorder_count ? ((playorder_count) * sizeof(char *)) : 0;
  182. alert = (duerapp_alert_node *)DUER_MALLOC(node_size);
  183. if(!alert) {
  184. DUER_LOGE("alert malloc failed.");
  185. return NULL;
  186. }
  187. alert->ring_count = playorder_count;
  188. alert->isbell = false;
  189. alert->handle = NULL;
  190. alert->ring_tab[0] = NULL;
  191. alert->token = duer_get_json_value_str(token);
  192. alert->type = duer_get_json_value_str(type);
  193. alert->time = duer_get_json_value_str(time);
  194. if(!(alert->token && alert->type && alert->time)) {
  195. if(alert->token) {
  196. DUER_FREE(alert->token);
  197. }
  198. if(alert->type) {
  199. DUER_FREE(alert->type);
  200. }
  201. if(alert->time) {
  202. DUER_FREE(alert->time);
  203. }
  204. if(alert) {
  205. DUER_FREE(alert);
  206. }
  207. return NULL;
  208. }
  209. for(int i = 0; i < playorder_count; i++) {
  210. playorder_id = baidu_json_GetArrayItem(playorder, i);
  211. if(playorder_id && playorder_id->valuestring) {
  212. alert->ring_tab[i] = duer_get_assets_url_str(assets, playorder_id->valuestring);
  213. } else {
  214. DUER_LOGE("get assetPlayOrder Id failed. num:%d", i);
  215. }
  216. }
  217. return alert;
  218. }
  219. static void duer_free_alert_node(duerapp_alert_node *alert)
  220. {
  221. if (alert) {
  222. for(int i = 0; i < alert->ring_count; i++) {
  223. if(alert->ring_tab[i]) {
  224. DUER_FREE(alert->ring_tab[i]);
  225. alert->ring_tab[i] = NULL;
  226. }
  227. }
  228. if (alert->token) {
  229. DUER_FREE(alert->token);
  230. alert->token = NULL;
  231. }
  232. if (alert->type) {
  233. DUER_FREE(alert->type);
  234. alert->type = NULL;
  235. }
  236. if (alert->time) {
  237. DUER_FREE(alert->time);
  238. alert->time = NULL;
  239. }
  240. if (alert->handle) {
  241. duer_timer_release(alert->handle);
  242. alert->handle = NULL;
  243. }
  244. DUER_FREE(alert);
  245. }
  246. }
  247. static gboolean bus_call(GstBus *bus, GstMessage *msg, gpointer data)
  248. {
  249. GMainLoop *loop = (GMainLoop *)data;
  250. switch (GST_MESSAGE_TYPE (msg)) {
  251. case GST_MESSAGE_EOS:
  252. g_main_loop_quit(loop);
  253. break;
  254. case GST_MESSAGE_ERROR: {
  255. gchar *debug;
  256. GError *error;
  257. gst_message_parse_error(msg, &error, &debug);
  258. g_free(debug);
  259. DUER_LOGE("gstreamer play : %s\n", error->message);
  260. g_error_free (error);
  261. g_main_loop_quit(loop);
  262. }
  263. break;
  264. default:
  265. break;
  266. }
  267. }
  268. static void duer_alert_play_local(const char *path) {
  269. GstElement *pipeline = gst_pipeline_new("audio-player");
  270. GstElement *source = gst_element_factory_make("filesrc", "file-source");
  271. GstElement *decoder = gst_element_factory_make("mad", "mad-decoder");
  272. GstElement *sink = gst_element_factory_make("autoaudiosink", "audio-output");
  273. if (!(pipeline && source && decoder && sink)) {
  274. DUER_LOGE("create alert element failed!");
  275. return;
  276. }
  277. g_object_set(G_OBJECT(source), "location", path, NULL);
  278. GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(pipeline));
  279. guint bus_watch_id = gst_bus_add_watch(bus, bus_call, s_loop);
  280. gst_object_unref(bus);
  281. gst_bin_add_many(GST_BIN(pipeline), source, decoder, sink, NULL);
  282. gst_element_link_many(source, decoder, sink, NULL);
  283. gst_element_set_state(pipeline, GST_STATE_PLAYING);
  284. g_main_loop_run(s_loop);
  285. gst_element_set_state(pipeline, GST_STATE_NULL);
  286. gst_object_unref(GST_OBJECT(pipeline));
  287. g_source_remove(bus_watch_id);
  288. }
  289. static void duer_alert_play_url(const char *url) {
  290. GstElement *pipeline = gst_element_factory_make("playbin", "alert");
  291. if (!pipeline) {
  292. DUER_LOGE("create alert element failed!");
  293. return;
  294. }
  295. g_object_set(G_OBJECT(pipeline), "uri", url, NULL);
  296. GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(pipeline));
  297. guint bus_watch_id = gst_bus_add_watch(bus, bus_call, s_loop);
  298. gst_object_unref(bus);
  299. gst_element_set_state(pipeline, GST_STATE_PLAYING);
  300. g_main_loop_run(s_loop);
  301. gst_element_set_state(pipeline, GST_STATE_NULL);
  302. gst_object_unref(GST_OBJECT(pipeline));
  303. g_source_remove(bus_watch_id);
  304. }
  305. static void duer_bell_thread(duerapp_alert_node *alert_info)
  306. {
  307. duer_mutex_lock(s_bell_mutex);
  308. pthread_detach(pthread_self());
  309. duer_media_audio_stop();
  310. duer_media_speak_stop();
  311. s_loop = g_main_loop_new(NULL, FALSE);
  312. if (!s_loop) {
  313. DUER_LOGE("create alert loop failed!");
  314. duer_mutex_unlock(s_bell_mutex);
  315. return;
  316. }
  317. alert_info->isbell = true;
  318. s_is_bell = true;
  319. if(alert_info->ring_count) {
  320. // play url
  321. for(int i = 0; i < alert_info->ring_count; i++) {
  322. duer_alert_play_url(alert_info->ring_tab[i]);
  323. if(!s_is_bell) {
  324. break;
  325. }
  326. }
  327. } else {
  328. // play loacl
  329. duer_alert_play_local(s_ring_path);
  330. }
  331. duer_dcs_report_alert_event(alert_info->token, ALERT_STOP);
  332. g_main_loop_unref (s_loop);
  333. s_loop = NULL;
  334. alert_info->isbell = false;
  335. s_is_bell = false;
  336. duer_mutex_unlock(s_bell_mutex);
  337. }
  338. static void duer_alert_start(duerapp_alert_node *alert_info)
  339. {
  340. if (!s_ring_path) {
  341. DUER_LOGE("not found wav path!");
  342. return;
  343. }
  344. if (s_is_bell) {
  345. duer_alert_stop();
  346. }
  347. pthread_t bell_threadid;
  348. int ret = pthread_create(&bell_threadid, NULL, (void *)duer_bell_thread, (void *)alert_info);
  349. if(ret != 0)
  350. {
  351. DUER_LOGE("Create alert pthread failed!");
  352. } else {
  353. pthread_setname_np(bell_threadid, "alert_bell");
  354. }
  355. }
  356. void duer_alert_stop()
  357. {
  358. if (s_is_bell) {
  359. s_is_bell = false;
  360. g_main_loop_quit(s_loop);
  361. } else {
  362. DUER_LOGI("Now the alert is not ringing.");
  363. }
  364. }
  365. static void duer_alert_callback(void *param)
  366. {
  367. duerapp_alert_node *alert = (duerapp_alert_node *)param;
  368. DUER_LOGI("alert started: token: %s", alert->token);
  369. duer_dcs_report_alert_event(alert->token, ALERT_START);
  370. // play url
  371. duer_alert_start(alert);
  372. }
  373. static time_t duer_dcs_get_time_stamp(const char *time)
  374. {
  375. time_t time_stamp = 0;
  376. struct tm time_tm;
  377. int rs = 0;
  378. int year = 0;
  379. int month = 0;
  380. int day = 0;
  381. int hour = 0;
  382. int min = 0;
  383. int sec = 0;
  384. rs = sscanf(time, "%d-%d-%dT%d:%d:%d+", &year, &month, &day, &hour, &min, &sec);
  385. if (rs != 6) {
  386. return (time_t)-1;
  387. }
  388. time_tm.tm_year = year - 1900;
  389. time_tm.tm_mon = month - 1;
  390. time_tm.tm_mday = day;
  391. time_tm.tm_hour = hour;
  392. time_tm.tm_min = min;
  393. time_tm.tm_sec = sec;
  394. time_tm.tm_isdst = 0;
  395. time_stamp = mktime(&time_tm);
  396. return time_stamp + (8 * 60 * 60);
  397. }
  398. static void duer_alert_set_thread(duerapp_alert_node *alert)
  399. {
  400. pthread_detach(pthread_self());
  401. int ret = 0;
  402. DuerTime cur_time;
  403. size_t delay = 0;
  404. int rs = DUER_OK;
  405. time_t time_stamp = 0;
  406. if(!alert) {
  407. DUER_LOGE("alert is null.");
  408. return;
  409. }
  410. DUER_LOGI("set alert: scheduled_time: %s, token: %s\n", alert->time, alert->token);
  411. time_stamp = duer_dcs_get_time_stamp(alert->time);
  412. if (time_stamp < 0) {
  413. duer_dcs_report_alert_event(alert->token, SET_ALERT_FAIL);
  414. duer_free_alert_node(alert);
  415. return;
  416. }
  417. DUER_LOGI("time_stamp: %d\n", time_stamp);
  418. ret = duer_ntp_client(NULL, 0, &cur_time, NULL);
  419. if (ret < 0) {
  420. DUER_LOGE("Failed to get NTP time.ret = %d", ret);
  421. duer_dcs_report_alert_event(alert->token, SET_ALERT_FAIL);
  422. duer_free_alert_node(alert);
  423. return;
  424. }
  425. if (time_stamp <= cur_time.sec) {
  426. DUER_LOGE("The alert is expired\n");
  427. duer_dcs_report_alert_event(alert->token, SET_ALERT_FAIL);
  428. duer_free_alert_node(alert);
  429. return;
  430. }
  431. delay = (time_stamp - cur_time.sec) * 1000 - cur_time.usec / 1000;
  432. alert->handle = duer_timer_acquire(duer_alert_callback, alert, DUER_TIMER_ONCE);
  433. if (!alert->handle) {
  434. DUER_LOGE("Failed to set alert: failed to create timer\n");
  435. duer_dcs_report_alert_event(alert->token, SET_ALERT_FAIL);
  436. duer_free_alert_node(alert);
  437. return;
  438. }
  439. rs = duer_timer_start(alert->handle, delay);
  440. if (rs != DUER_OK) {
  441. DUER_LOGE("Failed to set alert: failed to start timer\n");
  442. duer_dcs_report_alert_event(alert->token, SET_ALERT_FAIL);
  443. duer_free_alert_node(alert);
  444. return;
  445. }
  446. duer_mutex_lock(s_alert_mutex);
  447. duer_alert_list_push(alert);
  448. duer_mutex_unlock(s_alert_mutex);
  449. duer_dcs_report_alert_event(alert->token, SET_ALERT_SUCCESS);
  450. }
  451. duer_status_t duer_dcs_tone_alert_set_handler(const baidu_json *directive)
  452. {
  453. duerapp_alert_node *alert = NULL;
  454. alert = duer_create_alert_node(directive);
  455. if(alert && alert->token && alert->type && alert->time) {
  456. pthread_t set_alert_threadid;
  457. int ret = pthread_create(&set_alert_threadid, NULL,
  458. (void *)duer_alert_set_thread,
  459. (void *)alert);
  460. if(ret != 0) {
  461. DUER_LOGE("Create alert pthread failed!");
  462. duer_dcs_report_alert_event(alert->token, SET_ALERT_FAIL);
  463. } else {
  464. pthread_setname_np(set_alert_threadid, "alert_set");
  465. }
  466. return DUER_OK;
  467. } else {
  468. DUER_LOGE("ERROR SetAlert Failed.");
  469. return DUER_ERR_FAILED;
  470. }
  471. }
  472. static duerapp_alert_node *duer_find_target_alert(const char *token)
  473. {
  474. duer_alert_list_t *node = s_alert_head.next;
  475. while (node) {
  476. if (node->data) {
  477. if (strcmp(token, node->data->token) == 0) {
  478. return node->data;
  479. }
  480. }
  481. node = node->next;
  482. }
  483. return NULL;
  484. }
  485. void duer_dcs_alert_delete_handler(const char *token)
  486. {
  487. duerapp_alert_node *target_alert = NULL;
  488. DUER_LOGI("delete alert: token %s", token);
  489. duer_mutex_lock(s_alert_mutex);
  490. target_alert = duer_find_target_alert(token);
  491. if (!target_alert) {
  492. DUER_LOGE("Cannot find the target alert\n");
  493. duer_mutex_unlock(s_alert_mutex);
  494. duer_dcs_report_alert_event(token, DELETE_ALERT_FAIL);
  495. return;
  496. }
  497. duer_alert_list_remove(target_alert);
  498. duer_free_alert_node(target_alert);
  499. duer_mutex_unlock(s_alert_mutex);
  500. duer_dcs_report_alert_event(token, DELETE_ALERT_SUCCESS);
  501. }
  502. void duer_dcs_get_all_alert(baidu_json *alert_array)
  503. {
  504. duer_alert_list_t *alert_node = s_alert_head.next;
  505. duer_dcs_alert_info_type alert_info;
  506. bool is_active = false;
  507. while (alert_node) {
  508. alert_info.token = alert_node->data->token;
  509. alert_info.type = alert_node->data->type;
  510. alert_info.time = alert_node->data->time;
  511. duer_insert_alert_list(alert_array, &alert_info, alert_node->data->isbell);
  512. alert_node = alert_node->next;
  513. }
  514. }
  515. void duer_alert_init()
  516. {
  517. if (!s_alert_mutex) {
  518. s_alert_mutex = duer_mutex_create();
  519. }
  520. if (!s_bell_mutex) {
  521. s_bell_mutex = duer_mutex_create();
  522. }
  523. duer_dcs_alert_init();
  524. }