Welcome

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:

  1. Start a Call: This is the status when a Caller STARTs a call.
  2. In Call: This is the status when a Receiver accept a call and it start with the first Receiver and the Caller
  3. 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 Receiver or 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 the Caller cancel the call before any Receiver responds.

Implementation of message details

Each message related to a call will have a PimentaCall object assigned to it.

When a call is active

When call is active

  1. This message will appear when a call is active, in a direct or group call.
  2. This type of message will be showed when started field is not null and finished field is null

When a call is canceled by caller

When call is canceled

  1. This happens when the user that make the call, cancels it before any other user responds to call
  2. This message is showed only for the caller, for recipients, the term will be “Missed” or “Unanswered”
  3. To show this message, field started have to be null and callerCancel is true

When a call is missed

When call is missed

  1. This happens when the user that see the message missed the call, but was respond by other user
  2. You have to check if current user accepts the call by checking acceptedUserIds array.

When a call is unanswered

When call is unanswered

  1. This will be show only to the caller
  2. If the call was not canceled by caller, but was not answered by any user or timeout.
  3. Check if finished is not null and accepted is false and userId is the same that current user.

When a call was completed and finished

When call is finished

  1. When a call was completed and terminated
  2. First, check if started and finished are not null
  3. The field started contains 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.
  4. So, to check the start of each user, you have to check on log field. To access log field of user, you have to access by userId, like log[userId].
  5. 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 and ping, that is the time of last ping from this user.

When a call is finished and is group (timeout)

When call is unanswered

  1. The only difference for group is that this message will show more names (if applicable) and the date that user left the call.
  2. You can get the names from toNames array.

Table of colors and icons

Icon Color Description
or #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
or #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:

Video

Audio

Call Received

Call Send

Download all images

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>`;