RTMPPublisher::~RTMPPublisher() { //OSDebugOut (TEXT("*** ~RTMPPublisher (%d queued, %d buffered)\n"), queuedPackets.Num(), bufferedPackets.Num()); bStopping = true; //we're in the middle of connecting! wait for that to happen to avoid all manner of race conditions if (hConnectionThread) { WaitForSingleObject(hConnectionThread, INFINITE); OSCloseThread(hConnectionThread); } FlushBufferedPackets (); //OSDebugOut (TEXT("%d queued after flush\n"), queuedPackets.Num()); if(hSendThread) { //this marks the thread to exit after current work is done SetEvent(hSendLoopExit); //this wakes up the thread ReleaseSemaphore(hSendSempahore, 1, NULL); //wait 60 sec for it to exit OSTerminateThread(hSendThread, 60000); } if(hSendSempahore) CloseHandle(hSendSempahore); //OSDebugOut (TEXT("*** ~RTMPPublisher hSendThread terminated (%d queued, %d buffered, %d data)\n"), queuedPackets.Num(), bufferedPackets.Num(), curDataBufferLen); if (hSocketThread) { //mark the socket loop to shut down after the buffer is empty SetEvent(hSocketLoopExit); //wait 60 sec for it to exit OSTerminateThread(hSocketThread, 60000); } //OSDebugOut (TEXT("*** ~RTMPPublisher hSocketThread terminated (%d queued, %d buffered, %d data)\n"), queuedPackets.Num(), bufferedPackets.Num(), curDataBufferLen); if(rtmp) { //at this point nothing should be in the buffer, flush out what remains and make it blocking FlushDataBuffer(); //disable the buffered send, so RTMP_Close writes directly to the net rtmp->m_bCustomSend = 0; //ideally we need some kind of delay here, since we just dumped several seconds worth of timestamps to the network //at once, and Twitch at shows the offline screen as soon as the connection is severed even if there are //pending video frames. if (RTMP_IsConnected(rtmp)) Sleep (500); //for now RTMP_Close(rtmp); } if(hDataMutex) OSCloseMutex(hDataMutex); while (bufferedPackets.Num()) { //this should not happen any more... bufferedPackets[0].data.Clear(); bufferedPackets.Remove(0); } if (dataBuffer) Free(dataBuffer); if (hDataBufferMutex) OSCloseMutex(hDataBufferMutex); if (hBufferEvent) CloseHandle(hBufferEvent); if (hSendLoopExit) CloseHandle(hSendLoopExit); if (hSocketLoopExit) CloseHandle(hSocketLoopExit); if (hSendBacklogEvent) CloseHandle(hSendBacklogEvent); if (hBufferSpaceAvailableEvent) CloseHandle(hBufferSpaceAvailableEvent); if (hWriteEvent) CloseHandle(hWriteEvent); if(rtmp) RTMP_Free(rtmp); //-------------------------- for(UINT i=0; i<queuedPackets.Num(); i++) queuedPackets[i].data.Clear(); queuedPackets.Clear(); double dBFrameDropPercentage = double(numBFramesDumped)/NumTotalVideoFrames()*100.0; double dPFrameDropPercentage = double(numPFramesDumped)/NumTotalVideoFrames()*100.0; Log(TEXT("Number of times waited to send: %d, Waited for a total of %d bytes"), totalTimesWaited, totalBytesWaited); Log(TEXT("Number of b-frames dropped: %u (%0.2g%%), Number of p-frames dropped: %u (%0.2g%%), Total %u (%0.2g%%)"), numBFramesDumped, dBFrameDropPercentage, numPFramesDumped, dPFrameDropPercentage, numBFramesDumped+numPFramesDumped, dBFrameDropPercentage+dPFrameDropPercentage); /*if(totalCalls) Log(TEXT("average send time: %u"), totalTime/totalCalls);*/ strRTMPErrors.Clear(); //-------------------------- }
RTMPPublisher::~RTMPPublisher() { //OSDebugOut (TEXT("*** ~RTMPPublisher (%d queued, %d buffered, %d data)\n"), queuedPackets.Num(), bufferedPackets.Num(), curDataBufferLen); bStopping = true; //we're in the middle of connecting! wait for that to happen to avoid all manner of race conditions if (hConnectionThread) { WaitForSingleObject(hConnectionThread, INFINITE); OSCloseThread(hConnectionThread); } //send all remaining buffered packets, this may block since it respects timestamps FlushBufferedPackets (); //OSDebugOut (TEXT("%d queued after flush\n"), queuedPackets.Num()); if(hSendThread) { //this marks the thread to exit after current work is done SetEvent(hSendLoopExit); //these wake up the thread ReleaseSemaphore(hSendSempahore, 1, NULL); SetEvent(hBufferSpaceAvailableEvent); //wait 50 sec for all data to finish sending if (WaitForSingleObject(hSendThread, 50000) == WAIT_TIMEOUT) { Log(TEXT("~RTMPPublisher: Network appears stalled with %d / %d buffered, dropping connection!"), curDataBufferLen, dataBufferSize); FatalSocketShutdown(); //this will wake up and flush the sendloop if it's still trying to send out stuff ReleaseSemaphore(hSendSempahore, 1, NULL); SetEvent(hBufferSpaceAvailableEvent); } OSTerminateThread(hSendThread, 10000); } if(hSendSempahore) CloseHandle(hSendSempahore); //OSDebugOut (TEXT("*** ~RTMPPublisher hSendThread terminated (%d queued, %d buffered, %d data)\n"), queuedPackets.Num(), bufferedPackets.Num(), curDataBufferLen); if (hSocketThread) { //mark the socket loop to shut down after the buffer is empty SetEvent(hSocketLoopExit); //wake it up in case it already is empty SetEvent(hBufferEvent); //wait 60 sec for it to exit OSTerminateThread(hSocketThread, 60000); } //OSDebugOut (TEXT("*** ~RTMPPublisher hSocketThread terminated (%d queued, %d buffered, %d data)\n"), queuedPackets.Num(), bufferedPackets.Num(), curDataBufferLen); if(rtmp) { if (RTMP_IsConnected(rtmp)) { //at this point nothing should be in the buffer, flush out what remains to the net and make it blocking FlushDataBuffer(); //disable the buffered send, so RTMP_* functions write directly to the net (and thus block) rtmp->m_bCustomSend = 0; //manually shut down the stream and issue a graceful socket shutdown RTMP_DeleteStream(rtmp); shutdown(rtmp->m_sb.sb_socket, SD_SEND); //this waits for the socket shutdown to complete gracefully for (;;) { char buff[1024]; int ret; ret = recv(rtmp->m_sb.sb_socket, buff, sizeof(buff), 0); if (!ret) break; else if (ret == -1) { Log(TEXT("~RTMPublisher: Received error %d while waiting for graceful shutdown."), WSAGetLastError()); break; } } //OSDebugOut(TEXT("Graceful shutdown complete.\n")); } //this closes the socket if not already done RTMP_Close(rtmp); } if(hDataMutex) OSCloseMutex(hDataMutex); while (bufferedPackets.Num()) { //this should not happen any more... bufferedPackets[0].data.Clear(); bufferedPackets.Remove(0); } if (dataBuffer) Free(dataBuffer); if (hDataBufferMutex) OSCloseMutex(hDataBufferMutex); if (hBufferEvent) CloseHandle(hBufferEvent); if (hSendLoopExit) CloseHandle(hSendLoopExit); if (hSocketLoopExit) CloseHandle(hSocketLoopExit); if (hSendBacklogEvent) CloseHandle(hSendBacklogEvent); if (hBufferSpaceAvailableEvent) CloseHandle(hBufferSpaceAvailableEvent); if (hWriteEvent) CloseHandle(hWriteEvent); if(rtmp) { if (rtmp->Link.pubUser.av_val) Free(rtmp->Link.pubUser.av_val); if (rtmp->Link.pubPasswd.av_val) Free(rtmp->Link.pubPasswd.av_val); RTMP_Free(rtmp); } //-------------------------- for(UINT i=0; i<queuedPackets.Num(); i++) queuedPackets[i].data.Clear(); queuedPackets.Clear(); double dBFrameDropPercentage = double(numBFramesDumped)/NumTotalVideoFrames()*100.0; double dPFrameDropPercentage = double(numPFramesDumped)/NumTotalVideoFrames()*100.0; if (totalSendCount) Log(TEXT("Average send payload: %d bytes, average send interval: %d ms"), (DWORD)(totalSendBytes / totalSendCount), totalSendPeriod / totalSendCount); Log(TEXT("Number of times waited to send: %d, Waited for a total of %d bytes"), totalTimesWaited, totalBytesWaited); Log(TEXT("Number of b-frames dropped: %u (%0.2g%%), Number of p-frames dropped: %u (%0.2g%%), Total %u (%0.2g%%)"), numBFramesDumped, dBFrameDropPercentage, numPFramesDumped, dPFrameDropPercentage, numBFramesDumped+numPFramesDumped, dBFrameDropPercentage+dPFrameDropPercentage); /*if(totalCalls) Log(TEXT("average send time: %u"), totalTime/totalCalls);*/ strRTMPErrors.Clear(); //-------------------------- }
RTMPPublisher::~RTMPPublisher() { bStopping = true; //we're in the middle of connecting! wait for that to happen to avoid all manner of race conditions if (hConnectionThread) { WaitForSingleObject(hConnectionThread, INFINITE); OSCloseThread(hConnectionThread); } if(hSendThread) { ReleaseSemaphore(hSendSempahore, 1, NULL); //wake it up in case it's waiting for buffer space SetEvent(hBufferSpaceAvailableEvent); OSTerminateThread(hSendThread, 20000); } if(hSendSempahore) CloseHandle(hSendSempahore); if(hDataMutex) OSCloseMutex(hDataMutex); while (bufferedPackets.Num()) { bufferedPackets[0].data.Clear(); bufferedPackets.Remove(0); } //wake up and shut down the buffered sender SetEvent(hWriteEvent); SetEvent(hBufferEvent); if (hSocketThread) { OSTerminateThread(hSocketThread, 20000); //at this point nothing new should be coming in to the buffer, flush out what remains FlushDataBuffer(); } if(rtmp) { //disable the buffered send, so RTMP_Close writes directly to the net rtmp->m_bCustomSend = 0; RTMP_Close(rtmp); } if (dataBuffer) Free(dataBuffer); if (hDataBufferMutex) OSCloseMutex(hDataBufferMutex); if (hBufferEvent) CloseHandle(hBufferEvent); if (hBufferSpaceAvailableEvent) CloseHandle(hBufferSpaceAvailableEvent); if (hWriteEvent) CloseHandle(hWriteEvent); if(rtmp) RTMP_Free(rtmp); //-------------------------- for(UINT i=0; i<queuedPackets.Num(); i++) queuedPackets[i].data.Clear(); queuedPackets.Clear(); double dBFrameDropPercentage = double(numBFramesDumped)/NumTotalVideoFrames()*100.0; double dPFrameDropPercentage = double(numPFramesDumped)/NumTotalVideoFrames()*100.0; Log(TEXT("Number of times waited to send: %d, Waited for a total of %d bytes"), totalTimesWaited, totalBytesWaited); Log(TEXT("Number of b-frames dropped: %u (%0.2g%%), Number of p-frames dropped: %u (%0.2g%%), Total %u (%0.2g%%)"), numBFramesDumped, dBFrameDropPercentage, numPFramesDumped, dPFrameDropPercentage, numBFramesDumped+numPFramesDumped, dBFrameDropPercentage+dPFrameDropPercentage); /*if(totalCalls) Log(TEXT("average send time: %u"), totalTime/totalCalls);*/ strRTMPErrors.Clear(); //-------------------------- }