diff --git a/ShengShengBuXi.ConsoleApp/Services/SignalRService.cs b/ShengShengBuXi.ConsoleApp/Services/SignalRService.cs
index eb61d07..eab35e2 100644
--- a/ShengShengBuXi.ConsoleApp/Services/SignalRService.cs
+++ b/ShengShengBuXi.ConsoleApp/Services/SignalRService.cs
@@ -17,8 +17,8 @@ public class SignalRService : ISignalRService
private readonly SemaphoreSlim _semaphore = new(1, 1);
private string? _clientId;
private bool _isInitialConnection = true;
- private const int MAX_RETRY_COUNT = 10;
- private const int RETRY_INTERVAL_MS = 1000;
+ private const int MAX_RETRY_COUNT = 15;
+ private const int RETRY_INTERVAL_MS = 200;
private const int HEARTBEAT_INTERVAL_MS = 3000; // 3秒发送一次心跳
private Timer? _heartbeatTimer;
private DateTime _lastHeartbeatTime = DateTime.MinValue;
@@ -78,7 +78,7 @@ public class SignalRService : ISignalRService
_hubConnection = new HubConnectionBuilder()
.WithUrl(hubUrl)
- .WithAutomaticReconnect([TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(2), TimeSpan.FromSeconds(3)])
+ .WithAutomaticReconnect()
.Build();
// 启动心跳定时器
diff --git a/ShengShengBuXi.ConsoleApp/appsettings.json b/ShengShengBuXi.ConsoleApp/appsettings.json
index 7700478..f1dd3dd 100644
--- a/ShengShengBuXi.ConsoleApp/appsettings.json
+++ b/ShengShengBuXi.ConsoleApp/appsettings.json
@@ -1,5 +1,5 @@
{
- "SignalRHubUrl": "http://115.159.44.16/audiohub",
+ "SignalRHubUrl": "http://localhost:81/audiohub",
"ConfigBackupPath": "config.json",
"AutoConnectToServer": true,
"AllowOfflineStart": false
diff --git a/ShengShengBuXi.ConsoleApp/mp3/风铃.wav b/ShengShengBuXi.ConsoleApp/mp3/风铃.wav
new file mode 100644
index 0000000..001c391
Binary files /dev/null and b/ShengShengBuXi.ConsoleApp/mp3/风铃.wav differ
diff --git a/ShengShengBuXi/Hubs/AudioHub.cs b/ShengShengBuXi/Hubs/AudioHub.cs
index 55ff096..70eea15 100644
--- a/ShengShengBuXi/Hubs/AudioHub.cs
+++ b/ShengShengBuXi/Hubs/AudioHub.cs
@@ -874,44 +874,101 @@ namespace ShengShengBuXi.Hubs
///
private void InitializeDisplayTextTimer()
{
+ // 注意:不再需要实际启动定时器,因为已改为客户端主动请求模式
+ // 但保留此方法以保持代码结构兼容性
if (!_isDisplayTimerInitialized)
{
lock (_displayTimerLock)
{
if (!_isDisplayTimerInitialized)
{
- _displayTextTimer = new Timer(SendNextDisplayText, null, 0, Timeout.Infinite);
+ // 不再需要实际启动定时器
+ // _displayTextTimer = new Timer(SendNextDisplayText, null, 0, Timeout.Infinite);
_isDisplayTimerInitialized = true;
- _logger.LogInformation("显示文本定时器已初始化");
+ _logger.LogInformation("显示文本系统已初始化(客户端主动获取模式)");
}
}
}
}
+ // 注意:以下方法不再使用,由客户端主动获取替代,保留代码仅作参考
///
- /// 发送下一条显示文本
+ /// 发送下一条显示文本(不再使用,由客户端主动获取替代)
///
/// 状态对象
private async void SendNextDisplayText(object state)
{
+ // 这个方法不再使用,由客户端主动获取替代
+ // 保留原有逻辑仅作参考
+
try
{
- // 获取随机等待时间(5-10秒)
-
+ // 获取随机等待时间(10-30秒)
int nextInterval = new Random().Next(10000, 30000);
- // 设置下一次触发时间
- _displayTextTimer.Change(nextInterval, Timeout.Infinite);
+ // 设置下一次触发时间,此处设置为较长时间,避免频繁触发未使用的方法
+ _displayTextTimer?.Change(nextInterval, Timeout.Infinite);
+
+ _logger.LogWarning("使用了已废弃的发送显示文本方法,应改为客户端主动获取模式");
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError($"发送显示文本失败: {ex.Message}");
+ }
+ }
+
+ ///
+ /// 开始接收显示文本(兼容旧客户端,新客户端应使用GetNextDisplayText)
+ ///
+ public async Task StartReceivingDisplayText()
+ {
+ // 兼容旧版客户端的方法
+ _logger.LogWarning($"客户端 {Context.ConnectionId} 使用了已废弃的StartReceivingDisplayText方法,应改为GetNextDisplayText");
+
+ // 转发到新方法
+ await GetNextDisplayText();
+ }
+
+ ///
+ /// 获取下一条要显示的文本(由客户端主动请求)
+ ///
+ /// 处理任务
+ public async Task GetNextDisplayText()
+ {
+ try
+ {
+ // 检查客户端是否已注册
+ if (!_clients.TryGetValue(Context.ConnectionId, out var clientInfo))
+ {
+ _logger.LogWarning($"未注册的客户端尝试获取显示文本: {Context.ConnectionId}");
+ await Clients.Caller.SendAsync("Error", "请先注册客户端");
+ return;
+ }
+
+ // 检查客户端是否为Display类型
+ if (clientInfo.ClientType != ClientType.Display)
+ {
+ _logger.LogWarning($"非显示端客户端尝试获取显示文本: {Context.ConnectionId}, 类型: {clientInfo.ClientType}");
+ await Clients.Caller.SendAsync("Error", "只有显示端客户端可以获取显示文本");
+ return;
+ }
+
+ _logger.LogInformation($"显示端请求获取下一条显示文本: {Context.ConnectionId}");
// 检查队列是否为空
if (_displayTextQueue.IsEmpty)
{
- // 检查是否需要添加预设文本(如果30秒内没有真实用户说话)
+ // 检查是否需要添加预设文本
if (DateTime.Now.Subtract(_lastRealUserSpeakTime).TotalSeconds > 30)
{
AddFakeTextToQueue();
}
- return;
+ else
+ {
+ _logger.LogInformation("显示文本队列为空,且不需要添加预设文本");
+ // 如果队列为空且不需要添加预设文本,返回空
+ return;
+ }
}
// 从队列中选择最高优先级的消息
@@ -921,29 +978,28 @@ namespace ShengShengBuXi.Hubs
// 检查是否获取到有效的消息
if (highestPriority.Key == Guid.Empty || highestPriority.Value == null)
- return;
-
- // 获取大屏显示客户端数量
- int displayClientsCount = _clients.Values.Count(c => c.ClientType == ClientType.Display);
-
- if (displayClientsCount > 0)
{
- // 从队列中移除该消息
- if (_displayTextQueue.TryRemove(highestPriority.Key, out _))
- {
- // 发送给所有Display客户端
- await _hubContext.Clients.Group("displays").SendAsync("ReceiveDisplayText", highestPriority.Value.Text);
- _logger.LogInformation($"已发送显示文本到大屏: {highestPriority.Value.Text} (来源: {(highestPriority.Value.IsRealUser ? "真实用户" : "预设文本")})");
- }
+ _logger.LogWarning("无法从队列中获取有效的显示文本");
+ return;
}
+ // 从队列中移除该消息
+ if (_displayTextQueue.TryRemove(highestPriority.Key, out var textToDisplay))
+ {
+ // 只发送给请求的客户端
+ await Clients.Caller.SendAsync("ReceiveDisplayText", textToDisplay.Text);
+ _logger.LogInformation($"已发送显示文本到客户端: {textToDisplay.Text} (来源: {(textToDisplay.IsRealUser ? "真实用户" : "预设文本")})");
+ }
+ else
+ {
+ _logger.LogWarning($"无法从队列中移除显示文本: {highestPriority.Key}");
+ }
}
catch (Exception ex)
{
- _logger.LogError($"发送显示文本失败: {ex.Message}");
+ _logger.LogError($"获取显示文本失败: {ex.Message}");
}
}
- private static int _presetSentencesIndex = -1;
///
/// 添加预设文本到队列
@@ -964,14 +1020,6 @@ namespace ShengShengBuXi.Hubs
_presetSentences.Add("时光匆匆流逝,思念却越来越深。");
}
}
- //if (_presetSentencesIndex == -1)
- //{
- // _presetSentencesIndex = new Random().Next(_presetSentences.Count);
- //}
- //if (_presetSentencesIndex >= _presetSentences.Count)
- //{
- // _presetSentencesIndex = new Random().Next(_presetSentences.Count); ;
- //}
_presetSentences.OrderBy(it => Guid.NewGuid()).ToList().ForEach(item =>
{
var displayText = new DisplayText
@@ -982,16 +1030,8 @@ namespace ShengShengBuXi.Hubs
IsRealUser = false,
RecognitionId = ""
};
- //AddRecognizedTextToDisplay(item, false);
_displayTextQueue.TryAdd(displayText.Id, displayText);
- //_logger.LogInformation($"添加预设文本到显示队列: {text}");
});
-
- // 从未最近显示过的句子中随机选择一条
- //string randomText = _presetSentences[_presetSentencesIndex];
-
- //_presetSentencesIndex += new Random().Next(3);
-
}
catch (Exception ex)
{
diff --git a/ShengShengBuXi/Pages/Index.cshtml b/ShengShengBuXi/Pages/Index.cshtml
index 847bc05..638ebae 100644
--- a/ShengShengBuXi/Pages/Index.cshtml
+++ b/ShengShengBuXi/Pages/Index.cshtml
@@ -218,6 +218,12 @@
} else {
isAnimating = false;
if (callback) callback();
+
+ // 打字效果完成后,等待随机4-7秒,然后请求下一条文本
+ const delay = Math.floor(Math.random() * 3000) + 4000; // 4000-7000毫秒
+ console.log(`文本显示完成,将在${delay/1000}秒后请求下一条文本`);
+
+ setTimeout(requestNextText, delay);
}
}
typeWriter();
@@ -377,11 +383,8 @@
console.error("解析显示配置失败:", error);
}
}
- // 开始接收显示文本
- return hubConnection.invoke("StartReceivingDisplayText");
- })
- .then(function() {
- console.log("开始接收显示文本");
+ // 开始请求第一条显示文本
+ requestNextText();
})
.catch(function(err) {
console.error("客户端操作失败:", err);
@@ -507,12 +510,9 @@
$('#magazine').turn('previous');
else if (e.keyCode == 39)
$('#magazine').turn('next');
- // 空格键不再触发说话,改为请求下一条文本
- else if (e.keyCode == 32 && hubConnection && hubConnection.state === signalR.HubConnectionState.Connected) {
- hubConnection.invoke("StartReceivingDisplayText")
- .catch(function(err) {
- console.error("请求下一条文本失败:", err);
- });
+ // 空格键请求下一条文本
+ else if (e.keyCode == 32) {
+ requestNextText();
}
});
@@ -625,6 +625,25 @@
}
}
});
+
+ /**
+ * 请求下一条文本
+ */
+ function requestNextText() {
+ if (hubConnection && hubConnection.state === signalR.HubConnectionState.Connected) {
+ console.log("正在向服务器请求下一条文本...");
+ hubConnection.invoke("GetNextDisplayText")
+ .catch(function(err) {
+ console.error("请求下一条文本失败:", err);
+ // 如果请求失败,稍后重试
+ setTimeout(requestNextText, 5000);
+ });
+ } else {
+ console.warn("SignalR连接未就绪,无法请求下一条文本");
+ // 如果连接未就绪,稍后重试
+ setTimeout(requestNextText, 3000);
+ }
+ }