Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions PCL.Neo.Core/PCL.Neo.Core.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,13 @@
<PackageReference Include="System.Reactive.Linq" Version="6.0.1" />
</ItemGroup>


<ItemGroup>
<Folder Include="Utils\" />
</ItemGroup>

<ItemGroup>
<PackageReference Include="System.Runtime.InteropServices" Version="4.3.0" />
</ItemGroup>

</Project>
135 changes: 135 additions & 0 deletions PCL.Neo.Core/Service/Audio/AudioDemo.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
using System;
using System.IO;
using System.Threading.Tasks;

namespace PCL.Neo.Core.Service.Audio;

/// <summary>
/// 音频服务演示类,包含使用音频服务API的示例代码
/// </summary>
public static class AudioDemo
{
/// <summary>
/// 演示基本音频播放功能
/// </summary>
/// <param name="audioFilePath">音频文件路径</param>
/// <returns>演示任务</returns>
public static async Task BasicPlaybackDemo(string audioFilePath)
{
// 创建音频服务
IAudioService audioService = AudioServiceFactory.CreateForCurrentPlatform();

Console.WriteLine("开始播放音频...");
bool result = await audioService.PlayAsync(audioFilePath);

if (!result)
{
Console.WriteLine("播放失败,可能文件不存在或格式不支持");
return;
}

// 等待3秒后暂停
await Task.Delay(3000);
Console.WriteLine("暂停播放...");
await audioService.PauseAsync();

// 等待2秒后恢复播放
await Task.Delay(2000);
Console.WriteLine("恢复播放...");
await audioService.ResumeAsync();

// 等待3秒后设置音量
await Task.Delay(3000);
Console.WriteLine("设置音量为50%...");
await audioService.SetVolumeAsync(0.5f);

// 等待3秒后停止播放
await Task.Delay(3000);
Console.WriteLine("停止播放...");
await audioService.StopAsync();
}

/// <summary>
/// 演示使用扩展方法
/// </summary>
/// <param name="audioFilePath">音频文件路径</param>
/// <returns>演示任务</returns>
public static async Task ExtensionsDemo(string audioFilePath)
{
// 创建音频服务
IAudioService audioService = AudioServiceFactory.CreateForCurrentPlatform();

// 播放音效并等待完成
Console.WriteLine("播放音效并等待完成...");
bool result = await audioService.PlaySoundAndWaitAsync(audioFilePath, 10000); // 10秒超时

if (result)
{
Console.WriteLine("音效已完成播放");
}
else
{
Console.WriteLine("音效播放失败或超时");
}

// 音量渐变示例
Console.WriteLine("开始播放并渐入音量...");
await audioService.PlayAsync(audioFilePath);
await audioService.SetVolumeAsync(0.0f); // 开始时音量为0
await audioService.FadeVolumeAsync(1.0f, 3000); // 3秒内渐入

await Task.Delay(3000);

Console.WriteLine("渐出音量...");
await audioService.FadeVolumeAsync(0.0f, 3000); // 3秒内渐出

await Task.Delay(3000);
await audioService.StopAsync();
}

/// <summary>
/// 演示从流播放音频
/// </summary>
/// <param name="audioFilePath">用于演示的音频文件路径</param>
/// <returns>演示任务</returns>
public static async Task StreamPlaybackDemo(string audioFilePath)
{
// 创建音频服务
IAudioService audioService = AudioServiceFactory.CreateForCurrentPlatform();

// 从文件加载到流中(在实际应用中,这可能来自网络或嵌入资源)
Console.WriteLine("从流播放音频...");
using (FileStream stream = File.OpenRead(audioFilePath))
{
// 从流播放
string extension = Path.GetExtension(audioFilePath);
bool result = await audioService.PlayAsync(stream, extension);

if (!result)
{
Console.WriteLine("从流播放失败");
return;
}

// 等待10秒或播放完成
Console.WriteLine("等待播放完成...");
var completionSource = new TaskCompletionSource<bool>();

EventHandler? handler = null;
handler = (s, e) =>
{
audioService.PlaybackFinished -= handler;
completionSource.SetResult(true);
};

audioService.PlaybackFinished += handler;

// 10秒超时或等待播放完成
var timeoutTask = Task.Delay(10000);
await Task.WhenAny(completionSource.Task, timeoutTask);

audioService.PlaybackFinished -= handler;
await audioService.StopAsync();
}
}
}
42 changes: 42 additions & 0 deletions PCL.Neo.Core/Service/Audio/AudioOptions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
namespace PCL.Neo.Core.Service.Audio;

/// <summary>
/// 音频选项配置类
/// </summary>
public class AudioOptions
{
/// <summary>
/// 默认音量 (0.0 - 1.0)
/// </summary>
public float DefaultVolume { get; set; } = 0.7f;

/// <summary>
/// 是否启用音频系统
/// </summary>
public bool EnableAudio { get; set; } = true;

/// <summary>
/// 音频临时文件目录
/// </summary>
public string? TempDirectory { get; set; }

/// <summary>
/// 音频缓冲区大小(字节)
/// </summary>
public int BufferSize { get; set; } = 16384;

/// <summary>
/// 是否记录日志
/// </summary>
public bool EnableLogging { get; set; } = false;

/// <summary>
/// 音频错误重试次数
/// </summary>
public int RetryCount { get; set; } = 3;

/// <summary>
/// 音频错误重试延迟(毫秒)
/// </summary>
public int RetryDelayMs { get; set; } = 500;
}
133 changes: 133 additions & 0 deletions PCL.Neo.Core/Service/Audio/AudioPlayerExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
using System;
using System.IO;
using System.Threading.Tasks;

namespace PCL.Neo.Core.Service.Audio;

/// <summary>
/// 音频播放器扩展方法,提供更便捷的API
/// </summary>
public static class AudioPlayerExtensions
{
/// <summary>
/// 播放简短音效
/// </summary>
/// <param name="audioService">音频服务</param>
/// <param name="filePath">音频文件路径</param>
/// <returns>是否成功开始播放</returns>
public static async Task<bool> PlaySoundEffectAsync(this IAudioService audioService, string filePath)
{
if (audioService == null || string.IsNullOrEmpty(filePath))
return false;

return await audioService.PlayAsync(filePath);
}

/// <summary>
/// 播放嵌入资源音效
/// </summary>
/// <param name="audioService">音频服务</param>
/// <param name="resourceStream">资源流</param>
/// <param name="fileExtension">文件扩展名</param>
/// <returns>是否成功开始播放</returns>
public static async Task<bool> PlayEmbeddedSoundAsync(
this IAudioService audioService,
Stream resourceStream,
string fileExtension = ".mp3")
{
if (audioService == null || resourceStream == null)
return false;

return await audioService.PlayAsync(resourceStream, fileExtension);
}

/// <summary>
/// 同步播放音效(会等待完成)
/// </summary>
/// <param name="audioService">音频服务</param>
/// <param name="filePath">音频文件路径</param>
/// <param name="timeoutMs">超时时间(毫秒),超过此时间将返回,-1表示无超时</param>
/// <returns>是否成功完成播放</returns>
public static async Task<bool> PlaySoundAndWaitAsync(
this IAudioService audioService,
string filePath,
int timeoutMs = -1)
{
if (audioService == null || string.IsNullOrEmpty(filePath))
return false;

var completionSource = new TaskCompletionSource<bool>();
EventHandler? handler = null;

handler = (s, e) =>
{
audioService.PlaybackFinished -= handler;
completionSource.SetResult(true);
};

audioService.PlaybackFinished += handler;

if (!await audioService.PlayAsync(filePath))
{
audioService.PlaybackFinished -= handler;
return false;
}

if (timeoutMs > 0)
{
// 创建超时任务
var timeoutTask = Task.Delay(timeoutMs);

// 等待完成播放或超时
if (await Task.WhenAny(completionSource.Task, timeoutTask) == timeoutTask)
{
// 超时,停止播放并返回false
audioService.PlaybackFinished -= handler;
await audioService.StopAsync();
return false;
}
}
else
{
// 无超时,等待完成
await completionSource.Task;
}

return true;
}

/// <summary>
/// 渐变音量
/// </summary>
/// <param name="audioService">音频服务</param>
/// <param name="targetVolume">目标音量</param>
/// <param name="durationMs">渐变持续时间(毫秒)</param>
/// <returns>操作任务</returns>
public static async Task FadeVolumeAsync(
this IAudioService audioService,
float targetVolume,
int durationMs = 1000)
{
if (audioService == null || durationMs <= 0)
return;

// 获取当前音量的方法不直接支持,所以我们从0开始渐变
float currentVolume = 0.0f;
float startVolume = currentVolume;
float volumeDiff = targetVolume - startVolume;

// 至少进行10次调整,确保渐变平滑
int steps = Math.Max(10, durationMs / 50);
int stepDelayMs = durationMs / steps;

for (int i = 0; i <= steps; i++)
{
float progress = (float)i / steps;
float newVolume = startVolume + (volumeDiff * progress);
await audioService.SetVolumeAsync(newVolume);

if (i < steps)
await Task.Delay(stepDelayMs);
}
}
}
Loading
Loading