增加了自习系列组件
This commit is contained in:
lincube
2026-03-04 20:03:14 +08:00
parent 00a3c6a572
commit 40ddcd399d
20 changed files with 2932 additions and 79 deletions

View File

@@ -42,7 +42,7 @@ public interface IAudioRecorderService : IDisposable
public static class AudioRecorderServiceFactory
{
private static readonly Lazy<IAudioRecorderService> SharedService = new(
private static readonly Lazy<IAudioRecorderService> SharedRecorderService = new(
() =>
{
if (!OperatingSystem.IsWindows() && !OperatingSystem.IsLinux() && !OperatingSystem.IsMacOS())
@@ -54,9 +54,31 @@ public static class AudioRecorderServiceFactory
},
isThreadSafe: true);
private static readonly Lazy<IAudioRecorderService> SharedStudyMonitoringService = new(
() =>
{
if (!OperatingSystem.IsWindows() && !OperatingSystem.IsLinux() && !OperatingSystem.IsMacOS())
{
return new NoOpAudioRecorderService("Unsupported platform");
}
return new PortAudioRecorderService();
},
isThreadSafe: true);
public static IAudioRecorderService CreateRecorder()
{
return SharedRecorderService.Value;
}
public static IAudioRecorderService CreateStudyMonitoring()
{
return SharedStudyMonitoringService.Value;
}
public static IAudioRecorderService CreateDefault()
{
return SharedService.Value;
return CreateRecorder();
}
}

View File

@@ -0,0 +1,94 @@
using System;
using System.Threading;
using LanMountainDesktop.Models;
namespace LanMountainDesktop.Services;
public static class StudyAnalyticsMonitoringLeaseCoordinatorFactory
{
private static readonly Lazy<StudyAnalyticsMonitoringLeaseCoordinator> SharedCoordinator = new(
() => new StudyAnalyticsMonitoringLeaseCoordinator(),
isThreadSafe: true);
public static StudyAnalyticsMonitoringLeaseCoordinator CreateDefault()
{
return SharedCoordinator.Value;
}
}
public sealed class StudyAnalyticsMonitoringLeaseCoordinator
{
private readonly object _syncRoot = new();
private readonly IStudyAnalyticsService _studyAnalyticsService;
private int _activeLeaseCount;
public StudyAnalyticsMonitoringLeaseCoordinator(IStudyAnalyticsService? studyAnalyticsService = null)
{
_studyAnalyticsService = studyAnalyticsService ?? StudyAnalyticsServiceFactory.CreateDefault();
}
public IDisposable AcquireLease()
{
var shouldStartMonitoring = false;
lock (_syncRoot)
{
_activeLeaseCount++;
if (_activeLeaseCount == 1)
{
shouldStartMonitoring = true;
}
}
if (shouldStartMonitoring)
{
_ = _studyAnalyticsService.StartOrResumeMonitoring();
}
return new MonitoringLease(this);
}
private void ReleaseLease()
{
var shouldPauseMonitoring = false;
lock (_syncRoot)
{
if (_activeLeaseCount <= 0)
{
return;
}
_activeLeaseCount--;
if (_activeLeaseCount == 0)
{
shouldPauseMonitoring = true;
}
}
if (!shouldPauseMonitoring)
{
return;
}
var snapshot = _studyAnalyticsService.GetSnapshot();
if (snapshot.Session.State != StudySessionRuntimeState.Running)
{
_ = _studyAnalyticsService.PauseMonitoring();
}
}
private sealed class MonitoringLease : IDisposable
{
private StudyAnalyticsMonitoringLeaseCoordinator? _owner;
public MonitoringLease(StudyAnalyticsMonitoringLeaseCoordinator owner)
{
_owner = owner;
}
public void Dispose()
{
var owner = Interlocked.Exchange(ref _owner, null);
owner?.ReleaseLease();
}
}
}

View File

@@ -36,7 +36,7 @@ public sealed class StudyAnalyticsService : IStudyAnalyticsService
public StudyAnalyticsService(IAudioRecorderService? audioRecorderService = null)
{
_audioRecorderService = audioRecorderService ?? AudioRecorderServiceFactory.CreateDefault();
_audioRecorderService = audioRecorderService ?? AudioRecorderServiceFactory.CreateStudyMonitoring();
_pipeline = new NoiseFramePipeline(_config);
_samplingTimer = new Timer(OnSamplingTick, null, Timeout.Infinite, Timeout.Infinite);