PimentaCall Messages
This topic explains how the web and mobile apps can show a custom message to users about calls.
Always that a call object is changed, Meteor application change a special Message object.
This Message object contains a field called call. This field contains all details about call, and web and mobile apps can write code to interpret the call status and show a custom message to users.
User role and actions
To show custom messages to users, we will have two type of actors: Caller and Receiver.
The Caller is the user that make the call to one (direct or group call) or more (group call) Receiver.
The Caller can cancels the call and Receiver can reject or accept the call.
There’s a timeout of approximately 36 seconds. In this case, call will consider terminated and server application will set the flag finished of PimentaCall object to the current date.
The Seven Statuses
For each role (Caller or Receiver) we will have 7 status possible in a call to show a custom message to user:
- Start a Call: This is the status when a
CallerSTARTs a call. - In Call: This is the status when a
Receiveraccept a call and it start with the firstReceiverand theCaller - Finished: Here we have more 4 possible status:
3.1. Timeout: This is when a call is finished because user not responds
3.2. Rejected: This is when the
Receiveror All Receives (in a group call) reject the call or One Receiver reject and others timeout 3.3. Terminated: This is when a call started and now was finished because All participants left the call 3.4. Canceled: This is when theCallercancel the call before anyReceiverresponds.
Implementation of message details
Each message related to a call will have a PimentaCall object assigned to it.
When a call is active

- This message will appear when a call is active, in a direct or group call.
- This type of message will be showed when
startedfield is notnullandfinishedfield isnull
When a call is canceled by caller

- This happens when the user that make the call, cancels it before any other user responds to call
- This message is showed only for the caller, for recipients, the term will be “Missed” or “Unanswered”
- To show this message, field
startedhave to benullandcallerCancelistrue
When a call is missed

- This happens when the user that see the message missed the call, but was respond by other user
- You have to check if current user accepts the call by checking
acceptedUserIdsarray.
When a call is unanswered

- This will be show only to the caller
- If the call was not canceled by caller, but was not answered by any user or timeout.
- Check if
finishedis notnullandacceptedisfalseanduserIdis the same that current user.
When a call was completed and finished

- When a call was completed and terminated
- First, check if
startedandfinishedare notnull - The field
startedcontains the date of start of call, but can be from any user (on group call). Is the moment that call is accepted from any user. - So, to check the start of each user, you have to check on
logfield. To accesslogfield of user, you have to access by userId, likelog[userId]. - The log object for a user contains the fields:
startDate, is the time that user enter on call,endDate, is the time he left the call andping, that is the time of last ping from this user.
When a call is finished and is group (timeout)

- The only difference for group is that this message will show more names (if applicable) and the date that user left the call.
- You can get the names from
toNamesarray.
Table of colors and icons
| Icon | Color | Description |
|---|---|---|
#FF0000 for icon and red text#FDEDEE for block background#F1CDCF for border with 3px |
This is applied to all messages that was not completed. started field is null and is a video message |
|
#FF0000 for icon and red text#F7F9F8 for block background#DCF3DD for border with 3px |
This is applied to all messages that was started, finished or not. |
All icons:
The script bellow is exactly script used to format call message from pimentaCHAT web:
const call = message.call;
if (call) {
let name = call.senderName;
let pronoun = 'is';
let isCaller = false;
let directionIcon = 'call-from';
if (call.userId == userId) {
name = 'You';
isCaller = true;
pronoun = 'are'
directionIcon = 'call-to';
}
let callType = 'Video call';
icon = 'video-alt';
if (call.onlyAudio) {
callType = 'Audio call';
icon = 'phone-alt';
}
if (call.waiting && call.isGroup) {
msg = `${name} started a group <strong>${callType}</strong> in <strong>${call.senderGroup}</strong>:
<a href="${call.channel}" target="_blank">${call.channel}</a>`;
} else {
// Names of recipients
let toNames = '';
if (call.toNames) {
toNames = call.toNames.join(', ');
}
// Message if user out of call
let userOutCall = '';
if (call.log && call.log[userId] && call.log[userId]['endDate']) {
userOutCall = ' (You left the call at ' + call.log[userId]['endDate'].toLocaleTimeString() + ')';
}
// Participants string
let participantsHtml = '';
let participants = [];
if (call.acceptedUsers && call.acceptedUsers.length > 0) {
for (var i = 0; i < call.acceptedUsers.length; i++) {
let userName = call.acceptedUsers[i].name;
if (call.acceptedUsers[i]._id == userId)
userName = 'You';
participants.push(userName);
}
// Add the caller
participantsHtml = participants.join(', ');
participantsHtml += ', ' + name; // We do not add to array because we need participants array without caller
participantsHtml = `<div>Participants: ${participantsHtml}</div>`;
}
if (call.finished) {
// When the call is finished
msg = `<h4><strong>${callType}</strong> with <strong>${toNames}</strong></h4>`;
let direction = `<svg class="rc-icon tab-button-icon tab-button-icon--${directionIcon}" aria-hidden="true"><use xlink:href="${baseUrl}#icon-${directionIcon}"></use></svg>`;
if (call.acceptedUsers.length == 0 || (call.acceptedUserIds && call.acceptedUserIds.indexOf(userId) < 0 && userId != call.userId)) {
// Missed for all
svgClass = 'done';
let action;
if (call.callerCancel && isCaller) {
action = 'Canceled';
} else if (isCaller) {
action = 'Unanswered';
} else {
action = 'Missed';
}
let nameRelation = 'from';
if (isCaller) {
nameRelation = 'with';
}
msg = `<h4><strong>${callType}</strong> ${nameRelation} <strong>${toNames}</strong></h4>`;
msg += `<p class="not-received-color">${direction} <strong>${action}</strong> at ${call.finished.toLocaleString()}</p>`;
} else {
svgClass = 'calling';
wrapperClass = 'received';
// In this case, the current user was in the call
let diff = (call.finished - call.date) / 1000;
let duration = `<svg class="rc-icon tab-button-icon tab-button-icon--video-log" aria-hidden="true"><use xlink:href="${baseUrl}#icon-video-log"></use></svg>`;
let typeDirection;
if (call.userId == userId) typeDirection = 'Started at: ';
else typeDirection = ' Received on: ';
msg += '<p class="received-color">' + direction + typeDirection + call.date.toLocaleString() + ' - Ended at: ' + call.finished.toLocaleTimeString() + '</p>';
msg += '<p>' + duration + ' Duration: ' + this.getFormatedTime(diff) + userOutCall + '</p>';
}
} else if (call.started) {
// Call started but not finished yet
svgClass = 'calling';
wrapperClass = 'received';
icon = 'phone-alt';
msg = `<h4><strong>${name}</strong> ${pronoun} in a <strong>${callType}</strong> with <strong>${participants.join(', ')}</strong>`;
} else {
// Only ringing or fail
}
}
}
return `
<div class="pimenta-call-resume__wrapper pimenta-call-resume__wrapper--${wrapperClass}">
<span class="pimenta-call-resume__icon pimenta-call-resume__icon__${svgClass}">
<svg class="rc-icon tab-button-icon tab-button-icon--${icon}" aria-hidden="true">
<use xlink:href="${baseUrl}#icon-${icon}"></use>
</svg>
</span>
<span class="pimenta-call-resume__content">${msg}</span>
</div>`;