bool RTMPProtocolSerializer::Serialize(Channel &channel,
		Variant &message, IOBuffer &buffer, uint32_t chunkSize) {
	bool result = false;
	_internalBuffer.Ignore(GETAVAILABLEBYTESCOUNT(_internalBuffer));

	switch ((uint32_t) VH_MT(message)) {
		case RM_HEADER_MESSAGETYPE_INVOKE:
		{
			result = SerializeInvoke(_internalBuffer, message[RM_INVOKE]);
			break;
		}
		case RM_HEADER_MESSAGETYPE_NOTIFY:
		{
			result = SerializeNotify(_internalBuffer, message[RM_NOTIFY]);
			break;
		}
		case RM_HEADER_MESSAGETYPE_FLEXSTREAMSEND:
		{
			result = SerializeFlexStreamSend(_internalBuffer, message[RM_FLEXSTREAMSEND]);
			break;
		}
		case RM_HEADER_MESSAGETYPE_FLEXSHAREDOBJECT:
		{
			result = SerializeFlexSharedObject(_internalBuffer, message[RM_SHAREDOBJECT]);
			break;
		}
		case RM_HEADER_MESSAGETYPE_SHAREDOBJECT:
		{
			result = SerializeSharedObject(_internalBuffer, message[RM_SHAREDOBJECT]);
			break;
		}
		case RM_HEADER_MESSAGETYPE_ACK:
		{
			result = SerializeAck(_internalBuffer, message[RM_ACK]);
			break;
		}
		case RM_HEADER_MESSAGETYPE_USRCTRL:
		{
			result = SerializeUsrCtrl(_internalBuffer, message[RM_USRCTRL]);
			break;
		}
		case RM_HEADER_MESSAGETYPE_CHUNKSIZE:
		{
			result = SerializeChunkSize(_internalBuffer, message[RM_CHUNKSIZE]);
			break;
		}
		case RM_HEADER_MESSAGETYPE_WINACKSIZE:
		{
			result = SerializeWinAckSize(_internalBuffer, message[RM_WINACKSIZE]);
			break;
		}
		case RM_HEADER_MESSAGETYPE_PEERBW:
		{
			result = SerializeClientBW(_internalBuffer, message[RM_PEERBW]);
			break;
		}
		case RM_HEADER_MESSAGETYPE_ABORTMESSAGE:
		{
			result = SerializeAbortMessage(_internalBuffer, message[RM_ABORTMESSAGE]);
			break;
		}
		default:
		{
			FATAL("Invalid message type:\n%s", STR(message.ToString()));
		}
	}

	//2. Check out the result
	if (!result) {
		FATAL("Unable to serialize message body");
		return false;
	}

	//3. Update the message length
	VH_ML(message) = GETAVAILABLEBYTESCOUNT(_internalBuffer);

	//4. Extract the header
	Header header;
	if (!Header::GetFromVariant(header, message[RM_HEADER])) {
		FATAL("Unable to read RTMP header: %s", STR(message.ToString()));
		return false;
	}

	//5. Chunk and send the data
	uint32_t available = 0;
	while ((available = GETAVAILABLEBYTESCOUNT(_internalBuffer)) != 0) {
		if (!header.Write(channel, buffer)) {
			FATAL("Unable to serialize message header");
			result = false;
		}
		if (available >= chunkSize) {
			buffer.ReadFromInputBuffer(&_internalBuffer, 0, chunkSize);
			channel.lastOutProcBytes += chunkSize;
			_internalBuffer.Ignore(chunkSize);
		} else {
			buffer.ReadFromInputBuffer(&_internalBuffer, 0, available);
			channel.lastOutProcBytes += available;
			_internalBuffer.Ignore(available);
		}
	}
	channel.lastOutProcBytes = 0;

	//6. Done
	return result;
}
Example #2
0
////////////////////////////////////////////////////////////////////////////////////
///
///   \brief Writes message contents to packet for the transport layer to
///          send.  Begins writing from current write position in packet.
///
///   Message contents are written to the packet following the JAUS standard.
///
///   \param[out] packet Packet to write header and payload data to.
///   \param[out] header Packet transport header data.
///   \param[in] transportHeader Optional parameter for transport header data to
///                              write before the general transport header.
///   \param[in] clearPacket If true, packet contents are cleared before
///                          writing takes place.
///   \param[in] startingSequenceNumber Sequence number to use for packets.
///   \param[in] broadcastFlag Values to use to signify if message should be
///                            sent using any broadcast options (e.g. 
///                            multicast). 0 = no options, 1 = local broadcast,
///                            2 = global broadcast.
///
///   \return FAILURE on error, otherwise number of bytes written.
///
////////////////////////////////////////////////////////////////////////////////////
int Message::Write(Packet& packet, 
                   Header& header,
                   const Packet* transportHeader, 
                   const bool clearPacket,
                   const UShort startingSequenceNumber,
                   const Byte broadcastFlag) const
{
    int total = 0;
    //  Build JAUS header data.
    header.mSourceID = mSourceID;
    header.mDestinationID = mDestinationID;
    header.mPriorityFlag = mPriority;
    header.mControlFlag = Header::DataControl::Single;
    header.mCompressionFlag = Header::Compression::None;
    header.mSequenceNumber = startingSequenceNumber;
    header.mBroadcastFlag = broadcastFlag;

    //  Clear out any previous message data.
    if(clearPacket)
    {
        packet.Clear();
        packet.Reserve(Header::MinSize + USHORT_SIZE + 1);
    }
    unsigned int writePos = packet.GetWritePos();
    
    if(transportHeader && transportHeader->Length() > 0)
    {
        writePos += (unsigned int)packet.Write(*transportHeader);
    }
    //  The first thing we must do is advance
    //  the write position to after the JAUS Header
    //  data.  The header is not written first because
    //  we do not know how large the message body will
    //  be yet.
    packet.SetLength(writePos + Header::PayloadOffset);
    packet.SetWritePos(writePos + Header::PayloadOffset);
    total += packet.Write(mMessageCode);
    int payloadSize = 0;
    if( (payloadSize = WriteMessageBody(packet)) >= 0)
    {
        total += payloadSize;
        // Check for large data set.
        if(total + Header::MinSize > Header::MaxPacketSize)
        {
            return FAILURE;
        }
        else
        {
            header.mSize = total + Header::MinSize;
            packet.SetWritePos(writePos);
            // Go back, and re-write the header since 
            // we now know the size of the message.
            if(header.Write(packet))
            {
                // Set the write position to the end of message we just wrote.
                packet.SetWritePos(writePos + header.mSize);
                //  Return the number of bytes written.
                if(transportHeader)
                {
                    return header.mSize + transportHeader->Length();
                }
                else
                {
                    return header.mSize;
                }
            }
        }
    }

    return FAILURE;
}