Implementing Voice Call
Prerequisites
Before implementing basic real-time audio call, ensure that:
- ZEGO Express SDK has been integrated into the project to implement basic real-time audio and video features. For details, please refer to Quick Start - Integration.
- A project has been created in the ZEGOCLOUD Console, and a valid AppID and AppSign have been applied.
The SDK also supports Token authentication. If you have higher security requirements for your project, it is recommended to upgrade the authentication method. For details, please refer to How to upgrade from AppSign authentication to Token authentication.
Usage Steps
This section introduces how to use ZEGO Express SDK to implement basic real-time audio features. The API call sequence is as follows:

Creating Engine
1. (Optional) Create UI
Before creating the engine, it is recommended for developers to add the following UI elements to facilitate the implementation of basic real-time audio features.
- Audio window
- End button

2. Import Header File
Import the ZegoExpressEngine header file in your project.
// Import ZegoExpressEngine.h header file
#import <ZegoExpressEngine/ZegoExpressEngine.h>3. Create Engine
Call the createEngineWithProfile interface, pass the obtained AppID and AppSign into the parameters "appID" and "appSign", and create an engine singleton object.
Select an appropriate scenario based on the actual audio and video business of the App. Please refer to the Scenario-based Audio and Video Configuration document, and pass the selected scenario enumeration into the parameter "scenario".
If you need to register a callback, you can pass an object that implements ZegoEventHandler (e.g., "self") into the parameter "eventHandler". If you do not need to register a callback, you can pass "nil" into the parameter "eventHandler". If you still need to register a callback after creating the engine, you can set the callback by calling the setEventHandler interface.
The SDK also supports Token authentication. If you need to upgrade the authentication method, please refer to How to upgrade from AppSign authentication to Token authentication.
ZegoEngineProfile *profile = [ZegoEngineProfile new];
// Please obtain through official website registration, format: 1234567890
profile.appID = appID;
// Please obtain through official website registration, format: @"0123456789012345678901234567890123456789012345678901234567890123" (64 characters in total)
profile.appSign = appSign;
// Specify the broadcast scenario (please fill in the scenario suitable for your business according to the actual situation)
profile.scenario = ZegoScenarioBroadcast;
// Create engine and register self as eventHandler callback. If no callback is needed, the eventHandler parameter can be nil. You can call "-setEventHandler:" method to set the callback later
[ZegoExpressEngine createEngineWithProfile:profile eventHandler:self];4. Set Callback
You can monitor and handle the event callbacks you are interested in by implementing a class that conforms to the ZegoEventHandler interface and implementing the required callback methods. Then pass the instantiated object (e.g., self) as the eventHandler parameter to createEngineWithProfile or to setEventHandler to register the callback.
It is recommended to register the callback immediately when or after creating the engine, to avoid missing event notifications due to delayed registration.
Logging In to Room
1. Log In
After passing the user ID parameter "userID" to create a ZegoUser user object, call the loginRoom interface, pass in the room ID parameter "roomID" and user parameter "user", and log in to the room. If the room does not exist, calling this interface will create and log in to this room.
- Within the same AppID, ensure that "roomID" is globally unique.
- Within the same AppID, ensure that "userID" is globally unique. It is recommended for developers to set it to a meaningful value and associate "userID" with their own business account system.
- The constructor method of ZegoUser userWithUserID will set "userName" to be the same as the passed parameter "userID". "userID" cannot be "nil", otherwise logging in to the room will fail.
// Create user object. The constructor method of ZegoUser [userWithUserID ](@userWithUserID) will set "userName" to be the same as the passed parameter "userID". "userID" cannot be "nil", otherwise logging in to the room will fail.
ZegoUser *user = [ZegoUser userWithUserID:@"user1"];
// Only by passing ZegoRoomConfig with the "isUserStatusNotify" parameter set to "true" can you receive the onRoomUserUpdate callback.
ZegoRoomConfig *roomConfig = [[ZegoRoomConfig alloc] init];
// If you use appsign for authentication, you do not need to fill in the token parameter; if you need to use a more secure authentication method: token authentication, please refer to [How to upgrade from AppSign authentication to Token authentication](https://www.zegocloud.com/docs/faq/express-token-upgrade)
// roomConfig.token = @"xxxxx";
roomConfig.isUserStatusNotify = YES;
// Log in to room
[[ZegoExpressEngine sharedEngine] loginRoom:roomID user:user config:roomConfig callback:^(int errorCode, NSDictionary * _Nullable extendedData) {
// Log in to room result. If you only care about the login result, just pay attention to this callback
}];2. Listen for Event Callbacks After Logging In to Room
Depending on actual application needs, listen for event notifications of interest after logging in to the room, such as room state updates, user state updates, stream state updates, etc.
-
onRoomStateChanged: Room state update callback. After logging in to the room, when the room connection state changes (e.g., room disconnection, login authentication failure, etc.), the SDK will notify through this callback.
-
onRoomUserUpdate: User state update callback. After logging in to the room, when users are added to or removed from the room, the SDK will notify through this callback.
Only when logging in to the room by calling the loginRoom interface and passing the ZegoRoomConfig configuration with the "isUserStatusNotify" parameter set to "true" can users receive the onRoomUserUpdate callback.
-
onRoomStreamUpdate: Stream state update callback. After logging in to the room, when users in the room newly publish or stop publishing audio and video streams, the SDK will notify through this callback.
- Only when logging in to the room by calling the loginRoom interface and passing the ZegoRoomConfig configuration with the "isUserStatusNotify" parameter set to "true" can users receive the onRoomUserUpdate callback.
- Normally, if a user wants to play videos published by other users, they can call the startPlayingStream interface in the callback for stream state update (addition) to play remote published audio and video streams.
// Follow ZegoEventHandler protocol to handle related event callbacks
@interface ViewController () <ZegoEventHandler>
// ······
@end
@implementation ViewController
// Common room-related callbacks
// Room state update callback
-(void)onRoomStateChanged:(ZegoRoomStateChangedReason)reason errorCode:(int)errorCode extendedData:(NSDictionary *)extendedData roomID:(NSString *)roomID {
if(reason == ZegoRoomStateChangedReasonLogining)
{
// Logging in
}
else if(reason == ZegoRoomStateChangedReasonLogined)
{
// Login successful
// Only when the room state is login successful or reconnection successful can publishing streams (startPublishingStream) and playing streams (startPlayingStream) normally send and receive audio and video
// Publish your audio and video stream to ZEGO audio and video cloud
}
else if(reason == ZegoRoomStateChangedReasonLoginFailed)
{
// Login failed
}
else if(reason == ZegoRoomStateChangedReasonReconnecting)
{
// Reconnecting
}
else if(reason == ZegoRoomStateChangedReasonReconnected)
{
// Reconnection successful
}
else if(reason == ZegoRoomStateChangedReasonReconnectFailed)
{
// Reconnection failed
}
else if(reason == ZegoRoomStateChangedReasonKickOut)
{
// Kicked out of the room
}
else if(reason == ZegoRoomStateChangedReasonLogout)
{
// Logout successful
}
else if(reason == ZegoRoomStateChangedReasonLogoutFailed)
{
// Logout failed
}
}
// User state update callback
- (void)onRoomUserUpdate:(ZegoUpdateType)updateType userList:(NSArray<ZegoUser *> *)userList roomID:(NSString *)roomID {
// Implement event callbacks as needed
}
// Stream state update callback
- (void)onRoomStreamUpdate:(ZegoUpdateType)updateType streamList:(NSArray<ZegoStream *> *)streamList extendedData:(nullable NSDictionary *)extendedData roomID:(NSString *)roomID {
// Implement event callbacks as needed
}
@endPublishing Stream
1. Start Publishing Stream
Call the startPublishingStream interface, pass in the stream ID parameter "streamID", and send the local audio stream to remote users.
Within the same AppID, ensure that "streamID" is globally unique. If within the same AppID, different users each publish a stream with the same "streamID", it will cause the user who publishes later to fail publishing.
// Start publishing stream
[[ZegoExpressEngine sharedEngine] startPublishingStream:@"stream1"];2. Listen for Event Callbacks After Publishing Stream
Depending on actual application needs, listen for event notifications of interest after publishing stream, such as publishing state updates, etc.
onPublisherStateUpdate: Publishing state update callback. After successfully calling the publishing interface, when the publishing state changes (e.g., network interruption causing publishing abnormality, etc.), the SDK will notify through this callback while retrying publishing.
// Follow ZegoEventHandler protocol to handle related event callbacks
@interface ViewController () <ZegoEventHandler>
// ······
@end
@implementation ViewController
// Common publishing-related callbacks
// Publishing state update callback
- (void)onPublisherStateUpdate:(ZegoPublisherState)state errorCode:(int)errorCode extendedData:(nullable NSDictionary *)extendedData streamID:(NSString *)streamID {
// Implement event callbacks as needed
}
@endIf you need to know about Express's microphone/audio/speaker related interfaces, please refer to FAQ - How to implement switching camera/video/microphone/audio/speaker?.
Playing Stream
1. Start Playing Stream
Call the startPlayingStream interface, based on the passed stream ID parameter "streamID", to play remote published audio streams.
The "streamID" published by remote users can be obtained from the onRoomStreamUpdate callback in ZegoEventHandler.
// Start playing stream
[[ZegoExpressEngine sharedEngine] startPlayingStream:@"stream1"];2. Listen for Event Callbacks After Playing Stream
Depending on actual application needs, listen for event notifications of interest after playing stream, such as playing state updates, etc.
onPlayerStateUpdate: Playing state update callback. After successfully calling the playing interface, when the playing state changes (e.g., network interruption causing publishing abnormality, etc.), the SDK will notify through this callback while retrying playing.
// Follow ZegoEventHandler protocol to handle related event callbacks
@interface ViewController () <ZegoEventHandler>
// ······
@end
@implementation ViewController
// Common publishing-related callbacks
// Playing state update callback
- (void)onPlayerStateUpdate:(ZegoPlayerState)state errorCode:(int)errorCode extendedData:(NSDictionary *)extendedData streamID:(NSString *)streamID {
// Implement event callbacks as needed
}
@endExperience Real-time Audio and Video Features
Run the project on a real device. After successful execution, you can see the local video screen.
To facilitate experience, ZEGO provides a Web platform for debugging. On this page, enter the same AppID and RoomID, enter different UserIDs and corresponding Token, and you can join the same room to communicate with real device. When the audio and video call starts successfully, you can hear remote audio and see remote video screen.
Stopping Publishing and Playing Streams
1. Stop Publishing Stream
Call the stopPublishingStream interface to stop sending local audio streams to remote users.
// Stop publishing stream
[[ZegoExpressEngine sharedEngine] stopPublishingStream];2. Stop Playing Stream
Call the stopPlayingStream interface to stop playing remote published audio streams.
If developers receive a notification of "reduction" in audio and video streams through the onRoomStreamUpdate callback, please call the stopPlayingStream interface in time to stop playing streams to avoid playing empty streams and generating additional costs; or, developers can choose the appropriate timing according to their own business needs and actively call the stopPlayingStream interface to stop playing streams.
// Stop playing stream
[[ZegoExpressEngine sharedEngine] stopPlayingStream:@"stream1"];Logging Out of Room
Call the logoutRoom interface to log out of the room.
// Log out of room
[[ZegoExpressEngine sharedEngine] logoutRoom:@"room1"];Destroying Engine
Call the destroyEngine interface to destroy the engine, which is used to release resources used by the SDK.
-
If you need to listen to the callback to ensure that device hardware resources are released, you can pass "callback" when destroying the engine. This callback is only used for sending notifications, and developers cannot release engine-related resources in the callback.
-
If you do not need to listen to the callback, you can pass "nil".
[ZegoExpressEngine destroyEngine:nil];