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; }
//////////////////////////////////////////////////////////////////////////////////// /// /// \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; }