/**
* test the stream utility, access empty
*/
VOID TEST(KernelStreamTest, StreamEmpty)
{
    SrsStream s;
    char data[1024];
    
    EXPECT_TRUE(s.empty());
    EXPECT_TRUE(ERROR_SUCCESS == s.initialize(data, 1024));
    EXPECT_FALSE(s.empty());
    
    s.read_bytes(data, 1024);
    EXPECT_TRUE(s.empty());
}
/**
* test the stream utility, read string
*/
VOID TEST(KernelStreamTest, StreamReadString)
{
    SrsStream s;
    char data[] = "Hello, world!";
    
    EXPECT_TRUE(ERROR_SUCCESS == s.initialize(data, sizeof(data) - 1));
    
    string str = s.read_string(2);
    EXPECT_STREQ("He", str.c_str());
    
    str = s.read_string(2);
    EXPECT_STREQ("ll", str.c_str());
    
    s.skip(3);
    str = s.read_string(6);
    EXPECT_STREQ("world!", str.c_str());
    
    EXPECT_TRUE(s.empty());
}
/**
* test the stream utility, read bytes
*/
VOID TEST(KernelStreamTest, StreamReadBytes)
{
    SrsStream s;
    char data[] = "Hello, world!";
    
    EXPECT_TRUE(ERROR_SUCCESS == s.initialize(data, sizeof(data) - 1));
    
    char bytes[64];
    s.read_bytes(bytes, 2);
    bytes[2] = 0;
    EXPECT_STREQ("He", bytes);
    
    s.read_bytes(bytes, 2);
    bytes[2] = 0;
    EXPECT_STREQ("ll", bytes);
    
    s.skip(3);
    s.read_bytes(bytes, 6);
    bytes[6] = 0;
    EXPECT_STREQ("world!", bytes);
    
    EXPECT_TRUE(s.empty());
}
示例#4
0
// user scenario: coding and decoding with amf0
VOID TEST(AMF0Test, ScenarioMain)
{
    // coded amf0 object
    int nb_bytes = 0;
    char* bytes = NULL;
    
    // coding data to binaries by amf0
    // for example, send connect app response to client.
    if (true) {
        // props: object
        //        fmsVer: string
        //        capabilities: number
        //        mode: number
        // info: object
        //         level: string
        //        code: string
        //        descrption: string
        //        objectEncoding: number
        //        data: array
        //                version: string
        //                srs_sig: string
        SrsAmf0Object* props = SrsAmf0Any::object();
        SrsAutoFree(SrsAmf0Object, props);
        props->set("fmsVer", SrsAmf0Any::str("FMS/3,5,3,888"));
        props->set("capabilities", SrsAmf0Any::number(253));
        props->set("mode", SrsAmf0Any::number(123));
        
        SrsAmf0Object* info = SrsAmf0Any::object();
        SrsAutoFree(SrsAmf0Object, info);
        info->set("level", SrsAmf0Any::str("info"));
        info->set("code", SrsAmf0Any::str("NetStream.Connnect.Success"));
        info->set("descrption", SrsAmf0Any::str("connected"));
        info->set("objectEncoding", SrsAmf0Any::number(3));
        
        SrsAmf0EcmaArray* data = SrsAmf0Any::ecma_array();
        info->set("data", data);
        data->set("version", SrsAmf0Any::str("FMS/3,5,3,888"));
        data->set("srs_sig", SrsAmf0Any::str("srs"));
        
        // buf store the serialized props/info
        nb_bytes = props->total_size() + info->total_size();
        ASSERT_GT(nb_bytes, 0);
        bytes = new char[nb_bytes];
        
        // use SrsStream to write props/info to binary buf.
        SrsStream s;
        EXPECT_EQ(ERROR_SUCCESS, s.initialize(bytes, nb_bytes));
        EXPECT_EQ(ERROR_SUCCESS, props->write(&s));
        EXPECT_EQ(ERROR_SUCCESS, info->write(&s));
        EXPECT_TRUE(s.empty());
        
        // now, user can use the buf
        EXPECT_EQ(0x03, bytes[0]);
        EXPECT_EQ(0x09, bytes[nb_bytes - 1]);
    }
    SrsAutoFree(char, bytes);
    
    // decoding amf0 object from bytes
    // when user know the schema
    if (true) {
        ASSERT_TRUE(NULL != bytes);
        
        // use SrsStream to assist amf0 object to read from bytes.
        SrsStream s;
        EXPECT_EQ(ERROR_SUCCESS, s.initialize(bytes, nb_bytes));
        
        // decoding
        // if user know the schema, for instance, it's an amf0 object,
        // user can use specified object to decoding.
        SrsAmf0Object* props = SrsAmf0Any::object();
        SrsAutoFree(SrsAmf0Object, props);
        EXPECT_EQ(ERROR_SUCCESS, props->read(&s));
        
        // user can use specified object to decoding.
        SrsAmf0Object* info = SrsAmf0Any::object();
        SrsAutoFree(SrsAmf0Object, info);
        EXPECT_EQ(ERROR_SUCCESS, info->read(&s));
        
        // use the decoded data.
        SrsAmf0Any* prop = NULL;
        
        // if user requires specified property, use ensure of amf0 object
        EXPECT_TRUE(NULL != (prop = props->ensure_property_string("fmsVer")));
        // the property can assert to string.
        ASSERT_TRUE(prop->is_string());
        // get the prop string value.
        EXPECT_STREQ("FMS/3,5,3,888", prop->to_str().c_str());
        
        // get other type property value
        EXPECT_TRUE(NULL != (prop = info->get_property("data")));
        // we cannot assert the property is ecma array
        if (prop->is_ecma_array()) {
            SrsAmf0EcmaArray* data = prop->to_ecma_array();
            // it must be a ecma array.
            ASSERT_TRUE(NULL != data);
            
            // get property of array
            EXPECT_TRUE(NULL != (prop = data->ensure_property_string("srs_sig")));
            ASSERT_TRUE(prop->is_string());
            EXPECT_STREQ("srs", prop->to_str().c_str());
        }
        
        // confidence about the schema
        EXPECT_TRUE(NULL != (prop = info->ensure_property_string("level")));
        ASSERT_TRUE(prop->is_string());
        EXPECT_STREQ("info", prop->to_str().c_str());
    }
    
    // use any to decoding it,
    // if user donot know the schema
    if (true) {
        ASSERT_TRUE(NULL != bytes);
        
        // use SrsStream to assist amf0 object to read from bytes.
        SrsStream s;
        EXPECT_EQ(ERROR_SUCCESS, s.initialize(bytes, nb_bytes));
        
        // decoding a amf0 any, for user donot know
        SrsAmf0Any* any = NULL;
        EXPECT_EQ(ERROR_SUCCESS, srs_amf0_read_any(&s, &any));
        SrsAutoFree(SrsAmf0Any, any);
        
        // for amf0 object
        if (any->is_object()) {
            SrsAmf0Object* obj = any->to_object();
            ASSERT_TRUE(NULL != obj);
            
            // use foreach to process properties
            for (int i = 0; i < obj->count(); ++i) {
                string name = obj->key_at(i);
                SrsAmf0Any* value = obj->value_at(i);
                
                // use the property name
                EXPECT_TRUE("" != name);
                // use the property value
                EXPECT_TRUE(NULL != value);
            }
        }
    }
}
int SrsSource::on_aggregate(SrsMessage* msg)
{
    int ret = ERROR_SUCCESS;
    
    SrsStream* stream = aggregate_stream;
    if ((ret = stream->initialize((char*)msg->payload, msg->size)) != ERROR_SUCCESS) {
        return ret;
    }
    
    while (!stream->empty()) {
        if (!stream->require(1)) {
            ret = ERROR_RTMP_AGGREGATE;
            srs_error("invalid aggregate message type. ret=%d", ret);
            return ret;
        }
        int8_t type = stream->read_1bytes();
        
        if (!stream->require(3)) {
            ret = ERROR_RTMP_AGGREGATE;
            srs_error("invalid aggregate message size. ret=%d", ret);
            return ret;
        }
        int32_t data_size = stream->read_3bytes();
        
        if (data_size < 0) {
            ret = ERROR_RTMP_AGGREGATE;
            srs_error("invalid aggregate message size(negative). ret=%d", ret);
            return ret;
        }
        
        if (!stream->require(3)) {
            ret = ERROR_RTMP_AGGREGATE;
            srs_error("invalid aggregate message time. ret=%d", ret);
            return ret;
        }
        int32_t timestamp = stream->read_3bytes();
        
        if (!stream->require(1)) {
            ret = ERROR_RTMP_AGGREGATE;
            srs_error("invalid aggregate message time(high). ret=%d", ret);
            return ret;
        }
        int32_t time_h = stream->read_1bytes();
        
        timestamp |= time_h<<24;
        timestamp &= 0x7FFFFFFF;
        
        if (!stream->require(3)) {
            ret = ERROR_RTMP_AGGREGATE;
            srs_error("invalid aggregate message stream_id. ret=%d", ret);
            return ret;
        }
        int32_t stream_id = stream->read_3bytes();
        
        if (data_size > 0 && !stream->require(data_size)) {
            ret = ERROR_RTMP_AGGREGATE;
            srs_error("invalid aggregate message data. ret=%d", ret);
            return ret;
        }
        
        // to common message.
        SrsCommonMessage __o;
        SrsMessage& o = __o;
        
        o.header.message_type = type;
        o.header.payload_length = data_size;
        o.header.timestamp_delta = timestamp;
        o.header.timestamp = timestamp;
        o.header.stream_id = stream_id;
        o.header.perfer_cid = msg->header.perfer_cid;

        if (data_size > 0) {
            o.size = data_size;
            o.payload = new char[o.size];
            stream->read_bytes(o.payload, o.size);
        }
        
        if (!stream->require(4)) {
            ret = ERROR_RTMP_AGGREGATE;
            srs_error("invalid aggregate message previous tag size. ret=%d", ret);
            return ret;
        }
        stream->read_4bytes();

        // process parsed message
        if (o.header.is_audio()) {
            if ((ret = on_audio(&o)) != ERROR_SUCCESS) {
                return ret;
            }
        } else if (o.header.is_video()) {
            if ((ret = on_video(&o)) != ERROR_SUCCESS) {
                return ret;
            }
        }
    }
    
    return ret;
}