The call duration refers to the course from the start to the end of the call. It’s an essential function of audio and video calls, commonly used in:
- Real-time display of call duration;
- Call duration record;
- For the call billing;
This article will explain how to implement this functionality in your App.
Call duration formula
The calculation formula for call duration is as follows:
Call duration = call end timestamp - call start timestamp
You only need to get the call start timestamp
and call end timestamp
to calculate the call duration.
However, there are some exceptions. For example, in the case of a network interruption or app crash, how to ensure the accuracy of call duration calculation?
Furthermore, how to ensure that the billing logic is safe and that there is no manipulation?
Let’s see how to tackle these issues.
Real-time display of call duration

The call duration function is often implemented on the client side. Real-time and fluency of timing updates need special attention.
The processing logic is as such:
- the App listens to the call
start event
- The timer starts, polls once per second, and adds 1 second to the call duration

ZEGOCLOUD UIKits determines when the user starts and ends a call by monitoring the callback events of the user joining and exiting the call room.
Implement the real-time display of call duration
ZEGOCLOUD UIKits provides RoomStateChanged
callback notification. In particular, you can get notified when:
- Joining a call room.
- Being kicked out of the call room.
- Exiting the call room.
We can get the start
and end timestamp
of the call through it.
1. Add event listener
First, you need to call the ZegoUIKit.addRoomStateChangedListener
method to listen for room state changes.
private void addRoomStateChangedListener() {
roomStateChangedListener = new RoomStateChangedListener() {
@Override
public void onRoomStateChanged(String s, ZegoRoomStateChangedReason zegoRoomStateChangedReason, int i, JSONObject jsonObject) {
switch (zegoRoomStateChangedReason) {
case LOGINED:
roomID = s;
addTextView();
startTimer();
break;
case LOGOUT:
case KICK_OUT:
case RECONNECT_FAILED:
stopTimer();
break;
default:
break;
}
}
};
ZegoUIKit.addRoomStateChangedListener(roomStateChangedListener);
}

2. Callback event handling
In the RoomStateChanged
callback event, we need to handle two types of events:
- call start
- call end.
The call start
implements the following logic:
- View to display call duration.
- Start the timer
The call end
implements:
- Stop the timer.
public void onRoomStateChanged(String s, ZegoRoomStateChangedReason zegoRoomStateChangedReason, int i, JSONObject jsonObject) {
switch (zegoRoomStateChangedReason) {
case LOGINED:
roomID = s;
addTextView();
startTimer();
break;
case LOGOUT:
case KICK_OUT:
case RECONNECT_FAILED:
stopTimer();
break;
default:
break;
}
}
2.1 Added view to display call duration
Next, you need to add a TextView
to display the call duration.
private void addTextView() {
ZegoUIKitPrebuiltCallFragment fragment = ZegoUIKitPrebuiltCallInvitationService.getPrebuiltCallFragment();
ConstraintLayout rootView = (ConstraintLayout) fragment.getView();
textView = new TextView(MainActivity.this);
textView.setTextColor(Color.WHITE);
ConstraintLayout.LayoutParams params = new ConstraintLayout.LayoutParams(-2, -2);
params.startToStart = ConstraintLayout.LayoutParams.PARENT_ID;
params.endToEnd = ConstraintLayout.LayoutParams.PARENT_ID;
params.topToTop = ConstraintLayout.LayoutParams.PARENT_ID;
params.topMargin = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,20,getResources().getDisplayMetrics());
rootView.addView(textView, params);
}
2.2 Start timer
When the call starts, you need to create a Timer
, poll once a second, and update the text in TextView
.
private void startTimer() {
duration = 0;
timer = new Timer();
uploadCallDuration(duration);
TimerTask task = new TimerTask() {
@Override
public void run() {
duration += 1;
handler.post(new Runnable() {
@Override
public void run() {
textView.setText(transToHourMinSec(duration));
}
});
}
};
timer.schedule(task, 0, 1000);
}
2.3 Stop timer
When the call ends, you need to call timer.cancel()
to end the timer.
private void stopTimer() {
timer.cancel();
}
Call recording and call billing
Call records, as proof of payment. Accuracy and safety are paramount. In various abnormal situations, it is also necessary to accurately count the call duration. Therefore, the call duration cannot be reported only at the end of the call. If an abnormal situation occurs, such as network disconnection, application exit, etc. the call duration cannot be counted. Our solution is to regularly report the call duration. For example, report once every 30 seconds. You can also set the reporting frequency according to your billing rules. If billing is by the minute, the frequency of once every 30 seconds is the most appropriate.
1. Upload Call Duration

private void uploadCallDuration(int duration) {
int interval = 30;
if ((duration - 1) % interval != 0) {
return;
}
if (!isCaller) {
return;
}
Map<String, Object> param = new HashMap<String, Object>();
param.put("roomID", roomID);
param.put("duration", duration);
// request bussiness server API to upload call duration
requestBussinessServerAPI(param);
}
There are two things to note here:
1. In order to ensure that the call is recorded at the beginning, when calculating the reporting frequency, use duration - 1
.
if ((duration - 1) % interval != 0) {
return;
}
2. In order to avoid repeated reporting, the call duration is reported by the caller. So you need to judge whether you are the caller.
if (!isCaller) {
return;
}
Conclusion
We have seen together the commonly used calculation method for call duration. However, the call duration will vary according to different business scenarios and billing methods.
Of course, in case of necessity, you can contact us. We will formulate the best plan for you.
You can also download the sample code for this article from here.
Read more
Talk to Expert
Learn more about our solutions and get your question answered.