| 1327 | } |
| 1328 | |
| 1329 | ParseResult RtmpContext::OnChunks(butil::IOBuf* source, Socket* socket) { |
| 1330 | // Parse basic header. |
| 1331 | const char* p = (const char*)source->fetch1(); |
| 1332 | if (NULL == p) { |
| 1333 | return MakeParseError(PARSE_ERROR_NOT_ENOUGH_DATA); |
| 1334 | } |
| 1335 | const uint8_t first_byte = *p; |
| 1336 | // 2 bits, deciding type of following chunk message header. |
| 1337 | const RtmpChunkType fmt = (RtmpChunkType)(first_byte >> 6); |
| 1338 | // cs_id is short for "chunk stream id" |
| 1339 | uint32_t cs_id = (first_byte & 0x3F); |
| 1340 | uint8_t basic_header_len = 1u; |
| 1341 | if (cs_id == 0) { // 2-byte basic header |
| 1342 | if (source->size() < 2u) { |
| 1343 | return MakeParseError(PARSE_ERROR_NOT_ENOUGH_DATA); |
| 1344 | } |
| 1345 | char basic_header_buf[2]; |
| 1346 | const uint8_t* p = (const uint8_t*)source->fetch(basic_header_buf, 2); |
| 1347 | cs_id = ((uint32_t)p[1]) + 64; |
| 1348 | basic_header_len = 2u; |
| 1349 | } else if (cs_id == 1) { // 3-byte basic header |
| 1350 | if (source->size() < 3u) { |
| 1351 | return MakeParseError(PARSE_ERROR_NOT_ENOUGH_DATA); |
| 1352 | } |
| 1353 | char basic_header_buf[3]; |
| 1354 | const uint8_t* p = (const uint8_t*)source->fetch(basic_header_buf, 3); |
| 1355 | cs_id = ((uint32_t)p[2]) * 256 + ((uint32_t)p[1]) + 64; |
| 1356 | basic_header_len = 3u; |
| 1357 | } // else 1-byte basic header, keep cs_id as it is. |
| 1358 | RtmpBasicHeader bh = { cs_id, fmt, basic_header_len }; |
| 1359 | RtmpChunkStream* cstream = GetChunkStream(cs_id); |
| 1360 | if (cstream == NULL) { |
| 1361 | LOG(ERROR) << "Invalid chunk_stream_id=" << cs_id; |
| 1362 | return MakeParseError(PARSE_ERROR_NO_RESOURCE); |
| 1363 | } |
| 1364 | return cstream->Feed(bh, source, socket); |
| 1365 | } |
| 1366 | |
| 1367 | static int SendAck(Socket* socket, uint64_t received_bytes) { |
| 1368 | const uint32_t data = butil::HostToNet32(received_bytes); |
nothing calls this directly
no test coverage detected