Пример #1
0
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();

    //--------------------------
}
Пример #2
0
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();

    //--------------------------
}