All Products
Search
Document Center

ApsaraVideo Live:Send and receive SEI messages

Last Updated:Mar 26, 2026

The ARTC SDK supports sending and receiving supplemental enhancement information (SEI) messages. This feature lets you transmit custom messages from the RTC system to Alibaba Cloud CDN live streaming or third-party live streaming platforms.

Overview

In video encoding, supplemental enhancement information (SEI) is part of video encoding standards, such as H.264/AVC and H.265/HEVC, and is used to transmit additional information related to the video content. This information enables auxiliary functions on the receiving end, such as content synchronization and error recovery. Common use cases include precise video layouts, synchronized lyrics, and live interactive quizzes.

image

SEI is the recommended method for sending custom messages. This method embeds the message into the video stream and transmits it along with the video data to other users in the channel.

  • Benefits:

    • Real-time synchronization: Messages are synchronized with the video stream.

    • Unlimited receivers: Any user who subscribes to the stream can receive the messages.

  • Limitations:

    • To avoid impacting the video stream, each message has a maximum size of 4 KB.

Sample code

ARTC provides an open-source sample project for your reference. You can download the project or view the code in the following repositories:

Android: Android/ARTCExample/BasicUsage/src/main/java/com/aliyun/artc/api/basicusage/SEIUsage/SEIActivity.java.

iOS: iOS/ARTCExample/BasicUsage/SEIUsage/SEIUsageVC.swift.

Harmony: Harmony/ARTCExample/entry/src/main/ets/pages/basicusage/SEIPage.ets.

Before you begin

Before you implement this feature, ensure you meet the following requirements:

Implementation

Send an SEI message

After publishing a video stream, you can call thesendMediaExtensionMsg API to send SEI data.

API reference

The ARTC SDK provides two APIs for sending SEI messages.

API

Description

sendMediaExtensionMsg

Parameters:

  • message: The media extension message. The maximum size is 4096 bytes. We recommend using JSON or a plain string format.

  • repeatCount: The number of times to repeat the message. This adds redundancy to prevent message loss due to network packet drops. A value of -1 sends the message indefinitely.

  • delay: The delay in milliseconds between calling the API and sending the message.

  • isKeyFrame: Specifies whether to attach the message only to a keyframe. If true, the message is attached only to a keyframe.

sendMediaExtensionMsgEx

This API extends sendMediaExtensionMsg by including a payloadType parameter to set the SEI message type. The valid values are 5 or any integer from 100 to 254. Using payloadType=5 is equivalent to calling thesendMediaExtensionMsg API.

Note

Only one media extension message can be in transit at a time. Subsequent calls tosendMediaExtensionMsg overwrite the previous message.

Examples

The following examples demonstrate how to send a string as an SEI message using thesendMediaExtensionMsg API.

Android

// You must have already joined a channel and started publishing a video stream (which is enabled by default).
mSendSEIButton.setOnClickListener(v -> {
    if(mAliRtcEngine == null) {
        return;
    }
    String seiMessage = mEditText.getText().toString();
    if (TextUtils.isEmpty(seiMessage)) {
        return;
    }
    byte[] seiData = seiMessage.getBytes();
    mAliRtcEngine.sendMediaExtensionMsg(seiData,1,0,false);
    // mAliRtcEngine.sendMediaExtensionMsgEx(seiData,1,0,false, 5);
});

iOS

// Send an SEI message.
func sendSEI(seiMessage: String) -> Bool {
    guard let data = seiMessage.data(using: .utf8) else {
        return false
    }
    let repeatCount: Int32 = 1
    let delay: Int32 = 0
    let payloadType: Int32 = 5
    let isKeyFrameOnly = false
    let ret = self.rtcEngine?.sendMediaExtensionMsg(data, repeatCount: repeatCount, delay: delay, isKeyFrame: isKeyFrameOnly)
    // let ret = self.rtcEngine?.sendMediaExtensionMsgEx(data, repeatCount: repeatCount, delay: delay, isKeyFrame: isKeyFrameOnly, payloadType: payloadType)
    debugPrint("sendSEI: \(ret ?? -1)")
    return ret == 0
}

Harmony

const seiData = this.stringToArrayBuffer(this.SendText);
// Send an SEI message.
this.rtcEngine.sendMediaExtensionMsg(seiData, 1, 0, false);

Mac

NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat:@"YYYY-MM-dd HH:mm:ss"];
NSDate *datenow = [NSDate date];
NSString *currentTimeString = [formatter stringFromDate:datenow];
NSString *str =@"SEI Test time:" ;

NSString * ExtensionMsg = [str stringByAppendingString:currentTimeString];

NSData *data =[ExtensionMsg dataUsingEncoding:NSUTF8StringEncoding];

int code = [self.engine sendMediaExtensionMsg:data repeatCount:repectCount delay:100 isKeyFrame:true];
NSLog(@"--%d",code);

Windows

/* Specify the following parameters as needed. */
char * data = "xxxxx";
int length = strlen(data);
mAliRtcEngine->SendMediaExtensionMsg(data, length, 1,0,true);

Receive an SEI message

After subscribing to a video stream in the channel, users can receive SEI data by registering the appropriate callback.

API reference

Callback

Description

onMediaExtensionMsgReceived

The SDK triggers this callback when it receives an SEI message.

Parameters:

  • uid: The user ID of the user who sent the message.

  • payloadType: The type of the SEI message. The value is 5 for messages sent by sendMediaExtensionMsg. For messages sent by sendMediaExtensionMsgEx, the value is the specific type.

  • message: The received SEI message.

Examples

Android

@Override
public void onMediaExtensionMsgReceived(String uid, int payloadType, byte[]message) {
    super.onMediaExtensionMsgReceived(uid,payloadType, message);

    handler.post(new Runnable() {
        @Override
        public void run() {
            // Process the message.
            String receivedMsg = new String(message);
            ToastHelper.showToast(SEIActivity.this, receivedMsg, Toast.LENGTH_SHORT);
            
        }
    });
}

iOS

extension SEIUsageMainVC: AliRtcEngineDelegate {
    
    // Callback for receiving an SEI message.
    func onMediaExtensionMsgReceived(_ uid: String, payloadType: Int32, message data: Data) {
        // Process the message.
        guard let message = String(data: data, encoding: .utf8) else {
            print("Failed to parse the message")
            return
        }
        self.showToast(message: "Received SEI: \(message), from uid: \(uid), payloadType: \(payloadType)")
    }
    // Other callbacks...

}

Harmony

// Callback for receiving an SEI message.
listener.onMediaExtensionMsgReceived((uid: string, payloadType: number, message: ArrayBuffer) => {
  console.info(`Received SEI message: uid=${uid}, payloadType=${payloadType}, message=${message}`);
});

Mac

- (void)onMediaExtensionMsgReceived:(NSString *)uid payloadType:(int)payloadType message:(NSData *)data {
    
    NSString * string_message  = [[NSString alloc] initWithBytes:data.bytes length:data.length encoding:NSUTF8StringEncoding];

    NSLog(@"received uid:%@, payloadType: %d, message:%@ size:%lu \n\n", uid, payloadType, string_message, (unsigned long)data.length);
    dispatch_async(dispatch_get_main_queue(), ^{
        NSString *showString = [NSString stringWithFormat:@" uid:%@\n payloadtype:%d message:%@\n size:%lu\n",
                                uid, payloadType, string_message, (unsigned long)data.length];
        _extendinfoL.stringValue = showString;
    });
    
}

Windows

public:
virtual void OnMediaExtensionMsgReceived(const char* uid, const int8_t * message, uint32_t size) override {
    /* TODO: Add your processing logic here based on your business requirements. */
}