protected void PostMessage(int chunk_stream_id, RTMPMessage msg)
 {
     messageQueue.Enqueue(new QueuedMessage(QueuedMessage.MessageDirection.Out, chunk_stream_id, msg));
 }
        private async Task <bool> RecvMessage(MessageQueue <QueuedMessage> messages, CancellationToken cancel_token)
        {
            var basic_header    = (await RecvStream(1, cancel_token).ConfigureAwait(false))[0];
            var chunk_stream_id = basic_header & 0x3F;

            if (chunk_stream_id == 0)
            {
                chunk_stream_id = (await RecvStream(1, cancel_token).ConfigureAwait(false))[0] + 64;
            }
            else if (chunk_stream_id == 1)
            {
                var buf = await RecvStream(2, cancel_token).ConfigureAwait(false);

                chunk_stream_id = (buf[1] * 256 | buf[0]) + 64;
            }

            RTMPMessageBuilder msg      = null;
            RTMPMessageBuilder last_msg = null;

            if (!lastMessages.TryGetValue(chunk_stream_id, out last_msg))
            {
                last_msg = RTMPMessageBuilder.NullPacket;
            }
            switch ((basic_header & 0xC0) >> 6)
            {
            case 0:
                using (var reader = new RTMPBinaryReader(await RecvStream(11, cancel_token).ConfigureAwait(false))) {
                    long timestamp   = reader.ReadUInt24();
                    var  body_length = reader.ReadUInt24();
                    var  type_id     = reader.ReadByte();
                    var  stream_id   = reader.ReadUInt32LE();
                    if (timestamp == 0xFFFFFF)
                    {
                        using (var ext_reader = new RTMPBinaryReader(await RecvStream(4, cancel_token).ConfigureAwait(false))) {
                            timestamp = ext_reader.ReadUInt32();
                        }
                    }
                    msg = new RTMPMessageBuilder(
                        last_msg,
                        timestamp,
                        type_id,
                        stream_id,
                        body_length);
                    lastMessages[chunk_stream_id] = msg;
                }
                break;

            case 1:
                using (var reader = new RTMPBinaryReader(await RecvStream(7, cancel_token).ConfigureAwait(false))) {
                    long timestamp_delta = reader.ReadUInt24();
                    var  body_length     = reader.ReadUInt24();
                    var  type_id         = reader.ReadByte();
                    if (timestamp_delta == 0xFFFFFF)
                    {
                        using (var ext_reader = new RTMPBinaryReader(await RecvStream(4, cancel_token).ConfigureAwait(false))) {
                            timestamp_delta = ext_reader.ReadUInt32();
                        }
                    }
                    msg = new RTMPMessageBuilder(
                        last_msg,
                        timestamp_delta,
                        type_id,
                        body_length);
                    lastMessages[chunk_stream_id] = msg;
                }
                break;

            case 2:
                using (var reader = new RTMPBinaryReader(await RecvStream(3, cancel_token).ConfigureAwait(false))) {
                    long timestamp_delta = reader.ReadUInt24();
                    if (timestamp_delta == 0xFFFFFF)
                    {
                        using (var ext_reader = new RTMPBinaryReader(await RecvStream(4, cancel_token).ConfigureAwait(false))) {
                            timestamp_delta = ext_reader.ReadUInt32();
                        }
                    }
                    msg = new RTMPMessageBuilder(last_msg, timestamp_delta);
                    lastMessages[chunk_stream_id] = msg;
                }
                break;

            case 3:
                msg = last_msg;
                if (msg.ReceivedLength >= msg.BodyLength)
                {
                    msg = new RTMPMessageBuilder(last_msg);
                    lastMessages[chunk_stream_id] = msg;
                }
                break;
            }

            msg.ReceivedLength += await RecvStream(
                msg.Body,
                msg.ReceivedLength,
                Math.Min(recvChunkSize, msg.BodyLength - msg.ReceivedLength),
                cancel_token).ConfigureAwait(false);

            if (msg.ReceivedLength >= msg.BodyLength)
            {
                messages.Enqueue(new QueuedMessage(QueuedMessage.MessageDirection.In, chunk_stream_id, msg.ToMessage()));
            }
            return(true); //TODO:接続エラー時はfalseを返す
        }