/*static*/ Message Message::Connect(std::string app, int rpc_number) { uint8_t buf[4096]; size_t len; Message msg; amf0_data *data; msg.write_string("connect"); data = amf0_number_new(rpc_number); len = amf0_data_buffer_write(data, buf, 4096); msg.body_.insert(msg.body_.end(), buf, buf + len); amf0_data_free(data); data = amf0_object_new(); amf0_object_add(data, "app", amf0_str(app.c_str())); amf0_object_add(data, "type", amf0_str("nonprivate")); amf0_object_add(data, "flashVer", amf0_str("FMLE/3.0 (compatible; obs-studio/0.14.2; FMSc/1.0)")); amf0_object_add(data, "tcUrl", amf0_str("rtmp://live.hkstv.hk.lxdns.com:1935/live")); amf0_object_add(data, "capabilities", amf0_number_new(15)); amf0_object_add(data, "audioCodecs", amf0_number_new(4071)); amf0_object_add(data, "videoCodecs", amf0_number_new(252)); amf0_object_add(data, "videoFunction", amf0_number_new(1)); len = amf0_data_buffer_write(data, buf, 4096); msg.body_.insert(msg.body_.end(), buf, buf + len); amf0_data_free(data); msg.csid_ = 3; msg.type_ = COMMAND_AMF0; /* Command AMF0 */ msg.stream_id_ = 0; msg.length_ = msg.body_.size(); return msg; }
/* clone AMF data */ amf0_data * amf0_data_clone(amf0_data * data) { /* we copy data recursively */ if (data != NULL) { switch (data->type) { case AMF0_TYPE_NUMBER: return amf0_number_new(amf0_number_get_value(data)); case AMF0_TYPE_BOOLEAN: return amf0_boolean_new(amf0_boolean_get_value(data)); case AMF0_TYPE_STRING: if (data->string_data.mbstr != NULL) { return amf0_string_new((uint8_t *)strdup((char *)amf0_string_get_uint8_ts(data)), amf0_string_get_size(data)); } else { return amf0_str(NULL); } case AMF0_TYPE_NULL: return NULL; case AMF0_TYPE_UNDEFINED: return NULL; /*case AMF0_TYPE_REFERENCE:*/ case AMF0_TYPE_OBJECT: case AMF0_TYPE_ECMA_ARRAY: case AMF0_TYPE_STRICT_ARRAY: { amf0_data * d = amf0_data_new(data->type); if (d != NULL) { amf0_list_init(&d->list_data); amf0_list_clone(&data->list_data, &d->list_data); } return d; } case AMF0_TYPE_DATE: return amf0_date_new(amf0_date_get_milliseconds(data), amf0_date_get_timezone(data)); /*case AMF0_TYPE_SIMPLEOBJECT:*/ case AMF0_TYPE_XML_DOCUMENT: return NULL; case AMF0_TYPE_TYPED_OBJECT: return NULL; } } return NULL; }
size_t Message::write_string(std::string str) { uint8_t buf[4096]; size_t len; amf0_data *data = amf0_str(str.c_str()); len = amf0_data_buffer_write(data, buf, 4096); body_.insert(body_.end(), buf, buf + len); amf0_data_free(data); return len; }
amf0_data * amf0_object_add(amf0_data * data, const char * name, amf0_data * element) { if (data != NULL) { if (amf0_list_push(&data->list_data, amf0_str(name)) != NULL) { if (amf0_list_push(&data->list_data, element) != NULL) { return element; } else { amf0_data_free(amf0_list_pop(&data->list_data)); } } } return NULL; }
/* clone AMF data */ amf0_data * amf0_data_clone(const amf0_data *data) { /* we copy data recursively */ if (data != NULL) { switch (data->type) { case AMF0_TYPE_NUMBER: return amf0_number_new(amf0_number_get_value(data)); case AMF0_TYPE_BOOLEAN: return amf0_boolean_new(amf0_boolean_get_value(data)); case AMF0_TYPE_STRING: if (data->string_data.mbstr != NULL) { return amf0_string_new((uint8_t *)strdup((char *)amf0_string_get_bytes(data)), amf0_string_get_size(data)); } else { return amf0_str(NULL); } case AMF0_TYPE_MOVIECLIP: /* not supported */ case AMF0_TYPE_NULL: case AMF0_TYPE_UNDEFINED: case AMF0_TYPE_REFERENCE: /* TODO */ case AMF0_TYPE_OBJECT_END: return NULL; case AMF0_TYPE_OBJECT: case AMF0_TYPE_ECMA_ARRAY: case AMF0_TYPE_STRICT_ARRAY: { amf0_data * d = amf0_data_new(data->type); if (d != NULL) { amf0_list_init(&d->list_data); amf0_list_clone(&data->list_data, &d->list_data); } return d; } case AMF0_TYPE_DATE: return amf0_date_new(amf0_date_get_milliseconds(data), amf0_date_get_timezone(data)); case AMF0_TYPE_LONG_STRING: /* TODO */ case AMF0_TYPE_UNSUPPORTED: /* TODO */ case AMF0_TYPE_RECORDSET: /* not supported */ case AMF0_TYPE_XML_DOCUMENT: /* TODO */ case AMF0_TYPE_TYPED_OBJECT: /* TODO */ default: return NULL; } } return NULL; }