diff --git a/docs/Components/CallComposite.md b/docs/Components/CallComposite.md
index fb771d5..c12e659 100644
--- a/docs/Components/CallComposite.md
+++ b/docs/Components/CallComposite.md
@@ -92,6 +92,9 @@ To mute the microphone of the current user, call the `MuteAsync()` method on the
To unmute the microphone of the current user, call the `UnmuteAsync()` method on the `ICallAdapter`.
+### Gets available cameras
+To retrieve the list of available camera call the `QueryCamerasAsync()` method.
+
### Events
You can subsribe to the following asynchronous events using a standard delegate method:
- `OnCallEnded`: Occurs then the call is ended.
diff --git a/docs/PortedApi.md b/docs/PortedApi.md
index 1f0caab..f25b3ad 100644
--- a/docs/PortedApi.md
+++ b/docs/PortedApi.md
@@ -14,24 +14,24 @@ which has been ported to this library.
| offStateChange | TODO | |
| getState | TODO | |
| dispose | **Done** | |
-| holdCall (Beta) | No | Currently in beta |
+| holdCall (Beta) | No | Currently in beta in Microsoft library |
| joinCall (Deprecated) | No | Deprecated |
| joinCall | Partially | Need to wrap the Call returned object |
| leaveCall | **Done** | |
-| resumeCall (Beta) | No | Currently in beta |
+| resumeCall (Beta) | No | Currently in beta in Microsoft library |
| startCamera | TODO | |
| stopCamera | TODO | |
| mute | **Done** | |
| unmute | **Done** | |
-| startCall (Beta) | No | Currently in beta |
+| startCall (Beta) | No | Currently in beta in Microsoft library |
| startScreenShare | **Done** | |
| stopScreenShare | **Done** | |
-| addParticipant (Beta) | No | Currently in beta |
+| addParticipant (Beta) | No | Currently in beta in Microsoft library |
| removeParticipant | TODO | |
| createStreamView | TODO | |
| disposeStreamView | TODO | |
| askDevicePermission | TODO | |
-| queryCameras | TODO | |
+| queryCameras | **Done** | |
| queryMicrophones | TODO | |
| querySpeakers | TODO | |
| setCamera | TODO | |
diff --git a/src/Communication.UI.Blazor/Calling/CallAdapter.cs b/src/Communication.UI.Blazor/Calling/CallAdapter.cs
index 7bb347b..7e344b6 100644
--- a/src/Communication.UI.Blazor/Calling/CallAdapter.cs
+++ b/src/Communication.UI.Blazor/Calling/CallAdapter.cs
@@ -90,6 +90,14 @@ public async Task StopScreenShareAsync()
await this.Module.InvokeVoidAsync("adapterStopScreenShare", this.Id);
}
+ ///
+ public async Task> QueryCamerasAsync()
+ {
+ ObjectDisposedException.ThrowIf(this.callbackEvent is null, this);
+
+ return await this.Module.InvokeAsync>("adapterQueryCameras", this.Id);
+ }
+
///
public async ValueTask DisposeAsync()
{
diff --git a/src/Communication.UI.Blazor/Calling/CallComposite.razor.js b/src/Communication.UI.Blazor/Calling/CallComposite.razor.js
index 5d1747e..f4d1e86 100644
--- a/src/Communication.UI.Blazor/Calling/CallComposite.razor.js
+++ b/src/Communication.UI.Blazor/Calling/CallComposite.razor.js
@@ -69,6 +69,15 @@ export async function adapterMute(id) {
await adapter.mute();
}
+export async function adapterQueryCameras(id) {
+
+ const adapter = getAdapter(id);
+
+ var cameras = await adapter.queryCameras();
+
+ return cameras.map(createCameraDevice)
+}
+
export async function adapterUnmute(id) {
const adapter = getAdapter(id);
@@ -117,4 +126,12 @@ function createRemoteParticipant(remoteParticipant) {
identifier: remoteParticipant.identifier,
displayName: remoteParticipant.displayName,
};
+}
+
+function createCameraDevice(cameraDevice) {
+ return {
+ name: cameraDevice.name,
+ id: cameraDevice.id,
+ deviceType: cameraDevice.deviceType,
+ };
}
\ No newline at end of file
diff --git a/src/Communication.UI.Blazor/Calling/ICallAdapter.cs b/src/Communication.UI.Blazor/Calling/ICallAdapter.cs
index 6948d21..a09f09e 100644
--- a/src/Communication.UI.Blazor/Calling/ICallAdapter.cs
+++ b/src/Communication.UI.Blazor/Calling/ICallAdapter.cs
@@ -56,6 +56,13 @@ public interface ICallAdapter : IAsyncDisposable
/// If the has already been disposed.
Task MuteAsync();
+ ///
+ /// Query for available camera devices.
+ ///
+ /// A that represents the asynchronous invocation which contains the camera devices available.
+ /// If the has already been disposed.
+ Task> QueryCamerasAsync();
+
///
/// Start sharing the screen during a call.
///
diff --git a/src/Communication.UI.Blazor/Calling/VideoDeviceInfo.cs b/src/Communication.UI.Blazor/Calling/VideoDeviceInfo.cs
new file mode 100644
index 0000000..58bb5c9
--- /dev/null
+++ b/src/Communication.UI.Blazor/Calling/VideoDeviceInfo.cs
@@ -0,0 +1,51 @@
+//-----------------------------------------------------------------------
+//
+// Copyright (c) P.O.S Informatique. All rights reserved.
+//
+//-----------------------------------------------------------------------
+
+namespace PosInformatique.Azure.Communication.UI.Blazor
+{
+ using System.Text.Json.Serialization;
+
+ ///
+ /// Information about a camera device.
+ ///
+ public class VideoDeviceInfo
+ {
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The id of this video device.
+ /// The name of this video device.
+ /// The video device type.
+ public VideoDeviceInfo(string id, string name, VideoDeviceType deviceType)
+ {
+ this.Id = id;
+ this.Name = name;
+ this.DeviceType = deviceType;
+ }
+
+ ///
+ /// Gets the name of this video device.
+ ///
+ [JsonPropertyName("name")]
+ [JsonPropertyOrder(1)]
+ public string Name { get; }
+
+ ///
+ /// Gets the id of this video device.
+ ///
+ [JsonPropertyName("id")]
+ [JsonPropertyOrder(2)]
+ public string Id { get; }
+
+ ///
+ /// Gets the video device type.
+ ///
+ [JsonPropertyName("deviceType")]
+ [JsonPropertyOrder(3)]
+ [JsonConverter(typeof(JsonStringEnumConverter))]
+ public VideoDeviceType DeviceType { get; }
+ }
+}
diff --git a/src/Communication.UI.Blazor/Calling/VideoDeviceType.cs b/src/Communication.UI.Blazor/Calling/VideoDeviceType.cs
new file mode 100644
index 0000000..31cf51e
--- /dev/null
+++ b/src/Communication.UI.Blazor/Calling/VideoDeviceType.cs
@@ -0,0 +1,39 @@
+//-----------------------------------------------------------------------
+//
+// Copyright (c) P.O.S Informatique. All rights reserved.
+//
+//-----------------------------------------------------------------------
+
+namespace PosInformatique.Azure.Communication.UI.Blazor
+{
+ ///
+ /// Type of a video device.
+ ///
+ public enum VideoDeviceType
+ {
+ ///
+ /// The type of the device can not be determined.
+ ///
+ Unknown = 0,
+
+ ///
+ /// The camera is simple USB camera.
+ ///
+ UsbCamera = 1,
+
+ ///
+ /// The camera is a capture adapter.
+ ///
+ CaptureAdapter = 2,
+
+ ///
+ /// The camera is virtual (simulated by the host device).
+ ///
+ Virtual = 3,
+
+ ///
+ /// The camera is a screen sharing.
+ ///
+ ScreenSharing = 4,
+ }
+}
diff --git a/tests/Communication.UI.Blazor.Demo/Pages/Home.razor b/tests/Communication.UI.Blazor.Demo/Pages/Home.razor
index 38cf8d2..483a7d7 100644
--- a/tests/Communication.UI.Blazor.Demo/Pages/Home.razor
+++ b/tests/Communication.UI.Blazor.Demo/Pages/Home.razor
@@ -60,7 +60,15 @@
-
+
+
+
+
cameras;
+
private string userId;
private string groupIdLocator;
@@ -39,6 +41,8 @@ public Home()
this.groupIdLocator = "76FC6C87-2D4C-49C8-B909-7E3819A88621";
this.displayName = "John Doe";
+ this.cameras = [];
+
this.cameraButton = true;
this.devicesButton = true;
this.endCallButton = true;
@@ -122,6 +126,8 @@ private async Task LoadAsync()
this.callAdapter.OnMicrophoneMuteChanged += this.OnMicrophoneMuteChanged;
this.callAdapter.OnParticipantJoined += this.OnParticipantJoined;
this.callAdapter.OnParticipantLeft += this.OnParticipantLeft;
+
+ this.cameras = await this.callAdapter.QueryCamerasAsync();
}
private async Task MuteAsync()
diff --git a/tests/Communication.UI.Blazor.Tests/Calling/VideoDeviceInfoTest.cs b/tests/Communication.UI.Blazor.Tests/Calling/VideoDeviceInfoTest.cs
new file mode 100644
index 0000000..a816eba
--- /dev/null
+++ b/tests/Communication.UI.Blazor.Tests/Calling/VideoDeviceInfoTest.cs
@@ -0,0 +1,47 @@
+//-----------------------------------------------------------------------
+//
+// Copyright (c) P.O.S Informatique. All rights reserved.
+//
+//-----------------------------------------------------------------------
+
+namespace PosInformatique.Azure.Communication.UI.Blazor.Tests
+{
+ public class VideoDeviceInfoTest
+ {
+ [Fact]
+ public void Constructor()
+ {
+ var deviceInfo = new VideoDeviceInfo("The id", "The name", VideoDeviceType.CaptureAdapter);
+
+ deviceInfo.DeviceType.Should().Be(VideoDeviceType.CaptureAdapter);
+ deviceInfo.Id.Should().Be("The id");
+ deviceInfo.Name.Should().Be("The name");
+ }
+
+ [Fact]
+ public void Serialization()
+ {
+ var deviceInfo = new VideoDeviceInfo("The id", "The name", VideoDeviceType.CaptureAdapter);
+
+ deviceInfo.Should().BeJsonSerializableInto(new
+ {
+ name = "The name",
+ id = "The id",
+ deviceType = "CaptureAdapter",
+ });
+ }
+
+ [Fact]
+ public void Deserialization()
+ {
+ var json = new
+ {
+ name = "The name",
+ id = "The id",
+ deviceType = "CaptureAdapter",
+ };
+
+ json.Should().BeJsonDeserializableInto(new VideoDeviceInfo("The id", "The name", VideoDeviceType.CaptureAdapter));
+ }
+ }
+}
\ No newline at end of file