427 lines
12 KiB
C
427 lines
12 KiB
C
#ifdef SUPPORT_MS_EXTENSIONS
|
|
#pragma bss_seg(".tws_tone_player.data.bss")
|
|
#pragma data_seg(".tws_tone_player.data")
|
|
#pragma const_seg(".tws_tone_player.text.const")
|
|
#pragma code_seg(".tws_tone_player.text")
|
|
#endif
|
|
#include "tws_tone_player.h"
|
|
#include "os/os_api.h"
|
|
#include "system/init.h"
|
|
#include "system/timer.h"
|
|
#include "fs/resfile.h"
|
|
#include "sync/audio_syncts.h"
|
|
#include "media/bt_audio_timestamp.h"
|
|
#include "reference_time.h"
|
|
#include "classic/tws_api.h"
|
|
#include "app_config.h"
|
|
|
|
#if TCFG_USER_TWS_ENABLE
|
|
|
|
#define MAX_FNAME_LEN 32
|
|
|
|
struct tws_tone_message {
|
|
enum stream_scene scene;
|
|
enum stream_coexist coexist;
|
|
u8 file_num;
|
|
u8 network;
|
|
u8 reference_clk;
|
|
u8 net_addr[6];
|
|
u32 timestamp;
|
|
u32 tws_timestamp;
|
|
u32 func_uuid;
|
|
char name[MAX_FILE_NUM][MAX_FNAME_LEN];
|
|
};
|
|
|
|
struct tws_tone_file {
|
|
enum stream_scene scene;
|
|
enum stream_coexist coexist;
|
|
u16 delay_time;
|
|
u32 func_uuid;
|
|
char name[MAX_FNAME_LEN];
|
|
};
|
|
|
|
|
|
struct tws_tone_player {
|
|
struct tone_player player;
|
|
u8 reference;
|
|
u8 network;
|
|
u8 net_addr[6];
|
|
u32 timestamp;
|
|
u32 tws_timestamp;
|
|
u32 func_uuid;
|
|
char file_list[MAX_FILE_NUM][MAX_FNAME_LEN];
|
|
};
|
|
|
|
static u8 g_tws_tone_adding = 0;
|
|
|
|
static void tws_tone_reference_clock_close(u8 id);
|
|
static void tws_play_tone_try_timeout(void *arg);
|
|
extern int ring_player_start(struct tone_player *player);
|
|
|
|
static int tws_player_callback(int fname_uuid, u32 func_uuid, enum stream_event event)
|
|
{
|
|
const struct tws_tone_callback *p;
|
|
|
|
for (p = tws_tone_cb_begin; p < tws_tone_cb_end; p++) {
|
|
if (p->func_uuid == func_uuid) {
|
|
if (p->callback) {
|
|
p->callback(fname_uuid, event);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int tws_files_callback(void *priv, enum stream_event event)
|
|
{
|
|
return tws_player_callback(0, (u32)priv, event);
|
|
}
|
|
|
|
static void play_timestamp_init(struct tws_tone_player *player)
|
|
{
|
|
if (!player->timestamp) {
|
|
return;
|
|
}
|
|
|
|
if (!player->reference) {
|
|
player->reference = audio_reference_clock_select(player->net_addr,
|
|
player->network);
|
|
if (!player->reference) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (!audio_reference_network_exist(player->reference) && player->network == 0) {
|
|
audio_reference_clock_exit(player->reference);
|
|
player->network = 1;
|
|
player->reference = audio_reference_clock_select(NULL, player->network);
|
|
player->timestamp = player->tws_timestamp;
|
|
}
|
|
|
|
u8 current_network = audio_reference_clock_network(NULL);
|
|
if (current_network != (u8) - 1 && player->network != current_network) {
|
|
audio_reference_clock_exit(player->reference);
|
|
player->timestamp = audio_reference_clock_remapping(player->network,
|
|
current_network, player->timestamp);
|
|
current_network = audio_reference_clock_network(player->net_addr);
|
|
player->reference = audio_reference_clock_select(current_network == 0 ?
|
|
player->net_addr : NULL, current_network);
|
|
}
|
|
|
|
if (player->timestamp && player->timestamp != (u32) - 1) {
|
|
jlstream_node_ioctl(player->player.stream, NODE_UUID_DECODER,
|
|
NODE_IOC_SET_TIME_STAMP, player->timestamp);
|
|
}
|
|
}
|
|
|
|
static int tws_tone_player_callback(void *_player, enum stream_event event)
|
|
{
|
|
int err = 0;
|
|
struct tws_tone_player *player = (struct tws_tone_player *)_player;
|
|
|
|
switch (event) {
|
|
case STREAM_EVENT_INIT:
|
|
play_timestamp_init(player);
|
|
break;
|
|
case STREAM_EVENT_START:
|
|
if (player->func_uuid) {
|
|
tws_player_callback(player->player.fname_uuid, player->func_uuid, event);
|
|
}
|
|
break;
|
|
case STREAM_EVENT_STOP:
|
|
if (player->reference) {
|
|
tws_tone_reference_clock_close(player->reference);
|
|
}
|
|
int func_uuid = player->func_uuid;
|
|
int fname_uuid = player->player.fname_uuid;
|
|
free(player);
|
|
if (func_uuid) {
|
|
tws_player_callback(fname_uuid, func_uuid, event);
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
static void tws_tone_player_add_timeout(void *arg)
|
|
{
|
|
struct tws_tone_player *player = (struct tws_tone_player *)arg;
|
|
|
|
int offset = 30 * 1000 / 625;
|
|
player->timestamp += offset;
|
|
player->tws_timestamp += offset;
|
|
|
|
if (!tone_player_runing()) {
|
|
tone_player_add(&player->player);
|
|
g_tws_tone_adding = 0;
|
|
} else {
|
|
sys_timeout_add((void *)player, tws_tone_player_add_timeout, 30);
|
|
}
|
|
}
|
|
|
|
static void tws_tone_play_in_task(struct tws_tone_message *msg)
|
|
{
|
|
struct tws_tone_player *player;
|
|
const char *file_name = msg->name[0];
|
|
|
|
printf("tws_tone_play: %x, %s\n", msg->timestamp, file_name);
|
|
|
|
player = zalloc(sizeof(*player));
|
|
if (!player) {
|
|
goto __exit0;
|
|
}
|
|
|
|
for (int i = 0; i < msg->file_num; i++) {
|
|
strcpy(player->file_list[i], msg->name[i]);
|
|
player->player.file_name_list[i] = player->file_list[i];
|
|
}
|
|
|
|
int err = tone_player_init(&player->player, player->file_list[0]);
|
|
if (err) {
|
|
free(player);
|
|
goto __exit0;
|
|
}
|
|
|
|
player->player.ref = 2;
|
|
player->player.priv = player;
|
|
player->player.callback = tws_tone_player_callback;
|
|
player->player.scene = msg->scene;
|
|
player->player.coexist = msg->coexist;
|
|
|
|
player->func_uuid = msg->func_uuid;
|
|
player->timestamp = msg->timestamp;
|
|
player->tws_timestamp = msg->tws_timestamp;
|
|
player->network = msg->network;
|
|
player->reference = msg->reference_clk;
|
|
memcpy(player->net_addr, msg->net_addr, 6);
|
|
|
|
if (msg->scene == STREAM_SCENE_RING) {
|
|
ring_player_start(&player->player);
|
|
} else {
|
|
if (!tone_player_runing()) {
|
|
tone_player_add(&player->player);
|
|
g_tws_tone_adding = 0;
|
|
} else {
|
|
sys_timeout_add((void *)player, tws_tone_player_add_timeout, 30);
|
|
}
|
|
}
|
|
goto __exit1;
|
|
|
|
__exit0:
|
|
g_tws_tone_adding = 0;
|
|
tws_tone_reference_clock_close(msg->reference_clk);
|
|
__exit1:
|
|
free(msg);
|
|
}
|
|
|
|
static void tws_tone_file_data_in_irq(void *data, u16 len, bool rx)
|
|
{
|
|
int msg[4];
|
|
|
|
u8 *buf = malloc(len);
|
|
if (!buf) {
|
|
goto __err;
|
|
}
|
|
memcpy(buf, data, len);
|
|
|
|
msg[0] = (int)tws_tone_play_in_task;
|
|
msg[1] = 1;
|
|
msg[2] = (int)buf;
|
|
|
|
if (rx) {
|
|
((struct tws_tone_message *)buf)->reference_clk = 0;
|
|
}
|
|
|
|
int err = os_taskq_post_type("app_core", Q_CALLBACK, 3, msg);
|
|
if (err == OS_ERR_NONE) {
|
|
return;
|
|
}
|
|
if (buf) {
|
|
free(buf);
|
|
buf = NULL;
|
|
}
|
|
if (rx) {
|
|
return;
|
|
}
|
|
|
|
__err:
|
|
g_tws_tone_adding = 0;
|
|
struct tws_tone_message *tmsg = (struct tws_tone_message *)data;
|
|
tws_tone_reference_clock_close(tmsg->reference_clk);
|
|
}
|
|
|
|
REGISTER_TWS_FUNC_STUB(tws_tone_player_stub) = {
|
|
.func_id = 0xE70A68F2,
|
|
.func = tws_tone_file_data_in_irq,
|
|
};
|
|
|
|
static void tws_tone_reference_clock_setup(struct tws_tone_message *msg)
|
|
{
|
|
msg->reference_clk = audio_reference_clock_select(NULL, 1);
|
|
msg->network = audio_reference_clock_network(msg->net_addr);
|
|
}
|
|
|
|
static void tws_tone_reference_clock_close(u8 id)
|
|
{
|
|
audio_reference_clock_exit(id);
|
|
}
|
|
|
|
static int __tws_play_tone_file(const char *const file_list[], u8 file_num,
|
|
int delay_msec, enum stream_scene scene,
|
|
enum stream_coexist coexist,
|
|
u32 func_uuid)
|
|
{
|
|
struct tws_tone_message msg;
|
|
|
|
if (tws_api_is_sniff_state()) {
|
|
tws_api_tx_unsniff_req();
|
|
delay_msec += 1000;
|
|
}
|
|
|
|
if (scene == STREAM_SCENE_TONE &&
|
|
(tone_player_runing() || g_tws_tone_adding)) {
|
|
struct tws_tone_file *file = zalloc(sizeof(*file));
|
|
if (file) {
|
|
strcpy(file->name, file_list[0]);
|
|
file->delay_time = delay_msec;
|
|
file->scene = scene;
|
|
file->coexist = coexist;
|
|
file->func_uuid = func_uuid;
|
|
sys_timeout_add((void *)file, tws_play_tone_try_timeout, 200);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int slot = (delay_msec + 1) * 1000 / 625;
|
|
|
|
tws_tone_reference_clock_setup(&msg);
|
|
msg.timestamp = audio_reference_clock_time() + slot;
|
|
msg.tws_timestamp = audio_reference_network_clock_time(1) + slot;
|
|
msg.scene = scene;
|
|
msg.coexist = coexist;
|
|
msg.func_uuid = func_uuid;
|
|
msg.file_num = file_num;
|
|
|
|
for (int i = 0; i < file_num; i++) {
|
|
strcpy(msg.name[i], file_list[i]);
|
|
}
|
|
int data_len = offsetof(struct tws_tone_message, name) + file_num * MAX_FNAME_LEN;
|
|
|
|
printf("tws_play_tone_file: %x, %s, %d\n", msg.network, file_list[0], data_len);
|
|
|
|
int err = tws_api_send_data_to_sibling(&msg, data_len, 0xE70A68F2);
|
|
|
|
if (scene == STREAM_SCENE_TONE) {
|
|
g_tws_tone_adding = err == 0 ? 1 : 0;
|
|
}
|
|
|
|
if (err) {
|
|
tws_tone_reference_clock_close(msg.reference_clk);
|
|
|
|
if (scene == STREAM_SCENE_RING) {
|
|
err = play_ring_file(file_list[0]);
|
|
} else {
|
|
if (coexist == STREAM_COEXIST_AUTO) {
|
|
err = play_tone_files_callback(file_list, file_num, (void *)func_uuid,
|
|
tws_files_callback);
|
|
} else {
|
|
if (file_num == 1) {
|
|
err = play_tone_file_alone_callback(file_list[0], (void *)func_uuid,
|
|
tws_files_callback);
|
|
} else {
|
|
err = play_tone_files_callback(file_list, file_num, (void *)func_uuid,
|
|
tws_files_callback);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
static void tws_play_tone_try_timeout(void *arg)
|
|
{
|
|
struct tws_tone_file *file = (struct tws_tone_file *)arg;
|
|
if (file) {
|
|
const char *fname = file->name;
|
|
__tws_play_tone_file(&fname, 1, file->delay_time,
|
|
file->scene, file->coexist, file->func_uuid);
|
|
free(file);
|
|
}
|
|
}
|
|
|
|
int tws_play_tone_file(const char *file_name, int delay_msec)
|
|
{
|
|
return __tws_play_tone_file(&file_name, 1, delay_msec, STREAM_SCENE_TONE,
|
|
STREAM_COEXIST_AUTO, 0);
|
|
}
|
|
|
|
int tws_play_tone_file_callback(const char *file_name, int delay_msec, u32 func_uuid)
|
|
{
|
|
return __tws_play_tone_file(&file_name, 1, delay_msec, STREAM_SCENE_TONE,
|
|
STREAM_COEXIST_AUTO, func_uuid);
|
|
}
|
|
|
|
int tws_play_ring_file(const char *file_name, int delay_msec)
|
|
{
|
|
return __tws_play_tone_file(&file_name, 1, delay_msec, STREAM_SCENE_RING,
|
|
STREAM_COEXIST_AUTO, 0);
|
|
}
|
|
|
|
int tws_play_ring_file_alone(const char *file_name, int delay_msec)
|
|
{
|
|
return __tws_play_tone_file(&file_name, 1, delay_msec, STREAM_SCENE_RING,
|
|
STREAM_COEXIST_DISABLE, 0);
|
|
}
|
|
|
|
int tws_play_ring_file_callback(const char *file_name, int delay_msec, u32 func_uuid)
|
|
{
|
|
return __tws_play_tone_file(&file_name, 1, delay_msec, STREAM_SCENE_RING,
|
|
STREAM_COEXIST_AUTO, func_uuid);
|
|
}
|
|
|
|
int tws_play_ring_file_alone_callback(const char *file_name, int delay_msec, u32 func_uuid)
|
|
{
|
|
return __tws_play_tone_file(&file_name, 1, delay_msec, STREAM_SCENE_RING,
|
|
STREAM_COEXIST_DISABLE, func_uuid);
|
|
}
|
|
|
|
int tws_play_tone_files_callback(const char *const file_name[], u8 file_num,
|
|
int delay_msec, u32 func_uuid)
|
|
{
|
|
return __tws_play_tone_file(file_name, file_num, delay_msec, STREAM_SCENE_TONE,
|
|
STREAM_COEXIST_AUTO, func_uuid);
|
|
}
|
|
|
|
int tws_play_tone_files_alone_callback(const char *const file_name[], u8 file_num,
|
|
int delay_msec, u32 func_uuid)
|
|
{
|
|
return __tws_play_tone_file(file_name, file_num, delay_msec, STREAM_SCENE_TONE,
|
|
STREAM_COEXIST_DISABLE, func_uuid);
|
|
}
|
|
|
|
int tws_play_tone_file_alone(const char *file_name, int delay_msec)
|
|
{
|
|
return __tws_play_tone_file(&file_name, 1, delay_msec, STREAM_SCENE_TONE,
|
|
STREAM_COEXIST_DISABLE, 0);
|
|
}
|
|
|
|
int tws_play_tone_file_alone_callback(const char *file_name, int delay_msec, u32 func_uuid)
|
|
{
|
|
return __tws_play_tone_file(&file_name, 1, delay_msec, STREAM_SCENE_TONE,
|
|
STREAM_COEXIST_DISABLE, func_uuid);
|
|
}
|
|
|
|
|
|
static int tws_tone_player_init()
|
|
{
|
|
return 0;
|
|
}
|
|
__initcall(tws_tone_player_init);
|
|
|
|
#endif
|