winlin

support ecma array. connect app response.

... ... @@ -54,6 +54,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#define RTMP_AMF0_Invalid 0x3F
int srs_amf0_get_object_eof_size();
int srs_amf0_get_any_size(SrsAmf0Any* value);
int srs_amf0_read_object_eof(SrsStream* stream, SrsAmf0ObjectEOF*&);
int srs_amf0_write_object_eof(SrsStream* stream, SrsAmf0ObjectEOF*);
int srs_amf0_read_any(SrsStream* stream, SrsAmf0Any*& value);
... ... @@ -88,43 +89,51 @@ bool SrsAmf0Any::is_object()
return marker == RTMP_AMF0_Object;
}
bool SrsAmf0Any::is_ecma_array()
{
return marker == RTMP_AMF0_EcmaArray;
}
bool SrsAmf0Any::is_object_eof()
{
return marker == RTMP_AMF0_ObjectEnd;
}
SrsAmf0String::SrsAmf0String()
SrsAmf0String::SrsAmf0String(const char* _value)
{
marker = RTMP_AMF0_String;
if (_value) {
value = _value;
}
}
SrsAmf0String::~SrsAmf0String()
{
}
SrsAmf0Boolean::SrsAmf0Boolean()
SrsAmf0Boolean::SrsAmf0Boolean(bool _value)
{
marker = RTMP_AMF0_Boolean;
value = false;
value = _value;
}
SrsAmf0Boolean::~SrsAmf0Boolean()
{
}
SrsAmf0Number::SrsAmf0Number()
SrsAmf0Number::SrsAmf0Number(double _value)
{
marker = RTMP_AMF0_Number;
value = 0;
value = _value;
}
SrsAmf0Number::~SrsAmf0Number()
{
marker = RTMP_AMF0_ObjectEnd;
}
SrsAmf0ObjectEOF::SrsAmf0ObjectEOF()
{
marker = RTMP_AMF0_ObjectEnd;
utf8_empty = 0x00;
}
... ... @@ -173,6 +182,47 @@ SrsAmf0Any* SrsAmf0Object::ensure_property_string(std::string name)
return prop;
}
SrsASrsAmf0EcmaArray::SrsASrsAmf0EcmaArray()
{
marker = RTMP_AMF0_EcmaArray;
}
SrsASrsAmf0EcmaArray::~SrsASrsAmf0EcmaArray()
{
std::map<std::string, SrsAmf0Any*>::iterator it;
for (it = properties.begin(); it != properties.end(); ++it) {
SrsAmf0Any* any = it->second;
delete any;
}
properties.clear();
}
SrsAmf0Any* SrsASrsAmf0EcmaArray::get_property(std::string name)
{
std::map<std::string, SrsAmf0Any*>::iterator it;
if ((it = properties.find(name)) == properties.end()) {
return NULL;
}
return it->second;
}
SrsAmf0Any* SrsASrsAmf0EcmaArray::ensure_property_string(std::string name)
{
SrsAmf0Any* prop = get_property(name);
if (!prop) {
return NULL;
}
if (!prop->is_string()) {
return NULL;
}
return prop;
}
int srs_amf0_read_utf8(SrsStream* stream, std::string& value)
{
int ret = ERROR_SUCCESS;
... ... @@ -481,6 +531,14 @@ int srs_amf0_read_any(SrsStream* stream, SrsAmf0Any*& value)
value = p;
return ret;
}
case RTMP_AMF0_EcmaArray: {
SrsASrsAmf0EcmaArray* p = NULL;
if ((ret = srs_amf0_read_ecma_array(stream, p)) != ERROR_SUCCESS) {
return ret;
}
value = p;
return ret;
}
case RTMP_AMF0_Invalid:
default: {
ret = ERROR_RTMP_AMF0_INVALID;
... ... @@ -518,6 +576,10 @@ int srs_amf0_write_any(SrsStream* stream, SrsAmf0Any* value)
SrsAmf0Object* p = srs_amf0_convert<SrsAmf0Object>(value);
return srs_amf0_write_object(stream, p);
}
case RTMP_AMF0_EcmaArray: {
SrsASrsAmf0EcmaArray* p = srs_amf0_convert<SrsASrsAmf0EcmaArray>(value);
return srs_amf0_write_ecma_array(stream, p);
}
case RTMP_AMF0_Invalid:
default: {
ret = ERROR_RTMP_AMF0_INVALID;
... ... @@ -529,6 +591,52 @@ int srs_amf0_write_any(SrsStream* stream, SrsAmf0Any* value)
return ret;
}
int srs_amf0_get_any_size(SrsAmf0Any* value)
{
if (!value) {
return 0;
}
int size = 0;
switch (value->marker) {
case RTMP_AMF0_String: {
SrsAmf0String* p = srs_amf0_convert<SrsAmf0String>(value);
size += srs_amf0_get_string_size(p->value);
break;
}
case RTMP_AMF0_Boolean: {
size += srs_amf0_get_boolean_size();
break;
}
case RTMP_AMF0_Number: {
size += srs_amf0_get_number_size();
break;
}
case RTMP_AMF0_ObjectEnd: {
size += srs_amf0_get_object_eof_size();
break;
}
case RTMP_AMF0_Object: {
SrsAmf0Object* p = srs_amf0_convert<SrsAmf0Object>(value);
size += srs_amf0_get_object_size(p);
break;
}
case RTMP_AMF0_EcmaArray: {
SrsASrsAmf0EcmaArray* p = srs_amf0_convert<SrsASrsAmf0EcmaArray>(value);
size += srs_amf0_get_ecma_array_size(p);
break;
}
default: {
// TOOD: other AMF0 types.
srs_warn("ignore unkown AMF0 type size.");
break;
}
}
return size;
}
int srs_amf0_read_object_eof(SrsStream* stream, SrsAmf0ObjectEOF*& value)
{
int ret = ERROR_SUCCESS;
... ... @@ -699,6 +807,125 @@ int srs_amf0_write_object(SrsStream* stream, SrsAmf0Object* value)
return ret;
}
int srs_amf0_read_ecma_array(SrsStream* stream, SrsASrsAmf0EcmaArray*& value)
{
int ret = ERROR_SUCCESS;
// marker
if (!stream->require(1)) {
ret = ERROR_RTMP_AMF0_DECODE;
srs_error("amf0 read ecma_array marker failed. ret=%d", ret);
return ret;
}
char marker = stream->read_1bytes();
if (marker != RTMP_AMF0_EcmaArray) {
ret = ERROR_RTMP_AMF0_DECODE;
srs_error("amf0 check ecma_array marker failed. "
"marker=%#x, required=%#x, ret=%d", marker, RTMP_AMF0_Object, ret);
return ret;
}
srs_verbose("amf0 read ecma_array marker success");
// count
if (!stream->require(4)) {
ret = ERROR_RTMP_AMF0_DECODE;
srs_error("amf0 read ecma_array count failed. ret=%d", ret);
return ret;
}
int32_t count = stream->read_4bytes();
srs_verbose("amf0 read ecma_array count success. count=%d", count);
// value
value = new SrsASrsAmf0EcmaArray();
value->count = count;
while (!stream->empty()) {
// property-name: utf8 string
std::string property_name;
if ((ret =srs_amf0_read_utf8(stream, property_name)) != ERROR_SUCCESS) {
srs_error("amf0 ecma_array read property name failed. ret=%d", ret);
return ret;
}
// property-value: any
SrsAmf0Any* property_value = NULL;
if ((ret = srs_amf0_read_any(stream, property_value)) != ERROR_SUCCESS) {
srs_error("amf0 ecma_array read property_value failed. "
"name=%s, ret=%d", property_name.c_str(), ret);
return ret;
}
// AMF0 Object EOF.
if (property_name.empty() || !property_value || property_value->is_object_eof()) {
if (property_value) {
delete property_value;
}
srs_info("amf0 read ecma_array EOF.");
break;
}
// add property
value->properties[property_name] = property_value;
}
return ret;
}
int srs_amf0_write_ecma_array(SrsStream* stream, SrsASrsAmf0EcmaArray* value)
{
int ret = ERROR_SUCCESS;
srs_assert(value != NULL);
// marker
if (!stream->require(1)) {
ret = ERROR_RTMP_AMF0_ENCODE;
srs_error("amf0 write ecma_array marker failed. ret=%d", ret);
return ret;
}
stream->write_1bytes(RTMP_AMF0_EcmaArray);
srs_verbose("amf0 write ecma_array marker success");
// count
if (!stream->require(4)) {
ret = ERROR_RTMP_AMF0_ENCODE;
srs_error("amf0 write ecma_array count failed. ret=%d", ret);
return ret;
}
stream->write_4bytes(value->count);
srs_verbose("amf0 write ecma_array count success. count=%d", value->count);
// value
std::map<std::string, SrsAmf0Any*>::iterator it;
for (it = value->properties.begin(); it != value->properties.end(); ++it) {
std::string name = it->first;
SrsAmf0Any* any = it->second;
if ((ret = srs_amf0_write_utf8(stream, name)) != ERROR_SUCCESS) {
srs_error("write ecma_array property name failed. ret=%d", ret);
return ret;
}
if ((ret = srs_amf0_write_any(stream, any)) != ERROR_SUCCESS) {
srs_error("write ecma_array property value failed. ret=%d", ret);
return ret;
}
srs_verbose("write amf0 property success. name=%s", name.c_str());
}
if ((ret = srs_amf0_write_object_eof(stream, &value->eof)) != ERROR_SUCCESS) {
srs_error("write ecma_array eof failed. ret=%d", ret);
return ret;
}
srs_verbose("write ecma_array object success.");
return ret;
}
int srs_amf0_get_utf8_size(std::string value)
{
return 2 + value.length();
... ... @@ -733,21 +960,29 @@ int srs_amf0_get_object_size(SrsAmf0Object* obj)
SrsAmf0Any* value = it->second;
size += srs_amf0_get_utf8_size(name);
size += srs_amf0_get_any_size(value);
}
size += srs_amf0_get_object_eof_size();
return size;
}
int srs_amf0_get_ecma_array_size(SrsASrsAmf0EcmaArray* arr)
{
if (!arr) {
return 0;
}
int size = 1 + 4;
std::map<std::string, SrsAmf0Any*>::iterator it;
for (it = arr->properties.begin(); it != arr->properties.end(); ++it) {
std::string name = it->first;
SrsAmf0Any* value = it->second;
if (value->is_boolean()) {
size += srs_amf0_get_boolean_size();
} else if (value->is_number()) {
size += srs_amf0_get_number_size();
} else if (value->is_string()) {
SrsAmf0String* p = srs_amf0_convert<SrsAmf0String>(value);
size += srs_amf0_get_string_size(p->value);
} else if (value->is_object()) {
SrsAmf0Object* p = srs_amf0_convert<SrsAmf0Object>(value);
size += srs_amf0_get_object_size(p);
} else {
// TOOD: other AMF0 types.
srs_warn("ignore unkown AMF0 type size.");
}
size += srs_amf0_get_utf8_size(name);
size += srs_amf0_get_any_size(value);
}
size += srs_amf0_get_object_eof_size();
... ...
... ... @@ -56,6 +56,7 @@ struct SrsAmf0Any
virtual bool is_number();
virtual bool is_object();
virtual bool is_object_eof();
virtual bool is_ecma_array();
};
/**
... ... @@ -68,7 +69,7 @@ struct SrsAmf0String : public SrsAmf0Any
{
std::string value;
SrsAmf0String();
SrsAmf0String(const char* _value = NULL);
virtual ~SrsAmf0String();
};
... ... @@ -83,7 +84,7 @@ struct SrsAmf0Boolean : public SrsAmf0Any
{
bool value;
SrsAmf0Boolean();
SrsAmf0Boolean(bool _value = false);
virtual ~SrsAmf0Boolean();
};
... ... @@ -97,7 +98,7 @@ struct SrsAmf0Number : public SrsAmf0Any
{
double value;
SrsAmf0Number();
SrsAmf0Number(double _value = 0.0);
virtual ~SrsAmf0Number();
};
... ... @@ -132,6 +133,25 @@ struct SrsAmf0Object : public SrsAmf0Any
};
/**
* 2.10 ECMA Array Type
* ecma-array-type = associative-count *(object-property)
* associative-count = U32
* object-property = (UTF-8 value-type) | (UTF-8-empty object-end-marker)
*/
struct SrsASrsAmf0EcmaArray : public SrsAmf0Any
{
int32_t count;
std::map<std::string, SrsAmf0Any*> properties;
SrsAmf0ObjectEOF eof;
SrsASrsAmf0EcmaArray();
virtual ~SrsASrsAmf0EcmaArray();
virtual SrsAmf0Any* get_property(std::string name);
virtual SrsAmf0Any* ensure_property_string(std::string name);
};
/**
* read amf0 utf8 string from stream.
* 1.3.1 Strings and UTF-8
* UTF-8 = U16 *(UTF8-char)
... ... @@ -177,6 +197,16 @@ extern int srs_amf0_read_object(SrsStream* stream, SrsAmf0Object*& value);
extern int srs_amf0_write_object(SrsStream* stream, SrsAmf0Object* value);
/**
* read amf0 object from stream.
* 2.10 ECMA Array Type
* ecma-array-type = associative-count *(object-property)
* associative-count = U32
* object-property = (UTF-8 value-type) | (UTF-8-empty object-end-marker)
*/
extern int srs_amf0_read_ecma_array(SrsStream* stream, SrsASrsAmf0EcmaArray*& value);
extern int srs_amf0_write_ecma_array(SrsStream* stream, SrsASrsAmf0EcmaArray* value);
/**
* get amf0 objects size.
*/
extern int srs_amf0_get_utf8_size(std::string value);
... ... @@ -184,7 +214,8 @@ extern int srs_amf0_get_string_size(std::string value);
extern int srs_amf0_get_number_size();
extern int srs_amf0_get_boolean_size();
extern int srs_amf0_get_object_size(SrsAmf0Object* obj);
extern int srs_amf0_get_ecma_array_size(SrsASrsAmf0EcmaArray* arr);
/**
* convert the any to specified object.
* @return T*, the converted object. never NULL.
... ...
... ... @@ -92,6 +92,12 @@ int SrsClient::do_cycle()
return ret;
}
srs_verbose("set peer bandwidth success");
if ((ret = rtmp->response_connect_app()) != ERROR_SUCCESS) {
srs_error("response connect app failed. ret=%d", ret);
return ret;
}
srs_verbose("response connect app success");
return ret;
}
... ...
... ... @@ -1061,8 +1061,8 @@ SrsConnectAppResPacket::SrsConnectAppResPacket()
{
command_name = RTMP_AMF0_COMMAND_CONNECT;
transaction_id = 1;
props = NULL;
info = NULL;
props = new SrsAmf0Object();
info = new SrsAmf0Object();
}
SrsConnectAppResPacket::~SrsConnectAppResPacket()
... ...
... ... @@ -30,6 +30,15 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#include <srs_core_auto_free.hpp>
#include <srs_core_amf0.hpp>
/**
* the signature for packets to client.
*/
#define RTMP_SIG_FMS_VER "3,5,3,888"
#define RTMP_SIG_AMF0_VER 3
#define RTMP_SIG_SRS_NAME "srs(simple rtmp server)"
#define RTMP_SIG_SRS_URL "https://github.com/winlinvip/simple-rtmp-server"
#define RTMP_SIG_SRS_VERSION "0.1"
int SrsRequest::discovery_app()
{
int ret = ERROR_SUCCESS;
... ... @@ -205,3 +214,39 @@ int SrsRtmp::set_peer_bandwidth(int bandwidth, int type)
return ret;
}
int SrsRtmp::response_connect_app()
{
int ret = ERROR_SUCCESS;
SrsMessage* msg = new SrsMessage();
SrsConnectAppResPacket* pkt = new SrsConnectAppResPacket();
pkt->command_name = "_result";
pkt->props->properties["fmsVer"] = new SrsAmf0String("FMS/"RTMP_SIG_FMS_VER);
pkt->props->properties["capabilities"] = new SrsAmf0Number(123);
pkt->props->properties["mode"] = new SrsAmf0Number(1);
pkt->info->properties["level"] = new SrsAmf0String("status");
pkt->info->properties["code"] = new SrsAmf0String("NetConnection.Connect.Success");
pkt->info->properties["description"] = new SrsAmf0String("Connection succeeded");
pkt->info->properties["objectEncoding"] = new SrsAmf0Number(RTMP_SIG_AMF0_VER);
SrsASrsAmf0EcmaArray* data = new SrsASrsAmf0EcmaArray();
pkt->info->properties["data"] = data;
data->properties["version"] = new SrsAmf0String(RTMP_SIG_FMS_VER);
data->properties["server"] = new SrsAmf0String(RTMP_SIG_SRS_NAME);
data->properties["srs_url"] = new SrsAmf0String(RTMP_SIG_SRS_URL);
data->properties["srs_version"] = new SrsAmf0String(RTMP_SIG_SRS_VERSION);
msg->set_packet(pkt);
if ((ret = protocol->send_message(msg)) != ERROR_SUCCESS) {
srs_error("send connect app response message failed. ret=%d", ret);
return ret;
}
srs_info("send connect app response message success.");
return ret;
}
... ...
... ... @@ -79,6 +79,7 @@ public:
* using the Limit type field.
*/
virtual int set_peer_bandwidth(int bandwidth, int type);
virtual int response_connect_app();
};
#endif
\ No newline at end of file
... ...