Skip to content
Closed
Show file tree
Hide file tree
Changes from all 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
20 changes: 19 additions & 1 deletion AdaptiveRemote.sln
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,13 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AdaptiveRemote", "src\Adapt
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AdaptiveRemote.Console", "src\AdaptiveRemote.Console\AdaptiveRemote.Console.csproj", "{345B73FC-07F9-490F-B566-2677D10B1834}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AdaptiveRemote.Tests", "test\AdaptiveRemote.Tests\AdaptiveRemote.Tests.csproj", "{99181C45-EACC-45CE-87B3-20A4AA28E793}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AdaptiveRemote.Core.Tests", "test\AdaptiveRemote.Core.Tests\AdaptiveRemote.Core.Tests.csproj", "{99181C45-EACC-45CE-87B3-20A4AA28E793}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AdaptiveRemote.Tests", "test\AdaptiveRemote.Tests\AdaptiveRemote.Tests.csproj", "{C3D4E5F6-7890-ABCD-EF12-345678901234}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AdaptiveRemote.Core", "src\AdaptiveRemote.Core\AdaptiveRemote.Core.csproj", "{A1B2C3D4-E5F6-7890-ABCD-EF1234567890}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AdaptiveRemote.Electron", "src\AdaptiveRemote.Electron\AdaptiveRemote.Electron.csproj", "{B2C3D4E5-F678-90AB-CDEF-123456789012}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{02EA681E-C7D8-13C7-8484-4AC65E1B71E8}"
ProjectSection(SolutionItems) = preProject
Expand All @@ -31,10 +37,22 @@ Global
{99181C45-EACC-45CE-87B3-20A4AA28E793}.Debug|Any CPU.Build.0 = Debug|Any CPU
{99181C45-EACC-45CE-87B3-20A4AA28E793}.Release|Any CPU.ActiveCfg = Release|Any CPU
{99181C45-EACC-45CE-87B3-20A4AA28E793}.Release|Any CPU.Build.0 = Release|Any CPU
{C3D4E5F6-7890-ABCD-EF12-345678901234}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C3D4E5F6-7890-ABCD-EF12-345678901234}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C3D4E5F6-7890-ABCD-EF12-345678901234}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C3D4E5F6-7890-ABCD-EF12-345678901234}.Release|Any CPU.Build.0 = Release|Any CPU
{345B73FC-07F9-490F-B566-2677D10B1834}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{345B73FC-07F9-490F-B566-2677D10B1834}.Debug|Any CPU.Build.0 = Debug|Any CPU
{345B73FC-07F9-490F-B566-2677D10B1834}.Release|Any CPU.ActiveCfg = Release|Any CPU
{345B73FC-07F9-490F-B566-2677D10B1834}.Release|Any CPU.Build.0 = Release|Any CPU
{A1B2C3D4-E5F6-7890-ABCD-EF1234567890}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A1B2C3D4-E5F6-7890-ABCD-EF1234567890}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A1B2C3D4-E5F6-7890-ABCD-EF1234567890}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A1B2C3D4-E5F6-7890-ABCD-EF1234567890}.Release|Any CPU.Build.0 = Release|Any CPU
{B2C3D4E5-F678-90AB-CDEF-123456789012}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B2C3D4E5-F678-90AB-CDEF-123456789012}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B2C3D4E5-F678-90AB-CDEF-123456789012}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B2C3D4E5-F678-90AB-CDEF-123456789012}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down
2 changes: 2 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ templates for [bug reports](../.github/ISSUE_TEMPLATE/bug_report.md) and
- **Testing:**
- Add or update unit tests as appropriate for your changes.
- All tests must pass before your pull request will be considered.
- **Use Moq for mocking:** When creating test doubles, prefer using Moq over creating fake classes.
This keeps test code consistent and reduces the number of custom test helper classes.
- **Documentation:**
- Architecture and design notes are stored alongside implementations using `_doc_*.md` filenames so they surface at the top of each folder.
- Living documentation files should:
Expand Down
2 changes: 1 addition & 1 deletion src/AdaptiveRemote.Console/AdaptiveRemote.Console.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
</PropertyGroup>

<ItemGroup>
<Content Include="..\AdaptiveRemote\wwwroot\**\*.html;..\AdaptiveRemote\wwwroot\**\*.css;">
<Content Include="..\AdaptiveRemote.Core\wwwroot\**\*.html;..\AdaptiveRemote.Core\wwwroot\**\*.css;">
<Link>wwwroot\%(RecursiveDir)%(Filename)%(Extension)</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<Visible>true</Visible>
Expand Down
51 changes: 51 additions & 0 deletions src/AdaptiveRemote.Core/AdaptiveRemote.Core.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
<Project Sdk="Microsoft.NET.Sdk.Razor">

<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<RootNamespace>AdaptiveRemote</RootNamespace>
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like that the root namespace is still AdaptiveRemote and not AdaptiveRemote.Core. However, I think the generated Blazor component code is going to use AdaptiveRemote.Core for its namespaces. If it's possible, I want that to be configured as AdaptiveRemote namespace as well.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Already configured correctly - the Core csproj has <RootNamespace>AdaptiveRemote</RootNamespace> which means Blazor components in Components/ folder are generated with namespace AdaptiveRemote.Components, not AdaptiveRemote.Core.Components.

</PropertyGroup>

<ItemGroup>
<None Remove="Services\Conversation\static_grammar.xml" />
</ItemGroup>

<ItemGroup>
<EmbeddedResource Include="Services\Conversation\static_grammar.xml" />
</ItemGroup>

<ItemGroup>
<PackageReference Include="Azure.Extensions.AspNetCore.Configuration.Secrets" Version="1.3.2" />
<PackageReference Include="Azure.Identity" Version="1.11.4" />
<PackageReference Include="Azure.Monitor.OpenTelemetry.Exporter" Version="1.2.0" />
<PackageReference Include="I8Beef.TiVo" Version="1.0.0.14" />
<PackageReference Include="Microsoft.AspNetCore.Components.Web" Version="8.0.14" />
<PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.0" />
<PackageReference Include="Nerdbank.GitVersioning" Version="3.9.50">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="OpenTelemetry.Exporter.Console" Version="1.8.1" />
<PackageReference Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" Version="1.8.1" />
<PackageReference Include="OpenTelemetry.Extensions.Hosting" Version="1.8.1" />
<PackageReference Include="System.Configuration.ConfigurationManager" Version="8.0.0" />
<PackageReference Include="System.Text.Json" Version="8.0.5" />
</ItemGroup>

<ItemGroup>
<Compile Update="Logging\LoggingMessages.Designer.cs">
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
<DependentUpon>LoggingMessages.resx</DependentUpon>
</Compile>
</ItemGroup>

<ItemGroup>
<EmbeddedResource Update="Logging\LoggingMessages.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>LoggingMessages.Designer.cs</LastGenOutput>
</EmbeddedResource>
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;

namespace AdaptiveRemote.Configuration;

Expand All @@ -17,36 +16,18 @@ internal static IServiceCollection AddConversationServices(this IServiceCollecti
.AddScopedLifecycleService<ConversationController>()
.AddScoped<ISpeechRecognition, SpeechRecognition>()
.AddScoped<ISpeechSynthesis, SpeechSynthesis>()
.AddScoped<IGrammarProvider, StaticGrammarProvider>()
.AddScoped<ConversationStateMachine>()
.AddSingleton<ISpeechSynthesizer, SpeechSynthesizerWrapper>()
.AddSingleton<ISpeechRecognitionEngine, SpeechRecognitionEngineWrapper>()
.AddSingleton<IAudioConfigurationService, DefaultDeviceAudioConfiguration>()
.AddSingleton<IListeningController, ListeningController>()
.AddScoped(GetConversationViewModel);

internal static IServiceCollection AddConversationServices(this IServiceCollection services, IConfiguration config)
=> services
.AddConversationServices()
.OptionallyAddFakeSpeechRecognition(config)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OptionallyAddFakeSpeechRecognition and OptionallyAddSamplesRecorder shouldn't be removed. They're not related to the "Fakes" that were added for Electron. Rather, this is simulated speech and diagnostics that are used for testing without having to speak commands out loud.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 86c391a - restored FakeSpeechRecognitionEngine and SamplesRecorder support. The Windows project now registers FakeSpeechRecognitionEngine when Fake=true in config, and SamplesRecorder when RecordSamples=true, via the WindowsAcceleratedServices class.

.OptionallyAddSamplesRecorder(config)
.Configure<ConversationSettings>(config);

private static Models.ConversationView GetConversationViewModel(IServiceProvider provider)
{
IRemoteDefinitionService definition = provider.GetRequiredService<IRemoteDefinitionService>();
return definition.GetElement<Models.ConversationView>();
}

private static IServiceCollection OptionallyAddFakeSpeechRecognition(this IServiceCollection services, IConfiguration config)
=> config.GetValue<bool>(nameof(ConversationSettings.Fake)) == true
? services.AddSingleton<ISpeechRecognitionEngine, FakeSpeechRecognitionEngine>()
: services;

private static IServiceCollection OptionallyAddSamplesRecorder(this IServiceCollection services, IConfiguration config)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note to self: Find out where this went

=> config.GetValue<bool>(nameof(ConversationSettings.RecordSamples)) == false
? services
: services
.AddHostedService<SamplesRecorder>()
.AddSingleton<ILoggerProvider, SamplesRecorder.LoggerProvider>();
}
35 changes: 35 additions & 0 deletions src/AdaptiveRemote.Core/Configuration/CoreHostBuilderExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
using AdaptiveRemote.Models;
using AdaptiveRemote.Services;
using AdaptiveRemote.Services.Lifecycle;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

namespace AdaptiveRemote.Configuration;

/// <summary>
/// Public extension methods for configuring the cross-platform app
/// </summary>
public static class CoreHostBuilderExtensions
{
/// <summary>
/// Configures the core application services shared by all hosts
/// </summary>
public static IHostBuilder ConfigureCoreApp(this IHostBuilder hostBuilder)
=> hostBuilder
.ConfigureTelemetry()
.AddRemoteServices()
.AddBroadlinkSupport()
.AddTiVoSupport()
.AddConversationSystem()
.AddSystemWrapperServices();

/// <summary>
/// Adds the lifecycle view model and controller for hosting
/// </summary>
public static IServiceCollection AddLifecycleServices(this IServiceCollection services, LifecycleView lifecycleView, ILifecycleViewController lifecycleController)
{
services.AddSingleton(lifecycleView);
services.AddSingleton(lifecycleController);
return services;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ internal static IHostBuilder AddRemoteServices(this IHostBuilder builder)

internal static IServiceCollection AddRemoteServices(this IServiceCollection services)
=> services
.AddSingleton<IApplicationScopeFactory, BlazorWindowScopeFactory>()
.AddHostedService<ApplicationLifecycle>()
.AddScopedLifecycleService<LifecycleCommandService>()
.AddScoped<IRemoteDefinitionService, StaticCommandGroupProvider>()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ namespace AdaptiveRemote.Configuration;

internal static class SystemWrapperHostBuilderExtensions
{
public static IHostBuilder AddSystemWrapperServices(this IHostBuilder builder)
internal static IHostBuilder AddSystemWrapperServices(this IHostBuilder builder)
=> builder.ConfigureServices(services => services.AddSystemWrappers());

public static IServiceCollection AddSystemWrappers(this IServiceCollection services)
internal static IServiceCollection AddSystemWrappers(this IServiceCollection services)
=> services
.AddSingleton<INetworking, SystemNetWrapper>()
.AddSingleton<IFileSystem, SystemIOWrapper>();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System.Runtime.CompilerServices;

[assembly: InternalsVisibleTo("AdaptiveRemote.Tests")]
[assembly: InternalsVisibleTo("AdaptiveRemote")]
[assembly: InternalsVisibleTo("AdaptiveRemote.Core.Tests")]
[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c547cac37abd99c8db225ef2f6c8a3602f3b3606cc9891605d02baa56104f4cfc0734aa39b93bf7852f7d9266654753cc297e7d2edfe0bac1cdcf9f717241550e0a7b191195b7667bb4f64bcb8e2121380fd1d9d46ad2d92d2d15605093924cceaf74c4861eff62abf69b9291ed0a340e113be11e6a7d3113e92484cf7045cc7")]
[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")]
17 changes: 17 additions & 0 deletions src/AdaptiveRemote.Core/Services/Conversation/IGrammar.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
namespace AdaptiveRemote.Services.Conversation;

/// <summary>
/// Platform-independent grammar interface that abstracts System.Speech.Recognition.Grammar
/// </summary>
public interface IGrammar
{
/// <summary>
/// Gets or sets the name of the grammar.
/// </summary>
string Name { get; }

/// <summary>
/// Gets or sets whether the grammar is enabled for recognition.
/// </summary>
bool Enabled { get; set; }
}
12 changes: 12 additions & 0 deletions src/AdaptiveRemote.Core/Services/Conversation/IGrammarProvider.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
namespace AdaptiveRemote.Services.Conversation;

/// <summary>
/// Loader for Grammar objects
/// </summary>
public interface IGrammarProvider
{
/// <summary>
/// Load a grammar that supports the given kind of phrases
/// </summary>
IGrammar LoadGrammar(PhraseKinds phraseKind);
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
using System.Speech.Recognition;

namespace AdaptiveRemote.Services.Conversation;
namespace AdaptiveRemote.Services.Conversation;

/// <summary>
/// Think wrapper around System.Speech.Recognition.SpeechRecognitionEngine.
/// Thin wrapper around System.Speech.Recognition.SpeechRecognitionEngine.
/// </summary>
internal interface ISpeechRecognitionEngine
public interface ISpeechRecognitionEngine
{
/// <summary>
/// Raised when the SpeechRecognitionEngine receives input that matches any of its
Expand All @@ -22,12 +20,12 @@ internal interface ISpeechRecognitionEngine
/// <summary>
/// Synchronously loads a Grammar object.
/// </summary>
void LoadGrammar(Grammar grammar);
void LoadGrammar(IGrammar grammar);

/// <summary>
/// Unloads a specified Grammar object from the SpeechRecognitionEngine instance.
/// </summary>
void UnloadGrammar(Grammar grammar);
void UnloadGrammar(IGrammar grammar);

/// <summary>
/// Unloads all Grammar objects from the recognizer.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
namespace AdaptiveRemote.Services.Conversation;

[Flags]
internal enum PhraseKinds
public enum PhraseKinds
{
WakeWord = 1,
Commands = 2,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

public class RecognizedSpeechEventArgs : EventArgs
{
internal RecognizedSpeechEventArgs(IRecognizedSpeech result)
public RecognizedSpeechEventArgs(IRecognizedSpeech result)
{
Result = result;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using System.Speech.Recognition;
using System.Threading.Channels;
using System.Threading.Channels;
using AdaptiveRemote.Logging;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
Expand All @@ -21,7 +20,7 @@ internal class SpeechRecognition : ISpeechRecognition
private readonly IListeningController _listeningController;
private readonly ILogger<SpeechRecognition> _logger;

private readonly IReadOnlyDictionary<PhraseKinds, Grammar> _grammars;
private readonly IReadOnlyDictionary<PhraseKinds, IGrammar> _grammars;

public SpeechRecognition(IOptions<ConversationSettings> settings, ISpeechRecognitionEngine engine, IListeningController listeningController, IGrammarProvider grammarProvider, ILogger<SpeechRecognition> logger)
{
Expand All @@ -34,7 +33,7 @@ public SpeechRecognition(IOptions<ConversationSettings> settings, ISpeechRecogni

_grammars = GrammarKinds.ToDictionary(x => x, x => LoadGrammarIntoEngine(grammarProvider.LoadGrammar(x)));

Grammar LoadGrammarIntoEngine(Grammar grammar)
IGrammar LoadGrammarIntoEngine(IGrammar grammar)
{
grammar.Enabled = false;
_engine.LoadGrammar(grammar);
Expand All @@ -44,7 +43,7 @@ Grammar LoadGrammarIntoEngine(Grammar grammar)

void ISpeechRecognition.SetFilter(PhraseKinds filter)
{
foreach (KeyValuePair<PhraseKinds, Grammar> grammar in _grammars)
foreach (KeyValuePair<PhraseKinds, IGrammar> grammar in _grammars)
{
grammar.Value.Enabled = filter.HasFlag(grammar.Key);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
namespace AdaptiveRemote.Services;

internal interface ILifecycleActivity : IDisposable
public interface ILifecycleActivity : IDisposable
{
/// <summary>
/// The initialization status message associated with this activity.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
namespace AdaptiveRemote.Services;

internal interface ILifecycleViewController
public interface ILifecycleViewController
{
/// <summary>
/// Report an unrecoverable error that should stop the normal operation of
Expand Down
Loading
Loading