Skip to content

Commit

Permalink
A bit more clean up, and fixed a near oops.
Browse files Browse the repository at this point in the history
  • Loading branch information
IEvangelist committed Apr 6, 2022
1 parent fa1962b commit 9a443c6
Show file tree
Hide file tree
Showing 3 changed files with 102 additions and 62 deletions.
8 changes: 4 additions & 4 deletions src/Blazor.Permissions.WebAssembly/IPermissionsService.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
namespace Microsoft.JSInterop;

/// <summary></summary>
[JSAutoInterop(
TypeName = "Permissions",
Implementation = "window.navigator.permissions",
Url = "https://developer.mozilla.org/en-US/docs/Web/API/Navigator/permissions")]
//[JSAutoInterop(
// TypeName = "Permissions",
// Implementation = "window.navigator.permissions",
// Url = "https://developer.mozilla.org/en-US/docs/Web/API/Navigator/permissions")]
public partial interface IPermissionsService
{
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,13 @@ namespace Microsoft.JSInterop;
internal sealed class DefaultSpeechRecognitionService : ISpeechRecognitionService
{
readonly IJSInProcessRuntime _javaScript;

readonly ConcurrentDictionary<Guid, Action> _onStartedCallbackRegistry = new();
readonly ConcurrentDictionary<Guid, Action> _onEndedCallbackRegistry = new();
readonly ConcurrentDictionary<Guid, Action<SpeechRecognitionErrorEvent>> _onErrorCallbackRegistry = new();
readonly ConcurrentDictionary<Guid, Action<string>> _onResultCallbackRegistry = new();
readonly SpeechRecognitionCallbackRegistry _callbackRegistry = new();

SpeechRecognitionSubject? _speechRecognition;
IJSInProcessObjectReference? _speechRecognitionModule;

SpeechRecognitionSubject? _speechRecognition;

public DefaultSpeechRecognitionService(
IJSInProcessRuntime javaScript) => _javaScript = javaScript;
IJSInProcessRuntime javaScript) => _javaScript = javaScript;

void InitializeSpeechRecognitionSubject()
{
Expand All @@ -31,14 +27,7 @@ void InitializeSpeechRecognitionSubject()
}

_speechRecognition = SpeechRecognitionSubject.Create(
(key, speechRecognition) =>
{
if (Guid.TryParse(key, out var guid) &&
_onResultCallbackRegistry.TryGetValue(guid, out var onRecognized))
{
onRecognized?.Invoke(speechRecognition);
}
});
_callbackRegistry.InvokeOnRecognized);
}

/// <inheritdoc />
Expand Down Expand Up @@ -66,20 +55,17 @@ IDisposable ISpeechRecognitionService.RecognizeSpeech(
InitializeSpeechRecognitionSubject();

var key = Guid.NewGuid();

if (onStarted is not null) _onStartedCallbackRegistry[key] = onStarted;
if (onEnded is not null) _onEndedCallbackRegistry[key] = onEnded;
if (onError is not null) _onErrorCallbackRegistry[key] = onError;

_onResultCallbackRegistry.Clear();
_onResultCallbackRegistry[key] = onRecognized;
_callbackRegistry.RegisterOnRecognized(key, onRecognized);
_callbackRegistry.RegisterOnError(key, onError);
_callbackRegistry.RegisterOnStarted(key, onStarted);
_callbackRegistry.RegisterOnEnded(key, onEnded);

_speechRecognitionModule?.InvokeVoid(
InteropMethodIdentifiers.JavaScript.RecognizeSpeech,
DotNetObjectReference.Create(this),
language,
key,
nameof(OnSpeechRecongized),
nameof(OnSpeechRecognized),
nameof(OnRecognitionError),
nameof(OnStarted),
nameof(OnEnded));
Expand All @@ -88,50 +74,20 @@ IDisposable ISpeechRecognitionService.RecognizeSpeech(
}

[JSInvokable]
public void OnStarted(string key) =>
OnInvokeCallback(
key, _onStartedCallbackRegistry,
callback => callback?.Invoke());
public void OnStarted(string key) => _callbackRegistry.InvokeOnStarted(key);

[JSInvokable]
public void OnEnded(string key) =>
OnInvokeCallback(
key, _onEndedCallbackRegistry,
callback => callback?.Invoke());
public void OnEnded(string key) => _callbackRegistry.InvokeOnEnded(key);

[JSInvokable]
public void OnRecognitionError(string key, SpeechRecognitionErrorEvent errorEvent) =>
OnInvokeCallback(
key, _onErrorCallbackRegistry,
callback => callback?.Invoke(errorEvent));
_callbackRegistry.InvokeOnError(key, errorEvent);

[JSInvokable]
public void OnSpeechRecongized(string key, string transcript, bool isFinal) =>
public void OnSpeechRecognized(string key, string transcript, bool isFinal) =>
_speechRecognition?.RecognitionReceived(
new SpeechRecognitionResult(key, transcript, isFinal));

static void OnInvokeCallback<T>(
string key,
ConcurrentDictionary<Guid, T> callbackRegistry,
Action<T?> action)
{
if (key is null or { Length: 0 })
{
return;
}

if (callbackRegistry is null or { Count: 0 })
{
return;
}

if (Guid.TryParse(key, out var guid) &&
callbackRegistry.TryRemove(guid, out var callback))
{
action?.Invoke(callback);
}
}

async ValueTask IAsyncDisposable.DisposeAsync()
{
_speechRecognition?.Dispose();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
// Copyright (c) David Pine. All rights reserved.
// Licensed under the MIT License.

namespace Microsoft.JSInterop;

internal sealed class SpeechRecognitionCallbackRegistry
{
readonly ConcurrentDictionary<Guid, Action<string>> _onResultCallbackRegistry = new();
readonly ConcurrentDictionary<Guid, Action<SpeechRecognitionErrorEvent>> _onErrorCallbackRegistry = new();
readonly ConcurrentDictionary<Guid, Action> _onStartedCallbackRegistry = new();
readonly ConcurrentDictionary<Guid, Action> _onEndedCallbackRegistry = new();

internal void RegisterOnRecognized(
Guid key, Action<string> callback)
{
if (callback is not null)
_onResultCallbackRegistry[key] = callback;
}

internal void RegisterOnError(
Guid key, Action<SpeechRecognitionErrorEvent>? callback)
{
if (callback is not null)
_onErrorCallbackRegistry[key] = callback;
}

internal void RegisterOnStarted(
Guid key, Action? callback)
{
if (callback is not null)
_onStartedCallbackRegistry[key] = callback;
}

internal void RegisterOnEnded(
Guid key, Action? callback)
{
if (callback is not null)
_onEndedCallbackRegistry[key] = callback;
}

internal void InvokeOnRecognized(
string key, string transcript) =>
OnInvokeCallback(
key, _onResultCallbackRegistry,
callback => callback?.Invoke(transcript));

internal void InvokeOnError(
string key, SpeechRecognitionErrorEvent error) =>
OnInvokeCallback(
key, _onErrorCallbackRegistry,
callback => callback?.Invoke(error));

internal void InvokeOnStarted(string key) =>
OnInvokeCallback(
key, _onStartedCallbackRegistry,
callback => callback?.Invoke());

internal void InvokeOnEnded(string key) =>
OnInvokeCallback(
key, _onEndedCallbackRegistry,
callback => callback?.Invoke());

static void OnInvokeCallback<T>(
string key,
ConcurrentDictionary<Guid, T> callbackRegistry,
Action<T?> action)
{
if (key is null or { Length: 0 })
{
return;
}

if (callbackRegistry is null or { Count: 0 })
{
return;
}

if (Guid.TryParse(key, out var guid) &&
callbackRegistry.TryRemove(guid, out var callback))
{
action?.Invoke(callback);
}
}
}

0 comments on commit 9a443c6

Please sign in to comment.