增加景点长播放语音功能
This commit is contained in:
parent
bf8816ac83
commit
953f3187df
|
|
@ -28,18 +28,31 @@
|
|||
#define PLAY_DISTANCE_THRESHOLD 50.0 // 有效播报距离(米)
|
||||
#define DISTANCE_CHANGE_THRESHOLD 10.0 // 距离变化阈值(米)
|
||||
#define TTS_PRIORITY 5 // TTS播报优先级
|
||||
#define MAX_TTS_SEGMENT_LEN 50 // TTS每段最大长度(字符)
|
||||
|
||||
|
||||
static nmeaPARSER parser;
|
||||
|
||||
//该版本仅实现基本的靠近播报功能,长文字播放功能待开发
|
||||
|
||||
|
||||
// 全局景点链表
|
||||
// 文本分段结构 [新增]
|
||||
typedef struct {
|
||||
char** segments; // 分段文本数组
|
||||
int count; // 分段数量
|
||||
} SegmentedText;
|
||||
|
||||
|
||||
// 修改景点节点结构 [修改]
|
||||
typedef struct AttractionNode {
|
||||
Attraction attraction;
|
||||
double longitude;
|
||||
double latitude;
|
||||
char name[50];
|
||||
SegmentedText description; // 从char[]改为SegmentedText结构 [关键修改]
|
||||
struct AttractionNode* next;
|
||||
} AttractionNode;
|
||||
|
||||
|
||||
// 播报状态
|
||||
typedef struct {
|
||||
AttractionNode* last_broadcast;
|
||||
|
|
@ -76,6 +89,48 @@ static int tts_volume = 10;
|
|||
static osThreadId_t Attr_Broadcast_ThreadId = NULL; //串口数据接收、解析任务Handle
|
||||
|
||||
|
||||
// 智能分段函数
|
||||
SegmentedText smart_segment_text(const char* text, int max_segment_len) {
|
||||
SegmentedText result = {0};
|
||||
if (!text || *text == '\0') return result;
|
||||
|
||||
int text_len = strlen(text);
|
||||
int max_segments = (text_len / max_segment_len) + 2;
|
||||
result.segments = cm_malloc(max_segments * sizeof(char*));
|
||||
|
||||
int start = 0;
|
||||
int segment_count = 0;
|
||||
|
||||
while (start < text_len && segment_count < max_segments) {
|
||||
int end = start + max_segment_len;
|
||||
if (end > text_len) end = text_len;
|
||||
|
||||
if (end < text_len) {
|
||||
// 寻找最佳分割点(标点符号优先)
|
||||
int best_break = end;
|
||||
for (int i = end; i > start; i--) {
|
||||
if (strchr("。!?,;.!?", text[i])) {
|
||||
best_break = i + 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
end = best_break;
|
||||
}
|
||||
|
||||
// 创建分段
|
||||
int seg_len = end - start;
|
||||
result.segments[segment_count] = cm_malloc(seg_len + 1);
|
||||
strncpy(result.segments[segment_count], text + start, seg_len);
|
||||
result.segments[segment_count][seg_len] = '\0';
|
||||
segment_count++;
|
||||
|
||||
start = end;
|
||||
}
|
||||
|
||||
result.count = segment_count;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//多文字tts,景区播报专用
|
||||
|
|
@ -92,6 +147,18 @@ void safe_tts_play(const char* segments[], int count) {
|
|||
}
|
||||
|
||||
|
||||
// 释放分段内存 [新增]
|
||||
void free_segmented_text(SegmentedText* st) {
|
||||
if (st && st->segments) {
|
||||
for (int i = 0; i < st->count; i++) {
|
||||
cm_free(st->segments[i]);
|
||||
}
|
||||
cm_free(st->segments);
|
||||
st->segments = NULL;
|
||||
st->count = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//计算到景点的距离
|
||||
double location_service_calculate_distance(Location loc1, Location loc2) {
|
||||
|
|
@ -141,11 +208,13 @@ void attr_broadcast_add_attraction(double lon, double lat,
|
|||
}
|
||||
|
||||
// 填充景点信息
|
||||
new_node->attraction.longitude = lon;
|
||||
new_node->attraction.latitude = lat;
|
||||
strncpy(new_node->attraction.name, name, sizeof(new_node->attraction.name)-1);
|
||||
strncpy(new_node->attraction.description, desc, sizeof(new_node->attraction.description)-1);
|
||||
|
||||
new_node->longitude = lon;
|
||||
new_node->latitude = lat;
|
||||
strncpy(new_node->name, name, sizeof(new_node->name)-1);
|
||||
new_node->name[sizeof(new_node->name)-1] = '\0';
|
||||
|
||||
new_node->description = smart_segment_text(desc, MAX_TTS_SEGMENT_LEN);
|
||||
|
||||
// 添加到链表头部
|
||||
new_node->next = attractions_head;
|
||||
attractions_head = new_node;
|
||||
|
|
@ -154,6 +223,26 @@ void attr_broadcast_add_attraction(double lon, double lat,
|
|||
}
|
||||
|
||||
|
||||
// 释放所有景点内存 最新添加
|
||||
void attr_broadcast_free_all() {
|
||||
if (attractions_mutex == NULL) return;
|
||||
|
||||
osMutexAcquire(attractions_mutex, osWaitForever);
|
||||
|
||||
AttractionNode* current = attractions_head;
|
||||
while (current) {
|
||||
AttractionNode* next = current->next;
|
||||
free_segmented_text(¤t->description);
|
||||
cm_free(current);
|
||||
current = next;
|
||||
}
|
||||
|
||||
attractions_head = NULL;
|
||||
osMutexRelease(attractions_mutex);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// 设置播报距离阈值 (米)
|
||||
void attr_broadcast_set_distance_threshold(double threshold) {
|
||||
if (threshold > 0) {
|
||||
|
|
@ -171,13 +260,13 @@ static AttractionNode* find_nearest_attraction(Location current_pos) {
|
|||
AttractionNode* current = attractions_head;
|
||||
AttractionNode* nearest = attractions_head;
|
||||
double min_distance = location_service_calculate_distance(
|
||||
(Location){current->attraction.longitude, current->attraction.latitude},
|
||||
(Location){current->longitude, current->latitude},
|
||||
current_pos
|
||||
);
|
||||
|
||||
while (current != NULL) {
|
||||
double distance = location_service_calculate_distance(
|
||||
(Location){current->attraction.longitude, current->attraction.latitude},
|
||||
(Location){current->longitude, current->latitude},
|
||||
current_pos
|
||||
);
|
||||
|
||||
|
|
@ -197,25 +286,34 @@ static AttractionNode* find_nearest_attraction(Location current_pos) {
|
|||
static void play_attraction_info(AttractionNode* attraction, double distance) {
|
||||
if (!attraction) return;
|
||||
|
||||
// 构建播报文本
|
||||
char buffer[300];
|
||||
snprintf(buffer, sizeof(buffer), "您已到达%s,%s。距离%.1f米。",
|
||||
attraction->attraction.name,
|
||||
attraction->attraction.description,
|
||||
distance);
|
||||
|
||||
|
||||
broadcast_state.is_playing = 1;
|
||||
// 调用TTS接口播放文本
|
||||
local_tts_text_play(buffer, 0, 1);
|
||||
// 构建距离提示
|
||||
char distance_msg[100];
|
||||
snprintf(distance_msg, sizeof(distance_msg), "您已到达%s,距离%.1f米。",
|
||||
attraction->name, distance);
|
||||
|
||||
//等待
|
||||
while(local_tts_get_play_state() != 0) {
|
||||
osDelay(100);
|
||||
// 创建播放数组(距离提示 + 所有描述分段)
|
||||
int total_segments = attraction->description.count + 1;
|
||||
const char** segments = cm_malloc(total_segments * sizeof(char*));
|
||||
if (!segments) return;
|
||||
|
||||
segments[0] = distance_msg;
|
||||
for (int i = 0; i < attraction->description.count; i++) {
|
||||
segments[i+1] = attraction->description.segments[i];
|
||||
}
|
||||
|
||||
broadcast_state.is_playing = 1;
|
||||
DEBUG("Playing attraction info: %s (%d segments)\n",
|
||||
attraction->name, total_segments);
|
||||
|
||||
// 播放所有分段
|
||||
safe_tts_play(segments, total_segments);
|
||||
|
||||
cm_free(segments);
|
||||
|
||||
// 更新播报状态
|
||||
broadcast_state.last_broadcast = attraction;
|
||||
broadcast_state.last_distance = distance;
|
||||
broadcast_state.is_playing = 0;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -247,7 +345,7 @@ static void attr_broadcast_task(void* arg) {
|
|||
if (nearest != NULL) {
|
||||
// 计算距离
|
||||
double distance = location_service_calculate_distance(
|
||||
(Location){nearest->attraction.longitude, nearest->attraction.latitude},
|
||||
(Location){nearest->longitude, nearest->latitude},
|
||||
current_pos
|
||||
);
|
||||
|
||||
|
|
@ -314,7 +412,7 @@ void attr_broadcast_init(void) {
|
|||
|
||||
osThreadAttr_t attr_broadcast_task_attr = {0};
|
||||
attr_broadcast_task_attr.name = "attr_broadcast_task";
|
||||
attr_broadcast_task_attr.stack_size = 4096 * 5;
|
||||
attr_broadcast_task_attr.stack_size = 4096 * 8;
|
||||
attr_broadcast_task_attr.priority= osPriorityNormal;
|
||||
|
||||
Attr_Broadcast_ThreadId= osThreadNew(attr_broadcast_task, 0, &attr_broadcast_task_attr);
|
||||
|
|
|
|||
Loading…
Reference in New Issue