int SrsHandshakeBytes::create_s0s1s2(const char* c1)
{
    int ret = ERROR_SUCCESS;
    
    if (s0s1s2) {
        return ret;
    }
    
    s0s1s2 = new char[3073];
    srs_random_generate(s0s1s2, 3073);
    
    // plain text required.
    SrsStream stream;
    if ((ret = stream.initialize(s0s1s2, 9)) != ERROR_SUCCESS) {
        return ret;
    }
    stream.write_1bytes(0x03);
    stream.write_4bytes(::time(NULL));
    // s2 time2 copy from c1
    if (c0c1) {
        stream.write_bytes(c0c1 + 1, 4);
    }
    
    // if c1 specified, copy c1 to s2.
    // @see: https://github.com/winlinvip/simple-rtmp-server/issues/46
    if (c1) {
        memcpy(s0s1s2 + 1537, c1, 1536);
    }
    
    return ret;
}
srs_amf0_t srs_amf0_parse(char* data, int size, int* nparsed)
{
    int ret = ERROR_SUCCESS;
    
    srs_amf0_t amf0 = NULL;
    
    SrsStream stream;
    if ((ret = stream.initialize(data, size)) != ERROR_SUCCESS) {
        return amf0;
    }
    
    SrsAmf0Any* any = NULL;
    if ((ret = SrsAmf0Any::discovery(&stream, &any)) != ERROR_SUCCESS) {
        return amf0;
    }
    
    stream.reset();
    if ((ret = any->read(&stream)) != ERROR_SUCCESS) {
        srs_freep(any);
        return amf0;
    }
    
    *nparsed = stream.pos();
    amf0 = (srs_amf0_t)any;
    
    return amf0;
}
 // read/write stream using SrsStream.
 void __srs_stream_write_4bytes(char* pp, int32_t value) 
 {
     static SrsStream stream;
     
     int ret = stream.initialize(pp, 4);
     srs_assert(ret == ERROR_SUCCESS);
     
     stream.write_4bytes(value);
 }
/**
* test the stream utility, access size
*/
VOID TEST(KernelStreamTest, StreamSize)
{
    SrsStream s;
    char data[1024];
    
    EXPECT_TRUE(s.size() == 0);
    EXPECT_TRUE(ERROR_SUCCESS == s.initialize(data, 1024));
    EXPECT_TRUE(s.size() == 1024);
}
 int32_t __srs_stream_read_4bytes(char* pp)
 {
     static SrsStream stream;
     
     int ret = stream.initialize(pp, 4);
     srs_assert(ret == ERROR_SUCCESS);
     
     return stream.read_4bytes();
 }
/**
* test the stream utility, access data
*/
VOID TEST(KernelStreamTest, StreamData)
{
    SrsStream s;
    char data[1024];
    
    EXPECT_TRUE(s.data() == NULL);
    EXPECT_TRUE(ERROR_SUCCESS == s.initialize(data, 1024));
    EXPECT_TRUE(s.data() == data);
}
Exemple #7
0
int SrsRtpConn::on_udp_packet(sockaddr_in* from, char* buf, int nb_buf)
{
    int ret = ERROR_SUCCESS;

    pprint->elapse();

    if (true) {
        SrsStream stream;

        if ((ret = stream.initialize(buf, nb_buf)) != ERROR_SUCCESS) {
            return ret;
        }
    
        SrsRtpPacket pkt;
        if ((ret = pkt.decode(&stream)) != ERROR_SUCCESS) {
            srs_error("rtsp: decode rtp packet failed. ret=%d", ret);
            return ret;
        }

        if (pkt.chunked) {
            if (!cache) {
                cache = new SrsRtpPacket();
            }
            cache->copy(&pkt);
            cache->payload->append(pkt.payload->bytes(), pkt.payload->length());
            if (!cache->completed && pprint->can_print()) {
                srs_trace("<- "SRS_CONSTS_LOG_STREAM_CASTER" rtsp: rtp chunked %dB, age=%d, vt=%d/%u, sts=%u/%#x/%#x, paylod=%dB", 
                    nb_buf, pprint->age(), cache->version, cache->payload_type, cache->sequence_number, cache->timestamp, cache->ssrc, 
                    cache->payload->length()
                );
                return ret;
            }
        } else {
            srs_freep(cache);
            cache = new SrsRtpPacket();
            cache->reap(&pkt);
        }
    }

    if (pprint->can_print()) {
        srs_trace("<- "SRS_CONSTS_LOG_STREAM_CASTER" rtsp: rtp #%d %dB, age=%d, vt=%d/%u, sts=%u/%u/%#x, paylod=%dB, chunked=%d", 
            stream_id, nb_buf, pprint->age(), cache->version, cache->payload_type, cache->sequence_number, cache->timestamp, cache->ssrc, 
            cache->payload->length(), cache->chunked
        );
    }

    // always free it.
    SrsAutoFree(SrsRtpPacket, cache);
    
    if ((ret = rtsp->on_rtp_packet(cache, stream_id)) != ERROR_SUCCESS) {
        srs_error("rtsp: process rtp packet failed. ret=%d", ret);
        return ret;
    }

    return ret;
}
/**
* test the stream utility, bytes from/to basic types.
*/
VOID TEST(KernelStreamTest, StreamInitialize)
{
    SrsStream s;
    char data[1024];
    
    EXPECT_TRUE(ERROR_SUCCESS == s.initialize(data, 1024));
    EXPECT_TRUE(ERROR_SUCCESS != s.initialize(NULL, 1024));
    EXPECT_TRUE(ERROR_SUCCESS != s.initialize(data, 0));
    EXPECT_TRUE(ERROR_SUCCESS != s.initialize(data, -1));
}
int srs_amf0_serialize(srs_amf0_t amf0, char* data, int size)
{
    int ret = ERROR_SUCCESS;
    
    SrsAmf0Any* any = (SrsAmf0Any*)amf0;
    
    SrsStream stream;
    if ((ret = stream.initialize(data, size)) != ERROR_SUCCESS) {
        return ret;
    }
    
    if ((ret = any->write(&stream)) != ERROR_SUCCESS) {
        return ret;
    }
    
    return ret;
}
/**
* test the stream utility, write 8bytes
*/
VOID TEST(KernelStreamTest, StreamWrite8Bytes)
{
    SrsStream s;
    char data[1024];
    
    EXPECT_TRUE(ERROR_SUCCESS == s.initialize(data, 1024));
    
    s.write_8bytes(0x1011121314151617);
    s.write_8bytes(0x1819202122232425);

    s.skip(-1 * s.pos());
    EXPECT_EQ(0x10, s.read_1bytes());
    s.skip(2);
    EXPECT_EQ(0x13, s.read_1bytes());
    s.skip(5);
    EXPECT_EQ(0x19, s.read_1bytes());
}
/**
* test the stream utility, read 8bytes
*/
VOID TEST(KernelStreamTest, StreamRead8Bytes)
{
    SrsStream s;
    char data[1024];
    
    EXPECT_TRUE(ERROR_SUCCESS == s.initialize(data, 1024));
    
    data[0] = 0x01;
    data[1] = 0x02;
    data[2] = 0x03;
    data[3] = 0x04;
    data[4] = 0x05;
    data[5] = 0x06;
    data[6] = 0x07;
    data[7] = 0x08;
    data[8] = 0x09;
    data[9] = 0x0a;
    data[10] = 0x0b;
    data[11] = 0x0c;
    data[12] = 0x0d;
    data[13] = 0x0e;
    data[14] = 0x0f;
    data[15] = 0x10;
    data[16] = 0x11;
    data[17] = 0x12;
    data[18] = 0x13;
    data[19] = 0x14;
    
    EXPECT_EQ(0x0102030405060708, s.read_8bytes());
    EXPECT_EQ(0x090a0b0c0d0e0f10, s.read_8bytes());

    s.skip(-1 * s.pos());
    s.skip(5);
    EXPECT_EQ(0x060708090a0b0c0d, s.read_8bytes());
}
/**
* test the stream utility, read 4bytes
*/
VOID TEST(KernelStreamTest, StreamRead4Bytes)
{
    SrsStream s;
    char data[1024];
    
    EXPECT_TRUE(ERROR_SUCCESS == s.initialize(data, 1024));
    
    data[0] = 0x01;
    data[1] = 0x02;
    data[2] = 0x03;
    data[3] = 0x04;
    data[4] = 0x05;
    data[5] = 0x06;
    data[6] = 0x07;
    data[7] = 0x08;
    data[8] = 0x09;
    data[9] = 0x0a;
    
    EXPECT_EQ(0x01020304, s.read_4bytes());
    EXPECT_EQ(0x05060708, s.read_4bytes());

    s.skip(-1 * s.pos());
    s.skip(5);
    EXPECT_EQ(0x06070809, s.read_4bytes());
}
/**
* test the stream utility, access require
*/
VOID TEST(KernelStreamTest, StreamRequire)
{
    SrsStream s;
    char data[1024];
    
    EXPECT_FALSE(s.require(1));
    EXPECT_TRUE(ERROR_SUCCESS == s.initialize(data, 1024));
    EXPECT_TRUE(s.require(1));
    EXPECT_TRUE(s.require(1024));
    
    s.read_bytes(data, 1000);
    EXPECT_TRUE(s.require(1));
    
    s.read_bytes(data, 24);
    EXPECT_FALSE(s.require(1));
}
int SrsSource::on_dvr_request_sh()
{
    int ret = ERROR_SUCCESS;
    
#ifdef SRS_AUTO_DVR
    // feed the dvr the metadata/sequence header,
    // when reload to start dvr, dvr will never get the sequence header in stream,
    // use the SrsSource.on_dvr_request_sh to push the sequence header to DVR.
    if (cache_metadata) {
        char* payload = (char*)cache_metadata->payload;
        int size = (int)cache_metadata->size;
        
        SrsStream stream;
        if ((ret = stream.initialize(payload, size)) != ERROR_SUCCESS) {
            srs_error("dvr decode metadata stream failed. ret=%d", ret);
            return ret;
        }
        
        SrsOnMetaDataPacket pkt;
        if ((ret = pkt.decode(&stream)) != ERROR_SUCCESS) {
            srs_error("dvr decode metadata packet failed.");
            return ret;
        }
        
        if ((ret = dvr->on_meta_data(&pkt)) != ERROR_SUCCESS) {
            srs_error("dvr process onMetaData message failed. ret=%d", ret);
            return ret;
        }
    }
    
    if (cache_sh_video && (ret = dvr->on_video(cache_sh_video->copy())) != ERROR_SUCCESS) {
        srs_error("dvr process video sequence header message failed. ret=%d", ret);
        return ret;
    }
    if (cache_sh_audio && (ret = dvr->on_audio(cache_sh_audio->copy())) != ERROR_SUCCESS) {
        srs_error("dvr process audio sequence header message failed. ret=%d", ret);
        return ret;
    }
#endif
    
    return ret;
}
/**
* test the stream utility, write 1bytes
*/
VOID TEST(KernelStreamTest, StreamWrite1Bytes)
{
    SrsStream s;
    char data[1024];
    
    EXPECT_TRUE(ERROR_SUCCESS == s.initialize(data, 1024));
    
    s.write_1bytes(0x10);
    s.write_1bytes(0x11);
    s.write_1bytes(0x12);
    s.write_1bytes(0x13);

    s.skip(-1 * s.pos());
    EXPECT_EQ(0x10, s.read_1bytes());
    s.skip(2);
    EXPECT_EQ(0x13, s.read_1bytes());
}
/**
* test the stream utility, write bytes
*/
VOID TEST(KernelStreamTest, StreamWriteBytes)
{
    SrsStream s;
    char data[1024];
    
    EXPECT_TRUE(ERROR_SUCCESS == s.initialize(data, 1024));
    
    char str[] = {
        (char)0x10, (char)0x11, (char)0x12, (char)0x13,
        (char)0x14, (char)0x15, (char)0x16, (char)0x17, 
        (char)0x18, (char)0x19, (char)0x20, (char)0x21
    };
    
    s.write_bytes(str, 12);

    s.skip(-1 * s.pos());
    EXPECT_EQ(0x10, s.read_1bytes());
    s.skip(2);
    EXPECT_EQ(0x13, s.read_1bytes());
    s.skip(5);
    EXPECT_EQ(0x19, s.read_1bytes());
}
int SrsHandshakeBytes::create_c0c1()
{
    int ret = ERROR_SUCCESS;
    
    if (c0c1) {
        return ret;
    }
    
    c0c1 = new char[1537];
    srs_random_generate(c0c1, 1537);
    
    // plain text required.
    static SrsStream stream;
    if ((ret = stream.initialize(c0c1, 9)) != ERROR_SUCCESS) {
        return ret;
    }
    stream.write_1bytes(0x03);
    stream.write_4bytes(::time(NULL));
    stream.write_4bytes(0x00);
    
    return ret;
}
int SrsHandshakeBytes::create_c2()
{
    int ret = ERROR_SUCCESS;
    
    if (c2) {
        return ret;
    }
    
    c2 = new char[1536];
    srs_random_generate(c2, 1536);
    
    // time
    SrsStream stream;
    if ((ret = stream.initialize(c2, 8)) != ERROR_SUCCESS) {
        return ret;
    }
    stream.write_4bytes(::time(NULL));
    // c2 time2 copy from s1
    if (s0s1s2) {
        stream.write_bytes(s0s1s2 + 1, 4);
    }
    
    return ret;
}
/**
* test the stream utility, skip bytes
*/
VOID TEST(KernelStreamTest, StreamSkip)
{
    SrsStream s;
    char data[1024];
    
    EXPECT_TRUE(ERROR_SUCCESS == s.initialize(data, 1024));
    EXPECT_EQ(0, s.pos());
    
    s.skip(1);
    EXPECT_EQ(1, s.pos());

    s.skip(-1);
    EXPECT_EQ(0 , s.pos());
}
/**
* test the stream utility, access pos
*/
VOID TEST(KernelStreamTest, StreamPos)
{
    SrsStream s;
    char data[1024];
    
    EXPECT_TRUE(s.pos() == 0);
    EXPECT_TRUE(ERROR_SUCCESS == s.initialize(data, 1024));
    EXPECT_TRUE(s.pos() == 0);
    
    s.read_bytes(data, 1024);
    EXPECT_TRUE(s.pos() == 1024);
}
/**
* 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 1bytes
*/
VOID TEST(KernelStreamTest, StreamRead1Bytes)
{
    SrsStream s;
    char data[1024];
    
    EXPECT_TRUE(ERROR_SUCCESS == s.initialize(data, 1024));
    
    data[0] = 0x12;
    data[99] = 0x13;
    data[100] = 0x14;
    data[101] = 0x15;
    EXPECT_EQ(0x12, s.read_1bytes());
    
    s.skip(-1 * s.pos());
    s.skip(100);
    EXPECT_EQ(0x14, s.read_1bytes());
}
/**
* 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());
}
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;
}
VOID TEST(AMF0Test, ApiAnyAssert) 
{
    SrsStream s;
    SrsAmf0Any* o = NULL;
    
    char buf[1024];
    memset(buf, 0, sizeof(buf));
    EXPECT_EQ(ERROR_SUCCESS, s.initialize(buf, sizeof(buf)));
    
    // read any
    if (true) {
        s.reset();
        s.current()[0] = 0x12;
        EXPECT_NE(ERROR_SUCCESS, srs_amf0_read_any(&s, &o));
        EXPECT_TRUE(NULL == o);
        srs_freep(o);
    }
    
    // any convert
    if (true) {
        o = SrsAmf0Any::str();
        SrsAutoFree(SrsAmf0Any, o);
        EXPECT_TRUE(o->is_string());
    }
    if (true) {
        o = SrsAmf0Any::number();
        SrsAutoFree(SrsAmf0Any, o);
        EXPECT_TRUE(o->is_number());
    }
    if (true) {
        o = SrsAmf0Any::boolean();
        SrsAutoFree(SrsAmf0Any, o);
        EXPECT_TRUE(o->is_boolean());
    }
    if (true) {
        o = SrsAmf0Any::null();
        SrsAutoFree(SrsAmf0Any, o);
        EXPECT_TRUE(o->is_null());
    }
    if (true) {
        o = SrsAmf0Any::undefined();
        SrsAutoFree(SrsAmf0Any, o);
        EXPECT_TRUE(o->is_undefined());
    }
    if (true) {
        o = SrsAmf0Any::object();
        SrsAutoFree(SrsAmf0Any, o);
        EXPECT_TRUE(o->is_object());
    }
    if (true) {
        o = SrsAmf0Any::ecma_array();
        SrsAutoFree(SrsAmf0Any, o);
        EXPECT_TRUE(o->is_ecma_array());
    }
    if (true) {
        o = SrsAmf0Any::strict_array();
        SrsAutoFree(SrsAmf0Any, o);
        EXPECT_TRUE(o->is_strict_array());
    }
    
    // empty object
    if (true) {
        o = SrsAmf0Any::object();
        SrsAutoFree(SrsAmf0Any, o);
        s.reset();
        EXPECT_EQ(ERROR_SUCCESS, o->write(&s));
        EXPECT_EQ(1+3, s.pos());
    }
    
    // empty ecma array
    if (true) {
        o = SrsAmf0Any::ecma_array();
        SrsAutoFree(SrsAmf0Any, o);
        s.reset();
        EXPECT_EQ(ERROR_SUCCESS, o->write(&s));
        EXPECT_EQ(1+4+3, s.pos());
    }
    
    // strict array
    if (true) {
        o = SrsAmf0Any::strict_array();
        SrsAutoFree(SrsAmf0Any, o);
        s.reset();
        EXPECT_EQ(ERROR_SUCCESS, o->write(&s));
        EXPECT_EQ(1+4, s.pos());
    }
}
VOID TEST(AMF0Test, ApiAnyIO) 
{
    SrsStream s;
    SrsAmf0Any* o = NULL;
    
    char buf[1024];
    memset(buf, 0, sizeof(buf));
    EXPECT_EQ(ERROR_SUCCESS, s.initialize(buf, sizeof(buf)));
    
    // object eof
    if (true) {
        s.reset();
        s.current()[2] = 0x09;
        
        o = SrsAmf0Any::object_eof();
        SrsAutoFree(SrsAmf0Any, o);
        
        EXPECT_EQ(ERROR_SUCCESS, o->read(&s));
        EXPECT_EQ(o->total_size(), s.pos());
        EXPECT_EQ(3, s.pos());
        
        s.reset();
        s.current()[0] = 0x01;
        EXPECT_NE(ERROR_SUCCESS, o->read(&s));
    }
    if (true) {
        s.reset();
        
        o = SrsAmf0Any::object_eof();
        SrsAutoFree(SrsAmf0Any, o);
        
        EXPECT_EQ(ERROR_SUCCESS, o->write(&s));
        EXPECT_EQ(o->total_size(), s.pos());
        EXPECT_EQ(3, s.pos());
        
        s.skip(-3);
        EXPECT_EQ(0x09, s.read_3bytes());
    }
    
    // string
    if (true) {
        s.reset();
        
        o = SrsAmf0Any::str("winlin");
        SrsAutoFree(SrsAmf0Any, o);
        
        EXPECT_EQ(ERROR_SUCCESS, o->write(&s));
        EXPECT_EQ(o->total_size(), s.pos());
        
        s.reset();
        EXPECT_EQ(2, s.read_1bytes());
        EXPECT_EQ(6, s.read_2bytes());
        EXPECT_EQ('w', s.current()[0]);
        EXPECT_EQ('n', s.current()[5]);
        
        s.reset();
        s.current()[3] = 'x';
        EXPECT_EQ(ERROR_SUCCESS, o->read(&s));
        EXPECT_EQ(o->total_size(), s.pos());
        EXPECT_STREQ("xinlin", o->to_str().c_str());
    }
    
    // number
    if (true) {
        s.reset();
        
        o = SrsAmf0Any::number(10);
        SrsAutoFree(SrsAmf0Any, o);
        
        EXPECT_EQ(ERROR_SUCCESS, o->write(&s));
        EXPECT_EQ(o->total_size(), s.pos());

        s.reset();
        EXPECT_EQ(0, s.read_1bytes());
        
        s.reset();
        EXPECT_EQ(ERROR_SUCCESS, o->read(&s));
        EXPECT_EQ(o->total_size(), s.pos());
        EXPECT_DOUBLE_EQ(10, o->to_number());
    }
    
    // boolean
    if (true) {
        s.reset();
        
        o = SrsAmf0Any::boolean(true);
        SrsAutoFree(SrsAmf0Any, o);
        
        EXPECT_EQ(ERROR_SUCCESS, o->write(&s));
        EXPECT_EQ(o->total_size(), s.pos());

        s.reset();
        EXPECT_EQ(1, s.read_1bytes());
        
        s.reset();
        EXPECT_EQ(ERROR_SUCCESS, o->read(&s));
        EXPECT_EQ(o->total_size(), s.pos());
        EXPECT_TRUE(o->to_boolean());
    }
    if (true) {
        s.reset();
        
        o = SrsAmf0Any::boolean(false);
        SrsAutoFree(SrsAmf0Any, o);
        
        EXPECT_EQ(ERROR_SUCCESS, o->write(&s));
        EXPECT_EQ(o->total_size(), s.pos());

        s.reset();
        EXPECT_EQ(1, s.read_1bytes());
        
        s.reset();
        EXPECT_EQ(ERROR_SUCCESS, o->read(&s));
        EXPECT_EQ(o->total_size(), s.pos());
        EXPECT_FALSE(o->to_boolean());
    }
    
    // null
    if (true) {
        s.reset();
        
        o = SrsAmf0Any::null();
        SrsAutoFree(SrsAmf0Any, o);
        
        EXPECT_EQ(ERROR_SUCCESS, o->write(&s));
        EXPECT_EQ(o->total_size(), s.pos());

        s.reset();
        EXPECT_EQ(5, s.read_1bytes());
        
        s.reset();
        EXPECT_EQ(ERROR_SUCCESS, o->read(&s));
        EXPECT_EQ(o->total_size(), s.pos());
        EXPECT_TRUE(o->is_null());
    }
    
    // undefined
    if (true) {
        s.reset();
        
        o = SrsAmf0Any::undefined();
        SrsAutoFree(SrsAmf0Any, o);
        
        EXPECT_EQ(ERROR_SUCCESS, o->write(&s));
        EXPECT_EQ(o->total_size(), s.pos());

        s.reset();
        EXPECT_EQ(6, s.read_1bytes());
        
        s.reset();
        EXPECT_EQ(ERROR_SUCCESS, o->read(&s));
        EXPECT_EQ(o->total_size(), s.pos());
        EXPECT_TRUE(o->is_undefined());
    }

    // any: string
    if (true) {
        s.reset();
        
        o = SrsAmf0Any::str("winlin");
        SrsAutoFree(SrsAmf0Any, o);
        
        EXPECT_EQ(ERROR_SUCCESS, o->write(&s));
        EXPECT_EQ(o->total_size(), s.pos());

        s.reset();
        
        SrsAmf0Any* po = NULL;
        EXPECT_EQ(ERROR_SUCCESS, srs_amf0_read_any(&s, &po));
        ASSERT_TRUE(NULL != po);
        SrsAutoFree(SrsAmf0Any, po);
        ASSERT_TRUE(po->is_string());
        EXPECT_STREQ("winlin", po->to_str().c_str());
    }

    // any: number
    if (true) {
        s.reset();
        
        o = SrsAmf0Any::number(10);
        SrsAutoFree(SrsAmf0Any, o);
        
        EXPECT_EQ(ERROR_SUCCESS, o->write(&s));
        EXPECT_EQ(o->total_size(), s.pos());

        s.reset();
        
        SrsAmf0Any* po = NULL;
        EXPECT_EQ(ERROR_SUCCESS, srs_amf0_read_any(&s, &po));
        ASSERT_TRUE(NULL != po);
        SrsAutoFree(SrsAmf0Any, po);
        ASSERT_TRUE(po->is_number());
        EXPECT_DOUBLE_EQ(10, po->to_number());
    }

    // any: boolean
    if (true) {
        s.reset();
        
        o = SrsAmf0Any::boolean(true);
        SrsAutoFree(SrsAmf0Any, o);
        
        EXPECT_EQ(ERROR_SUCCESS, o->write(&s));
        EXPECT_EQ(o->total_size(), s.pos());

        s.reset();
        
        SrsAmf0Any* po = NULL;
        EXPECT_EQ(ERROR_SUCCESS, srs_amf0_read_any(&s, &po));
        ASSERT_TRUE(NULL != po);
        SrsAutoFree(SrsAmf0Any, po);
        ASSERT_TRUE(po->is_boolean());
        EXPECT_TRUE(po->to_boolean());
    }

    // any: null
    if (true) {
        s.reset();
        
        o = SrsAmf0Any::null();
        SrsAutoFree(SrsAmf0Any, o);
        
        EXPECT_EQ(ERROR_SUCCESS, o->write(&s));
        EXPECT_EQ(o->total_size(), s.pos());

        s.reset();
        
        SrsAmf0Any* po = NULL;
        EXPECT_EQ(ERROR_SUCCESS, srs_amf0_read_any(&s, &po));
        ASSERT_TRUE(NULL != po);
        SrsAutoFree(SrsAmf0Any, po);
        ASSERT_TRUE(po->is_null());
    }

    // any: undefined
    if (true) {
        s.reset();
        
        o = SrsAmf0Any::undefined();
        SrsAutoFree(SrsAmf0Any, o);
        
        EXPECT_EQ(ERROR_SUCCESS, o->write(&s));
        EXPECT_EQ(o->total_size(), s.pos());

        s.reset();
        
        SrsAmf0Any* po = NULL;
        EXPECT_EQ(ERROR_SUCCESS, srs_amf0_read_any(&s, &po));
        ASSERT_TRUE(NULL != po);
        SrsAutoFree(SrsAmf0Any, po);
        ASSERT_TRUE(po->is_undefined());
    }
    
    // mixed any
    if (true) {
        s.reset();
        
        o = SrsAmf0Any::str("winlin");
        EXPECT_EQ(ERROR_SUCCESS, o->write(&s));
        srs_freep(o);
        
        o = SrsAmf0Any::number(10);
        EXPECT_EQ(ERROR_SUCCESS, o->write(&s));
        srs_freep(o);
        
        o = SrsAmf0Any::boolean(true);
        EXPECT_EQ(ERROR_SUCCESS, o->write(&s));
        srs_freep(o);
        
        o = SrsAmf0Any::null();
        EXPECT_EQ(ERROR_SUCCESS, o->write(&s));
        srs_freep(o);
        
        o = SrsAmf0Any::undefined();
        EXPECT_EQ(ERROR_SUCCESS, o->write(&s));
        srs_freep(o);
        
        s.reset();
        SrsAmf0Any* po = NULL;
        
        EXPECT_EQ(ERROR_SUCCESS, srs_amf0_read_any(&s, &po));
        ASSERT_TRUE(NULL != po);
        ASSERT_TRUE(po->is_string());
        EXPECT_STREQ("winlin", po->to_str().c_str());
        srs_freep(po);
        
        EXPECT_EQ(ERROR_SUCCESS, srs_amf0_read_any(&s, &po));
        ASSERT_TRUE(NULL != po);
        ASSERT_TRUE(po->is_number());
        EXPECT_DOUBLE_EQ(10, po->to_number());
        srs_freep(po);
        
        EXPECT_EQ(ERROR_SUCCESS, srs_amf0_read_any(&s, &po));
        ASSERT_TRUE(NULL != po);
        ASSERT_TRUE(po->is_boolean());
        EXPECT_TRUE(po->to_boolean());
        srs_freep(po);
        
        EXPECT_EQ(ERROR_SUCCESS, srs_amf0_read_any(&s, &po));
        ASSERT_TRUE(NULL != po);
        ASSERT_TRUE(po->is_null());
        srs_freep(po);
        
        EXPECT_EQ(ERROR_SUCCESS, srs_amf0_read_any(&s, &po));
        ASSERT_TRUE(NULL != po);
        ASSERT_TRUE(po->is_undefined());
        srs_freep(po);
    }
}
// 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);
            }
        }
    }
}
VOID TEST(AMF0Test, ApiStrictArray)
{
    SrsStream s;
    
    char buf[1024];
    memset(buf, 0, sizeof(buf));
    EXPECT_EQ(ERROR_SUCCESS, s.initialize(buf, sizeof(buf)));
    
    SrsAmf0StrictArray* o = NULL;
    
    // append property
    if (true) {
        o = SrsAmf0Any::strict_array();
        SrsAutoFree(SrsAmf0StrictArray, o);
        
        o->append(SrsAmf0Any::number(100));
        EXPECT_DOUBLE_EQ(100, o->at(0)->to_number());
        
        o->append(SrsAmf0Any::number(101));
        EXPECT_DOUBLE_EQ(101, o->at(1)->to_number());
        
        o->append(SrsAmf0Any::str("winlin"));
        EXPECT_STREQ("winlin", o->at(2)->to_str().c_str());
    }
    
    // count
    if (true) {
        o = SrsAmf0Any::strict_array();
        SrsAutoFree(SrsAmf0StrictArray, o);
        
        EXPECT_EQ(0, o->count());
        
        o->append(SrsAmf0Any::boolean());
        EXPECT_EQ(1, o->count());
        
        o->append(SrsAmf0Any::boolean());
        EXPECT_EQ(2, o->count());

        o->clear();
        EXPECT_EQ(0, o->count());
    }
    
    // io
    if (true) {
        o = SrsAmf0Any::strict_array();
        SrsAutoFree(SrsAmf0StrictArray, o);
        
        s.reset();
        EXPECT_EQ(ERROR_SUCCESS, o->write(&s));
        EXPECT_EQ(5, s.pos());
        
        s.reset();
        EXPECT_EQ(0x0a, s.read_1bytes());
        EXPECT_EQ(0x00, s.read_4bytes());
    }
    
    if (true) {
        o = SrsAmf0Any::strict_array();
        SrsAutoFree(SrsAmf0StrictArray, o);
        
        o->append(SrsAmf0Any::number(0));
        
        s.reset();
        EXPECT_EQ(ERROR_SUCCESS, o->write(&s));
        EXPECT_EQ(5 + SrsAmf0Size::number(), s.pos());
    }
}