In today’s fast-paced digital landscape, live audio rooms have emerged as a dynamic platform for real-time interaction, fostering connections, and engaging audiences in innovative ways. A live audio room is a virtual space where participants can join in and share their voices, creating an immersive experience that transcends traditional text-based communication. These rooms are becoming increasingly popular for various purposes, from hosting discussions and interviews to facilitating workshops and networking events.
Implementing a live audio room not only enhances user engagement but also provides an opportunity for brands, creators, and communities to cultivate a loyal following. In this blog, you will explore the essential steps to set up a live audio room and discuss the key features that make it effective based on ZEGOCLOUD Video Chat and In-app Chat . Join us as we uncover the potential of live audio rooms and guide you through the process of bringing your own to life!
Before You Start
Before you begin, make sure:
- You have created a project in ZEGOCLOUD Console, and get the valid AppID and AppSign. For details, please refer to Admin Console – How to view project information.
- You have downloaded the demo.
- Your project has integrated ZEGO Express SDK , and your project has implemented basic real-time audio and video features. For details, please refer to Quick Start.
- Your project has activated the In-app Chat service.
Preview the Effect You Can Achieve with This Demo
You can achieve the following effect with the demo provided in this doc:
Using the demo provided in this document, you can achieve the following results:
Home page | Host page | Audience page | Audience taps the speaker seat | Host check the requests |
---|---|---|---|---|
The host can tap the Lock icon on the lower right to change the room mode.
- Free mode: Audience became the speaker once click the speaker seat.
- Request mode: Auidence has to wait for the host to agree with the seat-taking request that is triggered by clicking the speaker seat.
How Does It Work?
The usage of basic SDK functions has been introduced by Quick start. If you are not familiar with the concept of stream publishing/playing, please read the document carefully again.
In a live audio room:
- All the audience can start playing streams after entering the room to listen to the speakers on the speaker seat in the room.
- Speaker starts publishing streams after they are on the speaker seat to transmit local audio to the audience in the room.
How to manage speaker seats
In addition to implementing the above logic, the live audio room also needs to manage speaker seats. The speaker seat management function can usually be implemented using the room attribute feature of the ZIM SDK.
This feature allows app clients to set and synchronize custom room attributes in the room. Room attributes are stored on the ZEGOCLOUD server in a Key-Value manner, and the ZEGOCLOUD server handles write conflict arbitration and other issues to ensure data consistency.
At the same time, modifications made by app clients to room attributes are synchronized to all other audiences in the room in real time through the ZEGOCLOUD server.
Each room allows a maximum of 20 attributes to be set, with a
key
length limit of 16 bytes and avalue
length limit of 1024 bytes.
Taking Alice takes speaker seat as an example, the process is as follows:
Using Room Attributes to represent Speaker Seats:
You can use the speaker seat number in the live audio room as the key of the room attribute and use userID
as the value of the room attribute to represent the speaker seat status of the room.
For example, if the user with userID “user123” is on the No.0 speaker seat and the user with userID “user456” is on the No.1 speaker seat, then the room attribute is represented as follows:
{
"0":"user123", // Indicates te user123 is on the NO.0 speaker seat
"1":"user456", // Indicates te user456 is on the NO.1 speaker seat
}
The design of the room attribute feature can solve some common problems in speaker seat management in live audio room scenario:
Feature | Description | Usage |
---|---|---|
Owner | The first audience to set a key will become the owner of that key. By default, the key can only be modified by the owner. | Can be used to avoid conflicts when grabbing the speaker seat. |
Automatic Deletion | When setting KV, the key can be configured as “automatically deleted after the owner leaves the room”. | Can be used to achieve the function of “automatic update of speaker seat when speaker gets offline”, avoiding the problem of speaker seat disorder due to app client disconnection. |
Forced Modification | Supports ignoring the owner and forcefully modifying KV. | Can be used to achieve the function of “Host forcefully remove the audience from speaker seat”. |
Combined Operations | Multiple operations on different KVs can be combined into one combined operation to avoid conflicts caused by other users operating related KVs. | Can be used to achieve the function of changing the speaker seat. |
How to manage room mode
In the live audio room app, you may need to support the host to modify the room mode:
- Free mode: Audience became the speaker once click the speaker seat.
- Request mode: Auidence has to wait for the host to agree with the seat-taking request that is triggered by clicking the speaker seat.
The room mode is implemented using the setRoomExtraInfo
. RoomExtraInfo
is similar to the above RoomAttribute
, also stored on the ZEGOCLOUD server, but the usage of RoomExtraInfo
is simpler:
There are no complex parameters, only support for setting a key-value string (key maximum 10 bytes, value maximum 128 bytes), which is more suitable for simple business operations bound to the room, such as room mode, room announcements, etc.
You can encapsulate any business field into the JSON protocol and set it to RoomExtraInfo
to implement business logic such as room mode.
When the host calls the
setRoomExtraInfo
method, the in-room users can receive the setRoomExtraInfo
viaonRoomExtraInfoUpdate
.
How to request to take a speaker seat using roomrequest
What is roomrequest?
The process of co-hosting seat-taking request implemented based on roomrequest, roomrequest is a protocol or message to manage communication and connections in networks. ZEGOCLOUD packages all roomrequest capabilities into a SDK, providing you with a readily available real-time roomrequest API.
How to send & receive roomrequest messages through the ZIM SDK interface
The ZIM SDK provides rich functionality for sending and receiving messages, see Send & Receive messages (roomrequest). And here, you will need to use the customizable roomrequest message: ZIMCommandMessage
Complete demo code for this section can be found at ZIMService.java.
1. Send RoomRequests (ZIMCommandMessage
) in the room by calling sendMessage
with the following:
zim.sendMessage(commandMessage, mRoomID, ZIMConversationType.ROOM, config, new ZIMMessageSentCallback() {
// ...
@Override
public void onMessageSent(ZIMMessage message, ZIMError errorInfo) {
// ...
}
});
2. After sending, other users in the room will receive the RoomRequest from the onReceiveRoomMessage callback. You can listen to this callback by following below:
zim.setEventHandler(new ZIMEventHandler() {
@Override
public void onReceiveRoomMessage(ZIM zim, ArrayList<ZIMMessage> messageList, String fromRoomID) {
super.onReceiveRoomMessage(zim, messageList, fromRoomID);
// ...
}
});
How to customize business RoomRequests
Complete demo code for this section can be found at ZIMService.java and RoomRequest.java.
JSON RoomRequest encoding
Since a simple String
itself is difficult to express complex information, RoomRequests can be encapsulated in JSON
format, making it more convenient for you to organize the protocol content of the RoomRequests.
Taking the simplest JSON RoomRequest as an example: {"action_type": 0}
, in such a JSON RoomRequest, you can use the action_type
field to express different RoomRequest types, such as:
- Sending a request:
{"action_type": RoomRequestAction.ACTION_REQUEST}
- Canceling a request:
{"action_type": RoomRequestAction.ACTION_CANCEL}
- Accepting a request:
{"action_type": RoomRequestAction.ACTION_ACCEPT}
- Rejecting a request:
{"action_type": RoomRequestAction.ACTION_REJECT}
In addition, you can also extend other common fields for RoomRequests, such as senderID
,receiverID
,extended_data
:
public class RoomRequest {
// ...
public String toString() {
JSONObject jsonObject = new JSONObject();
try {
jsonObject.put("action_type", actionType);
jsonObject.put("sender_id", sender);
jsonObject.put("receiver_id", receiver);
jsonObject.put("extended_data", extendedData);
jsonObject.put("request_id", requestID);
} catch (JSONException e) {
throw new RuntimeException(e);
}
return jsonObject.toString();
}
// ...
}
public @interface RoomRequestAction {
int ACTION_REQUEST = 0;
int ACTION_ACCEPT = 1;
int ACTION_REJECT = 2;
int ACTION_CANCEL = 3;
}
JSON RoomRequest decoding
And users who receive RoomRequests can decode the JSON RoomRequest and know and process specific business logic based on the fields in it, such as:
zim.setEventHandler(new ZIMEventHandler() {
@Override
public void onReceiveRoomMessage(ZIM zim, ArrayList<ZIMMessage> messageList, String fromRoomID) {
super.onReceiveRoomMessage(zim, messageList, fromRoomID);
zimRoomService.onReceiveRoomMessage(zim, messageList, fromRoomID);
}
// ...
})
// ...
public void onReceiveRoomMessage(ZIM zim, ArrayList<ZIMMessage> messageList, String fromRoomID) {
try {
for (ZIMMessage zimMessage : messageList) {
if (zimMessage instanceof ZIMCommandMessage) {
ZIMCommandMessage commandMessage = (ZIMCommandMessage) zimMessage;
String message = new String(commandMessage.message, StandardCharsets.UTF_8);
JSONObject jsonObject = new JSONObject(message);
ZIMUserInfo currentUser = zimUserService.getCurrentUser();
if (jsonObject.has("action_type") && currentUser != null) {
String sender = jsonObject.getString("sender_id");
String receiver = jsonObject.getString("receiver_id");
int actionType = jsonObject.getInt("action_type");
if (currentUser.userID.equals(receiver)) {
// ...
}
}
}
}
} catch (JSONException e) {
// ...
}
}
Further extending RoomRequests
Based on this pattern, when you need to do any protocol extensions in your business, you only need to extend the extended_data
field of the RoomRequest to easily implement new business logic, such as:
- Muting audience: After receiving the corresponding RoomRequest, the UI blocks the user from sending live bullet messages.
- Sending virtual gifts: After receiving the RoomRequest, show the gift special effects.
- Removing audience: After receiving the RoomRequest, prompt the audience that they have been removed and exit the room.
Friendly reminder:
After reading the following text and further understanding the implementation of seat-taking request RoomRequests, you will be able to easily extend your business RoomRequests.
The demo in this document is a pure client API + ZEGOCLOUD solution. If you have your own business server and want to do more logical extensions, you can use our Server API to pass RoomRequests and combine your server’s room business logic to increase the reliability of your app.
Implementation
Based on the above technical principles, we will explain the implementation details of the live audio room solution to you in detail.
Integrate and start to use the ZIM SDK
If you have not used the ZIM SDK before, you can read the following section:
Import the ZIM SDK
To import the ZIM SDK, do the following:
1. Set up repositories.
- If your Android Gradle Plugin is v7.1.0 or later: go to the root directory of your project, open the
settings.gradle
file, and add the following line to thedependencyResolutionManagement
:
...
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
maven { url 'https://storage.zego.im/maven' }
mavenCentral()
google()
}
}
If you can not find the above fields in settings.gradle
, it’s probably because your Android Gradle Plugin version is lower than v7.1.0. For more details, see Android Gradle Plugin Release Note v7.1.0.
- If your Android Gradle Plugin is earlier than 7.1.0: go to the root directory of your project, open the
build.gradle
file, and add the following line to theallprojects
:
...
allprojects {
repositories {
maven { url 'https://storage.zego.im/maven' }
mavenCentral()
google()
}
}
2. Declare dependencies
Go to the app
directory, open the build.gradle
file, and add the following line to the dependencies
. (x.y.z is the SDK version number. To obtain the latest version number, see ZIM Release Notes.
...
dependencies {
...
implementation 'im.zego:zim:x.y.z'
}
Create and Manage SDK instances
After successful integration, you can use the ZIM SDK like this:
import im.zego.zim.ZIM
Creating a ZIM instance is the very first step, an instance corresponds to a user logging in to the system as a client.
ZIMAppConfig appConfig = new ZIMAppConfig();
appConfig.appID = yourAppID;
appConfig.appSign = yourAppSign;
zim = ZIM.create(appConfig, application);
Later on, we will provide you with detailed instructions on how to use the ZIM SDK to develop the live audio room feature.
Manage Multiple SDKs More Easily
In most cases, you need to use multiple SDKs together. For example, in the live audio room scenario described in this doc, you need to use the ZIM SDK
to implement the speak seat management
feature, and then use the ZEGO Express Engine SDK
to implement the live audio room
feature.
If your app has direct calls to SDKs everywhere, it can make the code difficult to manage and troubleshoot. To make your app code more organized, we recommend the following way to manage these SDKs:
1. Create a wrapper layer for each SDK so that you can reuse the code to the greatest extent possible.
Create a ZIMService
class for the ZIM SDK
, which manages the interaction with the SDK and stores the necessary data. Please refer to the complete code in ZIMService.java.
public class ZIMService {
// ...
public void initSDK(Application application, long appID, String appSign) {
zimProxy.create(application, appID, appSign);
// ...
}
}
class ZIMProxy {
private SimpleZIMEventHandler zimEventHandler;
public void create(Application application, long appID, String appSign) {
ZIMAppConfig zimAppConfig = new ZIMAppConfig();
zimAppConfig.appID = appID;
zimAppConfig.appSign = appSign;
ZIM.create(zimAppConfig, application);
zimEventHandler = new SimpleZIMEventHandler();
if (getZIM() != null) {
ZIM.getInstance().setEventHandler(zimEventHandler);
}
}
}
Similarly, create an ExpressService
class for the zego_express_engine sdk
, which manages the interaction with the SDK and stores the necessary data. Please refer to the complete code in ExpressService.java.
public class ExpressService {
// ...
public void initSDK(Application application, long appID, String appSign, ZegoScenario scenario) {
ZegoEngineConfig config = new ZegoEngineConfig();
config.advancedConfig.put("notify_remote_device_unknown_status", "true");
config.advancedConfig.put("notify_remote_device_init_status", "true");
ZegoExpressEngine.setEngineConfig(config);
engineProxy.createEngine(application, appID, appSign, scenario);
// ...
}
}
class ExpressEngineProxy {
private SimpleExpressEventHandler expressEventHandler;
public void createEngine(Application application, long appID, String appSign, ZegoScenario scenario) {
ZegoEngineProfile profile = new ZegoEngineProfile();
profile.appID = appID;
profile.appSign = appSign;
profile.scenario = scenario;
profile.application = application;
expressEventHandler = new SimpleExpressEventHandler();
ZegoExpressEngine.createEngine(profile, expressEventHandler);
}
}
With the service, you can add methods to the service whenever you need to use any SDK interface.
For example: Easily add the connectUser method to the ZIMService when you need to implement login.
public class ZIMService {
// ...
public void connectUser(String userID, String userName, String token,ZIMLoggedInCallback callback) {
ZIMUserInfo zimUserInfo = new ZIMUserInfo();
zimUserInfo.userID = userID;
zimUserInfo.userName = userName;
zim.login(zimUserInfo,token, new ZIMLoggedInCallback() {
@Override
public void onLoggedIn(ZIMError errorInfo) {
// ...
}
});
}
}
2. After completing the service encapsulation, you can further simplify the code by creating a ZEGOSDKManager
to manage these services, as shown below. Please refer to the complete code in ZEGOSDKManager.java.
public class ZEGOSDKManager {
public ExpressService expressService = new ExpressService();
public ZIMService zimService = new ZIMService();
private static final class Holder {
private static final ZEGOSDKManager INSTANCE = new ZEGOSDKManager();
}
public static ZEGOSDKManager getInstance() {
return Holder.INSTANCE;
}
public void initSDK(Application application, long appID, String appSign,ZegoScenario scenario) {
expressService.initSDK(application, appID, appSign,scenario);
zimService.initSDK(application, appID, appSign);
}
}
3. Now, you have implemented a singleton class that manages the SDK services you need. From now on, you can get an instance of this class anywhere in your project and use it to execute SDK-related logic, such as:
- When the app starts up: call
ZEGOSDKManager.getInstance().initSDK(application,appID,appSign);
- When login : call
ZEGOSDKManager.getInstance().connectUser(userID,userName,callback);
Later, we will introduce how to add a live audio room feature based on this.
Speaker seat management
Later, we will introduce how to add the speaker seat management feature based on that.
Take a speaker seat
- For an audience to take a speaker seat, call the
setRoomAttributes
and set the speaker seat number as the key and the audience’s userID as the attribute value in the room’s additional attributes. If the setting is successful, the audience member has successfully taken a speaker seat and can start publishing streams.
Sample code:
public void takeSeat(int seatIndex, ZIMRoomAttributesOperatedCallback callback) {
ZEGOSDKUser localUser = ZEGOSDKManager.getInstance().expressService.getCurrentUser();
if (localUser == null || isTakeSeat) {
return;
}
isTakeSeat = true;
String key = String.valueOf(seatIndex);
String value = localUser.userID;
ZIMRoomAttributesSetConfig config = new ZIMRoomAttributesSetConfig();
config.isDeleteAfterOwnerLeft = true;
config.isForce = true;
config.isUpdateOwner = true;
ZEGOSDKManager.getInstance().zimService.setRoomAttributes(key, value, config,
new ZIMRoomAttributesOperatedCallback() {
@Override
public void onRoomAttributesOperated(String roomID, ArrayList<String> errorKeys, ZIMError errorInfo) {
isTakeSeat = false;
if (callback != null) {
callback.onRoomAttributesOperated(roomID, errorKeys, errorInfo);
}
}
});
}
The complete reference code can be found at RoomSeatService.java.
Instructions for grabbing the speaker seat: When taking the speaker seat, set the isForce
attribute of ZIMRoomAttributesSetConfig
to false. When multiple audiences try to take the same speaker seat at the same time, the server will receive the first request and return a successful response, setting the owner of that key to the user who made the request. Subsequent modification requests from other users will fail.
Leave the speaker seat
- For a speaker to leave the speaker seat, call the
deleteRoomAttributes
to delete the speaker seat number that the speaker was using, and stop publishing streams.
Sample code:
public void leaveSeat(int seatIndex, ZIMRoomAttributesOperatedCallback callback) {
ZEGOSDKUser localUser = ZEGOSDKManager.getInstance().expressService.getCurrentUser();
if (localUser == null) {
return;
}
List<String> list = Collections.singletonList(String.valueOf(seatIndex));
ZEGOSDKManager.getInstance().zimService.deleteRoomAttributes(list, new ZIMRoomAttributesOperatedCallback() {
@Override
public void onRoomAttributesOperated(String roomID, ArrayList<String> errorKeys, ZIMError errorInfo) {
if (callback != null) {
callback.onRoomAttributesOperated(roomID, errorKeys, errorInfo);
}
}
});
}
The complete reference code can be found at RoomSeatService.java.
Remove a speaker
When the host needs to remove a speaker from the speaker seat, call the deleteRoomAttributes
, and set the isForce
field of ZIMRoomAttributesDeleteConfig
to true, to force clear the room attributes of the corresponding speaker seat, thereby removing the speaker from the seat.
public void removeSpeakerFromSeat(String userID, ZIMRoomAttributesOperatedCallback callback) {
ZEGOSDKUser localUser = ZEGOSDKManager.getInstance().expressService.getCurrentUser();
if (localUser == null) {
return;
}
for (LiveAudioRoomSeat seat : seatList) {
int seatIndex = seat.seatIndex;
ZEGOSDKUser seatUser = seat.getUser();
if (seatUser != null) {
String seatUserID = seatUser.userID;
if (Objects.equals(userID, seatUserID)) {
leaveSeat(seatIndex, callback);
break;
}
}
}
}
The complete reference code can be found at RoomSeatService.java.
Changing speaker seat
Ignore this section if you are not going to implement the seat changing function.
When a speaker switches from one seat to another, for example, Speaker A switches from the No.2 seat to the No.3 seat, he needs to first delete the room attribute corresponding to the No.2 seat (to leave No.2 seat), and then set the value of the room attribute corresponding to No.3 seat to their own userID (to take No.3 seat). This process involves two steps. Consider the following extreme situation:
When Speaker A has just completed the first step (deleting the room attribute corresponding to the No.2 seat and leaving the No.2 seat), User B takes the No.3 seat ahead of Speaker A, causing Speaker A to successfully leave the No.2 seat but fail to take the No.3 seat.
In this situation, Speaker A loses the speaker seat, which obviously does not meet expectations.
To handle this situation, you need to prevent other users from operating on the relevant speaker seats before Speaker A completes the two-step operation. This can be achieved using the feature of combined operations:
// 1. Start the combined operations.
ZIMRoomAttributesBatchOperationConfig config = new ZIMRoomAttributesBatchOperationConfig();
config.isForce = true;
config.isDeleteAfterOwnerLeft = false;
config.isUpdateOwner = false;
zim.beginRoomAttributesBatchOperation(mRoomID, config);
// 2. Operation 1: leave the No.2 seat
List<String> keys = Collections.singletonList(String.valueOf(3));
ZIMRoomAttributesDeleteConfig config = new ZIMRoomAttributesDeleteConfig();
zim.deleteRoomAttributes(keys, mRoomID, config, callback);
// 3. Operation 2: take the No.3 seat
String key = String.valueOf(2);
String value = localUser.userID;
ZIMRoomAttributesSetConfig config = new ZIMRoomAttributesSetConfig();
config.isDeleteAfterOwnerLeft = true;
config.isForce = false;
HashMap<String, String> attributes = new HashMap<>();
attributes.put(key, value);
zim.setRoomAttributes(attributes, mRoomID, config, callback);
// 4. End the combined operations.
zim.endRoomAttributesBatchOperation(mRoomID, callback);
In the demo, the method is encapsulated as switchSeat
.
The complete reference code is as follows:
public void switchSeat(int fromSeatIndex, int toSeatIndex, ZIMRoomAttributesBatchOperatedCallback callback) {
AudioRoomUser localUser = ZEGOSDKManager.getInstance().expressService.getLocalUser();
if (localUser == null) {
return;
}
if (!batchOperation) {
ZEGOSDKManager.getInstance().zimService.beginRoomPropertiesBatchOperation();
batchOperation = true;
tryTakeSeat(toSeatIndex, null);
leaveSeat(fromSeatIndex, null);
ZEGOSDKManager.getInstance().zimService.endRoomPropertiesBatchOperation(
new ZIMRoomAttributesBatchOperatedCallback() {
@Override
public void onRoomAttributesBatchOperated(String roomID, ZIMError errorInfo) {
batchOperation = false;
if (callback != null) {
callback.onRoomAttributesBatchOperated(roomID, errorInfo);
}
}
});
}
}
Room mode
We define the room mode as follows:
Free mode | Request mode | |
---|---|---|
roomExtraInfo | {"lockseat":false} | {"lockseat":true} |
The host can call the setRoomExtraInfo
to switch between the Free mode and the Request mode.
public void setHostAndLockSeat() {
JSONObject extraInfoValueJson = audioRoomExtraInfo.getExtraInfoValueJson();
try {
ZEGOSDKUser localUser = ZEGOSDKManager.getInstance().expressService.getCurrentUser();
JSONObject jsonObject = new JSONObject(extraInfoValueJson.toString());
jsonObject.put(EXTRA_INFO_VALUE_HOST, localUser.userID);
jsonObject.put(EXTRA_INFO_VALUE_LOCK_SEAT, true);
ZEGOSDKManager.getInstance().expressService.setRoomExtraInfo(EXTRA_INFO_KEY, jsonObject.toString());
} catch (JSONException e) {
throw new RuntimeException(e);
}
}
The complete reference code can be found at RoomSeatService.java.
Request to take a speaker seat using roomrequest
Send & Cancel a seat-taking request
The implementation of sending and canceling seat-taking requests is similar, with only the type of RoomRequest being different. Here, sending will be used as an example to explain the implementation of the demo.
In the Demo, a seat-taking request button has been placed in the lower right corner of the LiveAudioRoomActivity
as seen from the audience perspective. When the button is clicked, the following actions will be executed.
- Encode the JSON RoomRequest, where the
action_type
is defined asRoomRequestAction.ACTION_REQUEST
in the demo. - add
room_request_type
to extendedData, mark it asREQUEST_TAKE_SEAT
; - Call
sendRoomRequest
to send the RoomRequest. (sendRoomRequest
simplifies thesendMessage
interface ofZIM SDK
.)
- If the method call is successful: the applying status of the local end (i.e. the audience) will be switched to applying for take a seat, and the
seat-taking request
button will switch toCancel Take Seat
. - If the method call fails: an error message will be prompted. In actual app development, you should use a more user-friendly UI to prompt the failure of the seat-taking request.
@Override
protected void afterClick() {
super.afterClick();
// ...
RoomRequestExtendedData extendedData = new RoomRequestExtendedData();
extendedData.roomRequestType = RoomRequestType.REQUEST_TAKE_SEAT;
ZEGOSDKManager.getInstance().zimService.sendRoomRequest(hostUser.userID, jsonObject.toString(),
new RoomRequestCallback() {
@Override
public void onRoomRequestSend(int errorCode, String requestID) {
if (errorCode == 0) {
mRequestID = requestID;
}
}
});
// ...
}
public void sendRoomRequest(String receiverID, String extendedData, RoomRequestCallback callback) {
if (zimProxy.getZIM() == null || currentRoom == null || currentUser == null) {
return;
}
RoomRequest roomRequest = new RoomRequest();
roomRequest.receiver = receiverID;
roomRequest.sender = currentUser.userID;
roomRequest.extendedData = extendedData;
roomRequest.actionType = RoomRequestAction.ACTION_REQUEST;
byte[] bytes = roomRequest.toString().getBytes(StandardCharsets.UTF_8);
ZIMCommandMessage commandMessage = new ZIMCommandMessage(bytes);
zimProxy.sendMessage(commandMessage, currentRoom.roomID, ZIMConversationType.ROOM, new ZIMMessageSendConfig(),
new ZIMMessageSentCallback() {
@Override
public void onMessageAttached(ZIMMessage message) {
}
@Override
public void onMessageSent(ZIMMessage message, ZIMError errorInfo) {
if (errorInfo.code == ZIMErrorCode.SUCCESS) {
roomRequest.requestID = String.valueOf(message.getMessageID());
roomRequestMap.put(roomRequest.requestID, roomRequest);
}
//...
}
});
}
public void updateUI() {
RoomRequest roomRequest = ZEGOSDKManager.getInstance().zimService.getRoomRequestByRequestID(mRequestID);
if (roomRequest == null) {
setText("Apply to Take Seat");
} else {
setText("Cancel Take Seat");
}
setBackgroundResource(R.drawable.bg_cohost_btn);
setCompoundDrawablesWithIntrinsicBounds(R.drawable.liveaudioroom_bottombar_cohost, 0, 0, 0);
}
The complete reference code can be found at TakeSeatButton.java.
Afterwards, the local end (audience end) will wait for the response from the host.
- If the host rejects the seat-taking request: the applying status of the local end will be switched to not applying.
- If the host accepts the seat-taking request: the audience became a speaker, and can start publishing streams.
Accept & Reject the seat-taking request
- In the demo, when the host receives a seat-taking request RoomRequest, the audience who requested will show in the request list, the host can check the list and choose to accept or reject the audience’s seat-taking request after clicking on the request list.
- After the host responds, a RoomRequest of acceptance or rejection will be sent. The related logic of sending RoomRequests will not be further described here.
The relevant code snippet is as follows, and the complete code can be found in RoomRequestListDialog.java and RoomRequestListAdapter.java.
Code snippet
1. Add the audience to the request list after receiving his seat-taking request.
ZEGOSDKManager.getInstance().zimService.addIncomingRoomRequestListener(incomingRoomRequestListener);
// ...
incomingRoomRequestListener = new IZIMEventHandler() {
public void onInComingRoomRequestReceived(String requestID, String extendedData) {
RoomRequestExtendedData data = RoomRequestExtendedData.parse(extendedData);
if (data != null && data.roomRequestType == roomRequestType) {
RoomRequest request = ZEGOSDKManager.getInstance().zimService.getRoomRequestByRequestID(requestID);
if (request != null) {
seatRequestAdapter.addItem(request.sender);
}
}
}
// ...
}
2. In the user list, the host can choose to click accept or reject.
Add the audience to the request list after receiving his seat-taking request.
ZEGOSDKManager.getInstance().zimService.addIncomingRoomRequestListener(incomingRoomRequestListener);
// ...
incomingRoomRequestListener = new IZIMEventHandler() {
public void onInComingRoomRequestReceived(String requestID, String extendedData) {
RoomRequestExtendedData data = RoomRequestExtendedData.parse(extendedData);
if (data != null && data.roomRequestType == roomRequestType) {
RoomRequest request = ZEGOSDKManager.getInstance().zimService.getRoomRequestByRequestID(requestID);
if (request != null) {
seatRequestAdapter.addItem(request.sender);
}
}
}
// ...
}
In the user list, the host can choose to click accept or reject.
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
// ...
agree.setOnClickListener(v -> {
ZEGOSDKManager.getInstance().zimService.acceptRoomRequest(protocol, new RoomRequestCallback() {
@Override
public void onRoomRequestSend(int errorCode, String requestID) {
}
});
});
disagree.setOnClickListener(v -> {
ZEGOSDKManager.getInstance().zimService.rejectRoomRequest(protocol, new RoomRequestCallback() {
@Override
public void onRoomRequestSend(int errorCode, String requestID) {
}
});
});
}
FAQs
How to know if the speaker has turned on the microphone?
You can listen to the onRemoteMicStateUpdate
callback notification of Express SDK to determine whether the microphone device of the remote publishing stream device is working normally or turned off, and preliminarily understand the cause of the device problem according to the corresponding state.
This callback will not be triggered when the remote stream is played from the CDN. How to know if a speaker is speaking
How to know if a speaker is speaking?
You can listen to the onRemoteSoundLevelUpdate
callback notification of Express SDK to get the sound level of the speaker’s voice.
For details, refer to Visualize the sound level.
Conclusion
Live audio rooms are revolutionizing real-time interaction by fostering meaningful connections and engaging audiences in innovative ways. They provide a virtual space where participants can share their voices, creating immersive experiences that go beyond traditional text-based communication. By following this guide, you now have the tools to set up your own live audio room, equipped with essential features to ensure its success. This powerful medium allows for hosting discussions, facilitating workshops, and building vibrant communities, making your app more interactive and engaging. Sign up today and enjoy 10,000 minutes free of charge to start creating your live audio room today and unlock endless possibilities for connection and engagement! If you have any suggestions or comments, feel free to share them with us via Discord. We value your feedback.
Let’s Build APP Together
Start building with real-time video, voice & chat SDK for apps today!