这里主要接着上一篇继续网络连接部分的讲解。主要包括函数SocksNegotiate()、RTMP_ReconnectStream()、RTMP_ConnectStream()、RTMP_ToggleStream()、RTMP_DeleteStream()、RTMP_GetNextMediaPacket()和RTMP_ClientPacket()
1、socket协议协商
static int
SocksNegotiate(RTMP *r)
{
unsigned long addr;
struct sockaddr_storage service;
socklen_t addrlen = 0;
int socket_error = 0;
memset(&service, 0, sizeof(service));
add_addr_info(&service, &addrlen, &r->Link.hostname, r->Link.port, 0, &socket_error);
// not doing IPv6 socks
if (service.ss_family == AF_INET6)
return FALSE;
addr = htonl((*(struct sockaddr_in *)&service).sin_addr.s_addr);
{
char packet[] =
{
4, 1, /* SOCKS 4, connect */
(r->Link.port >> 8) & 0xFF,
(r->Link.port) & 0xFF,
(char)(addr >> 24) & 0xFF, (char)(addr >> 16) & 0xFF,
(char)(addr >> 8) & 0xFF, (char)addr & 0xFF,
0
}; /* NULL terminate */
WriteN(r, packet, sizeof packet);
if (ReadN(r, packet, 8) != 8)
return FALSE;
if (packet[0] == 0 && packet[1] == 90)
{
return TRUE;
}
else
{
RTMP_Log(RTMP_LOGERROR, "%s, SOCKS returned error code %d", __FUNCTION__, packet[1]);
return FALSE;
}
}
}
2、连接rtmp流
int
RTMP_ConnectStream(RTMP *r, int seekTime)
{
RTMPPacket packet = { 0 };
/* seekTime was already set by SetupStream / SetupURL.
* This is only needed by ReconnectStream.
*/
if (seekTime > 0)
r->Link.seekTime = seekTime;
r->m_mediaChannel = 0;
while (!r->m_bPlaying && RTMP_IsConnected(r) && RTMP_ReadPacket(r, &packet))
{
if (RTMPPacket_IsReady(&packet))
{
if (!packet.m_nBodySize)
continue;
if ((packet.m_packetType == RTMP_PACKET_TYPE_AUDIO) ||
(packet.m_packetType == RTMP_PACKET_TYPE_VIDEO) ||
(packet.m_packetType == RTMP_PACKET_TYPE_INFO))
{
RTMP_Log(RTMP_LOGWARNING, "Received FLV packet before play()! Ignoring.");
RTMPPacket_Free(&packet);
continue;
}
RTMP_ClientPacket(r, &packet);
RTMPPacket_Free(&packet);
}
}
return r->m_bPlaying;
}
2、重连rtmp流操作
int
RTMP_ReconnectStream(RTMP *r, int seekTime, int streamIdx)
{
RTMP_DeleteStream(r, streamIdx);
RTMP_SendCreateStream(r);
return RTMP_ConnectStream(r, seekTime);
}
3、暂停rtmp流操作
int
RTMP_ToggleStream(RTMP *r)
{
int res;
if (!r->m_pausing)
{
if (RTMP_IsTimedout(r) && r->m_read.status == RTMP_READ_EOF)
r->m_read.status = 0;
res = RTMP_SendPause(r, TRUE, r->m_pauseStamp);
if (!res)
return res;
r->m_pausing = 1;
sleep(1);
}
res = RTMP_SendPause(r, FALSE, r->m_pauseStamp);
r->m_pausing = 3;
return res;
}
4、删除rtmp流操作
void
RTMP_DeleteStream(RTMP *r, int streamIdx)
{
if (r->m_stream_id < 0)
return;
r->m_bPlaying = FALSE;
if ((r->Link.protocol & RTMP_FEATURE_WRITE))
SendFCUnpublish(r, streamIdx);
SendDeleteStream(r, r->m_stream_id);
r->m_stream_id = -1;
}
5、获取下一个媒体包
int
RTMP_GetNextMediaPacket(RTMP *r, RTMPPacket *packet)
{
int bHasMediaPacket = 0;
while (!bHasMediaPacket && RTMP_IsConnected(r)
&& RTMP_ReadPacket(r, packet))
{
if (!RTMPPacket_IsReady(packet))
{
continue;
}
bHasMediaPacket = RTMP_ClientPacket(r, packet);
if (!bHasMediaPacket)
{
RTMPPacket_Free(packet);
}
else if (r->m_pausing == 3)
{
if (packet->m_nTimeStamp <= r->m_mediaStamp)
{
bHasMediaPacket = 0;
#ifdef _DEBUG
RTMP_Log(RTMP_LOGDEBUG,
"Skipped type: %02X, size: %d, TS: %d ms, abs TS: %d, pause: %d ms",
packet->m_packetType, packet->m_nBodySize,
packet->m_nTimeStamp, packet->m_hasAbsTimestamp,
r->m_mediaStamp);
#endif
RTMPPacket_Free(packet);
continue;
}
r->m_pausing = 0;
}
}
if (bHasMediaPacket)
r->m_bPlaying = TRUE;
else if (r->m_sb.sb_timedout && !r->m_pausing)
r->m_pauseStamp = r->m_mediaChannel < r->m_channelsAllocatedIn ?
r->m_channelTimestamp[r->m_mediaChannel] : 0;
return bHasMediaPacket;
}
6、处理rtmp客户端收到的包
int
RTMP_ClientPacket(RTMP *r, RTMPPacket *packet)
{
int bHasMediaPacket = 0;
switch (packet->m_packetType)
{
case RTMP_PACKET_TYPE_CHUNK_SIZE:
/* chunk size */
HandleChangeChunkSize(r, packet);
break;
case RTMP_PACKET_TYPE_BYTES_READ_REPORT:
/* bytes read report */
RTMP_Log(RTMP_LOGDEBUG, "%s, received: bytes read report", __FUNCTION__);
break;
case RTMP_PACKET_TYPE_CONTROL:
/* ctrl */
HandleCtrl(r, packet);
break;
case RTMP_PACKET_TYPE_SERVER_BW:
/* server bw */
HandleServerBW(r, packet);
break;
case RTMP_PACKET_TYPE_CLIENT_BW:
/* client bw */
HandleClientBW(r, packet);
break;
case RTMP_PACKET_TYPE_AUDIO:
/* audio data */
/*RTMP_Log(RTMP_LOGDEBUG, "%s, received: audio %lu bytes", __FUNCTION__, packet.m_nBodySize); */
HandleAudio(r, packet);
bHasMediaPacket = 1;
if (!r->m_mediaChannel)
r->m_mediaChannel = packet->m_nChannel;
if (!r->m_pausing)
r->m_mediaStamp = packet->m_nTimeStamp;
break;
case RTMP_PACKET_TYPE_VIDEO:
/* video data */
/*RTMP_Log(RTMP_LOGDEBUG, "%s, received: video %lu bytes", __FUNCTION__, packet.m_nBodySize); */
HandleVideo(r, packet);
bHasMediaPacket = 1;
if (!r->m_mediaChannel)
r->m_mediaChannel = packet->m_nChannel;
if (!r->m_pausing)
r->m_mediaStamp = packet->m_nTimeStamp;
break;
case RTMP_PACKET_TYPE_FLEX_STREAM_SEND:
/* flex stream send */
RTMP_Log(RTMP_LOGDEBUG,
"%s, flex stream send, size %u bytes, not supported, ignoring",
__FUNCTION__, packet->m_nBodySize);
break;
case RTMP_PACKET_TYPE_FLEX_SHARED_OBJECT:
/* flex shared object */
RTMP_Log(RTMP_LOGDEBUG,
"%s, flex shared object, size %u bytes, not supported, ignoring",
__FUNCTION__, packet->m_nBodySize);
break;
case RTMP_PACKET_TYPE_FLEX_MESSAGE:
/* flex message */
{
RTMP_Log(RTMP_LOGDEBUG,
"%s, flex message, size %u bytes, not fully supported",
__FUNCTION__, packet->m_nBodySize);
/*RTMP_LogHex(packet.m_body, packet.m_nBodySize); */
/* some DEBUG code */
#if 0
RTMP_LIB_AMFObject obj;
int nRes = obj.Decode(packet.m_body+1, packet.m_nBodySize-1);
if(nRes < 0)
{
RTMP_Log(RTMP_LOGERROR, "%s, error decoding AMF3 packet", __FUNCTION__);
/*return; */
}
obj.Dump();
#endif
if (HandleInvoke(r, packet->m_body + 1, packet->m_nBodySize - 1) == 1)
bHasMediaPacket = 2;
break;
}
case RTMP_PACKET_TYPE_INFO:
/* metadata (notify) */
RTMP_Log(RTMP_LOGDEBUG, "%s, received: notify %u bytes", __FUNCTION__,
packet->m_nBodySize);
if (HandleMetadata(r, packet->m_body, packet->m_nBodySize))
bHasMediaPacket = 1;
break;
case RTMP_PACKET_TYPE_SHARED_OBJECT:
RTMP_Log(RTMP_LOGDEBUG, "%s, shared object, not supported, ignoring",
__FUNCTION__);
break;
case RTMP_PACKET_TYPE_INVOKE:
/* invoke */
RTMP_Log(RTMP_LOGDEBUG, "%s, received: invoke %u bytes", __FUNCTION__,
packet->m_nBodySize);
/*RTMP_LogHex(packet.m_body, packet.m_nBodySize); */
if (HandleInvoke(r, packet->m_body, packet->m_nBodySize) == 1)
bHasMediaPacket = 2;
break;
case RTMP_PACKET_TYPE_FLASH_VIDEO:
{
/* go through FLV packets and handle metadata packets */
unsigned int pos = 0;
uint32_t nTimeStamp = packet->m_nTimeStamp;
while (pos + 11 < packet->m_nBodySize)
{
uint32_t dataSize = AMF_DecodeInt24(packet->m_body + pos + 1); /* size without header (11) and prevTagSize (4) */
if (pos + 11 + dataSize + 4 > packet->m_nBodySize)
{
RTMP_Log(RTMP_LOGWARNING, "Stream corrupt?!");
break;
}
if (packet->m_body[pos] == 0x12)
{
HandleMetadata(r, packet->m_body + pos + 11, dataSize);
}
else if (packet->m_body[pos] == 8 || packet->m_body[pos] == 9)
{
nTimeStamp = AMF_DecodeInt24(packet->m_body + pos + 4);
nTimeStamp |= (packet->m_body[pos + 7] << 24);
}
pos += (11 + dataSize + 4);
}
if (!r->m_pausing)
r->m_mediaStamp = nTimeStamp;
/* FLV tag(s) */
/*RTMP_Log(RTMP_LOGDEBUG, "%s, received: FLV tag(s) %lu bytes", __FUNCTION__, packet.m_nBodySize); */
bHasMediaPacket = 1;
break;
}
default:
RTMP_Log(RTMP_LOGDEBUG, "%s, unknown packet type received: 0x%02x", __FUNCTION__,
packet->m_packetType);
#ifdef _DEBUG
RTMP_LogHex(RTMP_LOGDEBUG, (const uint8_t*)packet->m_body, packet->m_nBodySize);
#endif
}
return bHasMediaPacket;
}