123
This commit is contained in:
parent
97f852d5e5
commit
631019cf6a
|
|
@ -120,6 +120,11 @@ public class AudioFilesConfig
|
|||
/// 数字按键音频文件模板(0-9)
|
||||
/// </summary>
|
||||
public string DigitToneFileTemplate { get; set; } = "{0}.mp3";
|
||||
|
||||
/// <summary>
|
||||
/// 按键音的最小播放时间(毫秒),即使按键释放也会至少播放这么长时间
|
||||
/// </summary>
|
||||
public int MinKeyTonePlayTimeMs { get; set; } = 200;
|
||||
|
||||
/// <summary>
|
||||
/// 获取完整的音频文件路径
|
||||
|
|
@ -214,6 +219,21 @@ public class RecordingConfig
|
|||
/// 是否上传录音文件到服务器
|
||||
/// </summary>
|
||||
public bool UploadRecordingToServer { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// 是否在录音时播放背景音乐
|
||||
/// </summary>
|
||||
public bool EnableBackgroundMusic { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// 录音背景音乐文件名
|
||||
/// </summary>
|
||||
public string BackgroundMusicFile { get; set; } = "bj.mp3";
|
||||
|
||||
/// <summary>
|
||||
/// 背景音乐音量 (0.0-1.0)
|
||||
/// </summary>
|
||||
public float BackgroundMusicVolume { get; set; } = 0.1f;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
|||
|
|
@ -55,6 +55,12 @@ public class PhoneBoothService : IPhoneBoothService, IDisposable
|
|||
private Timer? _silenceTimer = null;
|
||||
private volatile bool _isHangUpKeyPressed = false;
|
||||
|
||||
// 背景音乐相关
|
||||
private WaveOutEvent? _backgroundMusicDevice = null;
|
||||
private AudioFileReader? _backgroundMusicReader = null;
|
||||
private CancellationTokenSource? _backgroundMusicCts = null;
|
||||
private volatile bool _isBackgroundMusicPlaying = false;
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
private struct KBDLLHOOKSTRUCT
|
||||
{
|
||||
|
|
@ -175,6 +181,12 @@ public class PhoneBoothService : IPhoneBoothService, IDisposable
|
|||
await Task.Delay(100); // 给一点时间让等待音停止
|
||||
}
|
||||
|
||||
// 停止背景音乐
|
||||
if (_isBackgroundMusicPlaying)
|
||||
{
|
||||
StopBackgroundMusic();
|
||||
}
|
||||
|
||||
// 停止录音
|
||||
if (_isRecording)
|
||||
{
|
||||
|
|
@ -241,6 +253,7 @@ public class PhoneBoothService : IPhoneBoothService, IDisposable
|
|||
// 释放取消令牌源
|
||||
_programCts.Dispose();
|
||||
_waitingToneCts?.Dispose();
|
||||
_backgroundMusicCts?.Dispose();
|
||||
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
|
@ -291,6 +304,26 @@ public class PhoneBoothService : IPhoneBoothService, IDisposable
|
|||
_waitingToneReader.Dispose();
|
||||
_waitingToneReader = null;
|
||||
}
|
||||
|
||||
// 释放背景音乐设备
|
||||
_backgroundMusicCts?.Cancel();
|
||||
_backgroundMusicCts?.Dispose();
|
||||
_backgroundMusicCts = null;
|
||||
|
||||
if (_backgroundMusicDevice != null)
|
||||
{
|
||||
_backgroundMusicDevice.Stop();
|
||||
_backgroundMusicDevice.Dispose();
|
||||
_backgroundMusicDevice = null;
|
||||
}
|
||||
|
||||
if (_backgroundMusicReader != null)
|
||||
{
|
||||
_backgroundMusicReader.Dispose();
|
||||
_backgroundMusicReader = null;
|
||||
}
|
||||
|
||||
_isBackgroundMusicPlaying = false;
|
||||
|
||||
foreach (var (device, reader) in _keyToneDevices.Values)
|
||||
{
|
||||
|
|
@ -542,13 +575,20 @@ public class PhoneBoothService : IPhoneBoothService, IDisposable
|
|||
{
|
||||
recordingCompletionSource.TrySetResult(true);
|
||||
});
|
||||
|
||||
// 启动背景音乐播放(不等待它完成)
|
||||
if (_config.Recording.EnableBackgroundMusic)
|
||||
{
|
||||
_ = StartPlayingBackgroundMusic(linkedCts.Token);
|
||||
}
|
||||
|
||||
// 等待录音完成
|
||||
await recordingCompletionSource.Task;
|
||||
}
|
||||
catch (Exception)
|
||||
catch (Exception ex)
|
||||
{
|
||||
// 捕获所有异常,确保不会中断主流程
|
||||
Console.WriteLine($"录音任务异常: {ex.Message}");
|
||||
}
|
||||
});
|
||||
|
||||
|
|
@ -564,6 +604,9 @@ public class PhoneBoothService : IPhoneBoothService, IDisposable
|
|||
|
||||
// 停止录音
|
||||
StopAudioRecording();
|
||||
|
||||
// 确保背景音乐停止
|
||||
StopBackgroundMusic();
|
||||
|
||||
Console.WriteLine("录音结束,重置状态...");
|
||||
|
||||
|
|
@ -825,6 +868,9 @@ public class PhoneBoothService : IPhoneBoothService, IDisposable
|
|||
{
|
||||
// 确保录音设备被释放
|
||||
StopAudioRecording();
|
||||
|
||||
// 确保背景音乐被停止
|
||||
StopBackgroundMusic();
|
||||
|
||||
// 清除录音状态
|
||||
_isRecording = false;
|
||||
|
|
@ -863,6 +909,16 @@ public class PhoneBoothService : IPhoneBoothService, IDisposable
|
|||
_pressedKeys.Clear();
|
||||
_currentPressedKeys.Clear();
|
||||
_keyToneDevices.Clear();
|
||||
|
||||
// 尝试停止背景音乐
|
||||
try
|
||||
{
|
||||
StopBackgroundMusic();
|
||||
}
|
||||
catch
|
||||
{
|
||||
// 忽略任何错误
|
||||
}
|
||||
|
||||
// 尝试重新开始播放等待音
|
||||
try
|
||||
|
|
@ -1084,12 +1140,12 @@ public class PhoneBoothService : IPhoneBoothService, IDisposable
|
|||
{
|
||||
try
|
||||
{
|
||||
if (_keyToneDevices.TryRemove(digit, out var deviceInfo))
|
||||
{
|
||||
deviceInfo.Device.Stop();
|
||||
deviceInfo.Device.Dispose();
|
||||
deviceInfo.Reader.Dispose();
|
||||
}
|
||||
// 当按键释放时,我们不做特殊处理
|
||||
// 按键音的播放和结束完全由PlayKeyTone中的逻辑控制
|
||||
// 这样确保了即使按键时间很短,声音也能够完整播放
|
||||
|
||||
// 我们只需要确认按键已经从当前按下状态列表中移除即可
|
||||
// 实际的音频资源释放由PlayKeyTone中的PlaybackStopped事件处理
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
|
@ -1104,18 +1160,68 @@ public class PhoneBoothService : IPhoneBoothService, IDisposable
|
|||
{
|
||||
try
|
||||
{
|
||||
// 如果该按键声音正在播放中,不再重新开始播放
|
||||
if (_keyToneDevices.ContainsKey(digit))
|
||||
{
|
||||
return; // 已经在播放中
|
||||
// 如果已经在播放中,可以选择重新开始播放,或者保持当前播放
|
||||
// 这里我们选择重新开始播放
|
||||
if (_keyToneDevices.TryRemove(digit, out var oldDeviceInfo))
|
||||
{
|
||||
// 安全地停止并释放旧设备
|
||||
try
|
||||
{
|
||||
oldDeviceInfo.Device.Stop();
|
||||
oldDeviceInfo.Device.Dispose();
|
||||
oldDeviceInfo.Reader.Dispose();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"停止旧按键音 {digit} 失败: {ex.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var device = new WaveOutEvent();
|
||||
var reader = new AudioFileReader(_config.AudioFiles.GetDigitToneFilePath(digit));
|
||||
device.Init(reader);
|
||||
|
||||
// 记录开始播放时间
|
||||
var startTime = DateTime.Now;
|
||||
int minPlayTime = _config.AudioFiles.MinKeyTonePlayTimeMs;
|
||||
|
||||
if (_keyToneDevices.TryAdd(digit, (device, reader)))
|
||||
{
|
||||
device.Play();
|
||||
|
||||
// 确保至少播放最小时长
|
||||
device.PlaybackStopped += async (s, e) =>
|
||||
{
|
||||
// 计算已经播放的时间
|
||||
var playedTime = (int)(DateTime.Now - startTime).TotalMilliseconds;
|
||||
|
||||
// 如果播放时间不足最小时间,延迟处理
|
||||
if (playedTime < minPlayTime)
|
||||
{
|
||||
try
|
||||
{
|
||||
// 如果播放已经停止但时间不够,先不删除设备
|
||||
// 等待剩余的时间后再处理
|
||||
var remainingTime = minPlayTime - playedTime;
|
||||
await Task.Delay(remainingTime);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"按键音 {digit} 最小播放时间延迟失败: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
// 播放完成后(包括可能的延迟),移除并释放资源
|
||||
if (_keyToneDevices.TryRemove(digit, out var deviceInfo) && deviceInfo.Device == device)
|
||||
{
|
||||
deviceInfo.Device.Dispose();
|
||||
deviceInfo.Reader.Dispose();
|
||||
}
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -1229,4 +1335,124 @@ public class PhoneBoothService : IPhoneBoothService, IDisposable
|
|||
reader?.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 开始播放背景音乐
|
||||
/// </summary>
|
||||
private async Task StartPlayingBackgroundMusic(CancellationToken token)
|
||||
{
|
||||
try
|
||||
{
|
||||
// 如果配置不启用背景音乐,则直接返回
|
||||
if (!_config.Recording.EnableBackgroundMusic)
|
||||
{
|
||||
Console.WriteLine("背景音乐功能已禁用");
|
||||
return;
|
||||
}
|
||||
|
||||
// 获取背景音乐文件路径
|
||||
string musicFilePath = _config.AudioFiles.GetFullPath(_config.Recording.BackgroundMusicFile);
|
||||
|
||||
// 检查文件是否存在
|
||||
if (!File.Exists(musicFilePath))
|
||||
{
|
||||
Console.WriteLine($"背景音乐文件不存在: {musicFilePath}");
|
||||
return;
|
||||
}
|
||||
|
||||
// 取消可能正在播放的背景音乐
|
||||
_backgroundMusicCts?.Cancel();
|
||||
_backgroundMusicCts?.Dispose();
|
||||
_backgroundMusicCts = CancellationTokenSource.CreateLinkedTokenSource(token);
|
||||
|
||||
// 初始化背景音乐设备
|
||||
_backgroundMusicDevice = new WaveOutEvent();
|
||||
_backgroundMusicReader = new AudioFileReader(musicFilePath);
|
||||
|
||||
// 设置音量(默认为10%)
|
||||
_backgroundMusicReader.Volume = _config.Recording.BackgroundMusicVolume;
|
||||
|
||||
_backgroundMusicDevice.Init(_backgroundMusicReader);
|
||||
|
||||
// 标记背景音乐开始播放
|
||||
_isBackgroundMusicPlaying = true;
|
||||
Console.WriteLine($"开始播放背景音乐,音量: {_backgroundMusicReader.Volume * 100}%");
|
||||
|
||||
// 循环播放背景音乐
|
||||
while (!_backgroundMusicCts.Token.IsCancellationRequested)
|
||||
{
|
||||
try
|
||||
{
|
||||
// 检查是否到达文件末尾,是则重置
|
||||
if (_backgroundMusicReader.Position >= _backgroundMusicReader.Length)
|
||||
{
|
||||
_backgroundMusicReader.Position = 0;
|
||||
}
|
||||
|
||||
// 如果没有在播放,则开始播放
|
||||
if (_backgroundMusicDevice.PlaybackState != PlaybackState.Playing)
|
||||
{
|
||||
_backgroundMusicDevice.Play();
|
||||
}
|
||||
|
||||
// 短暂等待,避免CPU占用过高
|
||||
await Task.Delay(100, _backgroundMusicCts.Token);
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
// 正常取消,退出循环
|
||||
break;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"背景音乐播放出错: {ex.Message}");
|
||||
// 短暂等待后继续尝试
|
||||
await Task.Delay(1000, _backgroundMusicCts.Token);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"启动背景音乐失败: {ex.Message}");
|
||||
}
|
||||
finally
|
||||
{
|
||||
// 停止并释放音乐设备
|
||||
StopBackgroundMusic();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 停止背景音乐
|
||||
/// </summary>
|
||||
private void StopBackgroundMusic()
|
||||
{
|
||||
try
|
||||
{
|
||||
// 取消播放任务
|
||||
_backgroundMusicCts?.Cancel();
|
||||
|
||||
// 停止并释放设备
|
||||
if (_backgroundMusicDevice != null)
|
||||
{
|
||||
_backgroundMusicDevice.Stop();
|
||||
_backgroundMusicDevice.Dispose();
|
||||
_backgroundMusicDevice = null;
|
||||
}
|
||||
|
||||
if (_backgroundMusicReader != null)
|
||||
{
|
||||
_backgroundMusicReader.Dispose();
|
||||
_backgroundMusicReader = null;
|
||||
}
|
||||
|
||||
// 标记背景音乐已停止
|
||||
_isBackgroundMusicPlaying = false;
|
||||
Console.WriteLine("背景音乐已停止");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"停止背景音乐失败: {ex.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -6,7 +6,8 @@
|
|||
"PhonePickupFile": "\u7535\u8BDD\u63A5\u8D77.mp3",
|
||||
"PromptUserRecordFile": "\u63D0\u793A\u7528\u6237\u5F55\u97F3.mp3",
|
||||
"BeepPromptFile": "\u6EF4\u63D0\u793A\u97F3.wav",
|
||||
"DigitToneFileTemplate": "{0}.mp3"
|
||||
"DigitToneFileTemplate": "{0}.mp3",
|
||||
"MinKeyTonePlayTimeMs": 200
|
||||
},
|
||||
"Dial": {
|
||||
"MinDigitsToDialOut": 8,
|
||||
|
|
@ -22,7 +23,10 @@
|
|||
"SilenceThreshold": 0.02,
|
||||
"SilenceTimeoutSeconds": 30,
|
||||
"AllowUserHangup": true,
|
||||
"UploadRecordingToServer": false
|
||||
"UploadRecordingToServer": false,
|
||||
"EnableBackgroundMusic": true,
|
||||
"BackgroundMusicFile": "bj.mp3",
|
||||
"BackgroundMusicVolume": 0.1
|
||||
},
|
||||
"CallFlow": {
|
||||
"WaitForPickupMinSeconds": 3,
|
||||
|
|
|
|||
BIN
ShengShengBuXi.ConsoleApp/mp3/bj.mp3
Normal file
BIN
ShengShengBuXi.ConsoleApp/mp3/bj.mp3
Normal file
Binary file not shown.
|
|
@ -386,7 +386,7 @@ namespace ShengShengBuXi.Services
|
|||
// 检查会话是否存在
|
||||
if (!_webSockets.TryGetValue(sessionId, out var webSocket))
|
||||
{
|
||||
_logger.LogWarning($"会话不存在: {sessionId}");
|
||||
_logger.LogWarning($"ProcessAudioAsync->会话不存在: {sessionId}");
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user