mirror of
https://github.com/ossrs/srs.git
synced 2025-03-09 15:49:59 +00:00
expect rtmp packet which decoded from message payload
This commit is contained in:
parent
bf5378434f
commit
f5672998fd
3 changed files with 304 additions and 90 deletions
|
@ -28,6 +28,100 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|||
#include <srs_core_socket.hpp>
|
||||
#include <srs_core_buffer.hpp>
|
||||
|
||||
/**
|
||||
5. Protocol Control Messages
|
||||
RTMP reserves message type IDs 1-7 for protocol control messages.
|
||||
These messages contain information needed by the RTM Chunk Stream
|
||||
protocol or RTMP itself. Protocol messages with IDs 1 & 2 are
|
||||
reserved for usage with RTM Chunk Stream protocol. Protocol messages
|
||||
with IDs 3-6 are reserved for usage of RTMP. Protocol message with ID
|
||||
7 is used between edge server and origin server.
|
||||
*/
|
||||
#define RTMP_MSG_SetChunkSize 0x01
|
||||
#define RTMP_MSG_AbortMessage 0x02
|
||||
#define RTMP_MSG_Acknowledgement 0x03
|
||||
#define RTMP_MSG_UserControlMessage 0x04
|
||||
#define RTMP_MSG_WindowAcknowledgementSize 0x05
|
||||
#define RTMP_MSG_SetPeerBandwidth 0x06
|
||||
#define RTMP_MSG_EdgeAndOriginServerCommand 0x07
|
||||
/**
|
||||
* The server sends this event to test whether the client is reachable.
|
||||
*
|
||||
* Event data is a 4-byte timestamp, representing the local server time when the server dispatched the command.
|
||||
* The client responds with PingResponse on receiving PingRequest.
|
||||
*/
|
||||
#define RTMP_MSG_PCUC_PingRequest 0x06
|
||||
|
||||
/**
|
||||
* The client sends this event to the server in response to the ping request.
|
||||
*
|
||||
* The event data is a 4-byte timestamp, which was received with the PingRequest request.
|
||||
*/
|
||||
#define RTMP_MSG_PCUC_PingResponse 0x07
|
||||
/**
|
||||
3. Types of messages
|
||||
The server and the client send messages over the network to
|
||||
communicate with each other. The messages can be of any type which
|
||||
includes audio messages, video messages, command messages, shared
|
||||
object messages, data messages, and user control messages.
|
||||
3.1. Command message
|
||||
Command messages carry the AMF-encoded commands between the client
|
||||
and the server. These messages have been assigned message type value
|
||||
of 20 for AMF0 encoding and message type value of 17 for AMF3
|
||||
encoding. These messages are sent to perform some operations like
|
||||
connect, createStream, publish, play, pause on the peer. Command
|
||||
messages like onstatus, result etc. are used to inform the sender
|
||||
about the status of the requested commands. A command message
|
||||
consists of command name, transaction ID, and command object that
|
||||
contains related parameters. A client or a server can request Remote
|
||||
Procedure Calls (RPC) over streams that are communicated using the
|
||||
command messages to the peer.
|
||||
*/
|
||||
#define RTMP_MSG_AMF3CommandMessage 17 // 0x11
|
||||
#define RTMP_MSG_AMF0CommandMessage 20 // 0x14
|
||||
/**
|
||||
3.2. Data message
|
||||
The client or the server sends this message to send Metadata or any
|
||||
user data to the peer. Metadata includes details about the
|
||||
data(audio, video etc.) like creation time, duration, theme and so
|
||||
on. These messages have been assigned message type value of 18 for
|
||||
AMF0 and message type value of 15 for AMF3.
|
||||
*/
|
||||
#define RTMP_MSG_AMF0DataMessage 18 // 0x12
|
||||
#define RTMP_MSG_AMF3DataMessage 15 // 0x0F
|
||||
/**
|
||||
3.3. Shared object message
|
||||
A shared object is a Flash object (a collection of name value pairs)
|
||||
that are in synchronization across multiple clients, instances, and
|
||||
so on. The message types kMsgContainer=19 for AMF0 and
|
||||
kMsgContainerEx=16 for AMF3 are reserved for shared object events.
|
||||
Each message can contain multiple events.
|
||||
*/
|
||||
#define RTMP_MSG_AMF3SharedObject 16 // 0x10
|
||||
#define RTMP_MSG_AMF0SharedObject 19 // 0x13
|
||||
/**
|
||||
3.4. Audio message
|
||||
The client or the server sends this message to send audio data to the
|
||||
peer. The message type value of 8 is reserved for audio messages.
|
||||
*/
|
||||
#define RTMP_MSG_AudioMessage 8 // 0x08
|
||||
/* *
|
||||
3.5. Video message
|
||||
The client or the server sends this message to send video data to the
|
||||
peer. The message type value of 9 is reserved for video messages.
|
||||
These messages are large and can delay the sending of other type of
|
||||
messages. To avoid such a situation, the video message is assigned
|
||||
the lowest priority.
|
||||
*/
|
||||
#define RTMP_MSG_VideoMessage 9 // 0x09
|
||||
/**
|
||||
3.6. Aggregate message
|
||||
An aggregate message is a single message that contains a list of submessages.
|
||||
The message type value of 22 is reserved for aggregate
|
||||
messages.
|
||||
*/
|
||||
#define RTMP_MSG_AggregateMessage 22 // 0x16
|
||||
|
||||
/**
|
||||
* 6.1.2. Chunk Message Header
|
||||
* There are four different formats for the chunk message header,
|
||||
|
@ -93,6 +187,89 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|||
*/
|
||||
#define RTMP_EXTENDED_TIMESTAMP 0xFFFFFF
|
||||
|
||||
SrsMessageHeader::SrsMessageHeader()
|
||||
{
|
||||
message_type = 0;
|
||||
payload_length = 0;
|
||||
timestamp = 0;
|
||||
stream_id = 0;
|
||||
}
|
||||
|
||||
SrsMessageHeader::~SrsMessageHeader()
|
||||
{
|
||||
}
|
||||
|
||||
SrsChunkStream::SrsChunkStream(int _cid)
|
||||
{
|
||||
fmt = 0;
|
||||
cid = _cid;
|
||||
extended_timestamp = false;
|
||||
msg = NULL;
|
||||
}
|
||||
|
||||
SrsChunkStream::~SrsChunkStream()
|
||||
{
|
||||
if (msg) {
|
||||
delete msg;
|
||||
msg = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
SrsMessage::SrsMessage()
|
||||
{
|
||||
size = 0;
|
||||
payload = NULL;
|
||||
decoded_payload = NULL;
|
||||
}
|
||||
|
||||
SrsMessage::~SrsMessage()
|
||||
{
|
||||
if (payload) {
|
||||
delete[] payload;
|
||||
payload = NULL;
|
||||
}
|
||||
|
||||
if (decoded_payload) {
|
||||
delete decoded_payload;
|
||||
decoded_payload = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
SrsPacket* SrsMessage::get_packet()
|
||||
{
|
||||
if (!decoded_payload) {
|
||||
srs_error("the payload is raw/undecoded, invoke decode_packet to decode it.");
|
||||
}
|
||||
srs_assert(decoded_payload != NULL);
|
||||
|
||||
return decoded_payload;
|
||||
}
|
||||
|
||||
int SrsMessage::decode_packet()
|
||||
{
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
// TODO: decode packet.
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
SrsPacket::SrsPacket()
|
||||
{
|
||||
}
|
||||
|
||||
SrsPacket::~SrsPacket()
|
||||
{
|
||||
}
|
||||
|
||||
SrsConnectAppPacket::SrsConnectAppPacket()
|
||||
{
|
||||
}
|
||||
|
||||
SrsConnectAppPacket::~SrsConnectAppPacket()
|
||||
{
|
||||
}
|
||||
|
||||
SrsProtocol::SrsProtocol(st_netfd_t client_stfd)
|
||||
{
|
||||
stfd = client_stfd;
|
||||
|
@ -129,6 +306,8 @@ SrsProtocol::~SrsProtocol()
|
|||
|
||||
int SrsProtocol::recv_message(SrsMessage** pmsg)
|
||||
{
|
||||
*pmsg = NULL;
|
||||
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
while (true) {
|
||||
|
@ -143,7 +322,9 @@ int SrsProtocol::recv_message(SrsMessage** pmsg)
|
|||
continue;
|
||||
}
|
||||
|
||||
// decode the msg
|
||||
// return the msg with raw/undecoded payload
|
||||
*pmsg = msg;
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
@ -440,26 +621,15 @@ int SrsProtocol::read_message_payload(SrsChunkStream* chunk, int bh_size, int mh
|
|||
srs_verbose("create empty payload for RTMP message. size=%d", chunk->header.payload_length);
|
||||
}
|
||||
|
||||
// copy payload from buffer.
|
||||
int copy_size = buffer->size() - bh_size - mh_size;
|
||||
if (copy_size > payload_size) {
|
||||
copy_size = payload_size;
|
||||
}
|
||||
memcpy(chunk->msg->payload + chunk->msg->size, buffer->bytes() + bh_size + mh_size, copy_size);
|
||||
buffer->erase(bh_size + mh_size + copy_size);
|
||||
chunk->msg->size += copy_size;
|
||||
|
||||
// when empty, read the left bytes from socket.
|
||||
int left_size = payload_size - copy_size;
|
||||
if (left_size > 0) {
|
||||
ssize_t nread;
|
||||
if ((ret = skt->read_fully(chunk->msg->payload + chunk->msg->size, left_size, &nread)) != ERROR_SUCCESS) {
|
||||
srs_error("read chunk payload from socket error. "
|
||||
"payload_size=%d, copy_size=%d, left_size=%d, size=%d, msg_size=%d, ret=%d",
|
||||
payload_size, copy_size, left_size, chunk->msg->size, chunk->header.payload_length, ret);
|
||||
return ret;
|
||||
}
|
||||
// read payload to buffer
|
||||
int required_size = bh_size + mh_size + payload_size;
|
||||
if ((ret = buffer->ensure_buffer_bytes(skt, required_size)) != ERROR_SUCCESS) {
|
||||
srs_error("read payload failed. required_size=%d, ret=%d", required_size, ret);
|
||||
return ret;
|
||||
}
|
||||
memcpy(chunk->msg->payload + chunk->msg->size, buffer->bytes() + bh_size + mh_size, payload_size);
|
||||
buffer->erase(bh_size + mh_size + payload_size);
|
||||
chunk->msg->size += payload_size;
|
||||
|
||||
srs_verbose("chunk payload read complted. bh_size=%d, mh_size=%d, payload_size=%d", bh_size, mh_size, payload_size);
|
||||
|
||||
|
@ -481,45 +651,3 @@ int SrsProtocol::read_message_payload(SrsChunkStream* chunk, int bh_size, int mh
|
|||
return ret;
|
||||
}
|
||||
|
||||
SrsMessageHeader::SrsMessageHeader()
|
||||
{
|
||||
message_type = 0;
|
||||
payload_length = 0;
|
||||
timestamp = 0;
|
||||
stream_id = 0;
|
||||
}
|
||||
|
||||
SrsMessageHeader::~SrsMessageHeader()
|
||||
{
|
||||
}
|
||||
|
||||
SrsChunkStream::SrsChunkStream(int _cid)
|
||||
{
|
||||
fmt = 0;
|
||||
cid = _cid;
|
||||
extended_timestamp = false;
|
||||
msg = NULL;
|
||||
}
|
||||
|
||||
SrsChunkStream::~SrsChunkStream()
|
||||
{
|
||||
if (msg) {
|
||||
delete msg;
|
||||
msg = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
SrsMessage::SrsMessage()
|
||||
{
|
||||
size = 0;
|
||||
payload = NULL;
|
||||
}
|
||||
|
||||
SrsMessage::~SrsMessage()
|
||||
{
|
||||
if (payload) {
|
||||
delete[] payload;
|
||||
payload = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -34,37 +34,15 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|||
|
||||
#include <st.h>
|
||||
|
||||
#include <srs_core_log.hpp>
|
||||
#include <srs_core_error.hpp>
|
||||
|
||||
class SrsSocket;
|
||||
class SrsBuffer;
|
||||
class SrsPacket;
|
||||
class SrsMessage;
|
||||
class SrsChunkStream;
|
||||
|
||||
/**
|
||||
* the protocol provides the rtmp-message-protocol services,
|
||||
* to recv RTMP message from RTMP chunk stream,
|
||||
* and to send out RTMP message over RTMP chunk stream.
|
||||
*/
|
||||
class SrsProtocol
|
||||
{
|
||||
private:
|
||||
std::map<int, SrsChunkStream*> chunk_streams;
|
||||
st_netfd_t stfd;
|
||||
SrsBuffer* buffer;
|
||||
SrsSocket* skt;
|
||||
int32_t in_chunk_size;
|
||||
int32_t out_chunk_size;
|
||||
public:
|
||||
SrsProtocol(st_netfd_t client_stfd);
|
||||
virtual ~SrsProtocol();
|
||||
public:
|
||||
virtual int recv_message(SrsMessage** pmsg);
|
||||
private:
|
||||
virtual int recv_interlaced_message(SrsMessage** pmsg);
|
||||
virtual int read_basic_header(char& fmt, int& cid, int& size);
|
||||
virtual int read_message_header(SrsChunkStream* chunk, char fmt, int bh_size, int& mh_size);
|
||||
virtual int read_message_payload(SrsChunkStream* chunk, int bh_size, int mh_size, int& payload_size, SrsMessage** pmsg);
|
||||
};
|
||||
|
||||
/**
|
||||
* 4.1. Message Header
|
||||
*/
|
||||
|
@ -127,7 +105,6 @@ public:
|
|||
public:
|
||||
SrsChunkStream(int _cid);
|
||||
virtual ~SrsChunkStream();
|
||||
public:
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -148,10 +125,114 @@ public:
|
|||
*/
|
||||
int32_t size;
|
||||
int8_t* payload;
|
||||
// decoded message payload.
|
||||
private:
|
||||
SrsPacket* decoded_payload;
|
||||
public:
|
||||
/**
|
||||
* get the decoded packet,
|
||||
* not all packets need to decode, for video/audio packet,
|
||||
* passthrough to peer are ok.
|
||||
* @remark, user must invoke decode_packet first.
|
||||
*/
|
||||
virtual SrsPacket* get_packet();
|
||||
virtual int decode_packet();
|
||||
public:
|
||||
SrsMessage();
|
||||
virtual ~SrsMessage();
|
||||
};
|
||||
|
||||
/**
|
||||
* the decoded message payload.
|
||||
*/
|
||||
class SrsPacket
|
||||
{
|
||||
public:
|
||||
SrsPacket();
|
||||
virtual ~SrsPacket();
|
||||
};
|
||||
|
||||
class SrsConnectAppPacket : public SrsPacket
|
||||
{
|
||||
public:
|
||||
SrsConnectAppPacket();
|
||||
virtual ~SrsConnectAppPacket();
|
||||
};
|
||||
|
||||
/**
|
||||
* the protocol provides the rtmp-message-protocol services,
|
||||
* to recv RTMP message from RTMP chunk stream,
|
||||
* and to send out RTMP message over RTMP chunk stream.
|
||||
*/
|
||||
class SrsProtocol
|
||||
{
|
||||
private:
|
||||
std::map<int, SrsChunkStream*> chunk_streams;
|
||||
st_netfd_t stfd;
|
||||
SrsBuffer* buffer;
|
||||
SrsSocket* skt;
|
||||
int32_t in_chunk_size;
|
||||
int32_t out_chunk_size;
|
||||
public:
|
||||
SrsProtocol(st_netfd_t client_stfd);
|
||||
virtual ~SrsProtocol();
|
||||
public:
|
||||
/**
|
||||
* recv a message with raw/undecoded payload from peer.
|
||||
* the payload is not decoded, use expect_message<T> if requires specifies message.
|
||||
* @pmsg, user must free it. NULL if not success.
|
||||
* @remark, only when success, user can use and must free the pmsg.
|
||||
*/
|
||||
virtual int recv_message(SrsMessage** pmsg);
|
||||
public:
|
||||
/**
|
||||
* expect a specified message, drop others util got specified one.
|
||||
* @pmsg, user must free it. NULL if not success.
|
||||
* @ppacket, store in the pmsg, user must never free it. NULL if not success.
|
||||
* @remark, only when success, user can use and must free the pmsg/ppacket.
|
||||
*/
|
||||
template<class T>
|
||||
int expect_message(SrsMessage** pmsg, T** ppacket)
|
||||
{
|
||||
*pmsg = NULL;
|
||||
*ppacket = NULL;
|
||||
|
||||
int ret = ERROR_SUCCESS;
|
||||
|
||||
while (true) {
|
||||
SrsMessage* msg = NULL;
|
||||
if ((ret = recv_message(&msg)) != ERROR_SUCCESS) {
|
||||
srs_error("recv message failed. ret=%d", ret);
|
||||
return ret;
|
||||
}
|
||||
srs_verbose("recv message success.");
|
||||
|
||||
if ((ret = msg->decode_packet()) != ERROR_SUCCESS) {
|
||||
delete msg;
|
||||
srs_error("decode message failed. ret=%d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
T* pkt = dynamic_cast<T*>(msg->get_packet());
|
||||
if (!pkt) {
|
||||
delete msg;
|
||||
srs_trace("drop message(type=%d, size=%d, time=%d, sid=%d).",
|
||||
msg->header.message_type, msg->header.payload_length,
|
||||
msg->header.timestamp, msg->header.stream_id);
|
||||
continue;
|
||||
}
|
||||
|
||||
*pmsg = msg;
|
||||
*ppacket = pkt;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
private:
|
||||
virtual int recv_interlaced_message(SrsMessage** pmsg);
|
||||
virtual int read_basic_header(char& fmt, int& cid, int& size);
|
||||
virtual int read_message_header(SrsChunkStream* chunk, char fmt, int bh_size, int& mh_size);
|
||||
virtual int read_message_payload(SrsChunkStream* chunk, int bh_size, int mh_size, int& payload_size, SrsMessage** pmsg);
|
||||
};
|
||||
|
||||
#endif
|
|
@ -94,7 +94,12 @@ int SrsRtmp::connect_app(SrsApp** papp)
|
|||
int ret = ERROR_SUCCESS;
|
||||
|
||||
SrsMessage* msg = NULL;
|
||||
protocol->recv_message(&msg);
|
||||
SrsConnectAppPacket* pkt = NULL;
|
||||
if ((ret = protocol->expect_message<SrsConnectAppPacket>(&msg, &pkt)) != ERROR_SUCCESS) {
|
||||
srs_error("expect connect app message failed. ret=%d", ret);
|
||||
return ret;
|
||||
}
|
||||
SrsAutoFree(SrsMessage, msg, false);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue