This page introduces how to use the RTSA Lite SDK to implement media and message transmission.
The RTSA Lite SDK uses licenses to authenticate devices. A license binds with a specific device at a time. Agora suggests that you use a unique value that binds with the device for the deviceId
parameter. Thus, you do not have to use new licenses when reactivating the license after flashing the device.
The SDK package includes a license file for you to try the RTSA Lite SDK.
Call agora_rtc_license_verify (licenseVerify for Java) to verify the license.
The sample code is as follows:
C sample code
#ifdef CONFIG_LICENSE
rval = agora_rtc_license_verify(certificate_for_test, strlen(certificate_for_test), NULL, 0);
if (rval < 0) {
printf("Failed to verify license, reason: %s\n", agora_rtc_err_2_str(rval));
return -1;
}
printf("Verify license successfully\n");
#endif
Java sample code
// Java
String rtcLicense = this.getString(R.string.rtc_license);
int licenseRet = mRtcService.licenseVerify(rtcLicense, null);
if (licenseRet < 0) {
Log.e(TAG, "<main> fail to licenseVerify(), licenseRet=" + licenseRet);
popupMessage("Fail to licenseVerify");
return;
}
Call agora_rtc_init
(init
for Java) to initialize the SDK.
In this method, you need to:
rtc_service_option_t
(RtcServiceOptions
for Java) to configure the SDK.C sample code
// C
// Initialize event callbacks
static void __on_join_channel_success(connection_id_t conn_id, uint32_t uid, int elapsed)
{
g_connected_flag = true;
agora_rtc_get_connection_info(conn_id, &g_conn_info);
printf("[conn-%u] Join the channel %s successfully, uid %u elapsed %d ms\n", conn_id, g_conn_info.channel_name, uid,
elapsed);
}
static void __on_connection_lost(connection_id_t conn_id)
{
g_connected_flag = false;
printf("[conn-%u] Lost connection from the channel\n", conn_id);
}
static void __on_rejoin_channel_success(connection_id_t conn_id, uint32_t uid, int elapsed_ms)
{
g_connected_flag = true;
printf("[conn-%u] Rejoin the channel successfully, uid %u elapsed %d ms\n", conn_id, uid, elapsed_ms);
}
static void __on_user_joined(connection_id_t conn_id, uint32_t uid, int elapsed_ms)
{
printf("[conn-%u] Remote user \"%u\" has joined the channel, elapsed %d ms\n", uid, conn_id, elapsed_ms);
}
static void __on_user_offline(connection_id_t conn_id, uint32_t uid, int reason)
{
printf("[conn-%u] Remote user \"%u\" has left the channel, reason %d\n", conn_id, uid, reason);
}
static void __on_user_mute_audio(connection_id_t conn_id, uint32_t uid, bool muted)
{
printf("[conn-%u] audio: uid=%u muted=%d\n", conn_id, uid, muted);
}
static void __on_user_mute_video(connection_id_t conn_id, uint32_t uid, bool muted)
{
printf("[conn-%u] video: uid=%u muted=%d\n", conn_id, uid, muted);
}
static void __on_error(connection_id_t conn_id, int code, const char *msg)
{
if (code == ERR_SEND_VIDEO_OVER_BANDWIDTH_LIMIT) {
printf("Not enough uplink bandwdith. Error msg \"%s\"\n", msg);
return;
}
if (code == ERR_INVALID_APP_ID) {
printf("Invalid App ID. Please double check. Error msg \"%s\"\n", msg);
} else if (code == ERR_INVALID_CHANNEL_NAME) {
printf("Invalid channel name. Please double check. Error msg \"%s\"\n", msg);
} else if (code == ERR_INVALID_TOKEN || code == ERR_TOKEN_EXPIRED) {
printf("Invalid token. Please double check. Error msg \"%s\"\n", msg);
} else if (code == ERR_DYNAMIC_TOKEN_BUT_USE_STATIC_KEY) {
printf("Dynamic token is enabled but is not provided. Error msg \"%s\"\n", msg);
} else {
printf("Error %d is captured. Error msg \"%s\"\n", code, msg);
}
g_stop_flag = true;
}
static void __on_audio_data(connection_id_t conn_id, const uint32_t uid, uint16_t sent_ts, const void *data, size_t len,
const audio_frame_info_t *info_ptr)
{
}
static void __on_mixed_audio_data(connection_id_t conn_id, const void *data, size_t len,
const audio_frame_info_t *info_ptr)
{
}
static void __on_video_data(connection_id_t conn_id, const uint32_t uid, uint16_t sent_ts, const void *data, size_t len,
const video_frame_info_t *info_ptr)
{
}
static void __on_target_bitrate_changed(connection_id_t conn_id, uint32_t target_bps)
{
printf("[conn-%u] Bandwidth change detected. Please adjust encoder bitrate to %u kbps\n", conn_id, target_bps / 1000);
}
static void __on_key_frame_gen_req(connection_id_t conn_id, uint32_t uid, video_stream_type_e stream_type)
{
printf("[conn-%u] Frame loss detected. Please notify the encoder to generate key frame immediately\n", conn_id);
}
static void app_init_event_handler(agora_rtc_event_handler_t *event_handler)
{
event_handler->on_join_channel_success = __on_join_channel_success;
event_handler->on_connection_lost = __on_connection_lost;
event_handler->on_rejoin_channel_success = __on_rejoin_channel_success;
event_handler->on_user_joined = __on_user_joined;
event_handler->on_user_offline = __on_user_offline;
event_handler->on_user_mute_audio = __on_user_mute_audio;
event_handler->on_user_mute_video = __on_user_mute_video;
event_handler->on_target_bitrate_changed = __on_target_bitrate_changed;
event_handler->on_key_frame_gen_req = __on_key_frame_gen_req;
event_handler->on_video_data = __on_video_data;
event_handler->on_error = __on_error;
event_handler->on_mixed_audio_data = __on_mixed_audio_data;
event_handler->on_audio_data = __on_audio_data;
}
agora_rtc_event_handler_t event_handler = { 0 };
app_init_event_handler(&event_handler);
rtc_service_option_t service_opt = { 0 };
service_opt.area_code = DEFAULT_AREA_CODE;
service_opt.log_cfg.log_path = DEFAULT_SDK_LOG_PATH;
rval = agora_rtc_init(AGORA_APP_ID_FOR_TEST, &event_handler, &service_opt);
if (rval < 0) {
printf("Failed to initialize Agora sdk, reason: %s\n", agora_rtc_err_2_str(rval));
return -1;
}
Java sample code
// Initialize
RtcServiceOptions options = new RtcServiceOptions();
options.areaCode = AreaCode.AREA_CODE_GLOB;
options.productId = "MyDevice01";
options.logCfg.logDisable = false;
options.logCfg.logDisableDesensitize = false;
options.logCfg.logLevel = LogLevel.RTC_LOG_DEFAULT;
options.logCfg.logPath = "./rtcsdk.log";
MyRtcEvent rtcEvent = new MyRtcEvent();
rtcEvent.mRtcService = mRtcService;
int ret = mRtcService.init(APPID, rtcEvent, options);
if (ret != ErrorCode.ERR_OKAY) {
RtsaLiteDemo.e(TAG, "<main> fail to init(), ret=" + ret);
return;
}
// Register media callbacks
class MyRtcEvent implements AgoraRtcEvents {
private final static String TAG = "DEMO/MyRtcEvent";
public AgoraRtcService mRtcService = null;
public ConnectionInfo connInfo = new ConnectionInfo();
@Override
public void onJoinChannelSuccess(int connId, int uid, int elapsed_ms) {
RtsaLiteDemo.d(TAG, "<onJoinChannelSuccess> connId=" + connId +
" uid=" + uid + " elapsed_ms=" + elapsed_ms);
if (mRtcService.getConnectionInfo(connId, connInfo) == 0) {
RtsaLiteDemo.d(TAG, "get connInfo: connId=" + connInfo.connId +
" uid=" + connInfo.uid + " cname=" + connInfo.channelName);
}
synchronized (RtsaLiteDemo.mJoinedEvent) {
RtsaLiteDemo.mJoinedEvent.notify(); // Event notification
}
}
@Override
public void onConnectionLost(int connId) {
RtsaLiteDemo.d(TAG, "<onConnectionLost> connId=" + connId);
}
@Override
public void onRejoinChannelSuccess(int connId, int uid, int elapsed_ms) {
RtsaLiteDemo.d(TAG,
"<onRejoinChannelSuccess> connId=" + connId + ", elapsed_ms=" + elapsed_ms);
synchronized (RtsaLiteDemo.mJoinedEvent) {
RtsaLiteDemo.mJoinedEvent.notify(); // Event notification
}
}
@Override
public void onError(int connId, int code, String msg) {
RtsaLiteDemo.d(TAG, "<onError> connId=" + connId + ", code=" + code + ", msg=" + msg);
}
@Override
public void onUserJoined(int connId, int uid, int elapsed_ms) {
RtsaLiteDemo.d(TAG, "<onUserJoined> connId=" + connId + ", uid=" + uid + ", elapsed_ms="
+ elapsed_ms);
}
@Override
public void onUserOffline(int connId, int uid, int reason) {
RtsaLiteDemo.d(TAG,
"<onUserOffline> connId=" + connId + ", uid=" + uid + ", reason=" + reason);
}
@Override
public void onUserMuteAudio(int connId, int uid, boolean muted) {
RtsaLiteDemo.d(TAG,
"<onUserMuteAudio> connId=" + connId + ", uid=" + uid + ", muted=" + muted);
}
@Override
public void onUserMuteVideo(int connId, int uid, boolean muted) {
RtsaLiteDemo.d(TAG,
"<onUserMuteVideo> connId=" + connId + ", uid=" + uid + ", muted=" + muted);
}
@Override
public void onKeyFrameGenReq(int connId, int requestedUid, int streamType) {
}
@Override
public void onAudioData(int connId, int uid, int sent_ts, byte[] data, AudioFrameInfo info) {
RtsaLiteDemo.d(TAG, "<onAudioData> connId=" + connId + " uid=" + uid
+ " dataType=" + info.dataType);
}
@Override
public void onMixedAudioData(int connId, byte[] data, AudioFrameInfo info) {
RtsaLiteDemo.d(TAG, "<onMixedAudioData> connId=" + connId
+ " dataType=" + info.dataType);
}
@Override
public void onVideoData(int connId, int uid, int sent_ts, byte[] data, VideoFrameInfo info) {
RtsaLiteDemo.d(TAG, "<onVideoData> connId=" + connId + " uid=" + uid
+ " dataType=" + info.dataType + " streamType=" + info.streamType
+ " frameType=" + info.frameType + " frameRate=" + info.frameRate);
}
@Override
public void onTargetBitrateChanged(int connId, int targetBps) {
}
@Override
public void onTokenPrivilegeWillExpire(int connId, String token) {
RtsaLiteDemo.d(TAG, "<onTokenPrivilegeWillExpire> token=" + token);
}
@Override
public void onMediaCtrlReceive(int connId, int uid, byte[] payload) {
RtsaLiteDemo.d(TAG, "<onMediaCtrlReceive> connId=" + connId + ", uid=" + uid);
}
}
// Register RTM event callbacks
class MyRtmEvent implements AgoraRtmEvents {
private final static String TAG = "DEMO/MyRtmEvent";
@Override
public void onRtmData(String rtm_uid, byte[] data) {
String dataText = "";
for (int i = 0; i < data.length; i++) {
dataText = dataText + data[i] + " ";
}
RtsaLiteDemo.d(TAG, "<onRtmData> rtm_uid=" + rtm_uid + ", dataSize=" + data.length
+ ", data=" + dataText);
}
@Override
public void onRtmEvent(String rtm_uid, int event_type, int err_code) {
RtsaLiteDemo.d(TAG, "<onRtmEvent> rtm_uid=" + rtm_uid + ", event_type=" + event_type
+ ", err_code=" + err_code);
if (event_type == AgoraRtmEvents.RtmEventType.RTM_EVENT_TYPE_LOGIN) {
synchronized (RtsaLiteDemo.mRtmLoginEvent) {
RtsaLiteDemo.mRtmLoginEvent.notify(); // Event notifications
}
}
}
@Override
public void onSendRtmDataResult(int message_id, int err_code) {
RtsaLiteDemo.d(TAG,
"<onSendRtmDataResult> message_id=" + message_id + ", err_code=" + err_code);
}
}
Call agora_rtc_create_connection
(createConnection
for Java API) to create a connection. Call agora_rtc_join_channel
(joinChannel
) for Java API to join an RTC channel corresponding to the connection.
In this method, you need to:
A user and an RTC channel have the following:
When you successfully join an RTC channel, the SDK triggers the on_join_channel_success
callback (onJoinChannelSuccess
callback for Java API).
The sample code is as follows:
C sample code
// C
// Create a connection
rval = agora_rtc_create_connection(&g_conn_id);
if (rval < 0) {
printf("Failed to create connection, reason: %s\n", agora_rtc_err_2_str(rval));
return -1;
}
rtc_channel_options_t channel_options = { 0 };
channel_options.auto_subscribe_audio = true;
channel_options.auto_subscribe_video = true;
// The sample uses the SDK built-in Opus codec
channel_options.audio_codec_opt.audio_codec_type = AUDIO_CODEC_TYPE_OPUS;
channel_options.audio_codec_opt.pcm_sample_rate = 16000;
channel_options.audio_codec_opt.pcm_channel_num = 1;
// Join an RTC channel
rval = agora_rtc_join_channel(g_conn_id, DEFAULT_CHANNEL_NAME, DEFAULT_USER_ID, DEFAULT_TOKEN, &channel_options);
if (rval < 0) {
printf("Failed to join channel \"%s\", reason: %s\n", DEFAULT_CHANNEL_NAME, agora_rtc_err_2_str(rval));
return -1;
}
while (!g_connected_flag) {
usleep(100 * 1000);
}
Java sample code
// Java
// Create a Connection
CONN_ID = mRtcService.createConnection();
if (CONN_ID == ConnectionIdSpecial.CONNECTION_ID_INVALID) {
RtsaLiteDemo.e(TAG, "<main> fail to createConnection(), ret=" + CONN_ID);
return;
}
// Set RTC channel properties
ChannelOptions chnlOption = new ChannelOptions();
chnlOption.autoSubscribeAudio = true;
chnlOption.autoSubscribeVideo = true;
// The sample uses the SDK built-in Opus codec
chnlOption.audioCodecOpt.audioCodecType = AudioCodecType.AUDIO_CODEC_TYPE_OPUS;
chnlOption.audioCodecOpt.pcmSampleRate = 16000;
chnlOption.audioCodecOpt.pcmChannelNum = 1;
// Join an RTC channel
ret = mRtcService.joinChannel(CONN_ID, CHANNEL_NAME, RTC_HOST_USER_ID, RTC_TOKEN,
chnlOption);
if (ret != ErrorCode.ERR_OKAY) {
RtsaLiteDemo.e(TAG, "<main> fail to joinChannel(), ret=" + ret);
mRtcService.fini();
return;
}
synchronized (mJoinedEvent) {
try {
mJoinedEvent.wait(10000);
} catch (InterruptedException e) {
e.printStackTrace();
RtsaLiteDemo.e(TAG, "<main> join channel timeout");
return;
}
}
RtsaLiteDemo.d(TAG, "<main> join channel: " + CHANNEL_NAME + " successful");
After joining an RTC channel, you can:
on_audio_data
callback (onAudioData
for Java API) to receive audio data from the RTC channels you have joined.on_video_data
callback (onVideoData
for Java API) to receive video data from the RTC channels you have joined.agora_rtc_send_audio_data
method (sendAudioData
for Java API) to send audio data to the RTC channels you have joined.agora_rtc_send_video_data
method (sendVideoData
for Java API) to send video data to the RTC channels you have joined.The sample code is as follows:
C sample code
// C
static void __on_audio_data(connection_id_t conn_id, const uint32_t uid, uint16_t sent_ts, const void *data, size_t len,
const audio_frame_info_t *info_ptr)
{
}
static void __on_video_data(connection_id_t conn_id, const uint32_t uid, uint16_t sent_ts, const void *data, size_t len,
const video_frame_info_t *info_ptr)
{
}
// Send audio data
static int send_audio_frame(uint8_t *data, uint32_t len)
{
// API: send audio data
audio_frame_info_t info = { 0 };
info.data_type = AUDIO_DATA_TYPE_PCM;
int rval = agora_rtc_send_audio_data(g_conn_id, data, len, &info);
if (rval < 0) {
printf("Failed to send audio data, reason: %s\n", agora_rtc_err_2_str(rval));
return -1;
}
return 0;
}
// Send video data
static int send_video_frame(uint8_t *data, uint32_t len)
{
video_frame_info_t info = { 0 };
info.frame_type = VIDEO_FRAME_KEY;
info.frame_rate = CONFIG_SEND_FRAME_RATE;
info.stream_type = VIDEO_STREAM_HIGH;
info.data_type = VIDEO_DATA_TYPE_H264;
int rval = agora_rtc_send_video_data(g_conn_id, data, len, &info);
if (rval < 0) {
printf("Failed to send video data, reason: %s\n", agora_rtc_err_2_str(rval));
return -1;
}
return 0;
}
When sending audio and video data, you need to set the sending interval so that the sending interval is consistent with the video frame rate and audio frame length.
// Video sending thread
#ifndef CONFIG_AUDIO_ONLY
static void *video_send_thread(void *threadid)
{
int video_send_interval_ms = 1000 / CONFIG_SEND_FRAME_RATE;
void *pacer = pacer_create(video_send_interval_ms);
uint32_t frame_count = 0;
int num_frames = sizeof(test_video_frames) / sizeof(test_video_frames[0]);
while (g_connected_flag && !g_stop_flag) {
int i = (frame_count++ % num_frames); // calculate frame index
send_video_frame(test_video_frames[i].data, test_video_frames[i].len);
wait_for_next_pace(pacer);
}
pacer_destroy(pacer);
return NULL;
}
#endif
#define CONFIG_PCM_FRAME_LEN (640) // The sample uses 640 KB. The actual value depends on the capture device of the PCM data
#define CONFIG_PCM_SAMPLE_RATE (16000)
#define CONFIG_PCM_CHANNEL_NUM (1)
#define CONFIG_AUDIO_FRAME_DURATION_MS \
(CONFIG_PCM_FRAME_LEN * 1000 / CONFIG_PCM_SAMPLE_RATE / CONFIG_PCM_CHANNEL_NUM / sizeof(int16_t))
// Audio sending thread
static void *audio_send_thread(void *threadid)
{
int audio_send_interval_ms = CONFIG_AUDIO_FRAME_DURATION_MS;
void *pacer = pacer_create(audio_send_interval_ms);
uint32_t pcm_offset = 0;
while (g_connected_flag && !g_stop_flag) {
send_audio_frame((uint8_t *)pcm_test_data + pcm_offset, CONFIG_PCM_FRAME_LEN);
pcm_offset += CONFIG_PCM_FRAME_LEN;
if ((pcm_offset + CONFIG_PCM_FRAME_LEN) > sizeof(pcm_test_data)) {
pcm_offset = 0;
}
// sleep and wait until time is up for next send
wait_for_next_pace(pacer);
}
pacer_destroy(pacer);
return NULL;
}
Java sample code
When sending audio and video data, you need to set the sending interval so that the sending interval is consistent with the video frame rate and audio frame length.
// Java
@Override
public void onAudioData(int connId, int uid, int sent_ts, byte[] data, AudioFrameInfo info) {
RtsaLiteDemo.d(TAG, "<onAudioData> connId=" + connId + " uid=" + uid
+ " dataType=" + info.dataType);
}
@Override
public void onVideoData(int connId, int uid, int sent_ts, byte[] data, VideoFrameInfo info) {
RtsaLiteDemo.d(TAG, "<onVideoData> connId=" + connId + " uid=" + uid
+ " dataType=" + info.dataType + " streamType=" + info.streamType
+ " frameType=" + info.frameType + " frameRate=" + info.frameRate);
}
// Send video
@Override
public void run() {
RtsaLiteDemo.d(TAG, "<VideoSendThread.run> ==>Enter");
StreamFile videoStream = new StreamFile();
videoStream.open(VIDEO_FILE);
int frameIndex = 0;
while (mVideoSending && (videoStream.isOpened())) {
// read video frame
if (frameIndex >= FRAME_COUNT) {
RtsaLiteDemo.d(TAG, "<VideoSendThread.run> read video frame EOF");
mVideoSending = false;
break;
}
int frameSize = FRAME_SIZE_ARR[frameIndex];
byte[] videoBuffer = new byte[frameSize];
int readSize = videoStream.readData(videoBuffer);
if (readSize <= 0) {
RtsaLiteDemo.e(TAG,
"<VideoSendThread.run> read video frame error, readSize=" + readSize);
}
// Send video
VideoFrameInfo videoFrameInfo = new VideoFrameInfo();
videoFrameInfo.dataType = VideoDataType.VIDEO_DATA_TYPE_H264;
videoFrameInfo.streamType = VideoStreamType.VIDEO_STREAM_HIGH;
videoFrameInfo.frameType = VideoFrameType.VIDEO_FRAME_KEY;
videoFrameInfo.frameRate = VideoFrameRate.VIDEO_FRAME_RATE_FPS_15;
int ret = mRtcService.sendVideoData(CONN_ID, videoBuffer, videoFrameInfo);
if (ret < 0) {
RtsaLiteDemo.e(TAG, "<VideoSendThread.run> sendVideoData() failure, ret=" + ret
+ ", dataSize=" + videoBuffer.length);
} else {
}
frameIndex++;
videoBuffer = null;
// Each loop of the thread sleeps for 66 ms, or 1000/15 ms
sleepCurrThread(66);
}
videoStream.close();
RtsaLiteDemo.d(TAG, "<VideoSendThread.run> <==Exit");
// Notify: exit video thread
synchronized (mVideoExitEvent) {
mVideoExitEvent.notify();
}
}
// Send audio
private final static int PCM_SAMPLE_RATE = 16000;
private final static int PCM_CHNL_NUMBER = 1;
private final static int PCM_SMPL_BYTES = 2;
@Override
public void run() {
RtsaLiteDemo.d(TAG, "<AudioSendThread.run> ==>Enter");
StreamFile audioStream = new StreamFile();
audioStream.open(AUDIO_FILE);
int bytesPerSec = PCM_SAMPLE_RATE * PCM_CHNL_NUMBER * PCM_SMPL_BYTES;
int bufferSize = bytesPerSec / 50; // Assume each audio frame contains 640 bytes, the sending interval is 640/32000 s = 20 ms. The you need to send audio 50 times per second. So the byte array size is 50.
byte[] readBuffer = new byte[bufferSize];
byte[] sendBuffer = new byte[bufferSize];
while (mAudioSending) {
// read audio frame
int readSize = audioStream.readData(readBuffer);
if (readSize <= 0) {
RtsaLiteDemo.d(TAG, "<AudioSendThread.run> read audio frame EOF");
mAudioSending = false;
break;
}
if (readSize != sendBuffer.length) {
sendBuffer = new byte[readSize];
}
System.arraycopy(readBuffer, 0, sendBuffer, 0, readSize);
AudioFrameInfo audioFrameInfo = new AudioFrameInfo();
audioFrameInfo.dataType = AudioDataType.AUDIO_DATA_TYPE_PCM;
int ret = mRtcService.sendAudioData(CONN_ID, sendBuffer, audioFrameInfo);
if (ret < 0) {
RtsaLiteDemo.e(TAG,
"<AudioSendThread.run> sendAudioData() failure, ret=" + ret);
}
// Each loop sleeps for 20 ms, which means the audio sending interval is 20 ms.
sleepCurrThread(20);
}
audioStream.close();
RtsaLiteDemo.d(TAG, "<AudioSendThread.run> <==Exit");
synchronized (mAudioExitEvent) {
mAudioExitEvent.notify();
}
}
Call agora_rtc_login_rtm
(loginRtm
for Java API) to login to RTM. You can send and receive messages after successful login.
In this method, you need to:
C sample code
// C
rval = agora_rtc_login_rtm(p_config->p_rtm_uid, p_config->p_token, &rtm_handler);
if (rval < 0) {
printf("login rtm failed\n");
goto EXIT;
}
Java sample code
// Java
MyRtmEvent rtmEvent = new MyRtmEvent();
int rtmRet = mRtcService.loginRtm(RTM_HOST_USER_ID, null, rtmEvent);
After login, you can:
on_rtm_data
callback (onRtmData
callback for Java API) to receive messages.on_rtm_event
callback (onRtmEvent
callback for Java API) to monitor local user status.on_send_rtm_data_result
callback (onSendRtmDataResult
for Java API) to monitor the local message sending results.agora_rtc_send_rtm_data
method (sendRtm
for Java API) to send messages to an RTM user.C sample code
// c
// Receive messages
static void __on_rtm_data(const char *user_id, const void *data, size_t data_len)
{
app_t *p_app = app_get_instance();
app_config_t *p_config = &p_app->config;
if (p_config->rtm_role == 3) {
// printf("Receive data[%s] from user[%s] length[%lu]\n", (char *)data, user_id, data_len);
printf("Receive data[%s] length[%d]\n", (char *)data, (int)data_len);
} else {
printf("data_callback %s data[], length[%lu]\n", user_id, data_len);
}
if (p_app->config.rtm_recv_dump_flag && p_app->rtm_recv_file_fd != INVALID_FD) {
if (write(p_app->rtm_recv_file_fd, data, data_len) != data_len) {
printf("write error\n");
return;
}
}
}
// Monitor local user status
static void __on_rtm_event(const char *user_id, uint32_t event_id, uint32_t event_code)
{
LOGD("%s event id[%u], event code[%u]", user_id, event_id, event_code);
if (event_id == 0 && event_code == 0) {
app_t *p_app = app_get_instance();
p_app->b_rtm_login_success_flag = 1;
}
}
// Monitor local message sending result
static void __on_rtm_send_data_res(uint32_t msg_id, uint32_t error_code)
{
LOGD("msg id [%u], error_code[%u]", msg_id, error_code);
}
// Send message to an RTM user
rval = agora_rtc_send_rtm_data(p_app->config.p_peer_uid, ++message_id, buffer, rval);
if (rval < 0) {
LOGE("%s send data failed, rval=%d", TAG_API, rval);
goto EXIT;
}
Java sample code
// Java
// Send message to an RTM user
rtmRet = mRtcService.sendRtm(PEER_USER_ID, message_id, message);
if (rtmRet != RtmErrCode.ERR_RTM_OK) {
RtsaLiteDemo.e(TAG, "<main> sendRtm() failure, rtmRet=" + rtmRet
+ ", message_id=" + message_id);
} else {
RtsaLiteDemo.d(TAG, "<main> sendRtm() success, rtmRet=" + rtmRet
+ ", message_id=" + message_id);
}
// Register RTM event callback
class MyRtmEvent implements AgoraRtmEvents {
private final static String TAG = "DEMO/MyRtmEvent";
// Receive messages
@Override
public void onRtmData(String rtm_uid, byte[] data) {
}
// Monitor local user status
@Override
public void onRtmEvent(String rtm_uid, int event_type, int err_code) {
}
// Monitor local message sending result
@Override
public void onSendRtmDataResult(int message_id, int err_code) {
}
}
Call agora_rtc_leave_channel
(leaveChannel
for Java API) to leave an RTC channel.
The sample code is as follows:
C sample code
// C
agora_rtc_leave_channel(g_conn_id);
agora_rtc_destroy_connection(g_conn_id);
Java sample code
// Java
ret = mRtcService.leaveChannel(CONN_ID);
if (ret != ErrorCode.ERR_OKAY) {
RtsaLiteDemo.e(TAG, "<main> fail to leaveChannel(), ret=" + ret);
}
// Destroy connection
ret = mRtcService.destroyConnection(CONN_ID);
CONN_ID = ConnectionIdSepcial.CONNECTION_ID_INVALID;
Call agora_rtc_logout_rtm
(logoutRtm
for Java API) to logout of RTM.
C sample code
// C
agora_rtc_logout_rtm();
Java sample code
// Java
ret = mRtcService.logoutRtm();
if (ret != RtmErrCode.ERR_RTM_OK) {
RtsaLiteDemo.e(TAG, "<main> fail to logoutRtm(), ret=" + ret);
}
When you no longer needs to run the SDK, call agora_rtc_fini
(fini
for Java API) to release the resources.
// C
agora_rtc_fini();
// Java
mRtcService.fini();
RTSA Lite SDK includes RTC APIs and RTM APIs.
RTC API sequence diagram
The following diagram shows the API sequence of sending media from the device app to the client app.
RTM API sequence diagram
The following diagram shows the API sequence of message transmission between the device and the client.
Refer to the API docs of C SDK and Java SDK for more information.