Skip to main content

You are viewing Agora Docs forBetaproducts and features. Switch to Docs

Android
iOS
macOS
Web
Linux C++
Unity

Presence

In Signaling solutions, it is often important to know a user's current online status. For example, in instant messaging, chat applications, and online collaboration tools, users need to see the availability of their contacts. This information is typically displayed as a status message or icon next to a user's name. Presence features in Signaling SDK enable you to monitor join, leave, and status change notifications for users in a channel. Using Presence, you can:

  • Get a list of users currently in a channel and their temporary status data.
  • Get a list of channels a specified user has joined or is subscribed to.
  • Get, set, or remove user statuses.
  • Receive real-time event notifications when users join or leave specified channels.
  • Receive user status change event notifications in real time.

Understand the tech

Presence provides real-time information about the availability, and the current status of users, for effective communication and collaboration. It enables you to retrieve a list of users in a channel, or to query the list of channels for a specific user. The following figure illustrates how you integrate presence features into your app.

Prerequisites

Ensure that you have integrated the Signaling SDK in your project, and implemented the framework functionality from the SDK quickstart page.

Implement presence features

Using presence, you can implement the following features:

Get channel users

To obtain a list of online users in a channel, call getOnlineUsers. Depending on your parameter settings, this method returns a list of online user IDs in a channel and their temporary status data, or just the number of online users in the channel. You do not need to join a channel to call this method. This method is applicable to both message channels and stream channels. Use the channelType parameter to specify the channel type.

After obtaining the initial online users list, update it in real time through onPresenceEvent event notifications.

Refer to the following sample code to query the list of online users in a channel and their current status:


_23
// Set the channelType to MESSAGE or STREAM
_23
RtmChannelType channelType = RtmChannelType.MESSAGE;
_23
PresenceOptions options = new PresenceOptions();
_23
options.setIncludeUserId(true);
_23
options.setIncludeState(true);
_23
_23
mRtmClient.getPresence().getOnlineUsers(channelName, channelType, options, new ResultCallback<GetOnlineUsersResult>() {
_23
@Override
_23
public void onSuccess(GetOnlineUsersResult result) {
_23
log(CALLBACK, "getOnlineUsers success");
_23
for (UserState state : result.getUserStateList()) {
_23
log(INFO, "user id: " + state.getUserId());
_23
state.getStates().forEach((key, value) -> {
_23
log(INFO, "key: " + key + ", value: " + value);
_23
});
_23
}
_23
}
_23
_23
@Override
_23
public void onFailure(ErrorInfo errorInfo) {
_23
log(ERROR, errorInfo.toString());
_23
}
_23
});

The getOnlineUsers method retrieves one page of data at a time. Each page contains up to 100 online users. If the channel has more than 100 users, the nextPage field in the returned result contains a bookmark for the next page. After each query, check if result.getNextPage is empty to determine if there is more data. To retrieve the next page, set the page field in PresenceOptions to the value of result.getNextPage. Repeat this process until result.getNextPage is null. Refer to the following code:


_26
PresenceOptions options = new PresenceOptions();
_26
options.setIncludeUserId(true);
_26
options.setIncludeState(true);
_26
options.setPage("your_Next_Page_Bookmark");
_26
_26
// Set the channelType to MESSAGE or STREAM
_26
RtmChannelType channelType = RtmChannelType.MESSAGE;
_26
mRtmClient.getPresence().getOnlineUsers(channelName, channelType, options, new ResultCallback<GetOnlineUsersResult>() {
_26
@Override
_26
public void onSuccess(GetOnlineUsersResult result) {
_26
// If nextPage exists, fill the value of nextPage into the page field of getOnlineUsersOptions for the next getOnlineUsers call
_26
log(CALLBACK, "getOnlineUsers success");
_26
log(INFO, "next page: " + result.getNextPage());
_26
for (UserState state : result.getUserStateList()) {
_26
log(INFO, "user id: " + state.getUserId());
_26
state.getStates().forEach((key, value) -> {
_26
log(INFO, "key: " + key + ", value: " + value);
_26
});
_26
}
_26
}
_26
_26
@Override
_26
public void onFailure(ErrorInfo errorInfo) {
_26
log(ERROR, errorInfo.toString());
_26
}
_26
});

When there is a large number of users in a channel, you may only care about the total number of online users, and not their identities or temporary status. To get the total channel occupancy, set includeState and includeUserId in PresenceOptions to false.


_17
PresenceOptions options = new PresenceOptions();
_17
options.setIncludeUserId(false);
_17
options.setIncludeState(false);
_17
_17
// Set the channelType to MESSAGE or STREAM
_17
RtmChannelType channelType = RtmChannelType.MESSAGE;
_17
mRtmClient.getPresence().getOnlineUsers(channelName, channelType, options, new ResultCallback<GetOnlineUsersResult>() {
_17
@Override
_17
public void onSuccess(GetOnlineUsersResult result) {
_17
log(CALLBACK, "Total occupancy: " + result.getTotalOccupancy());
_17
}
_17
_17
@Override
_17
public void onFailure(ErrorInfo errorInfo) {
_17
log(ERROR, errorInfo.toString());
_17
}
_17
});

In this case, only the totalOccupancy property in the result is valid while all other fields are empty.

info

You cannot set includeState to true and includeUserId to false at the same time. To get the temporary status of users, you must also retrieve their user IDs.

Get user channels

The getUserChannels method enables you to query which channels a user is currently in. This includes the message channels a user has subscribed to and the stream channels they have joined. This method is particularly useful for tracking user paths. Refer to the following sample code:


_14
mRtmClient.getPresence().getUserChannels("userid", new ResultCallback<ArrayList<ChannelInfo>>() {
_14
@Override
_14
public void onSuccess(ArrayList<ChannelInfo> channels) {
_14
log(CALLBACK, "get getUserChannels success");
_14
for (ChannelInfo channel : channels) {
_14
log(INFO, channel.toString());
_14
}
_14
}
_14
_14
@Override
_14
public void onFailure(ErrorInfo errorInfo) {
_14
log(ERROR, errorInfo.toString());
_14
}
_14
});

The getUserChannels method returns complete query results about the channels and their types that the queried user is in, without pagination.

User status management

Signaling enables you to set and delete user status messages for the local user in each channel. The SDK notifies other online users in the channel of these changes through event notifications. This feature is useful in scenarios where user status sharing is required, such as real-time synchronization of the user's microphone status, mood, personal signature, score, and message input status.

Signaling does not permanently save the status data. When a user unsubscribes from a channel, times out, or exits a channel, the data is deleted. To save user data permanently, use the Store user metadata feature.

When a user's temporary status changes, Signaling triggers a REMOTE_STATE_CHANGED event notification in real time. Users who set withPresence = true when joining the channel, receive the event notification.

Set status

Using presence, you can set the temporary user status for the local user. When you set the status before subscribing to or joining a channel, the data is cached on the client and does not take effect immediately. The status is updated and corresponding event notifications are triggered when you subscribe to or join a channel. The setState method applies to both message and stream channels; use the channelType parameter to specify the channel type.


_15
HashMap<String, String> items = new HashMap<String, String>();
_15
items.put("Mode", "Happy");
_15
items.put("Mic", "False");
_15
_15
mRtmClient.getPresence().setState("channel_name", RtmChannelType.MESSAGE, items, new ResultCallback<Void>() {
_15
@Override
_15
public void onSuccess(Void responseInfo) {
_15
log(CALLBACK, "setState success");
_15
}
_15
_15
@Override
_15
public void onFailure(ErrorInfo errorInfo) {
_15
log(ERROR, errorInfo.toString());
_15
}
_15
});

When using setState to set temporary user status, if the specified key already exists, its value is overwritten by the new value. If the specified key does not exist, a new key/value pair is added.

Get status

To obtain the temporary user status set by a user in a specified channel, use the getState method:


_12
String userId = "Tony";
_12
mRtmClient.getPresence().getState("Chat_room", RtmChannelType.MESSAGE, userId, new ResultCallback<UserState>() {
_12
@Override
_12
public void onSuccess(UserState state) {
_12
log(CALLBACK, "get users(" + state.getUserId() + ") state success, " + state.toString());
_12
}
_12
_12
@Override
_12
public void onFailure(ErrorInfo errorInfo) {
_12
log(ERROR, errorInfo.toString());
_12
}
_12
});

Use the getState method to obtain the temporary status of other online users in the channel. If the queried user is not present in the specified channel, a PRESENCE_USER_NOT_EXIST error message is returned by the SDK.

Delete status

Each user can set up to 32 key/value pairs in a channel. To remove items that are no longer needed, call removeState with a list of keys. The removeState method only deletes temporary user status data for the local user.


_12
ArrayList<String> keys = new ArrayList<>(Arrays.asList("Mode", "Mic"));
_12
mRtmClient.getPresence().removeState("Chat_room", RtmChannelType.MESSAGE, keys, new ResultCallback<Void>() {
_12
@Override
_12
public void onSuccess(Void responseInfo) {
_12
log(CALLBACK, "removeState success");
_12
}
_12
_12
@Override
_12
public void onFailure(ErrorInfo errorInfo) {
_12
log(ERROR, errorInfo.toString());
_12
}
_12
});

Both the setState and removeState methods trigger REMOTE_STATE_CHANGED event notifications. Users who join the channel with withPresence set to true receive event notifications containing full data of the user's temporary status.

Receive presence event notifications

A presence event notification returns the PresenceEvent data structure, which includes the RtmPresenceEventType parameter.

To receive presence event notifications, implement an event listener. See event listeners for details. In addition, set the withPresence parameter to true when subscribing to or joining a channel.

Event notification modes

The presence event notification mode determines how subscribed users receive event notifications. There are two notification modes:

  • Announce: Real-time notification mode
  • Interval: Scheduled notification mode

You set the Max number of instant event value in Agora Console to specify the condition for switching between the two modes. The scheduled notification mode helps prevent event noise that results from a large number of online users in the channel. You can set Max number of instant event to a value between 8 and 128. The default value is 50. If your specific requirement is beyond this range, contact technical support.

Real-time notification mode

If the number of online users in the channel is less than the Max number of instant event value, presence event notifications operate in real-time notification mode. In this mode, REMOTE_JOIN, REMOTE_LEAVE, REMOTE_TIMEOUT, and REMOTE_STATE_CHANGED notifications are sent to the client in real-time.

{      eventType: RtmPresenceEventType.REMOTE_JOIN;      channelType: RtmChannelType.MESSAGE;      channelName: "test_channel";      publisher: "publisher_name";      stateItems: {};      interval: {          joinUserList:[],          leaveUserList:[],          timeoutUserList:[],          userStateList:[],      };      snapshot: {          userStateList:[]      };      timestamp: 1710487149497;}

Scheduled notification

When the number of online users in the channel exceeds the Max number of instant event value, the channel switches to the scheduled notification mode. In this mode, REMOTE_JOIN, REMOTE_LEAVE, REMOTE_TIMEOUT, and REMOTE_STATE_CHANGED events are replaced by INTERVAL events and sent to all users in the channel at specific time intervals. Users receive the following notification:

{      eventType: RtmPresenceEventType.INTERVAL,      channelTye: RtmChannelType.MESSAGE,      channelName: "Chat_room",      publisher: "",      stateItems: {},      interval: {          joinUserList: ["Tony", "Lily"],          leaveUserList: ["Jason"],          timeoutUserList: ["Wang"],          userStateList: [              {                  userId: "Harvard",                  states: [                      {                          key: "Mic",                          value: "False"                      },                     {                          key: "Position",                          value: "Beijing"                      }                 ]              }          ]      },      snapshot: {          userStateList: []      },      timestamp: 1710487149497}

Reference

This section contains content that completes the information on this page, or points you to documentation that explains other aspects to this product.

API reference

Signaling