RTMPdump (libRTMP) 源代码分析4: 连接第一步——握手 (HandShake)
RTMPdump (libRTMP) 源代码分析7: 建立一个流媒体连接 (NetStream部分 2)
RTMPdump (libRTMP) 源代码分析10: 处理各种消息 (Message)
上回说到,有两个函数尤为重要:
- //处理接收到的Chunk
- int
- RTMP_ClientPacket(RTMP *r, RTMPPacket *packet)
- {
- int bHasMediaPacket = 0;
- switch (packet->m_packetType)
- {
- //RTMP消息类型ID=1,设置块大小
- case 0x01:
- /* chunk size */
- //----------------
- r->dlg->AppendCInfo("处理收到的数据。消息 Set Chunk Size (typeID=1)。");
- //-----------------------------
- RTMP_LogPrintf("处理消息 Set Chunk Size (typeID=1)\n");
- HandleChangeChunkSize(r, packet);
- break;
- //RTMP消息类型ID=3,致谢
- case 0x03:
- /* bytes read report */
- RTMP_Log(RTMP_LOGDEBUG, "%s, received: bytes read report", __FUNCTION__);
- break;
- //RTMP消息类型ID=4,用户控制
- case 0x04:
- /* ctrl */
- //----------------
- r->dlg->AppendCInfo("处理收到的数据。消息 User Control (typeID=4)。");
- //-----------------------------
- RTMP_LogPrintf("处理消息 User Control (typeID=4)\n");
- HandleCtrl(r, packet);
- break;
- //RTMP消息类型ID=5
- case 0x05:
- /* server bw */
- //----------------
- r->dlg->AppendCInfo("处理收到的数据。消息 Window Acknowledgement Size (typeID=5)。");
- //-----------------------------
- RTMP_LogPrintf("处理消息 Window Acknowledgement Size (typeID=5)\n");
- HandleServerBW(r, packet);
- break;
- //RTMP消息类型ID=6
- case 0x06:
- /* client bw */
- //----------------
- r->dlg->AppendCInfo("处理收到的数据。消息 Set Peer Bandwidth (typeID=6)。");
- //-----------------------------
- RTMP_LogPrintf("处理消息 Set Peer Bandwidth (typeID=6)\n");
- HandleClientBW(r, packet);
- break;
- //RTMP消息类型ID=8,音频数据
- case 0x08:
- /* 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;
- //RTMP消息类型ID=9,视频数据
- case 0x09:
- /* 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;
- //RTMP消息类型ID=15,AMF3编码,忽略
- case 0x0F: /* flex stream send */
- RTMP_Log(RTMP_LOGDEBUG,
- "%s, flex stream send, size %lu bytes, not supported, ignoring",
- __FUNCTION__, packet->m_nBodySize);
- break;
- //RTMP消息类型ID=16,AMF3编码,忽略
- case 0x10: /* flex shared object */
- RTMP_Log(RTMP_LOGDEBUG,
- "%s, flex shared object, size %lu bytes, not supported, ignoring",
- __FUNCTION__, packet->m_nBodySize);
- break;
- //RTMP消息类型ID=17,AMF3编码,忽略
- case 0x11: /* flex message */
- {
- RTMP_Log(RTMP_LOGDEBUG,
- "%s, flex message, size %lu 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;
- }
- //RTMP消息类型ID=18,AMF0编码,数据消息
- case 0x12:
- /* metadata (notify) */
- RTMP_Log(RTMP_LOGDEBUG, "%s, received: notify %lu bytes", __FUNCTION__,
- packet->m_nBodySize);
- //处理元数据,暂时注释
- /*
- if (HandleMetadata(r, packet->m_body, packet->m_nBodySize))
- bHasMediaPacket = 1;
- break;
- */
- //RTMP消息类型ID=19,AMF0编码,忽略
- case 0x13:
- RTMP_Log(RTMP_LOGDEBUG, "%s, shared object, not supported, ignoring",
- __FUNCTION__);
- break;
- //RTMP消息类型ID=20,AMF0编码,命令消息
- //处理命令消息!
- case 0x14:
- //----------------
- r->dlg->AppendCInfo("处理收到的数据。消息 命令 (AMF0编码) (typeID=20)。");
- //-----------------------------
- /* invoke */
- RTMP_Log(RTMP_LOGDEBUG, "%s, received: invoke %lu bytes", __FUNCTION__,
- packet->m_nBodySize);
- RTMP_LogPrintf("处理命令消息 (typeID=20,AMF0编码)\n");
- /*RTMP_LogHex(packet.m_body, packet.m_nBodySize); */
- if (HandleInvoke(r, packet->m_body, packet->m_nBodySize) == 1)
- bHasMediaPacket = 2;
- break;
- //RTMP消息类型ID=22
- case 0x16:
- {
- /* 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;
- }
可以发现它调用了HandleInvoke()函数来处理服务器发来的AMF0编码的命令,来看看细节:
2.调用AMFProp_GetString()获取具体命令的字符串
- AVMATCH(&methodInvoked, &av_connect)
- AVMATCH(&methodInvoked, &av_createStream)
- AVMATCH(&methodInvoked, &av_play)
- AVMATCH(&methodInvoked, &av_publish)
- AVMATCH(&method, &av_onBWDone)
等等,不一一例举了
- else if (AVMATCH(&methodInvoked, &av_createStream))
- {
- //----------------
- r->dlg->AppendMLInfo(20,0,"命令消息","Result (CreateStream)");
- //-----------------------------
- r->m_stream_id = (int)AMFProp_GetNumber(AMF_GetProp(&obj, NULL, 3));
- if (r->Link.protocol & RTMP_FEATURE_WRITE)
- {
- SendPublish(r);
- }
- else
- {
- if (r->Link.lFlags & RTMP_LF_PLST)
- SendPlaylist(r);
- //----------------
- r->dlg->AppendCInfo("发送数据。消息 命令 (typeID=20) (Play)。");
- //-----------------------------
- RTMP_LogPrintf("发送命令消息“play” (typeID=20)\n");
- SendPlay(r);
- RTMP_SendCtrl(r, 3, r->m_stream_id, r->m_nBufferMS);
- }
- }