diff --git a/.git-pr-release-template b/.git-pr-release-template
new file mode 100644
index 0000000..a471555
--- /dev/null
+++ b/.git-pr-release-template
@@ -0,0 +1,4 @@
+<%= ENV['APP_VERSION'] %>
+<% pull_requests.each do |pr| -%>
+<%= pr.to_checklist_item %>
+<% end -%>
\ No newline at end of file
diff --git a/.github/workflows/create-release.yml b/.github/workflows/create-release.yml
new file mode 100644
index 0000000..cd0f4f7
--- /dev/null
+++ b/.github/workflows/create-release.yml
@@ -0,0 +1,37 @@
+name: create a release pull request
+
+on:
+ workflow_dispatch:
+
+ pull_request:
+ types: [ closed ]
+ branches:
+ - develop
+
+env:
+ pathOfVersioning: ${{ github.workspace }}/SimpleVolumeMixer
+
+jobs:
+ create-release-pr:
+ runs-on: ubuntu-latest
+ steps:
+
+ - name: checkout this solution
+ uses: actions/checkout@v2
+ with:
+ fetch-depth: 0
+
+ - id: nbgv
+ run: |
+ VERSION=`nbgv get-version -p ${{ env.pathOfVersioning }} -v NuGetPackageVersion`
+ echo "::set-output name=version::$VERSION"
+
+ - name: create a release pull request
+ uses: bakunyo/git-pr-release-action@281e1fe424fac01f3992542266805e4202a22fe0
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ GIT_PR_RELEASE_BRANCH_PRODUCTION: master
+ GIT_PR_RELEASE_BRANCH_STAGING: develop
+ GIT_PR_RELEASE_LABELS: release
+ APP_VERSION: v${{ steps.nbgv.outputs.version }}
+ GIT_PR_RELEASE_TEMPLATE: .git-pr-release-template
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index a82c6e4..8077a9d 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -15,6 +15,7 @@ env:
jobs:
build-artifact:
+ if: github.event.pull_request.merged == true
runs-on: windows-2019
outputs:
artifactName: ${{ steps.vars.outputs.artifactName }}
@@ -79,10 +80,10 @@ jobs:
- id: vars
shell: bash
run: |
- if [[ "${{ needs.build-artifact.outputs.prereleaseVersionNoLeadingHyphen }}" = "beta" -o "${{ needs.build-artifact.outputs.prereleaseVersionNoLeadingHyphen }}" = "alpha" ]]; then
- echo "::set-output name=isPrerelease::true";
+ if [ "${{ needs.build-artifact.outputs.prereleaseVersionNoLeadingHyphen }}" = "beta" ] || [ "${{ needs.build-artifact.outputs.prereleaseVersionNoLeadingHyphen }}" = "alpha" ]; then
+ echo "::set-output name=isPrerelease::true"
else
- echo "::set-output name=isPrerelease::false";
+ echo "::set-output name=isPrerelease::false"
fi;
- id: create-release
@@ -99,6 +100,7 @@ jobs:
run: |
echo "::set-output name=uploadUrl::${{ steps.create-release.outputs.upload_url }}"
+
upload-release:
runs-on: ubuntu-latest
needs: [ create-release, build-artifact ]
diff --git a/.idea/.idea.SimpleVolumeMixer/.idea/misc.xml b/.idea/.idea.SimpleVolumeMixer/.idea/misc.xml
new file mode 100644
index 0000000..283b9b4
--- /dev/null
+++ b/.idea/.idea.SimpleVolumeMixer/.idea/misc.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/SimpleVolumeMixer/Core/Contracts/Models/Repository/ICoreAudioRepository.cs b/SimpleVolumeMixer/Core/Contracts/Models/Repository/ICoreAudioRepository.cs
index bdfa79f..c8b12f2 100644
--- a/SimpleVolumeMixer/Core/Contracts/Models/Repository/ICoreAudioRepository.cs
+++ b/SimpleVolumeMixer/Core/Contracts/Models/Repository/ICoreAudioRepository.cs
@@ -1,4 +1,5 @@
-using Reactive.Bindings;
+using System.Collections.ObjectModel;
+using Reactive.Bindings;
using SimpleVolumeMixer.Core.Helper.CoreAudio;
using SimpleVolumeMixer.Core.Helper.CoreAudio.Types;
@@ -6,8 +7,31 @@ namespace SimpleVolumeMixer.Core.Contracts.Models.Repository;
public interface ICoreAudioRepository
{
- ReadOnlyReactiveCollection AudioDevices { get; }
+ ///
+ /// 現在使用可能なの一覧を取得する。
+ /// 読み取り専用であり、このオブジェクトからデバイスの増減を行うことは出来ない。
+ /// デバイスの増減はによりCoreAudioAPIからデバイス一覧を取り直すか、
+ /// がCoreAudioAPIからの通知を受け、その結果デバイスが追加されるかに限る。
+ ///
+ ReadOnlyObservableCollection AudioDevices { get; }
+
+ ///
+ /// ロールのデバイスを取得する。
+ /// インスタンスはからロールを持つ物を検索して取得できる値と同一である。
+ ///
IReadOnlyReactiveProperty CommunicationRoleDevice { get; }
+
+ ///
+ /// ロールのデバイスを取得する。
+ /// インスタンスはからロールを持つ物を検索して取得できる値と同一である。
+ ///
IReadOnlyReactiveProperty MultimediaRoleDevice { get; }
+
+ ///
+ /// 引数のデバイスとのデバイスに対し、のロールを割り当てる。
+ ///
+ ///
+ ///
+ ///
void SetDefaultDevice(AudioDeviceAccessor accessor, DataFlowType dataFlowType, RoleType roleType);
}
\ No newline at end of file
diff --git a/SimpleVolumeMixer/Core/Helper/Component/DisposableComponent.cs b/SimpleVolumeMixer/Core/Helper/Component/DisposableComponent.cs
deleted file mode 100644
index d9beb63..0000000
--- a/SimpleVolumeMixer/Core/Helper/Component/DisposableComponent.cs
+++ /dev/null
@@ -1,72 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Reactive.Disposables;
-
-namespace SimpleVolumeMixer.Core.Helper.Component;
-
-///
-/// Concrete class for IDisposableComponent. See Interface for detailed behavior.
-///
-///
-public abstract class DisposableComponent : IDisposableComponent
-{
- ///
- public event EventHandler? Disposing;
-
- ///
- public event EventHandler? Disposed;
-
- ///
- /// An external component that delegates the entire destruction process.
- ///
- private readonly CompositeDisposable _disposable;
-
- ///
- /// ctor.
- ///
- public DisposableComponent()
- {
- _disposable = new CompositeDisposable();
- }
-
- ///
- public ICollection Disposable => _disposable;
-
- ///
- public bool IsDisposed => _disposable.IsDisposed;
-
- ///
- /// Called before the object is destroyed by a call to Dispose()
.
- ///
- protected virtual void OnDisposing()
- {
- Disposing?.Invoke(this, EventArgs.Empty);
- }
-
- ///
- /// Called after an object has been destroyed by a call to Dispose()
.
- ///
- protected virtual void OnDisposed()
- {
- Disposed?.Invoke(this, EventArgs.Empty);
- }
-
- ///
- public void Dispose()
- {
- if (_disposable.IsDisposed)
- {
- return;
- }
-
- OnDisposing();
- _disposable.Dispose();
- OnDisposed();
- }
-
- ///
- void IDisposable.Dispose()
- {
- Dispose();
- }
-}
\ No newline at end of file
diff --git a/SimpleVolumeMixer/Core/Helper/Component/IDisposableComponent.cs b/SimpleVolumeMixer/Core/Helper/Component/IDisposableComponent.cs
deleted file mode 100644
index 0eca6ea..0000000
--- a/SimpleVolumeMixer/Core/Helper/Component/IDisposableComponent.cs
+++ /dev/null
@@ -1,36 +0,0 @@
-using System;
-using System.Collections.Generic;
-
-namespace SimpleVolumeMixer.Core.Helper.Component;
-
-public interface IDisposableComponent : IDisposable
-{
- ///
- /// This event occurs before the destruction process by IDisposable.
- ///
- event EventHandler? Disposing;
-
- ///
- /// This event occurs after the destruction process by IDisposable.
- ///
- event EventHandler? Disposed;
-
- ///
- /// Obtains an ICollection that holds IDisposable and allows the IDisposable associated with this object to be destroyed at once.
- /// IDisposable registered with an ICollection that can be retrieved from this property will be destroyed as soon as this object's Dispose()
method is called.
- ///
- ICollection Disposable { get; }
-
- ///
- /// Gets whether the object has been destroyed.
- /// After calling the Dispose()
method, this property always returns false.
- ///
- bool IsDisposed { get; }
-
- ///
- /// Calls the object destruction process.
- /// After this function is called, this object cannot be used.
- ///
- ///
- new void Dispose();
-}
\ No newline at end of file
diff --git a/SimpleVolumeMixer/Core/Helper/Component/IPollingMonitor.cs b/SimpleVolumeMixer/Core/Helper/Component/IPollingMonitor.cs
new file mode 100644
index 0000000..d587f32
--- /dev/null
+++ b/SimpleVolumeMixer/Core/Helper/Component/IPollingMonitor.cs
@@ -0,0 +1,68 @@
+using System.ComponentModel;
+using SimpleVolumeMixer.Core.Helper.Component.Types;
+
+namespace SimpleVolumeMixer.Core.Helper.Component;
+
+///
+/// Provides an interface to a function that monitors certain values at regular intervals.
+///
+public interface IPollingMonitor : INotifyPropertyChanged
+{
+ ///
+ /// Occurs when the result of polling by this interface differs from the previous value.
+ ///
+ ///
+ new event PropertyChangedEventHandler? PropertyChanged;
+
+ ///
+ /// Holds the latest value obtained during polling.
+ /// If the value is rewritten by the polling process, the event is fired.
+ ///
+ object Value { get; }
+
+ ///
+ /// Gets or sets the interval for polling. The interval can be set in milliseconds.
+ /// See the enum definition for detailed seconds.
+ /// If is set,
+ /// no polling is performed and the value is updated only when the method is called externally.
+ /// If this property is changed while the polling process is running,
+ /// the polling process execution interval is adjusted; if is set, the polling process is stopped.
+ ///
+ ///
+ PollingMonitorIntervalType IntervalType { get; set; }
+
+ ///
+ /// Start polling. However, this method only starts the process and does not block the thread.
+ /// If this method is called when is set to or when a polling operation is already running,
+ /// no new polling operation will be started and nothing will happen.
+ ///
+ void Start();
+
+ ///
+ /// Stops polling, even if called when polling is not running,
+ /// including when is , no exception is made.
+ ///
+ void Stop();
+
+ ///
+ /// The process of obtaining the latest value of the polling process is implemented.
+ /// When the value is updated, the property is rewritten and the fact that the value has been updated is notified externally by .
+ ///
+ ///
+ ///
+ void Refresh();
+}
+
+///
+/// An interface that applies a generic to the property of the interface.
+///
+///
+public interface IPollingMonitor : IPollingMonitor
+{
+ ///
+ /// It has the same functionality as the inherited source, the only difference being that the type is generic.
+ /// See the documentation of the inherited source for detailed functionality.
+ ///
+ ///
+ new T Value { get; }
+}
\ No newline at end of file
diff --git a/SimpleVolumeMixer/Core/Helper/Component/IPropertyMonitor.cs b/SimpleVolumeMixer/Core/Helper/Component/IPropertyMonitor.cs
deleted file mode 100644
index a6ba34e..0000000
--- a/SimpleVolumeMixer/Core/Helper/Component/IPropertyMonitor.cs
+++ /dev/null
@@ -1,17 +0,0 @@
-using SimpleVolumeMixer.Core.Helper.Component.Types;
-
-namespace SimpleVolumeMixer.Core.Helper.Component;
-
-public interface IPropertyMonitor
-{
- object Value { get; set; }
- PropertyMonitorIntervalType IntervalType { get; set; }
- void Start();
- void Stop();
- void Refresh();
-}
-
-public interface IPropertyMonitor : IPropertyMonitor
-{
- new T Value { get; set; }
-}
\ No newline at end of file
diff --git a/SimpleVolumeMixer/Core/Helper/Component/KeyValueInstanceManager.cs b/SimpleVolumeMixer/Core/Helper/Component/KeyValueInstanceManager.cs
index 8ff5747..3c126eb 100644
--- a/SimpleVolumeMixer/Core/Helper/Component/KeyValueInstanceManager.cs
+++ b/SimpleVolumeMixer/Core/Helper/Component/KeyValueInstanceManager.cs
@@ -1,20 +1,36 @@
using System;
using System.Collections.Generic;
+using DisposableComponents;
namespace SimpleVolumeMixer.Core.Helper.Component;
+///
+/// This component is used to ensure that the TK and TV values are always 1-1.
+/// The key must implement so that the value can also be destroyed when the key is destroyed.
+///
+/// Key value type
+/// Type corresponding to TK
public class KeyValueInstanceManager : DisposableComponent where TK : IDisposableComponent
{
private readonly object _gate = new();
private readonly IDictionary _instances;
private readonly Func _factory;
+ ///
+ /// ctor
+ ///
+ /// Function to generate the value corresponding to a key
public KeyValueInstanceManager(Func factory)
{
_instances = new Dictionary();
_factory = factory;
}
+ ///
+ /// If the value corresponding to the key already exists, return that value; if not, create and return a new value.
+ ///
+ ///
+ ///
public TV Obtain(TK key)
{
lock (_gate)
@@ -33,6 +49,11 @@ public TV Obtain(TK key)
}
}
+ ///
+ /// Process to erase the value from this instance when the key is destroyed.
+ ///
+ ///
+ ///
private void KeyOnDisposed(object? sender, EventArgs e)
{
if (sender == null)
diff --git a/SimpleVolumeMixer/Core/Helper/Component/NotifyPropertyChangedBase.cs b/SimpleVolumeMixer/Core/Helper/Component/NotifyPropertyChangedBase.cs
index f1dc263..65c98ec 100644
--- a/SimpleVolumeMixer/Core/Helper/Component/NotifyPropertyChangedBase.cs
+++ b/SimpleVolumeMixer/Core/Helper/Component/NotifyPropertyChangedBase.cs
@@ -3,10 +3,25 @@
namespace SimpleVolumeMixer.Core.Helper.Component;
+///
+/// Abstract class for efficiently preparing implementations of the interface
+///
+///
public class NotifyPropertyChangedBase : INotifyPropertyChanged
{
+ ///
public event PropertyChangedEventHandler? PropertyChanged;
+ ///
+ /// Attempts to write the value of to the .
+ /// When the value of the is updated to the value of ,
+ /// a property change notification by is generated.
+ /// If the values are the same, the aforementioned process is not performed.
+ ///
+ /// A reference to a variable that holds a value. Note that the variable may be rewritten to the value of
+ /// new value
+ /// Name of the location where this function was called. This is set automatically, so you do not need to do anything explicitly.
+ ///
protected void SetValue(ref T holder, T newValue, [CallerMemberName] string? callerMemberName = null)
{
if (!Equals(holder, newValue))
@@ -16,6 +31,10 @@ protected void SetValue(ref T holder, T newValue, [CallerMemberName] string?
}
}
+ ///
+ /// Raises PropertyChanged event
+ ///
+ /// Name of the property where the change occurred
protected void RaisePropertyChanged(string? propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
diff --git a/SimpleVolumeMixer/Core/Helper/Component/PollingMonitor.cs b/SimpleVolumeMixer/Core/Helper/Component/PollingMonitor.cs
new file mode 100644
index 0000000..a92c625
--- /dev/null
+++ b/SimpleVolumeMixer/Core/Helper/Component/PollingMonitor.cs
@@ -0,0 +1,169 @@
+using System;
+using System.Reactive.Disposables;
+using System.Timers;
+using Reactive.Bindings.Extensions;
+using SimpleVolumeMixer.Core.Helper.Component.Types;
+
+namespace SimpleVolumeMixer.Core.Helper.Component;
+
+public static class PollingMonitor
+{
+ ///
+ /// Comparison function for int type only.
+ ///
+ public static Func IntComparer = (x, y) => x == y;
+
+ ///
+ /// Comparison function for float type only.
+ ///
+ public static Func FloatComparer = (x, y) => x.Equals(y);
+
+ ///
+ /// Comparison function for bool type only.
+ ///
+ public static Func BoolComparer = (x, y) => x == y;
+
+ ///
+ /// Comparison processing using object.Equals;
+ /// if boxing occurs, as in the case of ints and floats, it is more efficient to have a dedicated comparison function.
+ ///
+ ///
+ ///
+ public static Func GetDefaultComparer() => (x, y) => Equals(x, y);
+}
+
+public class PollingMonitor : NotifyPropertyChangedBase, IDisposable, IPollingMonitor
+{
+ private static readonly Action DefaultWriter = _ => { };
+ private readonly Func _comparer;
+
+ private readonly CompositeDisposable _disposable;
+ private readonly Func _reader;
+ private readonly Timer _timer;
+ private readonly Action _writer;
+ private PollingMonitorIntervalType _intervalType;
+ private T _value;
+
+ ///
+ /// ctor
+ ///
+ /// Polling interval
+ /// Function making the polling target call
+ /// This function delegates write processing when the Value property is written from the outside.
+ /// Comparison process to detect that a value has been rewritten
+ public PollingMonitor(
+ PollingMonitorIntervalType intervalType,
+ Func reader,
+ Action? writer = null,
+ Func? comparer = null
+ )
+ {
+ _disposable = new CompositeDisposable();
+ _reader = reader;
+ _writer = writer != null ? writer : DefaultWriter;
+ _comparer = comparer != null ? comparer : PollingMonitor.GetDefaultComparer();
+
+ _value = reader();
+ RaisePropertyChanged(nameof(Value));
+
+ _timer = new Timer().AddTo(_disposable);
+ _timer.Enabled = false;
+ _timer.Elapsed += TimerOnElapsed;
+
+ IntervalType = intervalType;
+ }
+
+ ///
+ /// Extend IPollingMonitor.Value to also support write processing.
+ /// The actual writing process is performed through the function object obtained at class initialization.
+ /// Also, to avoid changing the interface behavior (or rather, to avoid notification loops),
+ /// the event is not triggered when writing to this property.
+ ///
+ ///
+ public T Value
+ {
+ get => _value;
+ set
+ {
+ _writer(value);
+ _value = value;
+ }
+ }
+
+ ///
+ object IPollingMonitor.Value
+ {
+#pragma warning disable CS8603
+ get => Value;
+#pragma warning restore CS8603
+ }
+
+ ///
+ public PollingMonitorIntervalType IntervalType
+ {
+ get => _intervalType;
+ set
+ {
+ _intervalType = value;
+
+ if (_intervalType == PollingMonitorIntervalType.Manual)
+ {
+ _timer.Stop();
+ }
+ else
+ {
+ _timer.Interval = (double)_intervalType;
+ _timer.Start();
+ }
+ }
+ }
+
+ private void TimerOnElapsed(object sender, ElapsedEventArgs e)
+ {
+ Refresh();
+ }
+
+ ///
+ public void Start()
+ {
+ if (_intervalType == PollingMonitorIntervalType.Manual)
+ {
+ return;
+ }
+
+ if (_timer.Enabled)
+ {
+ return;
+ }
+
+ _timer.Enabled = true;
+ _timer.Start();
+ }
+
+ ///
+ public void Stop()
+ {
+ _timer.Enabled = false;
+ _timer.Stop();
+ }
+
+ ///
+ public void Refresh()
+ {
+ var newValue = _reader();
+ if (!_comparer(_value, newValue))
+ {
+ _value = newValue;
+ RaisePropertyChanged(nameof(Value));
+ }
+ }
+
+ ///
+ public void Dispose()
+ {
+ _timer.Elapsed -= TimerOnElapsed;
+ _timer.Stop();
+
+ _disposable.Dispose();
+ }
+}
\ No newline at end of file
diff --git a/SimpleVolumeMixer/Core/Helper/Component/PropertyMonitor.cs b/SimpleVolumeMixer/Core/Helper/Component/PropertyMonitor.cs
deleted file mode 100644
index bd2d8b4..0000000
--- a/SimpleVolumeMixer/Core/Helper/Component/PropertyMonitor.cs
+++ /dev/null
@@ -1,139 +0,0 @@
-using System;
-using System.Reactive.Disposables;
-using System.Timers;
-using Reactive.Bindings.Extensions;
-using SimpleVolumeMixer.Core.Helper.Component.Types;
-
-namespace SimpleVolumeMixer.Core.Helper.Component;
-
-public static class PropertyMonitor
-{
- public static readonly Func IntComparer = (x, y) => x == y;
- public static readonly Func FloatComparer = (x, y) => x.Equals(y);
- public static readonly Func BoolComparer = (x, y) => x == y;
-}
-
-public class PropertyMonitor : NotifyPropertyChangedBase, IDisposable, IPropertyMonitor
-{
- private static readonly Func DefaultComparer = (x, y) => Equals(x, y);
- private static readonly Action DefaultWriter = _ => { };
- private readonly Func _comparer;
-
- private readonly CompositeDisposable _disposable;
- private readonly Func _reader;
- private readonly Timer _timer;
- private readonly Action _writer;
- private PropertyMonitorIntervalType _intervalType;
- private T _value;
-
- public PropertyMonitor(
- PropertyMonitorIntervalType intervalType,
- Func reader,
- Action? writer = null,
- Func? comparer = null
- )
- {
- _disposable = new CompositeDisposable();
- _intervalType = intervalType;
- _reader = reader;
- _writer = writer != null ? writer : DefaultWriter;
- _comparer = comparer != null ? comparer : DefaultComparer;
-
- _timer = new Timer().AddTo(_disposable);
- _timer.Enabled = true;
- _timer.Elapsed += TimerOnElapsed;
- TimerSetting();
-
- _value = reader();
- RaisePropertyChanged(nameof(Value));
- }
-
- public T Value
- {
- get => _value;
- set
- {
- WriteValue(value);
- _value = value;
- }
- }
-
- object IPropertyMonitor.Value
- {
-#pragma warning disable CS8603
- get => Value;
-#pragma warning restore CS8603
- set => Value = (T)value;
- }
-
- public PropertyMonitorIntervalType IntervalType
- {
- get => _intervalType;
- set
- {
- _intervalType = value;
- TimerSetting();
- }
- }
-
- private void TimerOnElapsed(object sender, ElapsedEventArgs e)
- {
- Refresh();
- }
-
- private void TimerSetting()
- {
- if (_intervalType == PropertyMonitorIntervalType.Manual)
- {
- _timer.Stop();
- }
- else
- {
- _timer.Interval = (double)_intervalType;
- _timer.Start();
- }
- }
-
- public void Start()
- {
- if (_intervalType == PropertyMonitorIntervalType.Manual)
- {
- throw new InvalidOperationException("state is manual.");
- }
-
- _timer.Start();
- }
-
- public void Stop()
- {
- _timer.Stop();
- }
-
- public void Refresh()
- {
- var newValue = ReadValue();
- if (!_comparer(_value, newValue))
- {
- _value = newValue;
- RaisePropertyChanged(nameof(Value));
- }
- }
-
- protected virtual T ReadValue()
- {
- return _reader();
- }
-
- protected virtual void WriteValue(T value)
- {
- _writer(value);
- }
-
- public void Dispose()
- {
- _timer.Stop();
- _timer.Elapsed -= TimerOnElapsed;
-
- _disposable.Dispose();
- }
-}
\ No newline at end of file
diff --git a/SimpleVolumeMixer/Core/Helper/Component/QueueProcessor.cs b/SimpleVolumeMixer/Core/Helper/Component/QueueProcessor.cs
index aa5718d..bf202a1 100644
--- a/SimpleVolumeMixer/Core/Helper/Component/QueueProcessor.cs
+++ b/SimpleVolumeMixer/Core/Helper/Component/QueueProcessor.cs
@@ -2,57 +2,111 @@
using System.Collections.Concurrent;
using System.Threading;
using System.Threading.Tasks;
+using DisposableComponents;
+using Microsoft.Extensions.Logging;
using Reactive.Bindings.Extensions;
namespace SimpleVolumeMixer.Core.Helper.Component;
+///
+/// Provides a mechanism for managing (and related objects) in a queue and executing them sequentially in a worker thread.
+///
+/// Types of objects passed as Func arguments
+/// Type of object returned as the return value of Func
public class QueueProcessor : DisposableComponent
{
- private readonly BlockingCollection> _handles;
+ private readonly string _name;
+ private readonly ILogger _logger;
+ private readonly BlockingCollection> _items;
private readonly Task _loopTask;
private readonly CancellationTokenSource _cancellation;
- public QueueProcessor(int capacity = 1024)
+ ///
+ /// ctor
+ ///
+ ///
+ ///
+ /// Maximum number of queues registered
+ public QueueProcessor(string name, ILogger logger, int capacity = 4096)
{
- _handles = new BlockingCollection>(capacity).AddTo(Disposable);
- _loopTask = new Task(() => DoProcess()).AddTo(Disposable);
+ _name = name;
+ _logger = logger;
+ _items = new BlockingCollection>(capacity).AddTo(Disposable);
_cancellation = new CancellationTokenSource().AddTo(Disposable);
- }
-
- public void StartRequest()
- {
+ _loopTask = new Task(() => DoProcess(), _cancellation.Token).AddTo(Disposable);
_loopTask.Start();
}
- public void StopRequest()
+ ///
+ /// Register Func (and its auxiliary objects) in the queue.
+ /// When the number of registrations in the queue reaches the capacity set in the constructor,
+ /// the thread calling this method blocks until the number of registrations in the queue is less than the capacity.
+ ///
+ ///
+ public void Push(QueueProcessorItem item)
{
- _cancellation.Cancel(false);
- }
-
- public void Push(QueueProcessorHandle handle)
- {
- _handles.Add(handle);
+ if (IsDisposed)
+ {
+ return;
+ }
+
+ _items.Add(item);
}
+ ///
+ /// Infinite loop process called by worker thread
+ ///
private void DoProcess()
{
+ _logger.LogInformation("[{}] start looping...", _name);
+
while (!_cancellation.IsCancellationRequested)
{
- var handle = _handles.Take();
- if (handle.CancelRequest)
+ try
{
- handle.Executed = true;
- continue;
- }
+ var item = _items.Take(_cancellation.Token);
+ if (item.CancelRequest)
+ {
+ item.Executed = true;
+ continue;
+ }
- handle.Result = handle.Function(handle.Argument);
- handle.Executed = true;
+ item.Result = item.Function(item.Argument);
+ item.Executed = true;
+ }
+ catch (OperationCanceledException ex)
+ {
+ _logger.LogError(ex, "[{}] canceled", _name);
+ }
}
+
+ _logger.LogInformation("[{}] finish looping...", _name);
}
+ ///
protected override void OnDisposing()
{
- StopRequest();
+ _logger.LogInformation("[{}] disposing...", _name);
+
+ _cancellation.Cancel(false);
+
+ switch (_loopTask.Status)
+ {
+ case TaskStatus.Canceled:
+ case TaskStatus.Faulted:
+ case TaskStatus.RanToCompletion:
+ break;
+ default:
+ _loopTask.Wait();
+ break;
+ }
+
base.OnDisposing();
}
+
+ protected override void OnDisposed()
+ {
+ _logger.LogInformation("[{}] disposed...", _name);
+ base.OnDisposed();
+ }
}
\ No newline at end of file
diff --git a/SimpleVolumeMixer/Core/Helper/Component/QueueProcessorHandle.cs b/SimpleVolumeMixer/Core/Helper/Component/QueueProcessorHandle.cs
deleted file mode 100644
index d5de999..0000000
--- a/SimpleVolumeMixer/Core/Helper/Component/QueueProcessorHandle.cs
+++ /dev/null
@@ -1,70 +0,0 @@
-using System;
-
-namespace SimpleVolumeMixer.Core.Helper.Component;
-
-public static class QueueProcessorHandle
-{
- public static QueueProcessorHandle