diff --git a/shared/signaling/client-configuration/project-implementation/android.mdx b/shared/signaling/client-configuration/project-implementation/android.mdx index 679e7ff3a..e2134a402 100644 --- a/shared/signaling/client-configuration/project-implementation/android.mdx +++ b/shared/signaling/client-configuration/project-implementation/android.mdx @@ -19,6 +19,7 @@ In some environments with restricted network services, you may need to set up a ```java RtmProxyConfig proxyConfig = new RtmProxyConfig() + // Set proxy type as HTTP. proxyConfig.proxyType = RtmProxyType.HTTP; // Set your proxy server address. @@ -66,6 +67,23 @@ RtmConfig rtmConfig = new RtmConfig.Builder("appid", "userId") To deploy a private environment, you need to set up the backend service. For assistance, please contact [technical support](mailto:support@agora.io). + +### Connection protocol + +To ensure connection stability and continuous service availability, the RTM client establishes two transmission links for each service (message channel and stream channel) when connecting to the edge server. By default, these links use the TCP and UDP protocols, respectively. This design ensures that network issues on one link do not affect the overall transmission. Compared to other WebSocket-based message transmission solutions, RTM's redundant link design maximizes transmission stability and message delivery rate. + +In some cases, users may find that their network does not support UDP port transmission, either temporarily or permanently. To ensure the dual-link design operates effectively, the SDK allows users to configure both links to use the TCP protocol. This can be done by setting the `protocolType` field in the `RtmConfig`. Below is a code example that configures both links to use the TCP protocol: + +```java +RtmConfig rtmConfig = new RtmConfig.Builder("appid", "userId") + .protocolType(RtmProtocolType.TCP_ONLY) + .build(); +``` + + +The SDK does not support configuring both links to use the UDP protocol simultaneously. + + ### Log configuration In the development and testing phase of your , you may need to output more detailed information to locate and fix problems. Enable log output of the SDK and set the log information level by configuring `RtmLogLevel` when initializing the client instance. diff --git a/shared/signaling/client-configuration/project-implementation/obj-c.mdx b/shared/signaling/client-configuration/project-implementation/obj-c.mdx index 700308a03..107d6ff86 100644 --- a/shared/signaling/client-configuration/project-implementation/obj-c.mdx +++ b/shared/signaling/client-configuration/project-implementation/obj-c.mdx @@ -55,6 +55,22 @@ private_config.serviceType = AgoraRtmServiceTypeStream | AgoraRtmServiceTypeMess To deploy a private environment, you need to set up the backend service. For assistance, please contact [technical support](mailto:support@agora.io). +### Connection protocol + +To ensure connection stability and continuous service availability, the RTM client establishes two transmission links for each channel (message channel and stream channel) when connecting to the edge server. By default, these links use the TCP and UDP protocols respectively. This design ensures that network issues in one link do not affect transmission performance. Compared to other WebSocket-based message transmission solutions, RTM's redundant link design maximizes transmission stability and message arrival rates. + +In some cases, users may find that their network does not support UDP port transmission, either temporarily or permanently. To ensure the dual-link design functions effectively, the SDK allows users to configure both links to use the TCP protocol by setting the `protocolType` field in the `AgoraRtmClientConfig`. Here is an example of configuring both links to use the TCP protocol: + +```objc +AgoraRtmClientConfig* rtm_config = [[AgoraRtmClientConfig alloc] initWithAppId:@"your_appid" userId:@"your_userid"]; +rtm_config.protocolType = AgoraRtmProtocolTypeTcpOnly; +``` + +The SDK does not support configuring both links to use the UDP protocol simultaneously. + + + + ### Log configuration In the development and testing phase of your , you may need to output more detailed information to locate and fix problems. Enable log output of the SDK and set the log information level by configuring `AgoraRtmLogLevel` when initializing the client instance. diff --git a/shared/signaling/user-channel/index.mdx b/shared/signaling/user-channel/index.mdx new file mode 100644 index 000000000..1a71b8481 --- /dev/null +++ b/shared/signaling/user-channel/index.mdx @@ -0,0 +1,43 @@ +import ProjectImplement from '@docs/shared/signaling/user-channel/project-implementation/index.mdx'; +import Reference from '@docs/shared/signaling/user-channel/reference/index.mdx'; +import NotAvailable from '@docs/shared/common/not-available.mdx'; + + +A user channel in allows for direct, point-to-point communication between individual users. This is often used in scenarios such as private chats, customer support interactions, or one-on-one communication. + +This page shows you how to use the user channel to send messages to other users in the channel. + +## Understand the Tech + +To implement a user channel in your : + +1. **Set Up SDK**: Initialize an instance of the in your app. +2. **User Authentication**: Log in to the server using a unique user ID. +3. **Send Messages**: Use the `publish` method with the recipient's user ID to send messages. +4. **Handle Incoming Messages**: Listen for events to manage messages received directly by the user. + +## Prerequisites + +Ensure that you have: + +* Integrated the in your project, and implemented the framework functionality from the [SDK quickstart](../get-started/sdk-quickstart) page. + +## Implement communication in a user channel + +This section shows you how to use the to implement user channel communication in your . + + + + currently supports only string and binary message data formats. If your business requires other data types such as JSON, Object, or third-party data construction tools like protobuf, you need to serialize the message data before sending it. For more information on how to effectively construct the payload data structure and recommended serialization methods, please refer to [Message Payload Structuring](../best-practices/message-payload-structuring). + +## Reference + +This section contains information that completes the information in this page, or points you to documentation that explains other aspects to this product. + + + + + + + + diff --git a/shared/signaling/user-channel/project-implementation/android.mdx b/shared/signaling/user-channel/project-implementation/android.mdx new file mode 100644 index 000000000..4db474ce0 --- /dev/null +++ b/shared/signaling/user-channel/project-implementation/android.mdx @@ -0,0 +1,48 @@ + + +### Send message via user channel + +To send message in a user channel, call the `publish` method with the `channelType` parameter set to `USER` and the channelName parameter set to the specified user's userId. This method allows you to send messages to one user at a time. To send messages to multiple users, you need to call this method for each user. While RTM does not limit the number of users you can send messages to or receive messages from, it does limit the frequency at which you can send messages to users. + +- Send a string message: + + ```java + // Send string message + PublishOptions options = new PublishOptions(); + options.setChannelType(RtmChannelType.USER); + options.setCustomType("PlainText"); + rtmClient.publish("Tony", "Hello world", options, new ResultCallback() { + @Override + public void onSuccess(Void responseInfo) { + log(CALLBACK, "send message success"); + } + + @Override + public void onFailure(ErrorInfo errorInfo) { + log(ERROR, errorInfo.toString()); + } + }); + ``` + +- Send a binary message: + + ```java + // Send binary message + byte[] message = new byte[] {1, 2, 3, 4}; + PublishOptions options = new PublishOptions(); + options.setChannelType(RtmChannelType.USER); + options.setCustomType("ByteArray"); + rtmClient.publish("Tony", message, options, new ResultCallback() { + @Override + public void onSuccess(Void responseInfo) { + log(CALLBACK, "send message success"); + } + + @Override + public void onFailure(ErrorInfo errorInfo) { + log(ERROR, errorInfo.toString()); + } + }); + ``` + + diff --git a/shared/signaling/user-channel/project-implementation/index.mdx b/shared/signaling/user-channel/project-implementation/index.mdx new file mode 100644 index 000000000..c6c397199 --- /dev/null +++ b/shared/signaling/user-channel/project-implementation/index.mdx @@ -0,0 +1,11 @@ +import Android from './android.mdx' +import ObjC from './obj-c.mdx' +import LinuxCpp from './linux-cpp.mdx' +import Web from './web.mdx' +import Unity from './unity.mdx' + + + + + + \ No newline at end of file diff --git a/shared/signaling/user-channel/project-implementation/linux-cpp.mdx b/shared/signaling/user-channel/project-implementation/linux-cpp.mdx new file mode 100644 index 000000000..b3fa35947 --- /dev/null +++ b/shared/signaling/user-channel/project-implementation/linux-cpp.mdx @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/shared/signaling/user-channel/project-implementation/obj-c.mdx b/shared/signaling/user-channel/project-implementation/obj-c.mdx new file mode 100644 index 000000000..757eed6fd --- /dev/null +++ b/shared/signaling/user-channel/project-implementation/obj-c.mdx @@ -0,0 +1,44 @@ + + +### Send message via user channel + +In a user channel, you can send a point-to-point message to a specified user by calling the `publish` method. Set the `channelType` parameter to `AgoraRtmChannelTypeUser` and the `channelName` parameter to the user ID of the specified user. This method can only send messages to one user at a time. To send messages to multiple users, call this method multiple times. does not limit how many users you can send messages to or how many users can send messages to you, but it does limit the frequency of sending messages to users. + +- Send a string message: + ```objc + // Send string message + NSString* message = @"Hello Agora!"; + NSString* user = @"Tony"; + + AgoraRtmPublishOptions* publish_option = [[AgoraRtmPublishOptions alloc] init]; + publish_option.channelType = AgoraRtmChannelTypeUser; + + [rtm publish:user message:message option:publish_option completion:^(AgoraRtmCommonResponse * _Nullable response, AgoraRtmErrorInfo * _Nullable errorInfo) { + if (errorInfo == nil) { + NSLog(@"publish success!!"); + } else { + NSLog(@"publish failed, errorCode %d, reason %@", errorInfo.errorCode, errorInfo.reason); + } + }]; + ``` + +- Send a binary message: + + ```objc + // Send string message + NSString* message = @"Hello Agora!"; + NSString* user = @"Tony"; + + AgoraRtmPublishOptions* publish_option = [[AgoraRtmPublishOptions alloc] init]; + publish_option.channelType = AgoraRtmChannelTypeUser; + + [rtm publish:user message:message option:publish_option completion:^(AgoraRtmCommonResponse * _Nullable response, AgoraRtmErrorInfo * _Nullable errorInfo) { + if (errorInfo == nil) { + NSLog(@"publish success!!"); + } else { + NSLog(@"publish failed, errorCode %d, reason %@", errorInfo.errorCode, errorInfo.reason); + } + }]; + ``` + + \ No newline at end of file diff --git a/shared/signaling/user-channel/project-implementation/unity.mdx b/shared/signaling/user-channel/project-implementation/unity.mdx new file mode 100644 index 000000000..f97ce0db0 --- /dev/null +++ b/shared/signaling/user-channel/project-implementation/unity.mdx @@ -0,0 +1,148 @@ + + +### Create a stream channel + +To use stream channel functionality, call `CreateStreamChannel` to create a `IStreamChannel` object instance. + +```csharp +IStreamChannel streamChannel = rtmClient.CreateStreamChannel("chat_room"); +``` +This method creates only one `IStreamChannel` instance at a time. If you need to create multiple instances, call the method multiple times. + +```csharp +// Create the first instance +IStreamChannel streamChannel1 = rtmClient.CreateStreamChannel("chat_room1"); +// Create the second instance +IStreamChannel streamChannel2 = rtmClient.CreateStreamChannel("chat_room2"); +``` + + + enables you to create unlimited stream channel instances in a single . However, best practice is to create channels based on your actual requirements to maintain optimal client-side performance. For instance, if you hold multiple stream channel instances, destroy the ones that are no longer in use to prevent resource blocking, and recreate them when they are needed again. + + +### Join a stream channel + +Call the `JoinAsync` method on the `IStreamChannel` instance with appropriate options as follows: + +```csharp +var options = new JoinChannelOptions(); +options.token = "your_token"; +var (status,response) = await streamChannel.JoinAsync(options); +if (status.Error) +{ + Debug.Log(string.Format("{0} is failed, ErrorCode: {1}, due to: {2}", status.Operation, status.ErrorCode, status.Reason)); +} +else +{ + Debug.Log(string.Format("User:{0} Join stream channel success! at Channel:{1}", response.UserId, response.ChannelName)); +} +``` + +When joining a channel, set the `token` parameter in `JoinChannelOptions` with a temporary token from . + + + +To facilitate testing of the app during development, set the **Authentication mechanism** to **Debugging mode** when creating the project, and use the app ID in the `token` parameter when joining a channel. + + +```csharp +var options = new JoinChannelOptions(); +options.token = "your_appId"; +options.withLock = true; + +var (status,response) = await streamChannel.JoinAsync(options); +if (status.Error) +{ + Debug.Log(string.Format("{0} is failed,The error code is {1},because of: {2}", status.Operation, status.ErrorCode, status.Reason)); +} +else +{ + Debug.Log(string.Format("User:{0} Join stream channel success! at Channel:{1}", response.UserId, response.ChannelName)); +} +``` + +In stream channels, message flow is managed using topics. Even if you configure a global message listener, you must still join a topic to send messages. Similarly, to receive messages you must subscribe to a topic. See [Topics](../core-functionality/topics) for more information. + +### Send a message + +To send a message to a stream channel, you first need to: + +- Create an `IStreamChannel` instance. +- Use the `JoinAsync` method to join a channel. +- Call `JoinTopicAsync` to register as a message publisher for the specified topic. See [Topics](../core-functionality/topics). + +Call `PublishTopicMessageAsync` to publish a message to a topic. This method sends a message to a single topic at a time. To deliver messages to multiple topics, call the method separately for each topic. + +Refer to the following sample code for sending messages: + +* String message + + ```csharp + // Send a string message + string message = "left"; // Message content + string topic = "Motion"; // Topic to which the message is sent + var options = new TopicMessageOptions(); // Options for sending the message + options.customType = "PlainTxt"; // Set the custom message type to "PlainTxt" + var (status, response) = await streamChannel.PublishTopicMessageAsync(topic, message, options); // Send the message asynchronously + if (status.Error) + { + Debug.Log(string.Format("{0} is failed, ErrorCode {1}, due to: {2}", status.Operation, status.ErrorCode, status.Reason)); // Log error information if message send fails + } + ``` + +* Binary message + + ```csharp + // Send a binary message + byte[] message = new byte[] { 00, 01, 35, 196 }; // Binary message content + string topic = "Motion"; // Topic to which the message is sent + var options = new TopicMessageOptions(); // Options for sending the message + options.customType = "ByteArray"; // Set the custom message type to "ByteArray" + var (status, response) = await streamChannel.PublishTopicMessageAsync(topic, message, options); // Send the message asynchronously + if (status.Error) + { + Debug.Log(string.Format("{0} is failed, ErrorCode: {1}, due to: {2}", status.Operation, status.ErrorCode, status.Reason)); // Log error information if message send fails + } + ``` + +In , a user may register as a message publisher for up to 8 topics concurrently. However, there are no limitations on the number of users a single topic can accommodate. You can achieve a message transmission frequency to a topic of up to 120 QPS. This capability is useful in scenarios that demand high-frequency and high-concurrency data processing, such as Metaverse location status synchronization, collaborative office sketchpad applications, and parallel control operation-instructions transmission. + +### Leave a stream channel + +To leave a channel, call the `LeaveAsync` method on the `IStreamChannel` instance: + +```csharp +var (status,response) = await streamChannel.LeaveAsync(); +if (status.Error) +{ + Debug.Log(string.Format("{0} is failed, ErrorCode: {1}, due to: {2}", status.Operation, status.ErrorCode, status.Reason)); +} +else +{ + Debug.Log(string.Format("User:{0} Join stream channel success! at Channel:{1}", response.UserId, response.ChannelName)); +} +``` + +To rejoin a stream channel, call the `JoinAsync` method again. You can join and leave as long as the corresponding `IStreamChannel` instance remains active and has not been destroyed. + +### Destroy the stream channel instance + +To destroy a stream channel instance, call `Dispose`: + +```csharp +var status = streamChannel.Dispose(); +if (status.Error) +{ + Debug.Log(string.Format("{0} is failed, ErrorCode: {1}, due to: {2}", status.Operation, status.ErrorCode, status.Reason)); +} +else +{ + Debug.Log("Dispose Channel Success!"); +} +``` + + +Destroying a stream channel removes the `IStreamChannel` instance from your . This action is local to your and does not affect other users or the channel. + + + diff --git a/shared/signaling/user-channel/project-implementation/web.mdx b/shared/signaling/user-channel/project-implementation/web.mdx new file mode 100644 index 000000000..8f737f379 --- /dev/null +++ b/shared/signaling/user-channel/project-implementation/web.mdx @@ -0,0 +1,3 @@ + + + diff --git a/shared/signaling/user-channel/reference/android.mdx b/shared/signaling/user-channel/reference/android.mdx new file mode 100644 index 000000000..c2022cbb4 --- /dev/null +++ b/shared/signaling/user-channel/reference/android.mdx @@ -0,0 +1,23 @@ + + +### Message packet size + + imposes 32KB size limits on message payload packets sent in user channels. The message payload packet size includes the message payload itself plus the size of the `customType` field. If the message payload package size exceeds the limit, you receive an error message. + +```java +// ErrorInfo +ErrorInfo { + errorCode = -11010; + reason = "Publish too long message."; + operation = "publishTopicMessage"; // or "publish" +} +``` + +To avoid sending failure due to message payload packet size exceeding the limit, check the packet size before sending. + +### API reference + +- [`publish`](../reference/api#messagepublishpropsag_platform) +- [`receive`](../reference/api#receive) + + diff --git a/shared/signaling/user-channel/reference/index.mdx b/shared/signaling/user-channel/reference/index.mdx new file mode 100644 index 000000000..c6c397199 --- /dev/null +++ b/shared/signaling/user-channel/reference/index.mdx @@ -0,0 +1,11 @@ +import Android from './android.mdx' +import ObjC from './obj-c.mdx' +import LinuxCpp from './linux-cpp.mdx' +import Web from './web.mdx' +import Unity from './unity.mdx' + + + + + + \ No newline at end of file diff --git a/shared/signaling/user-channel/reference/linux-cpp.mdx b/shared/signaling/user-channel/reference/linux-cpp.mdx new file mode 100644 index 000000000..134335280 --- /dev/null +++ b/shared/signaling/user-channel/reference/linux-cpp.mdx @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/shared/signaling/user-channel/reference/obj-c.mdx b/shared/signaling/user-channel/reference/obj-c.mdx new file mode 100644 index 000000000..72627f31d --- /dev/null +++ b/shared/signaling/user-channel/reference/obj-c.mdx @@ -0,0 +1,23 @@ + + +### Message packet size + + imposes 32KB size limits on message payload packets sent in user channels. The message payload packet size includes the message payload itself plus the size of the `customType` field. If the message payload package size exceeds the limit, you receive an error message. + +```objc +// errorInfo +{ + errorInfo.errorCode = AgoraRtmErrorChannelMessageLengthExceedLimitation; + errorInfo.reason = @"Publish too long message."; + errorInfo.Operation = @"publish"; // or "publishTopicMessage" +} +``` + +To avoid sending failure due to message payload packet size exceeding the limit, check the packet size before sending. + +### API reference + +- [`publish`](../reference/api#messagepublishpropsag_platform) +- [`receive`](../reference/api#receive) + + \ No newline at end of file diff --git a/shared/signaling/user-channel/reference/unity.mdx b/shared/signaling/user-channel/reference/unity.mdx new file mode 100644 index 000000000..7a090839d --- /dev/null +++ b/shared/signaling/user-channel/reference/unity.mdx @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/shared/signaling/user-channel/reference/web.mdx b/shared/signaling/user-channel/reference/web.mdx new file mode 100644 index 000000000..04fdd6772 --- /dev/null +++ b/shared/signaling/user-channel/reference/web.mdx @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/signaling/core-functionality/user-channel.mdx b/signaling/core-functionality/user-channel.mdx new file mode 100644 index 000000000..34b7bd7b3 --- /dev/null +++ b/signaling/core-functionality/user-channel.mdx @@ -0,0 +1,13 @@ +--- +title: 'User channels' +sidebar_position: 2 +type: docs +description: > + Send P2P messages to other users. +--- + +import UserChannel from '@docs/shared/signaling/user-channel/index.mdx'; + +export const toc = [{}]; + + \ No newline at end of file