Skip to content

Commit

Permalink
Add the interface ICallAdapter.
Browse files Browse the repository at this point in the history
  • Loading branch information
GillesTourreau committed Jun 6, 2024
1 parent 9bca679 commit 81dab0e
Show file tree
Hide file tree
Showing 6 changed files with 112 additions and 60 deletions.
30 changes: 18 additions & 12 deletions docs/Components/CallComposite.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ To use the component:
builder.Services.AddCalling();
```

- Inject the `ICallingService` dependency a use it to create an instance of `CallAdapter`.
- Add the `CallComposite` component and bind the `Adapter` property with the `CallAdapter` previously created.
- Inject the `ICallingService` dependency a use it to create an instance of `ICallAdapter`.
- Add the `CallComposite` component and bind the `Adapter` property with the `ICallAdapter` previously created.

Example:
```razor
Expand All @@ -27,7 +27,7 @@ Example:
@code
{
private CallAdapter? callAdapter;
private ICallAdapter? callAdapter;
private async Task LoadAsync()
{
Expand Down Expand Up @@ -63,13 +63,13 @@ Example:
}
```

You can manage the `CallComposite` component using the `CallAdapter` associated. For example, you can
You can manage the `CallComposite` component using the `ICallAdapter` associated. For example, you can
subscribe to different events using a simple delegate.

### Join/Leave the call
After the `CallAdapter` has been associated to the `CallComposite` component
After the `ICallAdapter` has been associated to the `CallComposite` component
(or after leaving a call), it is possible to join the call
by calling the `JoinCall()` method on the `CallAdapter`.
by calling the `JoinCall()` method on the `ICallAdapter`.
You can define if the camera and/or the microphone have to be activated.

```csharp
Expand All @@ -85,18 +85,18 @@ private async Task JoinCallAsync()
}
```

To leave the call, call the `LeaveCallAsync()` method on the `CallAdapter`. This method
To leave the call, call the `LeaveCallAsync()` method on the `ICallAdapter`. This method
take a boolean parameter `forEveryone` to remove all participants when leaving.

### Start/Stop screen share
To start sharing the screen on the current device, call the `StartScreenShare()` method on the `CallAdapter`.
To start sharing the screen on the current device, call the `StartScreenShare()` method on the `ICallAdapter`.

To stop sharing the screen on the current device, call the `StopScreenShare()` method on the `CallAdapter`.
To stop sharing the screen on the current device, call the `StopScreenShare()` method on the `ICallAdapter`.

### Mute/Unmute
To mute the microphone of the current user, call the `MuteAsync()` method on the `CallAdapter`.
To mute the microphone of the current user, call the `MuteAsync()` method on the `ICallAdapter`.

To unmute the microphone of the current user, call the `UnmuteAsync()` method on the `CallAdapter`.
To unmute the microphone of the current user, call the `UnmuteAsync()` method on the `ICallAdapter`.

### Events
You can subsribe to the following asynchronous events using a standard delegate method:
Expand All @@ -107,4 +107,10 @@ You can subsribe to the following asynchronous events using a standard delegate

### Dispose the resources
It is recommanded to implement the `IAsyncDisposable` method in the class which create
and manage the `CallAdapter` instance.
and manage the `ICallAdapter` instance.

### Unit tests
The `ICallingService.CreateAdapterAsync()` method returns an instance of `ICallAdapter`
implemented by the `CallAdapter`. By returning interface implementation, developers
have no excuses to perform some units in their code by mocking the `ICallingService`
and `ICallAdapter` interfaces.
56 changes: 11 additions & 45 deletions src/Communication.UI.Blazor/Calling/CallAdapter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ namespace PosInformatique.Azure.Communication.UI.Blazor
/// <summary>
/// An adapter interface specific for Azure Communication identity which extends <see cref="CommonCallAdapter"/>.
/// </summary>
public class CallAdapter : CommonCallAdapter, IDisposable, IAsyncDisposable
public class CallAdapter : CommonCallAdapter, ICallAdapter, IDisposable
{
private readonly Guid id;

Expand All @@ -31,93 +31,59 @@ internal CallAdapter(IJSObjectReference module)
this.callbackEvent = new CallbackEvent(this);
}

/// <summary>
/// Occurs when the call is ended.
/// </summary>
/// <inheritdoc />
public event AsyncEventHandler<CallEndedEvent>? OnCallEnded;

/// <summary>
/// Occurs when the microphone is muted/unmuted on a participant.
/// </summary>
/// <inheritdoc />
public event AsyncEventHandler<MicrophoneMuteChangedEvent>? OnMicrophoneMuteChanged;

/// <summary>
/// Occurs when a participant join the call.
/// </summary>
/// <inheritdoc />
public event AsyncEventHandler<RemoteParticipantJoinedEvent>? OnParticipantJoined;

/// <summary>
/// Occurs when a participant leave the call.
/// </summary>
/// <inheritdoc />
public event AsyncEventHandler<RemoteParticipantLeftEvent>? OnParticipantLeft;

/// <summary>
/// Join an existing call.
/// </summary>
/// <param name="options">Options of the call.</param>
/// <returns>A <see cref="Task"/> that represents the asynchronous invocation.</returns>
/// <exception cref="ObjectDisposedException">If the <see cref="CallAdapter"/> has already been disposed.</exception>
/// <inheritdoc />
public async Task JoinCallAsync(JoinCallOptions options)
{
ObjectDisposedException.ThrowIf(this.callbackEvent is null, this);

await this.module.InvokeVoidAsync("adapterJoinCall", this.id, options);
}

/// <summary>
/// Leave the call.
/// </summary>
/// <param name="forEveryone">Whether to remove all participants when leaving.</param>
/// <returns>A <see cref="Task"/> that represents the asynchronous invocation.</returns>
/// <exception cref="ObjectDisposedException">If the <see cref="CallAdapter"/> has already been disposed.</exception>
/// <inheritdoc />
public async Task LeaveCallAsync(bool forEveryone)
{
ObjectDisposedException.ThrowIf(this.callbackEvent is null, this);

await this.module.InvokeVoidAsync("adapterLeaveCall", this.id, forEveryone);
}

/// <summary>
/// Mute the current user during the call or disable microphone locally.
/// </summary>
/// <returns>A <see cref="Task"/> that represents the asynchronous invocation.</returns>
/// <exception cref="ObjectDisposedException">If the <see cref="CallAdapter"/> has already been disposed.</exception>
/// <inheritdoc />
public async Task MuteAsync()
{
ObjectDisposedException.ThrowIf(this.callbackEvent is null, this);

await this.module.InvokeVoidAsync("adapterMute", this.id);
}

/// <summary>
/// Unmute the current user during the call or enable microphone locally.
/// </summary>
/// <returns>A <see cref="Task"/> that represents the asynchronous invocation.</returns>
/// <exception cref="ObjectDisposedException">If the <see cref="CallAdapter"/> has already been disposed.</exception>
/// <inheritdoc />
public async Task UnmuteAsync()
{
ObjectDisposedException.ThrowIf(this.callbackEvent is null, this);

await this.module.InvokeVoidAsync("adapterUnmute", this.id);
}

/// <summary>
/// Start sharing the screen during a call.
/// </summary>
/// <returns>A <see cref="Task"/> that represents the asynchronous invocation.</returns>
/// <exception cref="ObjectDisposedException">If the <see cref="CallAdapter"/> has already been disposed.</exception>
/// <inheritdoc />
public async Task StartScreenShareAsync()
{
ObjectDisposedException.ThrowIf(this.callbackEvent is null, this);

await this.module.InvokeVoidAsync("adapterStartScreenShare", this.id);
}

/// <summary>
/// Stop sharing the screen.
/// </summary>
/// <returns>A <see cref="Task"/> that represents the asynchronous invocation.</returns>
/// <exception cref="ObjectDisposedException">If the <see cref="CallAdapter"/> has already been disposed.</exception>
/// <inheritdoc />
public async Task StopScreenShareAsync()
{
ObjectDisposedException.ThrowIf(this.callbackEvent is null, this);
Expand Down
2 changes: 1 addition & 1 deletion src/Communication.UI.Blazor/Calling/CallingService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ public async ValueTask DisposeAsync()
}

/// <inheritdoc />
public async Task<CallAdapter> CreateAdapterAsync(CallAdapterArgs args)
public async Task<ICallAdapter> CreateAdapterAsync(CallAdapterArgs args)
{
await this.EnsureModuleLoadAsync();

Expand Down
80 changes: 80 additions & 0 deletions src/Communication.UI.Blazor/Calling/ICallAdapter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
//-----------------------------------------------------------------------
// <copyright file="ICallAdapter.cs" company="P.O.S Informatique">
// Copyright (c) P.O.S Informatique. All rights reserved.
// </copyright>
//-----------------------------------------------------------------------

namespace PosInformatique.Azure.Communication.UI.Blazor
{
using System.Threading.Tasks;

/// <summary>
/// Adapter which allows to manage the <see cref="CallComposite"/> component.
/// </summary>
public interface ICallAdapter : IAsyncDisposable
{
/// <summary>
/// Occurs when the call is ended.
/// </summary>
event AsyncEventHandler<CallEndedEvent>? OnCallEnded;

/// <summary>
/// Occurs when the microphone is muted/unmuted on a participant.
/// </summary>
event AsyncEventHandler<MicrophoneMuteChangedEvent>? OnMicrophoneMuteChanged;

/// <summary>
/// Occurs when a participant join the call.
/// </summary>
event AsyncEventHandler<RemoteParticipantJoinedEvent>? OnParticipantJoined;

/// <summary>
/// Occurs when a participant leave the call.
/// </summary>
event AsyncEventHandler<RemoteParticipantLeftEvent>? OnParticipantLeft;

/// <summary>
/// Join an existing call.
/// </summary>
/// <param name="options">Options of the call.</param>
/// <returns>A <see cref="Task"/> that represents the asynchronous invocation.</returns>
/// <exception cref="ObjectDisposedException">If the <see cref="CallAdapter"/> has already been disposed.</exception>
Task JoinCallAsync(JoinCallOptions options);

/// <summary>
/// Leave the call.
/// </summary>
/// <param name="forEveryone">Whether to remove all participants when leaving.</param>
/// <returns>A <see cref="Task"/> that represents the asynchronous invocation.</returns>
/// <exception cref="ObjectDisposedException">If the <see cref="CallAdapter"/> has already been disposed.</exception>
Task LeaveCallAsync(bool forEveryone);

/// <summary>
/// Mute the current user during the call or disable microphone locally.
/// </summary>
/// <returns>A <see cref="Task"/> that represents the asynchronous invocation.</returns>
/// <exception cref="ObjectDisposedException">If the <see cref="CallAdapter"/> has already been disposed.</exception>
Task MuteAsync();

/// <summary>
/// Start sharing the screen during a call.
/// </summary>
/// <returns>A <see cref="Task"/> that represents the asynchronous invocation.</returns>
/// <exception cref="ObjectDisposedException">If the <see cref="CallAdapter"/> has already been disposed.</exception>
Task StartScreenShareAsync();

/// <summary>
/// Stop sharing the screen.
/// </summary>
/// <returns>A <see cref="Task"/> that represents the asynchronous invocation.</returns>
/// <exception cref="ObjectDisposedException">If the <see cref="CallAdapter"/> has already been disposed.</exception>
Task StopScreenShareAsync();

/// <summary>
/// Unmute the current user during the call or enable microphone locally.
/// </summary>
/// <returns>A <see cref="Task"/> that represents the asynchronous invocation.</returns>
/// <exception cref="ObjectDisposedException">If the <see cref="CallAdapter"/> has already been disposed.</exception>
Task UnmuteAsync();
}
}
2 changes: 1 addition & 1 deletion src/Communication.UI.Blazor/Calling/ICallingService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,6 @@ public interface ICallingService
/// <param name="args">Parameters of the <see cref="CallAdapter"/> to create.</param>
/// <returns>A new instance of the <see cref="CallAdapter"/> which can be use by a <see cref="CallComposite"/> using the <see cref="CallComposite.Adapter"/>
/// property.</returns>
Task<CallAdapter> CreateAdapterAsync(CallAdapterArgs args);
Task<ICallAdapter> CreateAdapterAsync(CallAdapterArgs args);
}
}
2 changes: 1 addition & 1 deletion tests/Communication.UI.Blazor.Demo/Pages/Home.razor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ public partial class Home
{
private readonly List<string> log;

private CallAdapter? callAdapter;
private ICallAdapter? callAdapter;

private string userId;

Expand Down

0 comments on commit 81dab0e

Please sign in to comment.