static int SendConnectResult(RTMP *r, double txn) { RTMPPacket packet; char pbuf[384], *pend = pbuf+sizeof(pbuf); AMFObject obj; AMFObjectProperty p, op; AVal av; packet.m_nChannel = 0x03; // control channel (invoke) packet.m_headerType = 1; /* RTMP_PACKET_SIZE_MEDIUM; */ packet.m_packetType = RTMP_PACKET_TYPE_INVOKE; packet.m_nTimeStamp = 0; packet.m_nInfoField2 = 0; packet.m_hasAbsTimestamp = 0; packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE; char *enc = packet.m_body; enc = AMF_EncodeString(enc, pend, &av__result); enc = AMF_EncodeNumber(enc, pend, txn); *enc++ = AMF_OBJECT; STR2AVAL(av, "FMS/3,5,1,525"); enc = AMF_EncodeNamedString(enc, pend, &av_fmsVer, &av); enc = AMF_EncodeNamedNumber(enc, pend, &av_capabilities, 31.0); enc = AMF_EncodeNamedNumber(enc, pend, &av_mode, 1.0); *enc++ = 0; *enc++ = 0; *enc++ = AMF_OBJECT_END; *enc++ = AMF_OBJECT; STR2AVAL(av, "status"); enc = AMF_EncodeNamedString(enc, pend, &av_level, &av); STR2AVAL(av, "NetConnection.Connect.Success"); enc = AMF_EncodeNamedString(enc, pend, &av_code, &av); STR2AVAL(av, "Connection succeeded."); enc = AMF_EncodeNamedString(enc, pend, &av_description, &av); enc = AMF_EncodeNamedNumber(enc, pend, &av_objectEncoding, r->m_fEncoding); #if 0 STR2AVAL(av, "58656322c972d6cdf2d776167575045f8484ea888e31c086f7b5ffbd0baec55ce442c2fb"); enc = AMF_EncodeNamedString(enc, pend, &av_secureToken, &av); #endif STR2AVAL(p.p_name, "version"); STR2AVAL(p.p_vu.p_aval, "3,5,1,525"); p.p_type = AMF_STRING; obj.o_num = 1; obj.o_props = &p; op.p_type = AMF_OBJECT; STR2AVAL(op.p_name, "data"); op.p_vu.p_object = obj; enc = AMFProp_Encode(&op, enc, pend); *enc++ = 0; *enc++ = 0; *enc++ = AMF_OBJECT_END; packet.m_nBodySize = enc - packet.m_body; return RTMP_SendPacket(r, &packet, FALSE); }
int SendPlayStop(RTMP *r) { RTMPPacket packet; char pbuf[512], *pend = pbuf+sizeof(pbuf); packet.m_nChannel = 0x03; // control channel (invoke) packet.m_headerType = RTMP_PACKET_SIZE_MEDIUM; packet.m_packetType = RTMP_PACKET_TYPE_INVOKE; packet.m_nTimeStamp = 0; packet.m_nInfoField2 = 0; packet.m_hasAbsTimestamp = 0; packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE; char *enc = packet.m_body; enc = AMF_EncodeString(enc, pend, &av_onStatus); enc = AMF_EncodeNumber(enc, pend, 0); *enc++ = AMF_NULL; *enc++ = AMF_OBJECT; enc = AMF_EncodeNamedString(enc, pend, &av_level, &av_status); enc = AMF_EncodeNamedString(enc, pend, &av_code, &av_NetStream_Play_Stop); enc = AMF_EncodeNamedString(enc, pend, &av_description, &av_Stopped_playing); enc = AMF_EncodeNamedString(enc, pend, &av_details, &r->Link.playpath); enc = AMF_EncodeNamedString(enc, pend, &av_clientid, &av_clientid); *enc++ = 0; *enc++ = 0; *enc++ = AMF_OBJECT_END; packet.m_nBodySize = enc - packet.m_body; return RTMP_SendPacket(r, &packet, FALSE); }
int CRtmpdSession::SendPacketBin( int format, int csi, int type, int ext, sqbind::CSqBinary *b, int nQueue ) { // Sanity checks if ( !b ) return 0; // Must have a session if ( !m_session.m_sb.sb_socket ) return 0; // Initialize packet oexZero( m_packet ); // Initialize packet headers m_packet.m_nChannel = csi; m_packet.m_headerType = format; m_packet.m_packetType = type; m_packet.m_nInfoField2 = ext; /* // Audio if ( 8 == type ) m_packet.m_nTimeStamp = m_nTs++; // Video else if ( 9 == type ) m_packet.m_nTimeStamp = m_nTs; else */ m_packet.m_nTimeStamp = 0; // Timestamps? m_packet.m_hasAbsTimestamp = ( 0 < m_nTs ) ? 1 : 0; sqbind::CSqBinary body; if ( !body.Allocate( RTMP_MAX_HEADER_SIZE + b->getUsed() + 128 ) ) return 0; // Add padding byte for AMF3 if ( 0x11 == type ) body.setUsed( RTMP_MAX_HEADER_SIZE + 1 ), body.setUCHAR( RTMP_MAX_HEADER_SIZE, 0 ); else body.setUsed( RTMP_MAX_HEADER_SIZE ); // Append data body.Append( b ); // Point the packet at the encoded variables m_packet.m_body = (char*)body.Ptr( RTMP_MAX_HEADER_SIZE ); // Set body size m_packet.m_nBodySize = body.getUsed() - RTMP_MAX_HEADER_SIZE; // Send the packet return RTMP_SendPacket( &m_session, &m_packet, nQueue ); }
int ExecuteAuthenticationDetails(RTMP *r, AMFObject *proplist, YLENGStream *yle) { long authResult = -1; int i; for (i=0; i<AMF_CountProp(proplist); i++) { AVal name; AMFObjectProperty *prop = AMF_GetProp(proplist, NULL, i); AMFProp_GetName(prop, &name); if (AVMATCH(&name, &av_locatedInBroadcastTerritory)) { yle->locatedInBroadcastTerritory = AMFProp_GetBoolean(prop); } else if (AVMATCH(&name, &av_randomAuth)) { authResult = ((long)AMFProp_GetNumber(prop) + 447537687) % 6834253; } else if (AVMATCH(&name, &av_tvFeeActivated)) { yle->tvFeeActivated = AMFProp_GetBoolean(prop); } } if (authResult != -1) { RTMPPacket packet; char pbuf[128], *pend = pbuf+sizeof(pbuf); packet.m_nChannel = 0x03; // control channel packet.m_headerType = RTMP_PACKET_SIZE_LARGE; packet.m_packetType = 0x11; // FLEX MESSAGE packet.m_nTimeStamp = RTMP_GetTime(); packet.m_nInfoField2 = 0; packet.m_hasAbsTimestamp = 0; packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE; char *enc = packet.m_body; *enc++ = 0x00; // Unknown enc = AMF_EncodeString(enc, pend, &av_authenticateRandomNumber); enc = AMF_EncodeNumber(enc, pend, 0); *enc++ = AMF_NULL; enc = AMF_EncodeNumber(enc, pend, (double)authResult); packet.m_nBodySize = enc-packet.m_body; RTMP_Log(RTMP_LOGDEBUG, "sending authenticateRandomNumber"); return RTMP_SendPacket(r, &packet, FALSE); } return FALSE; }
int RequestData(RTMP *r, YLENGStream *yle) { RTMPPacket packet; char pbuf[128], *pend = pbuf+sizeof(pbuf); AVal clipID; packet.m_nChannel = 0x03; // control channel packet.m_headerType = RTMP_PACKET_SIZE_LARGE; packet.m_packetType = 0x11; // FLEX MESSAGE packet.m_nTimeStamp = RTMP_GetTime(); packet.m_nInfoField2 = 0; packet.m_hasAbsTimestamp = 0; packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE; char *enc = packet.m_body; *enc++ = 0x00; // Unknown enc = AMF_EncodeString(enc, pend, &av_requestData); enc = AMF_EncodeNumber(enc, pend, 0); *enc++ = AMF_NULL; enc = AMF_EncodeString(enc, pend, &av_e0); if ((r->Link.lFlags & RTMP_LF_LIVE) != 0) { char *tmp = malloc(yle->clipID.av_len+12); strcpy(tmp, "streams/fi/"); strncat(tmp, yle->clipID.av_val, yle->clipID.av_len); STR2AVAL(clipID, tmp); enc = AMF_EncodeString(enc, pend, &clipID); free(tmp); } else { char *tmp = malloc(yle->clipID.av_len+2); strcpy(tmp, "/"); strncat(tmp, yle->clipID.av_val, yle->clipID.av_len); STR2AVAL(clipID, tmp); enc = AMF_EncodeString(enc, pend, &clipID); free(tmp); } if (!enc) { RTMP_Log(RTMP_LOGERROR, "Buffer too short in RequestData"); return FALSE; } packet.m_nBodySize = enc-packet.m_body; return RTMP_SendPacket(r, &packet, FALSE); }
void LibRtmp::SendSetChunkSize(unsigned int chunkSize) { RTMPPacket rtmp_pakt; RTMPPacket_Reset(&rtmp_pakt); RTMPPacket_Alloc(&rtmp_pakt, 4); rtmp_pakt.m_packetType = 0x01; rtmp_pakt.m_nChannel = 0x02; // control channel rtmp_pakt.m_headerType = RTMP_PACKET_SIZE_LARGE; rtmp_pakt.m_nInfoField2 = 0; rtmp_pakt.m_nBodySize = 4; UI32ToBytes(rtmp_pakt.m_body, chunkSize); RTMP_SendPacket(rtmp_, &rtmp_pakt, 0); RTMPPacket_Free(&rtmp_pakt); }
bool LibRtmp::Send(const char* buf, int bufLen, int type, unsigned int timestamp) { RTMPPacket rtmp_pakt; RTMPPacket_Reset(&rtmp_pakt); RTMPPacket_Alloc(&rtmp_pakt, bufLen); rtmp_pakt.m_packetType = type; rtmp_pakt.m_nBodySize = bufLen; rtmp_pakt.m_nTimeStamp = timestamp; rtmp_pakt.m_nChannel = 4; rtmp_pakt.m_headerType = RTMP_PACKET_SIZE_LARGE; rtmp_pakt.m_nInfoField2 = rtmp_->m_stream_id; memcpy(rtmp_pakt.m_body, buf, bufLen); int retval = RTMP_SendPacket(rtmp_, &rtmp_pakt, 0); RTMPPacket_Free(&rtmp_pakt); return !!retval; }
int SendResultNumber(RTMP *r, double txn, double ID) { RTMPPacket packet; char pbuf[256], *pend = pbuf+sizeof(pbuf); packet.m_nChannel = 0x03; // control channel (invoke) packet.m_headerType = RTMP_PACKET_SIZE_MEDIUM; packet.m_packetType = RTMP_PACKET_TYPE_INVOKE; packet.m_nTimeStamp = 0; packet.m_nInfoField2 = 0; packet.m_hasAbsTimestamp = 0; packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE; char *enc = packet.m_body; enc = AMF_EncodeString(enc, pend, &av__result); enc = AMF_EncodeNumber(enc, pend, txn); *enc++ = AMF_NULL; enc = AMF_EncodeNumber(enc, pend, ID); packet.m_nBodySize = enc - packet.m_body; return RTMP_SendPacket(r, &packet, FALSE); }
int CRtmpdSession::SendPacket2( int format, int csi, int type, int ext, sqbind::CSqMulti *m, int nQueue ) { // Sanity checks if ( !m || !m->size() ) return 0; // Must have a session if ( !m_session.m_sb.sb_socket ) return 0; // Initialize packet oexZero( m_packet ); // Initialize packet headers m_packet.m_nChannel = csi; m_packet.m_headerType = format; m_packet.m_packetType = type; m_packet.m_nInfoField2 = ext; /* // Audio if ( 8 == type ) m_packet.m_nTimeStamp = m_nTs++; // Video else if ( 9 == type ) m_packet.m_nTimeStamp = m_nTs; else */ m_packet.m_nTimeStamp = 0; // Timestamps? m_packet.m_hasAbsTimestamp = ( 0 < m_nTs ) ? 1 : 0; sqbind::CSqBinary body; if ( !body.Allocate( RTMP_MAX_HEADER_SIZE + 1024 ) ) return 0; // Apparently, somewhere, RTMP_SendPacket() reaches backward // in the buffer, and apparently, it's by design. // I'm not sure how to feel about that ... // Add padding byte for AMF3 if ( 0x11 == type ) body.setUsed( RTMP_MAX_HEADER_SIZE + 1 ), body.setUCHAR( RTMP_MAX_HEADER_SIZE, 0 ); else body.setUsed( RTMP_MAX_HEADER_SIZE ); // Is it a raw buffer? if ( m->isset( "body" ) ) body.appendString( (*m)[ "body" ].str() ); // Serialize our data else if ( !SerializePacket( &body, m, 0 ) ) return 0; // Point the packet at the encoded variables m_packet.m_body = (char*)body.Ptr( RTMP_MAX_HEADER_SIZE ); // Set body size m_packet.m_nBodySize = body.getUsed() - RTMP_MAX_HEADER_SIZE; // Send the packet return RTMP_SendPacket( &m_session, &m_packet, nQueue ); }
void RTMPPublisher::BeginPublishingInternal() { RTMPPacket packet; char pbuf[2048], *pend = pbuf+sizeof(pbuf); packet.m_nChannel = 0x03; // control channel (invoke) packet.m_headerType = RTMP_PACKET_SIZE_LARGE; packet.m_packetType = RTMP_PACKET_TYPE_INFO; packet.m_nTimeStamp = 0; packet.m_nInfoField2 = rtmp->m_stream_id; packet.m_hasAbsTimestamp = TRUE; packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE; char *enc = packet.m_body; enc = AMF_EncodeString(enc, pend, &av_setDataFrame); enc = AMF_EncodeString(enc, pend, &av_onMetaData); enc = App->EncMetaData(enc, pend); packet.m_nBodySize = enc - packet.m_body; if(!RTMP_SendPacket(rtmp, &packet, FALSE)) { App->PostStopMessage(); return; } //---------------------------------------------- List<BYTE> packetPadding; DataPacket mediaHeaders; //---------------------------------------------- packet.m_nChannel = 0x05; // source channel packet.m_packetType = RTMP_PACKET_TYPE_AUDIO; App->GetAudioHeaders(mediaHeaders); packetPadding.SetSize(RTMP_MAX_HEADER_SIZE); packetPadding.AppendArray(mediaHeaders.lpPacket, mediaHeaders.size); packet.m_body = (char*)packetPadding.Array()+RTMP_MAX_HEADER_SIZE; packet.m_nBodySize = mediaHeaders.size; if(!RTMP_SendPacket(rtmp, &packet, FALSE)) { App->PostStopMessage(); return; } //---------------------------------------------- packet.m_nChannel = 0x04; // source channel packet.m_headerType = RTMP_PACKET_SIZE_LARGE; packet.m_packetType = RTMP_PACKET_TYPE_VIDEO; App->GetVideoHeaders(mediaHeaders); packetPadding.SetSize(RTMP_MAX_HEADER_SIZE); packetPadding.AppendArray(mediaHeaders.lpPacket, mediaHeaders.size); packet.m_body = (char*)packetPadding.Array()+RTMP_MAX_HEADER_SIZE; packet.m_nBodySize = mediaHeaders.size; if(!RTMP_SendPacket(rtmp, &packet, FALSE)) { App->PostStopMessage(); return; } }
void RTMPPublisher::SendLoop() { SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_ABOVE_NORMAL); while(WaitForSingleObject(hSendSempahore, INFINITE) == WAIT_OBJECT_0) { while(true) { OSEnterMutex(hDataMutex); if(queuedPackets.Num() == 0) { OSLeaveMutex(hDataMutex); break; } List<BYTE> packetData; PacketType type = queuedPackets[0].type; DWORD timestamp = queuedPackets[0].timestamp; packetData.TransferFrom(queuedPackets[0].data); currentBufferSize -= packetData.Num(); queuedPackets.Remove(0); OSLeaveMutex(hDataMutex); //-------------------------------------------- RTMPPacket packet; packet.m_nChannel = (type == PacketType_Audio) ? 0x5 : 0x4; packet.m_headerType = RTMP_PACKET_SIZE_MEDIUM; packet.m_packetType = (type == PacketType_Audio) ? RTMP_PACKET_TYPE_AUDIO : RTMP_PACKET_TYPE_VIDEO; packet.m_nTimeStamp = timestamp; packet.m_nInfoField2 = rtmp->m_stream_id; packet.m_hasAbsTimestamp = TRUE; packet.m_nBodySize = packetData.Num()-RTMP_MAX_HEADER_SIZE; packet.m_body = (char*)packetData.Array()+RTMP_MAX_HEADER_SIZE; //QWORD sendTimeStart = OSGetTimeMicroseconds(); if(!RTMP_SendPacket(rtmp, &packet, FALSE)) { //should never reach here with the new shutdown sequence. RUNONCE Log(TEXT("RTMP_SendPacket failure, should not happen!")); if(!RTMP_IsConnected(rtmp)) { App->PostStopMessage(); break; } } //---------------------------------------------------------- /*outputRateSize += packetData.Num(); packetSizeRecord << PacketTimeSize(timestamp, packetData.Num()); if(packetSizeRecord.Num()) { UINT packetID=0; for(; packetID<packetSizeRecord.Num(); packetID++) { if(timestamp-packetSizeRecord[packetID].timestamp < outputRateWindowTime) break; else outputRateSize -= packetSizeRecord[packetID].size; } if(packetID != 0) packetSizeRecord.RemoveRange(0, packetID); }*/ //bytesSent += packetData.Num(); } if (bStopping && WaitForSingleObject(hSendLoopExit, 0) == WAIT_OBJECT_0) return; } }
//Publish using RTMP_SendPacket() int publish_using_packet(){ RTMP *rtmp=NULL; RTMPPacket *packet=NULL; uint32_t start_time=0; uint32_t now_time=0; //the timestamp of the previous frame long pre_frame_time=0; long lasttime=0; int bNextIsKey=1; uint32_t preTagsize=0; //packet attributes uint32_t type=0; uint32_t datalength=0; uint32_t timestamp=0; uint32_t streamid=0; FILE*fp=NULL; fp=fopen("../live.flv","rb"); if (!fp){ RTMP_LogPrintf("Open File Error.\n"); // CleanupSockets(); return -1; } /* set log level */ //RTMP_LogLevel loglvl=RTMP_LOGDEBUG; //RTMP_LogSetLevel(loglvl); // if (!InitSockets()){ // RTMP_LogPrintf("Init Socket Err\n"); // return -1; // } rtmp=RTMP_Alloc(); RTMP_Init(rtmp); //set connection timeout,default 30s rtmp->Link.timeout=5; if(!RTMP_SetupURL(rtmp,"rtmp://101.251.251.93:1935/myapp/mystream")) { RTMP_Log(RTMP_LOGERROR,"SetupURL Err\n"); RTMP_Free(rtmp); // CleanupSockets(); return -1; } //if unable,the AMF command would be 'play' instead of 'publish' RTMP_EnableWrite(rtmp); if (!RTMP_Connect(rtmp,NULL)){ RTMP_Log(RTMP_LOGERROR,"Connect Err\n"); RTMP_Free(rtmp); // CleanupSockets(); return -1; } if (!RTMP_ConnectStream(rtmp,0)){ RTMP_Log(RTMP_LOGERROR,"ConnectStream Err\n"); RTMP_Close(rtmp); RTMP_Free(rtmp); // CleanupSockets(); return -1; } packet=(RTMPPacket*)malloc(sizeof(RTMPPacket)); RTMPPacket_Alloc(packet,1024*64); RTMPPacket_Reset(packet); packet->m_hasAbsTimestamp = 0; packet->m_nChannel = 0x04; packet->m_nInfoField2 = rtmp->m_stream_id; RTMP_LogPrintf("Start to send data ...\n"); //jump over FLV Header fseek(fp,9,SEEK_SET); //jump over previousTagSizen fseek(fp,4,SEEK_CUR); start_time=RTMP_GetTime(); while(1) { if((((now_time=RTMP_GetTime())-start_time) <(pre_frame_time)) && bNextIsKey){ //wait for 1 sec if the send process is too fast //this mechanism is not very good,need some improvement if(pre_frame_time>lasttime){ RTMP_LogPrintf("TimeStamp:%8lu ms\n",pre_frame_time); lasttime=pre_frame_time; } sleep(1); continue; } //not quite the same as FLV spec if(!ReadU8(&type,fp)) break; if(!ReadU24(&datalength,fp)) break; if(!ReadTime(×tamp,fp)) break; if(!ReadU24(&streamid,fp)) break; if (type!=0x08&&type!=0x09){ //jump over non_audio and non_video frame, //jump over next previousTagSizen at the same time fseek(fp,datalength+4,SEEK_CUR); continue; } if(fread(packet->m_body,1,datalength,fp)!=datalength) break; packet->m_headerType = RTMP_PACKET_SIZE_LARGE; packet->m_nTimeStamp = timestamp; packet->m_packetType = type; packet->m_nBodySize = datalength; pre_frame_time=timestamp; if (!RTMP_IsConnected(rtmp)){ RTMP_Log(RTMP_LOGERROR,"rtmp is not connect\n"); break; } if (!RTMP_SendPacket(rtmp,packet,0)){ RTMP_Log(RTMP_LOGERROR,"Send Error\n"); break; } if(!ReadU32(&preTagsize,fp)) break; if(!PeekU8(&type,fp)) break; if(type==0x09){ if(fseek(fp,11,SEEK_CUR)!=0) break; if(!PeekU8(&type,fp)){ break; } if(type==0x17) bNextIsKey=1; else bNextIsKey=0; fseek(fp,-11,SEEK_CUR); } } RTMP_LogPrintf("\nSend Data Over\n"); if(fp) fclose(fp); if (rtmp!=NULL){ RTMP_Close(rtmp); RTMP_Free(rtmp); rtmp=NULL; } if (packet!=NULL){ RTMPPacket_Free(packet); free(packet); packet=NULL; } // CleanupSockets(); return 0; }
void RTMPPublisher::SendLoop() { SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_ABOVE_NORMAL); while(WaitForSingleObject(hSendSempahore, INFINITE) == WAIT_OBJECT_0) { /*//-------------------------------------------- // read DWORD pendingBytes = 0; ioctlsocket(rtmp->m_sb.sb_socket, FIONREAD, &pendingBytes); if(pendingBytes) { RTMPPacket packet; zero(&packet, sizeof(packet)); while(RTMP_ReadPacket(rtmp, &packet) && !RTMPPacket_IsReady(&packet) && RTMP_IsConnected(rtmp)); if(!RTMP_IsConnected(rtmp)) { App->PostStopMessage(); bStopping = true; break; } RTMPPacket_Free(&packet); }*/ //-------------------------------------------- // send while(true) { if(bStopping) return; OSEnterMutex(hDataMutex); if(queuedPackets.Num() == 0) { OSLeaveMutex(hDataMutex); break; } List<BYTE> packetData; PacketType type = queuedPackets[0].type; DWORD timestamp = queuedPackets[0].timestamp; packetData.TransferFrom(queuedPackets[0].data); currentBufferSize -= packetData.Num(); queuedPackets.Remove(0); OSLeaveMutex(hDataMutex); //-------------------------------------------- RTMPPacket packet; packet.m_nChannel = (type == PacketType_Audio) ? 0x5 : 0x4; packet.m_headerType = RTMP_PACKET_SIZE_MEDIUM; packet.m_packetType = (type == PacketType_Audio) ? RTMP_PACKET_TYPE_AUDIO : RTMP_PACKET_TYPE_VIDEO; packet.m_nTimeStamp = timestamp; packet.m_nInfoField2 = rtmp->m_stream_id; packet.m_hasAbsTimestamp = TRUE; packet.m_nBodySize = packetData.Num()-RTMP_MAX_HEADER_SIZE; packet.m_body = (char*)packetData.Array()+RTMP_MAX_HEADER_SIZE; //QWORD sendTimeStart = OSGetTimeMicroseconds(); if(!RTMP_SendPacket(rtmp, &packet, FALSE)) { if(!RTMP_IsConnected(rtmp)) { App->PostStopMessage(); bStopping = true; break; } RUNONCE Log(TEXT("okay, this is strange")); } //---------------------------------------------------------- /*outputRateSize += packetData.Num(); packetSizeRecord << PacketTimeSize(timestamp, packetData.Num()); if(packetSizeRecord.Num()) { UINT packetID=0; for(; packetID<packetSizeRecord.Num(); packetID++) { if(timestamp-packetSizeRecord[packetID].timestamp < outputRateWindowTime) break; else outputRateSize -= packetSizeRecord[packetID].size; } if(packetID != 0) packetSizeRecord.RemoveRange(0, packetID); }*/ //bytesSent += packetData.Num(); } } }