Open Channel

Open Channel is a public chat by nature and it can handle a large number of participation online. In this channel type, anyone can enter and participate in the chat without permission. A single channel can handle up to one thousand, simultaneous users like Twitch-style public chat. This default number of participants can increase per request.


Create an open channel with additional information

Open Channel is ideal for use cases that require a small and static number of channel. To create an open channel from the SendBird Dashboard, do the following.

In the dashboard, click OPEN CHANNELS, then click CREATE at the top-left corner. In the dialog box that appears, specify the name, url, cover image, and custom type of a channel. The channel url is a unique identifier.

You can also create a channel on demand or dynamically via the SDK or the SendBird Platform API.

[SBDOpenChannel createChannelWithName:NAME coverUrl:COVER_URL data:DATA operatorUserIds:nil completionHandler:^(SBDOpenChannel * _Nullable channel, SBDError * _Nullable error) {
    if (error != nil) {    // Error.
        return;
    }

    // ...
}];
SBDOpenChannel.createChannel(withName: NAME, coverUrl: COVER_URL, data: DATA, operatorUserIds: nil, completionHandler: { (channel, error) in
    guard error == nil else {    // Error.
        return
       }

    // ...
})

When creating a channel, you can also append additional information like cover image and description by specifying several arguments.

[SBDOpenChannel createChannelWithName:NAME coverImage:COVER_IMAGE coverImageName:@"" data:nil operatorUserIds:@[user.userId] customType:CUSTOM_TYPE progressHandler:nil  completionHandler:^(SBDOpenChannel * _Nullable channel, SBDError * _Nullable error) {

}];
SBDOpenChannel.createChannel(withName: NAME, coverImage: COVER_IMAGE, coverImageName: "", data: DATA, operatorUserIds: nil, customType: CUSTOM_TYPE, progressHandler: nil) { (channel, error) in
    // ...
}
  • NAME: the name of a channel, or the channel topic.
  • COVER_IMAGE: the file of the cover image, which you can fetch to render into the UI. Alternatively, you can pass a URL of an image by changing coverImage to coverUrl.
  • DATA: the String field to store structured information, such as a JSON String.
  • CUSTOM_TYPE: the String field that allows you to subclassify your channel.

Note: See the Advanced section for more information on cover images and custom types.


Enter an open channel

A user must enter an open channel to receive messages. The user can enter up to 10 open channels at once, which are valid only within a current connection. So if the disconnected user is reconnected to SendBird, the user must re-enter the channels to continue receiving messages.

[SBDOpenChannel getChannelWithUrl:CHANNEL_URL completionHandler:^(SBDOpenChannel * _Nullable channel, SBDError * _Nullable error) {
    if (error != nil) {    // Error.
        return;
    }

    [channel enterChannelWithCompletionHandler:^(SBDError * _Nullable error) {
        if (error != nil) {    // Error.
            return;
        }

        // ...
    }];
}];
SBDOpenChannel.getWithUrl(CHANNEL_URL) { (channel, error) in
    guard error == nil else {    // Error. 
        return
    }

    channel?.enter(completionHandler: { (error) in
        guard error == nil else {    // Error.
            return
        }

        // ...
    })
}

Exit an open channel

If a user exit an open channel, the user can't receive any messages from that channel.

[SBDOpenChannel getChannelWithUrl:CHANNEL_URL completionHandler:^(SBDOpenChannel * _Nullable channel, SBDError * _Nullable error) {
    if (error != nil) {    // Error. 
        return;
    }

    [channel exitChannelWithCompletionHandler:^(SBDError * _Nullable error) {
        if (error != nil) {    // Error.
            return;
        }

        // ...
    }];
}];
SBDOpenChannel.getWithUrl(CHANNEL_URL) { (channel, error) in
    guard error == nil else {    // Error.
        return
    }

    channel?.exitChannel(completionHandler: { (error) in
        guard error == nil else {    // Error.
            return
        }

        // ...
    })
}

Retrieve a list of open channels

You can obtain a list of all open channels by creating a SBDOpenChannelListQuery instance. Its loadNextPageWithCompletionHandler: method returns a list of SBDOpenChannel objects.

SBDOpenChannelListQuery *query = [SBDOpenChannel createOpenChannelListQuery];
[query loadNextPageWithCompletionHandler:^(NSArray<SBDOpenChannel *> * _Nullable channels, SBDError * _Nullable error) {
    if (error != nil) {    // Error.
        return;
    }

    // ...
}];
let query = SBDOpenChannel.createOpenChannelListQuery()!
query.loadNextPage(completionHandler: { (channels, error) in
    guard error == nil else {    // Error.
        return
    }

    // ...
})

Retrieve an open channel by its URL

Since a channel URL is a unique identifier of an open channel, you can use a URL to retrieve a channel instance. It is important to remember that a user must enter the channel to send or receive messages within it.

Store channel URLs to handle lifecycle or state changes in your app. For example, if a user disconnects from SendBird by temporarily switching to another app, you can provide a smooth restoration of the user's state using a stored URL to fetch the appropriate channel instance, then re-entering the user into the channel.

[SBDOpenChannel getChannelWithUrl:CHANNEL_URL completionHandler:^(SBDOpenChannel * _Nonnull openChannel, SBDError * _Nullable error) {
    if (error != nil) {    // Error!
        return;
    }

    // Successfully retrieving an open channel.
    // Do something with the channel.
}];
SBDOpenChannel.getWithUrl(CHANNEL_URL) { (openChannel, error) in
    guard error == nil else {    // Error.
        return
    }

    // Successfully retrieving an open channel.
    // Do something with the channel.
}

Send messages to an open channel

In an entered channel, a user can send messages of the following types:

  • UserMessage: text message sent by user.
  • FileMessage: binary message sent by user.

You can additionally specify a CUSTOM_TYPE to further subclassify a message. When you send a text message, you can attach arbitrary strings via a DATA field. You can utilize this field to send structured data such as font sizes, font types, or custom JSON objects.

Delivery failures due to the network issues return an exception. By implementing the completionHandler, it is possible to display only the messages that are successfully sent.

[channel sendUserMessage:MESSAGE data:DATA completionHandler:^(SBDUserMessage * _Nullable userMessage, SBDError * _Nullable error) {
    if (error != nil) {    // Error.
        return;
    }

    // ...
}];
channel.sendUserMessage(MESSAGE, data: DATA, completionHandler: { (userMessage, error) in
    guard error == nil else {    // Error.
        return
    }

    // ...
})

A user can also send any binary file through a SendBird server. There are two ways in which you can send a binary file: by sending the file itself, or by sending a URL.

Sending a raw file means that you upload it to a SendBird server. Alternatively, you can choose to send a file hosted in your own server by passing in a URL that points to the file. In this case, your file isn't hosted in the SendBird server, and downloaded through your own server instead.

Note: If you upload your file directly, a size limit is imposed per file. This limit depends on your plan, and can be viewed from your Dashboard. No file size limit is imposed if you send a file message via a URL. Then the file isn't uploaded to the SendBird server.

// Sending a file message with a raw file
[channel sendFileMessageWithBinaryData:FILE filename:FILE_NAME type:FILE_TYPE size:FILE_SIZE data:CUSTOM_DATA completionHandler:^(SBDFileMessage * _Nonnull fileMessage, SBDError * _Nullable error) {
    if (error != nil) {    // Error.
        return;
    }

    // ...
}];

// Sending a file message with a file URL
[channel sendFileMessageWithUrl:FILE_URL size:FILE_SIZE type:FILE_TYPE data:CUSTOM_DATA completionHandler:^(SBDFileMessage * _Nonnull fileMessage, SBDError * _Nullable error) {
    if (error != nil) {    // Error.
        return;
    }

    // ...
}];
// Sending a file message with a raw file
channel.sendFileMessage(withBinaryData: FILE, filename: FILE_NAME, type: FILE_TYPE, size: FILE_SIZE, data: CUSTOM_DATA, completionHandler: { (fileMessage, error) in
    guard error == nil else {    // Error. 
        return
    }

    // ...
})

// Sending a file message with a file URL
channel.sendFileMessage(withUrl: FILE_URL, size: FILE_SIZE, type: FILE_TYPE, data: CUSTOM_DATA) { (fileMessage, error) in
    guard error == nil else {    // Error.
        return
    }

    // ...
}

Note: If an app is moved into the background while uploading a file such as a profile image, picture, or etc., the app can complete the uploading process by using the application:handleEventsForBackgroundURLSession:completionHandler: method in your AppDelegate. To complete the uploading, a background event delegate must be added and implemented in the following delegation. If you don't want to upload the file on the background mode, remove the following delegation in the AppDelegate.

   // AppDelegate.m
   @implementation AppDelegate
       
       // ... 
       
       - (void)application:(UIApplication *)application handleEventsForBackgroundURLSession:(NSString *)identifier completionHandler:(void (^)(void))completionHandler {
           if (completionHandler != nil) {
               completionHandler();
           }
       }
   @end
   // AppDelegate.swift
   class AppDelegate: UIResponder, UIApplicationDelegate {
       func application(_ application: UIApplication, handleEventsForBackgroundURLSession identifier: String, completionHandler: @escaping () -> Void) {
           debugPrint("method for handling events for background url session is waiting to be process. background session id: \(identifier)")
           completionHandler()
       }
   ]

Receive messages through a channel delegate

Messages can be received by adding a SBDChannelDelegate. A received BaseMessage object is one of the following three message types.

  • UserMessage: text message sent by user.
  • FileMessage: binary message sent by user.
  • AdminMessage: message sent by an admin through the Platform API.

UNIQUE_DELEGATE_ID is a unique identifier to register multiple concurrent delegates.

@interface OpenChannelViewController : ViewController<SBDChannelDelegate>

@end

// ...

[SBDMain addChannelDelegate:self identifier:UNIQUE_DELEGATE_ID];

// ...

- (void)channel:(SBDBaseChannel * _Nonnull)sender didReceiveMessage:(SBDBaseMessage * _Nonnull)message {
    if (message isKindOfClass:[SBDUserMessage class]]) {
        // Do something when the received message is a UserMessage.
    }
    else if (message isKindOfClass:[SBDFileMessage class]]) {
        // Do something when the received message is a FileMessage.
    }
    else if (message isKindOfClass:[SBDAdminMessage class]]) {
        // Do something when the received message is an AdminMessage.
    }
}
class OpenChannelChattingViewController: UIViewController, SBDChannelDelegate {

    // ...
    SBDMain.add(self as SBDChannelDelegate, identifier: self.delegateIdentifier)

    // ...

    func channel(_ sender: SBDBaseChannel, didReceive message: SBDBaseMessage) {
        if message is SBDUserMessage {
            // Do something when the received message is a UserMessage.
        }
        else if message is SBDFileMessage {
            // Do something when the received message is a FileMessage.
        }
        else if message is SBDAdminMessage {
            // Do something when the received message is an AdminMessage.
        }
    }
}

If the UI isn't valid anymore, remove the channel delegate.

[SBDMain removeChannelDelegateForIdentifier:UNIQUE_DELEGATE_ID];
SBDMain.removeChannelDelegate(forIdentifier: UNIQUE_DELEGATE_ID)

Load previous messages in an open channel

You can load previous messages by creating a SBDPreviousMessageListQuery instance. Its loadPreviousMessagesWithLimit:reverse:completionHandler: method returns a list of SBDBaseMessage objects. With the returned list, you can display the past messages in your UI once they have loaded.

SBDPreviousMessageListQuery *previousMessageQuery = [self.channel createPreviousMessageListQuery];
[previousMessageQuery loadPreviousMessagesWithLimit:30 reverse:YES completionHandler:^(NSArray<SBDBaseMessage *> * _Nullable messages, SBDError * _Nullable error) {
    if (error != nil) {    // Error.
        return;
    }    

    // ...
}];
let previousMessageQuery = self.channel.createPreviousMessageListQuery()
previousMessageQuery?.loadPreviousMessages(withLimit: 30, reverse: true, completionHandler: { (messages, error) in
    guard error == nil else {    // Error.
        return
    }

    // ...
})

Past messages are queried in fixed numbers (30 in the above code). A new SBDPreviousMessageListQuery instance loads the most recent n messages. And loadPreviousMessagesWithLimit:reverse:completionHandler: method on the same query instance returns the n messages before that. So if you store your query instance as a member variable, you can traverse through your entire message history.

Note: Before invoking loadPreviousMessagesWithLimit:reverse:completionHandler: method again, you must receive completionHandler callback first.


Load messages by timestamp or message ID in an open channel

You can retrieve a set number of messages starting from a specific timestamp. To load messages sent prior to a specified timestamp, use getPreviousMessagesByTimestamp:limit:reverse:messageType:customType:completionHandler: method.

[self.channel getPreviousMessagesByTimestamp:TIMESTAMP limit:LIMIT reverse:REVERSE messageType:MESSAGE_TYPE customType:CUSTOM_TYPE completionHandler:^(NSArray<SBDBaseMessage *> * _Nullable messages, SBDError * _Nullable error) {
    if (error != nil) {    // Error.
        return;
    }

    // A list of messages sent before timestamp is successfully retrieved.
}];
self.channel.getPreviousMessages(byTimestamp: TIMESTAMP, limit: LIMIT, reverse: REVERSE, messageType: MESSAGE_TYPE, customType: nil) { (messages, error) in
    guard error == nil else {    // Error.
        return
    }

    // A list of messages sent before timestamp is successfully retrieved.
}
  • TIMESTAMP: the reference timestamp.
  • LIMIT: the number of messages to load. Note that the actual number of results may be larger than the set value when there are multiple messages with the same timestamp as the earliest message.
  • REVERSE: whether to reverse the results.
  • MESSAGE_TYPE: a SBDMessageTypeFilter enum type. Possible values are limited to SBDMessageTypeFilterAll, SBDMessageTypeFilterUser, SBDMessageTypeFilterFile, or SBDMessageTypeFilterAdmin.
  • CUSTOM_TYPE: the custom type of the messages to be returned.

Note: In a similar way, to load messages sent after a specified timestamp, call getNextMessagesByTimestamp:limit: ... :completionHandler: method. And to load results on either side of the reference timestamp, use getPreviousAndNextMessagesByTimestamp:prevLimit:nextLimit: ... :completionHandler: method.

You can also retrieve a set number of messages starting from a specific message ID. To load messages sent prior to the specified message ID, use getPreviousMessagesByMessageId:limit:reverse:messageType:customType:completionHandler: method.

[self.channel getPreviousMessagesByMessageId:MESSAGE_ID limit:LIMIT reverse:REVERSE messageType:MESSAGE_TYPE customType:CUSTOM_TYPE completionHandler:^(NSArray<SBDBaseMessage *> * _Nullable messages, SBDError * _Nullable error) {
    if (error != nil) {     // Error.
        return;
    }

    // A list of messages, the IDs of which are prior to the specified message ID, is successfully retrieved.
}];
self.channel.getPreviousMessages(byMessageId: MESSAGE_ID, limit: LIMIT, reverse: REVERSE, messageType: MESSAGE_TYPE, customType: CUSTOM_TYPE) { (messages, error) in
    guard error == nil else {       // Error.
        return
    }

    // A list of messages, the IDs of which are prior to the specified message ID, is successfully retrieved.
}
  • MESSAGE_ID: the reference message ID.
  • LIMIT: the number of messages to load. Note that the actual number of results may be larger than the set value when there are multiple messages with the same timestamp as the earliest message.
  • REVERSE: whether to reverse the results.
  • MESSAGE_TYPE: a SBDMessageTypeFilter enum type. Possible values are limited to SBDMessageTypeFilterAll, SBDMessageTypeFilterUser, SBDMessageTypeFilterFile, or SBDMessageTypeFilterAdmin.
  • CUSTOM_TYPE: the custom type of the messages to be returned.

Note: To load messages sent after a specified message ID, call getNextMessagesByMessageId: ... : completionHandler: in a similar fashion. To load results on either side of the reference message ID, use getPreviousAndNextMessagesByMessageId:prevLimit:nextLimit: ... :completionHandler: method.


Update a message in an open channel

Users can update any of their own text and file messages sent. An error is returned if a user attempts to update another user's messages. In addition, channel operators can update any messages sent in the channel.

// In case of UserMessage
[self.channel updateUserMessage:userMessage messageText:@"messageText" data:@"data" customType:@"customType" completionHandler:^(SBDUserMessage * _Nullable userMessage, SBDError * _Nullable error) {
    if (error != nil) {     // Error.
        return;
    }
}];

// In case of FileMessage
[self.channel updateFileMessage:fileMessage data:@"data" customType:@"customType" completionHandler:^(SBDFileMessage * _Nullable fileMessage, SBDError * _Nullable error) {
    if (error != nil) {     // Error.
        return;
    }
}];
// In case of UserMessage
self.openChannel.update(userMessage, messageText: "messageText", data: "data", customType: "customType") { (updatedUserMessage, error) in
    guard error == nil else {       // Error.
        return
    }
}

// In case of FileMessage
self.openChannel.update(fileMessage, data: "data", customType: "customType") { (updatedFileMessage, error) in
    guard error == nil else {       // Error.
        return
    }
}

The didUpdateMessage: callback of the channel delegate will be invoked after the message is updated, and all participants of the channel will be notified.

@interface GroupChannelViewController : ViewController<SBDChannelDelegate>

@end

- (void)channel:(SBDBaseChannel *)sender didUpdateMessage:(SBDBaseMessage *)message {

}

[SBDMain addChannelDelegate:self identifier:UNIQUE_DELEGATE_ID];
class GroupChannelChattingViewController: UIViewController, SBDChannelDelegate {

    // ...
    SBDMain.add(self as SBDChannelDelegate, identifier: self.delegateIdentifier)

    // ...
    func channel(_ sender: SBDBaseChannel, didUpdate message: SBDBaseMessage) {

    }
}

Delete a message from an open channel

Users can delete any messages which were sent by themselves. An error is returned if a user attempts to delete the messages of other participants. Also channel operators can delete any messages in the channel.

[channel deleteMessage:baseMessage completionHandler:^(SBDError * _Nullable error) {
    if (error != nil) {    // Error.
        return;
    }
}];
self.openChannel.delete(baseMessage) { (error) in
    if error != nil {    // Error.
        return
    }

    // ...
}

The messageWasDeleted: callback of the channel delegate will be invoked after the message is deleted, and the result also notified to all other participants in the channel.

@interface OpenChannelViewController : ViewController<SBDChannelDelegate>

@end

- (void)channel:(SBDBaseChannel * _Nonnull)sender messageWasDeleted:(long long)messageId {

}

[SBDMain addChannelDelegate:self identifier:UNIQUE_DELEGATE_ID];
class OpenChannelChattingViewController: UIViewController, SBDChannelDelegate {
    // ...

    SBDMain.add(self as SBDChannelDelegate, identifier: self.delegateIdentifier)

    // ...

    func channel(_ sender: SBDBaseChannel, messageWasDeleted messageId: Int64) {

    // ...
    }
}

Retrieve a list of participants in an open channel

You can retrieve a list of participants who are online and receiving all messages from an open channel.

SBDParticipantListQuery *participantListQuery = [channel createParticipantListQuery];
[self.participantListQuery loadNextPageWithCompletionHandler:^(NSArray<SBDUser *> * _Nullable participants, SBDError * _Nullable error) {
    if (error != nil) {    // Error.
        return;
    }

    // ...
}];
let participantListQuery = openChannel.createParticipantListQuery()
participantListQuery?.loadNextPage(completionHandler: { (participants, error) in
    if error != nil {    // Error.
        return
    }

    // ...
})

Retrieve participant online status in an open channel

To retrieve current connection status of each participant, you should create a new SBDParticipantListQuery to see the latest and updated information on each user. To do like the Retrieve a list of participants in an open channel section above, get a SBDParticipantListQuery for the channel and call createParticipantListQuery(). If you want to see a list of all users in your application, call createApplicationUserListQuery() of SBDMain instead.

You can check each of the users' connection statuses by checking connectionStatus of SBDUser. connectionStatus returns one of the following three values:

Objective-C
  • SBDUserConnectionStatusNonAvailable: user's status information cannot be reached.
  • SBDUserConnectionStatusOffline: user is disconnected from SendBird.
  • SBDUserConnectionStatusOnline: user is connected to SendBird.
Swift
  • SBDUserConnectionStatus.nonAvailable: user's status information cannot be reached.
  • SBDUserConnectionStatus.offline: user is disconnected from SendBird.
  • SBDUserConnectionStatus.online: user is connected to SendBird.

Note: If your app needs to keep track of users' connection statuses in real time, we recommend that you receive a new SBDApplicationUserListQuery periodically, perhaps in intervals of one minute or more.


Retrieve a list of operators in an open channel

You can follow the simple implementation below to retrieve a list of operators who monitor and control the activities in an open channel.

[SBDOpenChannel getChannelWithUrl:CHANNEL_URL completionHandler:^(SBDOpenChannel * _Nullable channel, SBDError * _Nullable error) {
    if (error != nil) {    // Error.
        return;
    }

    // Retrieving a list of operators.
    for (SBDUser *operator in channel.operators) {
        ...    
    }
}];
SBDOpenChannel.getWithUrl(CHANNEL_URL) { (channel, error) in
    guard error == nil else {    // Error. 
        return
    }

    // Retrieving a list of operators.
    for var op in channel!.operators! {
        ...
    }
}

Retrieve a list of banned or muted users in an open channel

You can also create a query to get a list of banned or muted users in an open channel. This query is only available for users who are registered as operators of an open channel.

// In case of retrieving banned users
SBDBannedUserListQuery *bannedListQuery = [channel createBannedUserListQuery];
[bannedListQuery loadNextPageWithCompletionHandler:^(NSArray<SBDUser *> * _Nullable users, SBDError * _Nullable error) {
    if (error != nil) {    // Error.
        return;
    }
}];

// In case of retrieving muted users
SBDMutedUserListQuery *mutedListQuery = [channel createMutedUserListQuery];
[mutedListQuery loadNextPageWithCompletionHandler:^(NSArray<SBDUser *> * _Nullable users, SBDError * _Nullable error) {
    if (error != nil) {    // Error.
        return;
    }
}];
// In case of retrieving banned users
let bannedListQuery = self.channel.createBannedUserListQuery()
bannedListQuery?.loadNextPage(completionHandler: { (users, error) in
    guard error == nil else {    // Error.
        return
    }

    // ...
})

// In case of retrieving muted users
let mutedListQuery = self.channel.createMutedUserListQuery()
mutedListQuery?.loadNextPage(completionHandler: { (users, error) in
    guard error == nil else {    // Error.
        return
    }

    // ...
})

Ban and unban a participant in an open channel

Operators of an open channel can remove any participants that behave inappropriately in the channel by using our Ban function. Users that are banned from a channel can participate in the channel again after the time period set by the operators. Operators can ban and unban participants in open channels using the following code.

[SBDOpenChannel getChannelWithUrl:CHANNEL_URL completionHandler:^(SBDOpenChannel * _Nullable channel, SBDError * _Nullable error) {
    if (error != nil) {    // Error.
        return;
    }

    // Banning and unbanning a participant
    if ([channel isOperatorWithUser:[SBDMain getCurrentUser]]) {
        [channel banUser:USER seconds:SECONDS completionHandler:^(SBDError * _Nullable error) {
            if (error != nil) {    // Error.
                return;
            }

            // Custom implementation for what to do after banning.
            }];

        [channel unbanUser:USER completionHandler:^(SBDError * _Nullable error) {
            if (error != nil) {    // Error. 
                return;
            }

            // Custom implementation for what to do after unbanning.
        }];
    }
}];
SBDOpenChannel.getWithUrl(CHANNEL_URL) { (channel, error) in
    guard error == nil else {    // Error. 
        return
    }

    // Banning and unbanning a participant
    if channel!.isOperator(with: SBDMain.getCurrentUser()!) {
        channel?.ban(USER, seconds: SECONDS, completionHandler: { (error) in
            guard error == nil else {    // Error. 
                return
            }

            // Custom implementation for what to do after banning.
        })

        channel?.unbanUser(USER, completionHandler: { (error) in
            guard error == nil else {    // Error.
                return
            }

            // Custom implementation for what to do after unbanning.
        })
    }
}

Note: You can also use banUserWithUserId() and unbanUserWithUserId() methods, instead of banUser:seconds:completionHandler: and unbanUser:completionHandler: methods, as they have the same functionalities. Please see our API reference on banUserWithUserId:seconds:completionHandler: and unbanUserWithUserId:completionHandler:.


Mute and unmute a participant in an open channel

Operators of an open channel can prohibit selected participants from sending messages using our Mute function. Muted participants will remain in the channel and view the messages, but will not be allowed to send any messages until the operators unmute them. Operators can mute and unmute participants in open channels using the following code:

[SBDOpenChannel getChannelWithUrl:CHANNEL_URL completionHandler:^(SBDOpenChannel * _Nullable channel, SBDError * _Nullable error) {
    if (error != nil) {    // Error. 
        return;
    }

    // Muting and unmuting a participant
    if ([channel isOperatorWithUser:[SBDMain getCurrentUser]]) {
        [channel muteUser:USER completionHandler:^(SBDError * _Nullable error) {
            if (error != nil) {    // Error. 
                return;
            }

            // Custom implementation for what to do after muting.
        }];

        [channel unmuteUser:USER completionHandler:^(SBDError * _Nullable error) {
            if (error != nil) {    // Error.
                return;
            }

            // Custom implementation for what to do after unmuting.
        }];
    }
}];
SBDOpenChannel.getWithUrl(CHANNEL_URL) { (channel, error) in
    guard error == nil else {    // Error.
        return
    }

    // Muting and unmuting a participant
    if channel?.isOperator(with: USER) {
        channel?.muteUser(USER, completionHandler: { (error) in
            guard error == nil else {    // Error.
                        return
                    }

            // Custom implementation for what to do after muting.
        })

        channel?.unmuteUser(USER, completionHandler: { (error) in
            guard error == nil else {    // Error. 
                return
            }

            // Custom implementation for what to do after unmuting.
        })
    }
}

Note: You can also use muteUserWithUserId:completionHandler: and unmuteUserWithUserId(), instead of muteUser:completionHandler: and unmuteUser:completionHandler:methods, as they have same functionalities. Please see our API reference on muteUserWithUserId:completionHandler: and unmuteUserWithUserId:completionHandler:.


Freeze and unfreeze an open channel

Currently, you can only freeze and unfreeze an open channel by using the SendBird Dashboard or the Platform API as opposed to the group channel. You can take the following steps to freeze an open channel using the SendBird Dashboard: Open Channels > open channel > Freeze icon at the upper right corner. To unfreeze the open channel, click the icon again.