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; }
bool MonitorRTMPProtocol::ProcessBytes(IOBuffer &buffer) { while (true) { uint32_t availableBytesCount = GETAVAILABLEBYTESCOUNT(buffer); if (_selectedChannel < 0) { if (availableBytesCount < 1) { return true; } else { switch (GETIBPOINTER(buffer)[0]&0x3f) { case 0: { if (availableBytesCount < 2) { FINEST("Not enough data"); return true; } _selectedChannel = 64 + GETIBPOINTER(buffer)[1]; _channels[_selectedChannel].lastInHeaderType = GETIBPOINTER(buffer)[0] >> 6; buffer.Ignore(2); availableBytesCount -= 2; break; } case 1: { // if (availableBytesCount < 3) { // FINEST("Not enough data"); // return true; // } // _selectedChannel = GETIBPOINTER(buffer)[2]*256 + GETIBPOINTER(buffer)[1] + 64; // _channels[_selectedChannel].lastInHeaderType = GETIBPOINTER(buffer)[0] >> 6; // buffer.Ignore(3); // availableBytesCount -= 3; // break; FATAL("The server doesn't support channel ids bigger than 319"); return false; }; default: { _selectedChannel = GETIBPOINTER(buffer)[0]&0x3f; _channels[_selectedChannel].lastInHeaderType = GETIBPOINTER(buffer)[0] >> 6; buffer.Ignore(1); availableBytesCount -= 1; break; } } } } Channel &channel = _channels[_selectedChannel]; Header &header = channel.lastInHeader; FINEST("header: %s", STR(header)); if (channel.state == CS_HEADER) { if (!header.Read(_selectedChannel, channel.lastInHeaderType, buffer, availableBytesCount)) { FATAL("Unable to read header"); return false; } else { if (!header.readCompleted) return true; if (H_SI(header) >= _maxStreamCount) { FATAL("%s", STR(header)); FATAL("buffer:\n%s", STR(buffer)); ASSERT("invalid stream index"); } if (H_CI(header) >= _maxChannelsCount) { FATAL("%s", STR(header)); FATAL("buffer:\n%s", STR(buffer)); ASSERT("invalid channel index"); } switch ((uint8_t) H_MT(header)) { case RM_HEADER_MESSAGETYPE_ABORTMESSAGE: case RM_HEADER_MESSAGETYPE_ACK: case RM_HEADER_MESSAGETYPE_AGGREGATE: case RM_HEADER_MESSAGETYPE_AUDIODATA: case RM_HEADER_MESSAGETYPE_CHUNKSIZE: case RM_HEADER_MESSAGETYPE_FLEX: case RM_HEADER_MESSAGETYPE_FLEXSHAREDOBJECT: case RM_HEADER_MESSAGETYPE_FLEXSTREAMSEND: case RM_HEADER_MESSAGETYPE_INVOKE: case RM_HEADER_MESSAGETYPE_NOTIFY: case RM_HEADER_MESSAGETYPE_PEERBW: case RM_HEADER_MESSAGETYPE_SHAREDOBJECT: case RM_HEADER_MESSAGETYPE_USRCTRL: case RM_HEADER_MESSAGETYPE_VIDEODATA: case RM_HEADER_MESSAGETYPE_WINACKSIZE: { break; } default: { FATAL("%s", STR(header)); FATAL("buffer:\n%s", STR(buffer)); ASSERT("invalid message type"); } } channel.state = CS_PAYLOAD; switch (channel.lastInHeaderType) { case HT_FULL: { channel.lastInAbsTs = H_TS(header); break; } case HT_SAME_STREAM: case HT_SAME_LENGTH_AND_STREAM: { channel.lastInAbsTs += H_TS(header); break; } case HT_CONTINUATION: { if (channel.lastInProcBytes == 0) { channel.lastInAbsTs += H_TS(header); } break; } } } } if (channel.state == CS_PAYLOAD) { uint32_t tempSize = H_ML(header) - channel.lastInProcBytes; tempSize = (tempSize >= _inboundChunkSize) ? _inboundChunkSize : tempSize; uint32_t availableBytes = GETAVAILABLEBYTESCOUNT(buffer); if (tempSize > availableBytes) return true; channel.state = CS_HEADER; _selectedChannel = -1; switch (H_MT(header)) { case RM_HEADER_MESSAGETYPE_VIDEODATA: { if (H_SI(header) >= _maxStreamCount) { FATAL("Incorrect stream index"); return false; } //FINEST("Video data"); channel.lastInProcBytes += tempSize; if (H_ML(header) == channel.lastInProcBytes) { channel.lastInProcBytes = 0; } if (!buffer.Ignore(tempSize)) { FATAL("V: Unable to ignore %u bytes", tempSize); return false; } break; } case RM_HEADER_MESSAGETYPE_AUDIODATA: { if (H_SI(header) >= _maxStreamCount) { FATAL("Incorrect stream index"); return false; } //FINEST("Audio data"); channel.lastInProcBytes += tempSize; if (H_ML(header) == channel.lastInProcBytes) { channel.lastInProcBytes = 0; } if (!buffer.Ignore(tempSize)) { FATAL("A: Unable to ignore %u bytes", tempSize); return false; } break; } default: { channel.inputData.ReadFromInputBuffer(buffer, tempSize); channel.lastInProcBytes += tempSize; if (!buffer.Ignore(tempSize)) { FATAL("Unable to ignore %u bytes", tempSize); return false; } if (H_ML(header) == channel.lastInProcBytes) { channel.lastInProcBytes = 0; Variant msg; if (!_rtmpProtocolSerializer.Deserialize(header, channel.inputData, msg)) { FATAL("Unable to deserialize message"); return false; } if ((uint8_t) VH_MT(msg) == RM_HEADER_MESSAGETYPE_CHUNKSIZE) { _inboundChunkSize = (uint32_t) msg[RM_CHUNKSIZE]; } if ((uint8_t) VH_MT(msg) == RM_HEADER_MESSAGETYPE_ABORTMESSAGE) { uint32_t channelId = (uint32_t) msg[RM_ABORTMESSAGE]; if (channelId >= _maxChannelsCount) { FATAL("Invalid channel id in reset message: %" PRIu32, channelId); return false; } o_assert(_channels[channelId].id == channelId); _channels[channelId].Reset(); } if (GETAVAILABLEBYTESCOUNT(channel.inputData) != 0) { FATAL("Invalid message! We have leftovers: %u bytes", GETAVAILABLEBYTESCOUNT(channel.inputData)); return false; } } break; } } } } }