private async Task<bool> RecvMessage(Queue<RTMPMessage> messages, CancellationToken cancel_token)
{
var basic_header = (await RecvStream(1, cancel_token))[0];
var chunk_stream_id = basic_header & 0x3F;
if (chunk_stream_id==0) {
chunk_stream_id = (await RecvStream(1, cancel_token))[0] + 64;
}
else if (chunk_stream_id==1) {
var buf = await RecvStream(2, cancel_token);
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))) {
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))) {
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))) {
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))) {
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))) {
long timestamp_delta = reader.ReadUInt24();
if (timestamp_delta==0xFFFFFF) {
using (var ext_reader=new RTMPBinaryReader(await RecvStream(4, cancel_token))) {
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);
if (msg.ReceivedLength>=msg.BodyLength) {
messages.Enqueue(msg.ToMessage());
}
return true; //TODO:接続エラー時はfalseを返す
}