start and stop recording
This commit is contained in:
parent
e388c18e03
commit
3129d90318
@ -31,6 +31,7 @@ class VideoCall {
|
|||||||
this.onCreateLocalVideoStream = options.onCreateLocalVideoStream;
|
this.onCreateLocalVideoStream = options.onCreateLocalVideoStream;
|
||||||
this.remoteParticipantStateChanged = options.remoteParticipantStateChanged;
|
this.remoteParticipantStateChanged = options.remoteParticipantStateChanged;
|
||||||
this.remoteVideoIsAvailableChanged = options.remoteVideoIsAvailableChanged;
|
this.remoteVideoIsAvailableChanged = options.remoteVideoIsAvailableChanged;
|
||||||
|
this.onGetServerCallID = options.onGetServerCallID;
|
||||||
|
|
||||||
const tokenCredential = new AzureCommunicationTokenCredential(userAccessToken);
|
const tokenCredential = new AzureCommunicationTokenCredential(userAccessToken);
|
||||||
|
|
||||||
@ -58,15 +59,10 @@ class VideoCall {
|
|||||||
const localVideoStream = await this.createLocalVideoStream();
|
const localVideoStream = await this.createLocalVideoStream();
|
||||||
const videoOptions = localVideoStream ? { localVideoStreams: [localVideoStream] } : undefined;
|
const videoOptions = localVideoStream ? { localVideoStreams: [localVideoStream] } : undefined;
|
||||||
|
|
||||||
const roomCallLocator = { roomId: roomId };
|
|
||||||
let call = this.callAgent.join(roomCallLocator, { videoOptions });
|
|
||||||
this.subscribeToCall(call);
|
|
||||||
|
|
||||||
this.callAgent.on('callsUpdated', e => {
|
this.callAgent.on('callsUpdated', e => {
|
||||||
e.added.forEach((addedCall) => {
|
e.added.forEach((addedCall) => {
|
||||||
addedCall.on('stateChanged', () => {
|
addedCall.on('stateChanged', () => {
|
||||||
if (addedCall.state === 'Connected') {
|
if (addedCall.state === 'Connected') {
|
||||||
debugger;
|
|
||||||
addedCall.info.getServerCallId().then(result => {
|
addedCall.info.getServerCallId().then(result => {
|
||||||
this.onGetServerCallID?.(result);
|
this.onGetServerCallID?.(result);
|
||||||
}).catch(err => {
|
}).catch(err => {
|
||||||
@ -76,6 +72,10 @@ class VideoCall {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const roomCallLocator = { roomId: roomId };
|
||||||
|
let call = this.callAgent.join(roomCallLocator, { videoOptions });
|
||||||
|
this.subscribeToCall(call);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error);
|
console.error(error);
|
||||||
}
|
}
|
||||||
|
@ -14,13 +14,15 @@ namespace EnotaryoPH.Web.Common.Services
|
|||||||
private readonly CommunicationIdentityClient _communicationIdentityClient;
|
private readonly CommunicationIdentityClient _communicationIdentityClient;
|
||||||
private readonly RoomsClient _roomsClient;
|
private readonly RoomsClient _roomsClient;
|
||||||
private readonly CallAutomationClient _callAutomationClient;
|
private readonly CallAutomationClient _callAutomationClient;
|
||||||
|
private readonly IConfiguration _configuration;
|
||||||
|
|
||||||
public ConferenceSheduleService(NotaryoDBContext dbContext, CommunicationIdentityClient communicationIdentityClient, RoomsClient roomsClient, CallAutomationClient callAutomationClient)
|
public ConferenceSheduleService(NotaryoDBContext dbContext, CommunicationIdentityClient communicationIdentityClient, RoomsClient roomsClient, CallAutomationClient callAutomationClient, IConfiguration configuration)
|
||||||
{
|
{
|
||||||
_dbContext = dbContext;
|
_dbContext = dbContext;
|
||||||
_communicationIdentityClient = communicationIdentityClient;
|
_communicationIdentityClient = communicationIdentityClient;
|
||||||
_roomsClient = roomsClient;
|
_roomsClient = roomsClient;
|
||||||
_callAutomationClient = callAutomationClient;
|
_callAutomationClient = callAutomationClient;
|
||||||
|
_configuration = configuration;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<Guid> GetOrCreateScheduleIDAsync(Guid transaction_UID)
|
public async Task<Guid> GetOrCreateScheduleIDAsync(Guid transaction_UID)
|
||||||
@ -105,19 +107,20 @@ namespace EnotaryoPH.Web.Common.Services
|
|||||||
_dbContext.Update(schedule);
|
_dbContext.Update(schedule);
|
||||||
}
|
}
|
||||||
_dbContext.SaveChanges();
|
_dbContext.SaveChanges();
|
||||||
|
schedule_UID = schedule.LawyerVideoConferenceSchedule_UID;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return schedule_UID;
|
return schedule_UID;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task StartRecordingAsync(Guid transaction_UID)
|
public async Task StartRecordingAsync(Guid transaction_UID, string serverCallID)
|
||||||
{
|
{
|
||||||
var transactionEntity = _dbContext.Transactions
|
var transactionEntity = _dbContext.Transactions
|
||||||
.FirstOrDefault(t => t.Transaction_UID == transaction_UID) ?? throw new ArgumentException("Transaction not found.");
|
.FirstOrDefault(t => t.Transaction_UID == transaction_UID) ?? throw new ArgumentException("Transaction not found.");
|
||||||
|
|
||||||
var existingSchedule = _dbContext.LawyerVideoConferenceSchedules.FirstOrDefault(sched => sched.TransactionID == transactionEntity.TransactionID) ?? throw new ArgumentException("Schedule not found.");
|
var existingSchedule = _dbContext.LawyerVideoConferenceSchedules.FirstOrDefault(sched => sched.TransactionID == transactionEntity.TransactionID) ?? throw new ArgumentException("Schedule not found.");
|
||||||
if (string.IsNullOrEmpty(existingSchedule.ServerCallID))
|
if (string.IsNullOrEmpty(existingSchedule.ServerCallID) && string.IsNullOrEmpty(serverCallID))
|
||||||
{
|
{
|
||||||
throw new ArgumentException("ServerCallID is not set for this transaction.");
|
throw new ArgumentException("ServerCallID is not set for this transaction.");
|
||||||
}
|
}
|
||||||
@ -127,8 +130,18 @@ namespace EnotaryoPH.Web.Common.Services
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(serverCallID))
|
||||||
|
{
|
||||||
|
existingSchedule.ServerCallID = serverCallID;
|
||||||
|
}
|
||||||
|
|
||||||
CallLocator callLocator = new ServerCallLocator(existingSchedule.ServerCallID);
|
CallLocator callLocator = new ServerCallLocator(existingSchedule.ServerCallID);
|
||||||
var recordingResult = await _callAutomationClient.GetCallRecording().StartAsync(new StartRecordingOptions(callLocator) { RecordingStorage = RecordingStorage.CreateAzureBlobContainerRecordingStorage(new Uri("")) });
|
var uri = _configuration.GetValue<string>("UriRecordingBloblContainer") ?? string.Empty;
|
||||||
|
var recordingResult = await _callAutomationClient
|
||||||
|
.GetCallRecording().StartAsync(new StartRecordingOptions(callLocator)
|
||||||
|
{
|
||||||
|
RecordingStorage = RecordingStorage.CreateAzureBlobContainerRecordingStorage(new Uri(uri))
|
||||||
|
});
|
||||||
existingSchedule.RecordingID = recordingResult.Value.RecordingId;
|
existingSchedule.RecordingID = recordingResult.Value.RecordingId;
|
||||||
_dbContext.Update(existingSchedule);
|
_dbContext.Update(existingSchedule);
|
||||||
_dbContext.SaveChanges();
|
_dbContext.SaveChanges();
|
||||||
@ -150,7 +163,6 @@ namespace EnotaryoPH.Web.Common.Services
|
|||||||
throw new ArgumentException("Recording ID is not set for this transaction.");
|
throw new ArgumentException("Recording ID is not set for this transaction.");
|
||||||
}
|
}
|
||||||
|
|
||||||
CallLocator callLocator = new ServerCallLocator(existingSchedule.ServerCallID);
|
|
||||||
await _callAutomationClient.GetCallRecording().StopAsync(existingSchedule.RecordingID);
|
await _callAutomationClient.GetCallRecording().StopAsync(existingSchedule.RecordingID);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
{
|
{
|
||||||
Task<Guid> GetOrCreateScheduleIDAsync(Guid transaction_UID);
|
Task<Guid> GetOrCreateScheduleIDAsync(Guid transaction_UID);
|
||||||
|
|
||||||
Task StartRecordingAsync(Guid transaction_UID);
|
Task StartRecordingAsync(Guid transaction_UID, string serverCallID);
|
||||||
|
|
||||||
Task StopRecordingAsync(Guid transaction_UID);
|
Task StopRecordingAsync(Guid transaction_UID);
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
@using System.Text.Json
|
@using System.Text.Json
|
||||||
@model EnotaryoPH.Web.Pages.Participant.VideoCall.RoomModel
|
@model EnotaryoPH.Web.Pages.Participant.VideoCall.RoomModel
|
||||||
@{
|
@{
|
||||||
|
Layout = "_Blank";
|
||||||
}
|
}
|
||||||
|
|
||||||
@section Head {
|
@section Head {
|
||||||
@ -64,7 +65,19 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
<div class="container-fluid py-3" id="videoGrid-container">
|
<div class="container-fluid py-3" id="videoGrid-container">
|
||||||
<div class="row g-2" id="videoGrid">
|
<div class="d-flex mb-1">
|
||||||
|
<div>
|
||||||
|
<span>32:04</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex-fill"></div>
|
||||||
|
<div>
|
||||||
|
<a href="#" id="ViewDocument" class="btn btn-sm btn-secondary">View Document</a>
|
||||||
|
<a href="#" id="Approve" class="btn btn-sm btn-success">Approve</a>
|
||||||
|
<a href="#" id="Reject" class="btn btn-sm btn-danger">Reject</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div class="row g-2" id="VideoGrid">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -74,100 +87,17 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<input type="hidden" value="@JsonSerializer.Serialize(Model.Participants)" />
|
<input type="hidden" id="Participants" value="@(System.Web.HttpUtility.JavaScriptStringEncode(JsonSerializer.Serialize(Model.Participants)).Replace("\\", ""))" />
|
||||||
|
<input type="hidden" id="CommunicationUserToken" value="@Model.CommunicationUserToken" />
|
||||||
|
<input type="hidden" id="CommunicationUserId" value="@Model.CommunicationUserId" />
|
||||||
|
<input type="hidden" id="CommunicationRoomId" value="@Model.CommunicationRoomId" />
|
||||||
|
|
||||||
|
<form method="post" asp-page-handler="StartRecording">
|
||||||
|
<input type="hidden" asp-for="ServerCallID" />
|
||||||
|
<input type="hidden" asp-for="Transaction_UID" />
|
||||||
|
</form>
|
||||||
|
|
||||||
@section Scripts {
|
@section Scripts {
|
||||||
<script type="text/javascript" src="/dist/_jfa.js"></script>
|
<script type="text/javascript" src="/dist/_jfa.js"></script>
|
||||||
<script>
|
<script src="~/Pages/Participant/VideoCall/Room.cshtml.js" asp-append-version="true"></script>
|
||||||
|
|
||||||
let participants = JSON.parse('@Html.Raw(JsonSerializer.Serialize(Model.Participants))');
|
|
||||||
function updateGrid() {
|
|
||||||
const videoGrid = document.getElementById('videoGrid');
|
|
||||||
videoGrid.innerHTML = '';
|
|
||||||
|
|
||||||
participants.forEach((participant, index) => {
|
|
||||||
const col = document.createElement('div');
|
|
||||||
col.className = 'participant-col';
|
|
||||||
var tmpl = document.getElementById("templateVideo").cloneNode(true).content;
|
|
||||||
let vidcontainer = tmpl.querySelector(".video-container")
|
|
||||||
if (vidcontainer) {
|
|
||||||
vidcontainer.id = participant.Id;
|
|
||||||
vidcontainer.classList.add(participant.Id);
|
|
||||||
vidcontainer.classList.add(participant.Type == 'Notary' ? 'local-video-container' : 'remote-video-container');
|
|
||||||
}
|
|
||||||
let participantName = tmpl.querySelector(".participant-name")
|
|
||||||
if (participantName) {
|
|
||||||
participantName.textContent = participant.DisplayName;
|
|
||||||
}
|
|
||||||
col.appendChild(tmpl);
|
|
||||||
videoGrid.appendChild(col);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Dynamically adjust grid columns based on participant count
|
|
||||||
const count = participants.length;
|
|
||||||
const cols = count <= 2 ? 'col-12 col-sm-12 offset-md-1 col-md-10 offset-lg-0 col-lg-6' :
|
|
||||||
count <= 4 ? 'col-6 col-sm-6 col-md-6 col-lg-6 col-xl-6' :
|
|
||||||
count <= 8 ? 'col-6 col-md-6 col-lg-4 col-xl-4' :
|
|
||||||
count <= 9 ? 'col-4' :
|
|
||||||
'col-6 col-sm-4 col-lg-3';
|
|
||||||
|
|
||||||
document.querySelectorAll('.participant-col').forEach(el => {
|
|
||||||
el.className = `participant-col ${cols}`;
|
|
||||||
});
|
|
||||||
|
|
||||||
const fluid = count <= 2 ? 'container-fluid' :
|
|
||||||
count <= 8 ? 'container-xxl' :
|
|
||||||
'container-xl'
|
|
||||||
document.getElementById('videoGrid-container').className = `${fluid} py-3`;
|
|
||||||
}
|
|
||||||
|
|
||||||
async function initVideoCall() {
|
|
||||||
let userAccessToken = '@Model.CommunicationUserToken';
|
|
||||||
const videoCall = jfa.communication.videocall;
|
|
||||||
let options = {
|
|
||||||
onCreateLocalVideoStream: function(el) {
|
|
||||||
if (el) {
|
|
||||||
el.style['transform'] = '';
|
|
||||||
let notary = participants.find(p => p.RoomUserID == '@Model.CommunicationUserId');
|
|
||||||
document.getElementById(notary.Id).appendChild(el);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
remoteVideoIsAvailableChanged: function(e) {
|
|
||||||
let participant = participants.find(p => p.RoomUserID == e.participantId);
|
|
||||||
if (participant) {
|
|
||||||
e.el.querySelector('video').style['object-fit'] = 'cover';
|
|
||||||
document.getElementById(participant.Id).appendChild(e.el);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
onGetServerCallID: function(e) {
|
|
||||||
debugger;
|
|
||||||
let url = jfa.utilities.routing.getCurrentURLWithHandler("StartRecording");
|
|
||||||
debugger;
|
|
||||||
url.searchParams.append("ServerCallID", e.serverCallId || "");
|
|
||||||
jfa.utilities.request.post(url, {})
|
|
||||||
.then(resp => {
|
|
||||||
if (resp.ok === true) {
|
|
||||||
jfa.page.reload();
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.catch(err => console.error(err));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
await videoCall.init(userAccessToken, options);
|
|
||||||
videoCall.joinRoom('@Model.CommunicationRoomId');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (document.readyState !== 'loading') {
|
|
||||||
init();
|
|
||||||
} else {
|
|
||||||
document.addEventListener('DOMContentLoaded', init);
|
|
||||||
}
|
|
||||||
|
|
||||||
async function init() {
|
|
||||||
updateGrid();
|
|
||||||
window.addEventListener('resize', updateGrid);
|
|
||||||
|
|
||||||
await initVideoCall();
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,7 @@ namespace EnotaryoPH.Web.Pages.Participant.VideoCall
|
|||||||
{
|
{
|
||||||
public class RoomModel : PageModel
|
public class RoomModel : PageModel
|
||||||
{
|
{
|
||||||
|
private const int VideoConferenceExpirationInHours = 2;
|
||||||
private readonly IConferenceSheduleService _conferenceSheduleService;
|
private readonly IConferenceSheduleService _conferenceSheduleService;
|
||||||
private readonly ICurrentUserService _currentUserService;
|
private readonly ICurrentUserService _currentUserService;
|
||||||
private readonly NotaryoDBContext _dbContext;
|
private readonly NotaryoDBContext _dbContext;
|
||||||
@ -22,10 +23,7 @@ namespace EnotaryoPH.Web.Pages.Participant.VideoCall
|
|||||||
|
|
||||||
public async Task<IActionResult> OnGetAsync()
|
public async Task<IActionResult> OnGetAsync()
|
||||||
{
|
{
|
||||||
_Transaction = _dbContext.Transactions
|
LoadTransaction();
|
||||||
.Include(t => t.TransactionSignatories)
|
|
||||||
.Include(t => t.Principal)
|
|
||||||
.FirstOrDefault(t => t.Transaction_UID == Transaction_UID);
|
|
||||||
if (_Transaction == null)
|
if (_Transaction == null)
|
||||||
{
|
{
|
||||||
return NotFound();
|
return NotFound();
|
||||||
@ -48,12 +46,20 @@ namespace EnotaryoPH.Web.Pages.Participant.VideoCall
|
|||||||
return Redirect("/");
|
return Redirect("/");
|
||||||
}
|
}
|
||||||
|
|
||||||
_LawyerVideoConferenceSchedule = _dbContext.LawyerVideoConferenceSchedules
|
LoadVideoConferenceSchedule(schedule_UID);
|
||||||
.Include(sched => sched.LawyerVideoConferenceParticipants)
|
|
||||||
.ThenInclude(p => p.Participant)
|
if ((DateTime.UtcNow - _LawyerVideoConferenceSchedule.MeetingDate).TotalHours > VideoConferenceExpirationInHours)
|
||||||
.Include(sched => sched.Lawyer)
|
{
|
||||||
.ThenInclude(l => l.User)
|
if (!_LawyerVideoConferenceSchedule.Status.IsInList(VideoConferenceStatus.Abandoned, VideoConferenceStatus.Completed))
|
||||||
.FirstOrDefault(sched => sched.LawyerVideoConferenceSchedule_UID == schedule_UID);
|
{
|
||||||
|
_LawyerVideoConferenceSchedule.Status = nameof(VideoConferenceStatus.Expired);
|
||||||
|
_dbContext.Update(_LawyerVideoConferenceSchedule);
|
||||||
|
_dbContext.SaveChanges();
|
||||||
|
}
|
||||||
|
|
||||||
|
TempData["Warning"] = "The video conference has expired.";
|
||||||
|
return Redirect("/");
|
||||||
|
}
|
||||||
|
|
||||||
CommunicationUserToken = currentUser.Role == nameof(UserType.Notary)
|
CommunicationUserToken = currentUser.Role == nameof(UserType.Notary)
|
||||||
? _LawyerVideoConferenceSchedule.MeetingRoomTokenID
|
? _LawyerVideoConferenceSchedule.MeetingRoomTokenID
|
||||||
@ -66,7 +72,33 @@ namespace EnotaryoPH.Web.Pages.Participant.VideoCall
|
|||||||
return Page();
|
return Page();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task OnPostStartRecordingAsync() => await _conferenceSheduleService.StartRecordingAsync(Transaction_UID);
|
public async Task OnPostStartRecordingAsync()
|
||||||
|
{
|
||||||
|
LoadTransaction();
|
||||||
|
var schedule_UID = await _conferenceSheduleService.GetOrCreateScheduleIDAsync(Transaction_UID);
|
||||||
|
LoadVideoConferenceSchedule(schedule_UID);
|
||||||
|
await _conferenceSheduleService.StartRecordingAsync(Transaction_UID, ServerCallID);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task OnPostStopRecordingAsync()
|
||||||
|
{
|
||||||
|
LoadTransaction();
|
||||||
|
var schedule_UID = await _conferenceSheduleService.GetOrCreateScheduleIDAsync(Transaction_UID);
|
||||||
|
LoadVideoConferenceSchedule(schedule_UID);
|
||||||
|
await _conferenceSheduleService.StopRecordingAsync(Transaction_UID);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void LoadTransaction() => _Transaction = _dbContext.Transactions
|
||||||
|
.Include(t => t.TransactionSignatories)
|
||||||
|
.Include(t => t.Principal)
|
||||||
|
.FirstOrDefault(t => t.Transaction_UID == Transaction_UID);
|
||||||
|
|
||||||
|
private void LoadVideoConferenceSchedule(Guid schedule_UID) => _LawyerVideoConferenceSchedule = _dbContext.LawyerVideoConferenceSchedules
|
||||||
|
.Include(sched => sched.LawyerVideoConferenceParticipants)
|
||||||
|
.ThenInclude(p => p.Participant)
|
||||||
|
.Include(sched => sched.Lawyer)
|
||||||
|
.ThenInclude(l => l.User)
|
||||||
|
.FirstOrDefault(sched => sched.LawyerVideoConferenceSchedule_UID == schedule_UID);
|
||||||
|
|
||||||
public string CommunicationRoomId { get; private set; }
|
public string CommunicationRoomId { get; private set; }
|
||||||
|
|
||||||
@ -101,7 +133,7 @@ namespace EnotaryoPH.Web.Pages.Participant.VideoCall
|
|||||||
}
|
}
|
||||||
|
|
||||||
[BindProperty(SupportsGet = true)]
|
[BindProperty(SupportsGet = true)]
|
||||||
public string ServerCallingID { get; set; }
|
public string ServerCallID { get; set; }
|
||||||
|
|
||||||
[BindProperty(SupportsGet = true)]
|
[BindProperty(SupportsGet = true)]
|
||||||
public Guid Transaction_UID { get; set; }
|
public Guid Transaction_UID { get; set; }
|
||||||
|
@ -0,0 +1,119 @@
|
|||||||
|
"use strict";
|
||||||
|
(async function () {
|
||||||
|
let
|
||||||
|
control_approve = document.getElementById("Approve"),
|
||||||
|
control_communicationRoomId = document.getElementById("CommunicationRoomId"),
|
||||||
|
control_communicationUserId = document.getElementById("CommunicationUserId"),
|
||||||
|
control_communicationUserToken = document.getElementById("CommunicationUserToken"),
|
||||||
|
control_participants = document.getElementById("Participants"),
|
||||||
|
control_reject = document.getElementById("Reject"),
|
||||||
|
control_templateVideo = document.getElementById("templateVideo"),
|
||||||
|
control_videoGrid = document.getElementById("VideoGrid"),
|
||||||
|
control_videoGridContainer = document.getElementById("videoGrid-container"),
|
||||||
|
control_viewDocument = document.getElementById("ViewDocument"),
|
||||||
|
control_serverCallIID = document.getElementById("ServerCallID"),
|
||||||
|
x = 1;
|
||||||
|
|
||||||
|
let participants = JSON.parse(control_participants.value);
|
||||||
|
|
||||||
|
async function _initVideoCall() {
|
||||||
|
let userAccessToken = control_communicationUserToken.value;
|
||||||
|
const videoCall = jfa.communication.videocall;
|
||||||
|
let options = {
|
||||||
|
onCreateLocalVideoStream: function (el) {
|
||||||
|
if (el) {
|
||||||
|
el.style['transform'] = '';
|
||||||
|
let notary = participants.find(p => p.RoomUserID == control_communicationUserId.value);
|
||||||
|
document.getElementById(notary.Id).appendChild(el);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
remoteVideoIsAvailableChanged: function (e) {
|
||||||
|
let participant = participants.find(p => p.RoomUserID == e.participantId);
|
||||||
|
if (participant) {
|
||||||
|
e.el.querySelector('video').style['object-fit'] = 'cover';
|
||||||
|
document.getElementById(participant.Id).appendChild(e.el);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onGetServerCallID: function (serverCallId) {
|
||||||
|
let url = jfa.utilities.routing.getCurrentURLWithHandler("StartRecording");
|
||||||
|
url.searchParams.append("ServerCallID", serverCallId);
|
||||||
|
jfa.utilities.request.post(url, {})
|
||||||
|
.then(resp => {
|
||||||
|
if (resp.ok === true) {
|
||||||
|
console.log("started recording");
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(err => console.error(err));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
await videoCall.init(userAccessToken, options);
|
||||||
|
videoCall.joinRoom(control_communicationRoomId.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
function _updateGrid() {
|
||||||
|
control_videoGrid.innerHTML = '';
|
||||||
|
|
||||||
|
participants.forEach((participant, index) => {
|
||||||
|
const col = document.createElement('div');
|
||||||
|
col.className = 'participant-col';
|
||||||
|
const tmpl = control_templateVideo.cloneNode(true).content;
|
||||||
|
const vidcontainer = tmpl.querySelector(".video-container")
|
||||||
|
if (vidcontainer) {
|
||||||
|
vidcontainer.id = participant.Id;
|
||||||
|
vidcontainer.classList.add(participant.Id);
|
||||||
|
vidcontainer.classList.add(participant.Type == 'Notary' ? 'local-video-container' : 'remote-video-container');
|
||||||
|
}
|
||||||
|
let participantName = tmpl.querySelector(".participant-name")
|
||||||
|
if (participantName) {
|
||||||
|
participantName.textContent = participant.DisplayName;
|
||||||
|
}
|
||||||
|
col.appendChild(tmpl);
|
||||||
|
control_videoGrid.appendChild(col);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Dynamically adjust grid columns based on participant count
|
||||||
|
const count = participants.length;
|
||||||
|
const cols = count <= 2 ? 'col-12 col-sm-12 offset-md-1 col-md-10 offset-lg-0 col-lg-6' :
|
||||||
|
count <= 4 ? 'col-6 col-sm-6 col-md-6 col-lg-6 col-xl-6' :
|
||||||
|
count <= 8 ? 'col-6 col-md-6 col-lg-4 col-xl-4' :
|
||||||
|
count <= 9 ? 'col-4' :
|
||||||
|
'col-6 col-sm-4 col-lg-3';
|
||||||
|
|
||||||
|
document.querySelectorAll('.participant-col').forEach(el => {
|
||||||
|
el.className = `participant-col ${cols}`;
|
||||||
|
});
|
||||||
|
|
||||||
|
const fluid = count <= 2 ? 'container-fluid' :
|
||||||
|
count <= 8 ? 'container-xxl' :
|
||||||
|
'container-xl'
|
||||||
|
control_videoGridContainer.className = `${fluid} py-3`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function _bindEvents() {
|
||||||
|
window.addEventListener('resize', _updateGrid);
|
||||||
|
control_viewDocument.addEventListener("click", function () {
|
||||||
|
alert('not yet implemented');
|
||||||
|
});
|
||||||
|
control_approve.addEventListener("click", function () {
|
||||||
|
let url = jfa.utilities.routing.getCurrentURLWithHandler("StopRecording");
|
||||||
|
jfa.utilities.request.post(url, {})
|
||||||
|
.then(resp => {
|
||||||
|
if (resp.ok === true) {
|
||||||
|
console.log("stopped recording");
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(err => console.error(err));
|
||||||
|
});
|
||||||
|
control_reject.addEventListener("click", function () {
|
||||||
|
alert('not yet implemented');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async function _init() {
|
||||||
|
_bindEvents();
|
||||||
|
_updateGrid();
|
||||||
|
await _initVideoCall();
|
||||||
|
}
|
||||||
|
|
||||||
|
await _init();
|
||||||
|
})();
|
Loading…
x
Reference in New Issue
Block a user