#ifdef SUPPORT_MS_EXTENSIONS #pragma bss_seg(".tone_player.data.bss") #pragma data_seg(".tone_player.data") #pragma const_seg(".tone_player.text.const") #pragma code_seg(".tone_player.text") #endif #include "tone_player.h" #include "fs/resfile.h" #include "os/os_api.h" #include "system/init.h" #include "decoder_node.h" #include "jldemuxer.h" #include "app_config.h" extern const struct decoder_plug_ops decoder_plug_begin[]; extern const struct decoder_plug_ops decoder_plug_end[]; const struct stream_file_ops tone_file_ops; static u8 g_player_id = 0; static OS_MUTEX g_tone_mutex; static struct list_head g_head = LIST_HEAD_INIT(g_head); static int tone_player_start(struct tone_player *); static int tone_file_close(void *file); __attribute__((weak)) void tone_event_to_user(int event, u16 fname_uuid) { } static void *open_next_file(struct tone_player *player) { if (player->next_file) { void *file = player->next_file; player->next_file = NULL; return file; } int index = ++player->index; do { if (player->file_name_list[index]) { char file_path[48]; strcpy(file_path, FLASH_RES_PATH); strcpy(file_path + strlen(FLASH_RES_PATH), player->file_name_list[index]); void *file = resfile_open(file_path); if (file) { player->index = index; return file; } index++; } else { player->index = 0; break; } } while (index != player->index); return NULL; } static int tone_player_post_asyc_callback(tone_player_cb_t callback, void *cb_priv) { int msg[4]; msg[0] = (int)callback; msg[1] = 2; msg[2] = (int)cb_priv; msg[3] = (int)STREAM_EVENT_STOP; return os_taskq_post_type("app_core", Q_CALLBACK, 4, msg); } void tone_player_free(struct tone_player *player) { int fname_uuid = player->fname_uuid; void *cb_priv = player->priv; tone_player_cb_t callback = player->callback; if (--player->ref == 0) { tone_file_close(player); free(player); } if (callback) { /* callback(cb_priv, STREAM_EVENT_STOP); */ tone_player_post_asyc_callback(callback, cb_priv); } else { tone_event_to_user(STREAM_EVENT_STOP, fname_uuid); } } static void tone_player_callback(void *_player_id, int event) { void *file = NULL; struct tone_player *player; printf("tone_callback: %x, %d\n", event, (u8)_player_id); switch (event) { case STREAM_EVENT_START: os_mutex_pend(&g_tone_mutex, 0); if (list_empty(&g_head)) { //先判断是否为空防止触发异常 os_mutex_post(&g_tone_mutex); break; } player = list_first_entry(&g_head, struct tone_player, entry); if (player->player_id == (u8)_player_id) { if (player->callback) { player->callback(player->priv, STREAM_EVENT_START); } } os_mutex_post(&g_tone_mutex); break; case STREAM_EVENT_PREEMPTED: case STREAM_EVENT_NEGOTIATE_FAILD: /* * 提示音被抢占或者参数协商失败,直接结束播放 */ case STREAM_EVENT_STOP: os_mutex_pend(&g_tone_mutex, 0); if (list_empty(&g_head)) { //先判断是否为空防止触发异常 os_mutex_post(&g_tone_mutex); break; } player = list_first_entry(&g_head, struct tone_player, entry); if (player->player_id != (u8)_player_id) { os_mutex_post(&g_tone_mutex); printf("player_id_not_match: %d\n", player->player_id); break; } if (event == STREAM_EVENT_STOP) { /* * 打开文件列表的下一个文件,重新启动解码 */ while (1) { file = open_next_file(player); if (!file) { break; } resfile_close(player->file); player->file = file; int err = jlstream_start(player->stream); if (err == 0) { break; } } } if (!file) { jlstream_release(player->stream); list_del(&player->entry); if (!list_empty(&g_head)) { struct tone_player *p; p = list_first_entry(&g_head, struct tone_player, entry); tone_player_start(p); } tone_player_free(player); } os_mutex_post(&g_tone_mutex); break; } } static int tone_file_read(void *p_file, u8 *buf, int len) { int offset = 0; struct tone_player *player = (struct tone_player *)p_file; while (len) { if (!player->file) { break; } int rlen = resfile_read(player->file, buf + offset, len); if (rlen < 0) { break; } offset += rlen; if ((len -= rlen) == 0) { break; } if (player->scene == STREAM_SCENE_RING) { if (player->coding_type == AUDIO_CODING_WTGV2) { //WTS拼接提示音时,去掉头1byte resfile_seek(player->file, 1, RESFILE_SEEK_SET); } else { resfile_seek(player->file, 0, RESFILE_SEEK_SET); if (player->coding_type == AUDIO_CODING_MP3) { break; } } continue; } if (player->next_file) { break; } /* * 打开文件列表中的下一个文件,检查format是否和当前文件相同 * 如果相同就继读下一个文件, 可以保证TWS同步播放文件列表情况下的音频同步 */ int index = player->index; void *file = open_next_file(player); if (!file) { player->index = index; break; } char name[16]; resfile_get_name(file, name, 16); struct stream_file_ops file_ops = { .read = (int (*)(void *, u8 *, int))resfile_read, .seek = (int (*)(void *, int, int))resfile_seek, }; struct stream_file_info file_info = { .file = file, .fname = name, .ops = &file_ops, }; struct stream_fmt fmt; int err = jldemuxer_get_tone_file_fmt(&file_info, &fmt); if (err == 0) { if (player->coding_type == fmt.coding_type && player->sample_rate == fmt.sample_rate && player->channel_mode == fmt.channel_mode) { resfile_close(player->file); player->file = file; if (player->coding_type == AUDIO_CODING_WTGV2) { //WTS拼接提示音时,去掉头1byte resfile_seek(player->file, 1, RESFILE_SEEK_SET); } continue; } } player->next_file = file; break; } return offset; } static int tone_file_seek(void *file, int offset, int fromwhere) { struct tone_player *player = (struct tone_player *)file; return resfile_seek(player->file, offset, fromwhere); } static int tone_file_flen(void *file) { struct tone_player *player = (struct tone_player *)file; u32 len = 0; if (player->file) { len = resfile_get_len(player->file); } return len; } static int tone_file_close(void *file) { struct tone_player *player = (struct tone_player *)file; if (player->file) { resfile_close(player->file); player->file = NULL; } if (player->next_file) { resfile_close(player->next_file); player->next_file = NULL; } return 0; } static int tone_file_get_fmt(void *file, struct stream_fmt *fmt) { struct tone_player *player = (struct tone_player *)file; char name[16]; resfile_get_name(player->file, name, 16); struct stream_file_info file_info = { .file = player, .fname = name, .ops = &tone_file_ops, }; int err = jldemuxer_get_tone_file_fmt(&file_info, fmt); if (err) { player->coding_type = AUDIO_CODING_UNKNOW; return err; } player->coding_type = fmt->coding_type; player->sample_rate = fmt->sample_rate; player->channel_mode = fmt->channel_mode; return 0; } const struct stream_file_ops tone_file_ops = { .read = tone_file_read, .seek = tone_file_seek, .close = tone_file_close, .get_fmt = tone_file_get_fmt, }; int tone_player_get_cur_time(struct tone_player *player) { os_mutex_pend(&g_tone_mutex, 0); if (list_empty(&(g_head))) { //先判断是否为空 os_mutex_post(&g_tone_mutex); return -1; } if (!player) { player = list_first_entry(&g_head, struct tone_player, entry); } if (player && player->stream) { int ret = jlstream_node_ioctl(player->stream, NODE_UUID_DECODER, NODE_IOC_GET_CUR_TIME, 0); os_mutex_post(&g_tone_mutex); return ret; } os_mutex_post(&g_tone_mutex); return -1; } int tone_player_get_total_time(struct tone_player *player) { os_mutex_pend(&g_tone_mutex, 0); if (list_empty(&(g_head))) { //先判断是否为空 os_mutex_post(&g_tone_mutex); return -1; } if (!player) { player = list_first_entry(&g_head, struct tone_player, entry); } if (player && player->stream) { int ret = jlstream_node_ioctl(player->stream, NODE_UUID_DECODER, NODE_IOC_GET_TOTAL_TIME, 0); os_mutex_post(&g_tone_mutex); return ret; } os_mutex_post(&g_tone_mutex); return -1; } static int tone_player_start(struct tone_player *player) { int err = -EINVAL; u16 uuid = jlstream_event_notify(STREAM_EVENT_GET_PIPELINE_UUID, (int)"tone"); player->stream = jlstream_pipeline_parse(uuid, NODE_UUID_TONE); if (!player->stream) { goto __exit0; } int player_id = player->player_id; jlstream_set_callback(player->stream, (void *)player_id, tone_player_callback); jlstream_set_scene(player->stream, player->scene); jlstream_set_coexist(player->stream, player->coexist); jlstream_node_ioctl(player->stream, NODE_UUID_DECODER, NODE_IOC_SET_FILE_LEN, (int)tone_file_flen(player)); if (player->callback) { err = player->callback(player->priv, STREAM_EVENT_INIT); if (err) { goto __exit1; } } jlstream_set_dec_file(player->stream, player, &tone_file_ops); err = jlstream_start(player->stream); if (err) { goto __exit1; } return 0; __exit1: jlstream_release(player->stream); __exit0: list_del(&player->entry); tone_player_free(player); return err; } int tone_player_init(struct tone_player *player, const char *file_name) { void *file = NULL; int fname_uuid = 0; player->ref = 1; if (file_name) { char file_path[64]; strcpy(file_path, FLASH_RES_PATH); strcpy(file_path + strlen(FLASH_RES_PATH), file_name); file = resfile_open(file_path); if (!file) { printf("tone_player_faild: %s\n", file_name); return -EINVAL; } fname_uuid = JBHash((u8 *)file_name, strlen(file_name)); printf("tone_player: %s\n", file_name); } player->file = file; player->scene = STREAM_SCENE_TONE; player->player_id = g_player_id++; player->fname_uuid = fname_uuid; player->coexist = STREAM_COEXIST_AUTO; INIT_LIST_HEAD(&player->entry); return 0; } static struct tone_player *tone_player_create(const char *file_name) { struct tone_player *player; player = zalloc(sizeof(*player)); if (!player) { return NULL; } int err = tone_player_init(player, file_name); if (err) { tone_player_free(player); return NULL; } return player; } int tone_player_add(struct tone_player *player) { os_mutex_pend(&g_tone_mutex, 0); if (list_empty(&g_head)) { int err = tone_player_start(player); if (err) { os_mutex_post(&g_tone_mutex); return err; } } list_add_tail(&player->entry, &g_head); os_mutex_post(&g_tone_mutex); return 0; } int play_tone_file(const char *file_name) { struct tone_player *player; player = tone_player_create(file_name); if (!player) { return -ENOMEM; } return tone_player_add(player); } int play_tone_file_callback(const char *file_name, void *priv, tone_player_cb_t callback) { struct tone_player *player; player = tone_player_create(file_name); if (!player) { if (callback) { callback(priv, STREAM_EVENT_STOP); } return -ENOMEM; } player->priv = priv; player->callback = callback; return tone_player_add(player); } static struct tone_player *tone_files_create(const char *const file_name[], u8 file_num) { struct tone_player *player; if (file_num > MAX_FILE_NUM) { return NULL; } player = tone_player_create(file_name[0]); if (!player) { return NULL; } for (int i = 0; i < file_num; i++) { player->file_name_list[i] = file_name[i]; } return player; } int play_tone_files(const char *const file_name[], u8 file_num) { struct tone_player *player; player = tone_files_create(file_name, file_num); if (!player) { return -EFAULT; } return tone_player_add(player); } int play_tone_files_alone(const char *const file_name[], u8 file_num) { struct tone_player *player; player = tone_files_create(file_name, file_num); if (!player) { return -EFAULT; } player->coexist = STREAM_COEXIST_DISABLE; return tone_player_add(player); } int play_tone_files_callback(const char *const file_name[], u8 file_num, void *priv, tone_player_cb_t callback) { struct tone_player *player; player = tone_files_create(file_name, file_num); if (!player) { if (callback) { callback(priv, STREAM_EVENT_STOP); } return -EFAULT; } player->priv = priv; player->callback = callback; return tone_player_add(player); } int play_tone_files_alone_callback(const char *const file_name[], u8 file_num, void *priv, tone_player_cb_t callback) { struct tone_player *player; player = tone_files_create(file_name, file_num); if (!player) { if (callback) { callback(priv, STREAM_EVENT_STOP); } return -EFAULT; } player->priv = priv; player->callback = callback; player->coexist = STREAM_COEXIST_DISABLE; return tone_player_add(player); } int play_tone_file_alone(const char *file_name) { struct tone_player *player; player = tone_player_create(file_name); if (!player) { return -ENOMEM; } player->coexist = STREAM_COEXIST_DISABLE; return tone_player_add(player); } int play_tone_file_alone_callback(const char *file_name, void *priv, tone_player_cb_t callback) { struct tone_player *player; player = tone_player_create(file_name); if (!player) { callback(priv, STREAM_EVENT_STOP); return -ENOMEM; } player->coexist = STREAM_COEXIST_DISABLE; player->priv = priv; player->callback = callback; return tone_player_add(player); } int tone_player_runing() { local_irq_disable(); int ret = list_empty(&g_head) ? 0 : 1; local_irq_enable(); return ret; } void tone_player_stop() { struct tone_player *player, *n; os_mutex_pend(&g_tone_mutex, 0); list_for_each_entry_safe(player, n, &g_head, entry) { __list_del_entry(&player->entry); if (player->stream) { jlstream_stop(player->stream, 50); jlstream_release(player->stream); } tone_player_free(player); } os_mutex_post(&g_tone_mutex); } u16 tone_player_get_fname_uuid(const char *fname) { return JBHash((u8 *)fname, strlen(fname)); } static int __tone_player_init() { os_mutex_create(&g_tone_mutex); return 0; } __initcall(__tone_player_init);