Skip to content

Commit

Permalink
Add the GetStateAsync() API and the OnStateChanged.
Browse files Browse the repository at this point in the history
  • Loading branch information
GillesTourreau committed Jun 13, 2024
1 parent eb9baab commit 371175d
Show file tree
Hide file tree
Showing 18 changed files with 558 additions and 29 deletions.
7 changes: 7 additions & 0 deletions docs/Components/CallComposite.md
Original file line number Diff line number Diff line change
Expand Up @@ -105,12 +105,19 @@ To raise the hand during a call, call the `RaiseHandAsync()` method.

To lower the hand during a call, call the `LowerHandAsync()` method.

### Gets the state of the CallAdapter
To retrieve the current state of the `CallAdapter`, call the `GetStateAsync()` method.

You can also subscribe to the `OnStateChanged` event which is raised when the state of the `CallAdapter` is changed.

### Events
You can subsribe to the following asynchronous events using a standard delegate method:
- `OnCallEnded`: Occurs then the call is ended.
- `OnMicrophoneMuteChanged`: Occurs when the microphone of a participant is mute/unmute.
- `OnParticipantJoined`: Occurs when a participant join the call.
- `OnParticipantLeft`: Occurs when a participant leave the call.
- `OnStateChanged`: Occurs when the `CallAdapterState` has been changed.
You can also call manually the `GetStateAsync()` method to retrieve the last state of the `CallAdapter`

### Dispose the resources
It is recommanded to implement the `IAsyncDisposable` method in the class which create
Expand Down
32 changes: 29 additions & 3 deletions docs/PortedApi.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ which has been ported to this library.

| Method | Available | Remarks |
|-------------------------------|------------|------------------------------------------------------|
| onStateChange | TODO | |
| offStateChange | TODO | |
| getState | TODO | |
| onStateChange | **Done** | |
| offStateChange | **Done** | |
| getState | Partially | Need to fully wrap the CallAdapterState object |
| dispose | **Done** | |
| holdCall (Beta) | No | Currently in beta in Microsoft library |
| joinCall (Deprecated) | No | Deprecated |
Expand Down Expand Up @@ -68,3 +68,29 @@ which has been ported to this library.
| transferAccepted | TODO | |
| capabilitiesChanged | TODO | |
| spotlightChanged | TODO | |


### CallAdapterState
| Name | Available | Remarks |
|--------------------------------------|-----------|---------|
| userId | **Done** | |
| displayName | **Done** | |
| call | TODO | |
| targetCallees | TODO | |
| devices | TODO | |
| endedCall | TODO | |
| isTeamsCall | **Done** | |
| isRoomsCall | **Done** | |
| latestErrors | TODO | |
| alternateCallerId | TODO | |
| environmentInfo | TODO | |
| cameraStatus | **Done** | |
| videoBackgroundImages | TODO | |
| onResolveVideoEffectDependency | TODO | |
| selectedVideoBackgroundEffect | TODO | |
| acceptedTransferCallState | TODO | |
| hideAttendeeNames | TODO | |
| sounds | TODO | |
| isLocalPreviewMicrophoneEnabled | **Done** | |
| page | **Done** | |
| unsupportedBrowserVersionsAllowed | TODO | |
62 changes: 41 additions & 21 deletions src/Communication.UI.Blazor/Calling/CallAdapter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,42 @@ internal CallAdapter(IJSObjectReference module)
/// <inheritdoc />
public event AsyncEventHandler<RemoteParticipantLeftEvent>? OnParticipantLeft;

/// <inheritdoc />
public event AsyncEventHandler<StateChangedEvent>? OnStateChanged;

internal Guid Id { get; }

internal IJSObjectReference Module { get; }

/// <inheritdoc />
public void Dispose()
{
if (this.callbackEvent != null)
{
this.callbackEvent.Dispose();
this.callbackEvent = null;
}
}

/// <inheritdoc />
public async ValueTask DisposeAsync()
{
if (this.callbackEvent != null)
{
await this.Module.InvokeVoidAsync("dispose", this.Id);
}

this.Dispose();
}

/// <inheritdoc />
public async Task<CallAdapterState> GetStateAsync()
{
ObjectDisposedException.ThrowIf(this.callbackEvent is null, this);

return await this.Module.InvokeAsync<CallAdapterState>("adapterGetState", this.Id);
}

/// <inheritdoc />
public async Task JoinCallAsync(JoinCallOptions options)
{
Expand Down Expand Up @@ -130,27 +162,6 @@ public async Task UnmuteAsync()
await this.Module.InvokeVoidAsync("adapterUnmute", this.Id);
}

/// <inheritdoc />
public async ValueTask DisposeAsync()
{
if (this.callbackEvent != null)
{
await this.Module.InvokeVoidAsync("dispose", this.Id);
}

this.Dispose();
}

/// <inheritdoc />
public void Dispose()
{
if (this.callbackEvent != null)
{
this.callbackEvent.Dispose();
this.callbackEvent = null;
}
}

internal async Task InitializeAsync(CallAdapterArgs args)
{
await this.Module.InvokeVoidAsync("createCallAdapter", this.Id, args, this.callbackEvent!.Reference);
Expand Down Expand Up @@ -218,6 +229,15 @@ public async Task OnParticipantsLeftAsync(RemoteParticipant[] removed)
}
}
}

[JSInvokable]
public async Task OnStateChangedAsync(CallAdapterState state)
{
if (this.owner.OnStateChanged is not null)
{
await this.owner.OnStateChanged(new StateChangedEvent(state));
}
}
}
}
}
83 changes: 83 additions & 0 deletions src/Communication.UI.Blazor/Calling/CallAdapterState.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
//-----------------------------------------------------------------------
// <copyright file="CallAdapterState.cs" company="P.O.S Informatique">
// Copyright (c) P.O.S Informatique. All rights reserved.
// </copyright>
//-----------------------------------------------------------------------

namespace PosInformatique.Azure.Communication.UI.Blazor
{
using System.Text.Json.Serialization;

/// <summary>
/// Represents the current <see cref="CallAdapter"/> state.
/// </summary>
public class CallAdapterState
{
/// <summary>
/// Initializes a new instance of the <see cref="CallAdapterState"/> class.
/// </summary>
/// <param name="userId">The <see cref="CommunicationUserKind"/> of the current user.</param>
public CallAdapterState(CommunicationUserKind userId)
{
this.UserId = userId;
}

/// <summary>
/// Gets the <see cref="CommunicationUserKind"/> of the current user.
/// </summary>
[JsonPropertyName("userId")]
[JsonPropertyOrder(1)]
public CommunicationUserKind UserId { get; }

/// <summary>
/// Gets the display name of the current user.
/// </summary>
[JsonPropertyName("displayName")]
[JsonPropertyOrder(2)]
[JsonInclude]
public string? DisplayName { get; init; }

/// <summary>
/// Gets a value indicating whether if the current call is Teams call.
/// </summary>
[JsonPropertyName("isTeamsCall")]
[JsonPropertyOrder(7)]
[JsonInclude]
public bool IsTeamsCall { get; init; }

/// <summary>
/// Gets a value indicating whether if the call is a rooms call.
/// </summary>
[JsonPropertyName("isRoomsCall")]
[JsonPropertyOrder(8)]
[JsonInclude]
public bool IsRoomsCall { get; init; }

/// <summary>
/// Gets a value indicating whether the local participant's camera is on.
/// To be used when creating a custom control bar with the CallComposite.
/// </summary>
[JsonPropertyName("cameraStatus")]
[JsonPropertyOrder(12)]
[JsonConverter(typeof(JsonStringEnumConverter))]
[JsonInclude]
public CameraStatus? CameraStatus { get; init; }

/// <summary>
/// Gets a value indicating whether if the microphone is enabled.
/// </summary>
[JsonPropertyName("isLocalPreviewMicrophoneEnabled")]
[JsonPropertyOrder(50)]
[JsonInclude]
public bool IsLocalPreviewMicrophoneEnabled { get; init; }

/// <summary>
/// Gets the current page display on the <see cref="CallComposite"/>.
/// </summary>
[JsonPropertyName("page")]
[JsonPropertyOrder(51)]
[JsonConverter(typeof(JsonCamelCaseStringEnumConverter))]
[JsonInclude]
public CallCompositePage Page { get; init; }
}
}
24 changes: 24 additions & 0 deletions src/Communication.UI.Blazor/Calling/CallComposite.razor.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,11 @@ export async function createCallAdapter(id, args, eventCallback) {
return eventCallback.invokeMethodAsync('OnParticipantsLeftAsync', event.removed.map(createRemoteParticipant));
});

adapter.onStateChange((state) => {
console.log(state);
return eventCallback.invokeMethodAsync('OnStateChangedAsync', createState(state));
});

registerAdapter(id, adapter);
}

Expand All @@ -48,6 +53,13 @@ export function initializeControl(divElement, adapterId, callControls) {
createRoot(divElement).render(element);
}

export function adapterGetState(id) {

const adapter = getAdapter(id);

return createState(adapter.getState());
}

export function adapterJoinCall(id, options) {

const adapter = getAdapter(id);
Expand Down Expand Up @@ -169,6 +181,18 @@ function createRemoteParticipant(remoteParticipant) {
};
}

function createState(state) {
return {
cameraStatus: state.cameraStatus,
displayName: state.displayName,
isLocalPreviewMicrophoneEnabled: state.isLocalPreviewMicrophoneEnabled,
isRoomsCall: state.isRoomsCall,
isTeamsCall: state.isTeamsCall,
page: state.page,
userId: state.userId,
};
}

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

namespace PosInformatique.Azure.Communication.UI.Blazor
{
/// <summary>
/// Major UI screens shown in the <see cref="CallComposite"/>.
/// </summary>
public enum CallCompositePage
{
/// <summary>
/// The teams meeting is denied.
/// </summary>
AccessDeniedTeamsMeeting,

/// <summary>
/// Call is ongoing.
/// </summary>
Call,

/// <summary>
/// Configuration step page.
/// </summary>
Configuration,

/// <summary>
/// The call is currently hold.
/// </summary>
Hold,

/// <summary>
/// The join call has been failed to network issues.
/// </summary>
JoinCallFailedDueToNoNetwork,

/// <summary>
/// The user has left the call.
/// </summary>
LeftCall,

/// <summary>
/// The user is currently leaving the call.
/// </summary>
Leaving,

/// <summary>
/// The user is waiting in the lobby.
/// </summary>
Lobby,

/// <summary>
/// The user has been removed from the call.
/// </summary>
RemovedFromCall,

/// <summary>
/// The <see cref="CallComposite"/> can not be loaded because the current environment is not supported.
/// </summary>
UnsupportedEnvironment,

/// <summary>
/// Transferring the current call.
/// </summary>
Transferring,
}
}
24 changes: 24 additions & 0 deletions src/Communication.UI.Blazor/Calling/CameraStatus.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
//-----------------------------------------------------------------------
// <copyright file="CameraStatus.cs" company="P.O.S Informatique">
// Copyright (c) P.O.S Informatique. All rights reserved.
// </copyright>
//-----------------------------------------------------------------------

namespace PosInformatique.Azure.Communication.UI.Blazor
{
/// <summary>
/// Represents the camera status.
/// </summary>
public enum CameraStatus
{
/// <summary>
/// The camera is off.
/// </summary>
Off,

/// <summary>
/// The camera is on.
/// </summary>
On,
}
}
Loading

0 comments on commit 371175d

Please sign in to comment.