Skip to main content

You are looking at Interactive Live Streaming v3.x Docs. The newest version is  Interactive Live Streaming v4.x

Exception Handling for Media Push

To optimize the user experience in Media Push scenarios and avoid frequent streaming exceptions, you can refer to this page to optimize your code logic.

This page shows the best practice for handling error codes reported by the onRtmpStreamingStateChanged callback. If you are still using the onStreamPublished callback, you need to refer to this page and What is the relationship between the old and new callbacks of Media Push? as well.

Troubleshooting by error code

After you call startRtmpStreamWithTranscoding or startRtmpStreamWithoutTranscoding, you can troubleshoot using the error codes reported by the onRtmpStreamingStateChanged callback.

The events reported by the onRtmpStreamingEvent callback do not affect the streaming process, but are only used as event alerts. The errors reported by the onRtmpStreamingStateChanged callback can cause the streaming to be interrupted, so refer to this page to troubleshoot accordingly when an error code is received.

No troubleshooting required

  • RTMP_STREAM_PUBLISH_ERROR_OK (0): Streaming to CDN is successful.
  • RTMP_STREAM_UNPUBLISH_ERROR_OK (100): The streaming is stopped normally.

Retry pushing the stream to the CDN

  • RTMP_STREAM_PUBLISH_ERROR_CONNECTION_TIMEOUT (3): The request to the Agora streaming server timed out. Common reason: Network exception. Solution: Call stopRtmpStream and start in turn to retry pushing the stream.
  • RTMP_STREAM_PUBLISH_ERROR_INTERNAL_SERVER_ERROR (4): An error occurred in the Agora streaming server. Solution: Call stopRtmpStream and start in turn to retry pushing the stream.
  • RTMP_STREAM_PUBLISH_ERROR_RTMP_SERVER_ERROR (5): An error occurred in the CDN network or between the Agora streaming server and CDN network. Solution: Call stopRtmpStream and start in turn to retry pushing the stream. If the streaming still fails after three to five attempts, contact the CDN vendor and Agora technical support in turn for troubleshooting.
  • RTMP_STREAM_PUBLISH_ERROR_STREAM_NOT_FOUND (9): The streaming URL cannot be found. Solution: After checking and replacing the streaming URL you are passing, call start to retry pushing the stream.
  • RTMP_STREAM_PUBLISH_ERROR_NET_DOWN (14): An error occurred in the host's network. Solution: Call stopRtmpStream and start in turn to retry pushing the stream.
  • When calling the stop and start methods to retry pushing a stream, ensure that you call start only after you receive the onRtmpStreamingStateChanged callback reporting that the stop call is successful.
  • Agora recommends that you retry pushing a stream three to five times. If the streaming still fails, contact Agora technical support.
  • Do not confuse the URLs used when the streaming ends normally and when a stream is pushed again.
  • Miscellaneous troubleshooting

    • RTMP_STREAM_PUBLISH_ERROR_INVALID_ARGUMENT (1): Invalid parameter. Solution: Check API call sequences and passed parameters.
    • RTMP_STREAM_PUBLISH_ERROR_ENCRYPTED_STREAM_NOT_ALLOWED (2): The pushed media stream is encrypted and cannot be pushed. See Media Stream Encryption.
    • RTMP_STREAM_PUBLISH_ERROR_REACH_LIMIT (7): The streaming URL limit has been reached. The maximum number of streaming URLs per uid is 10 for each channel under each project. Solution: Delete unused streaming URLs to make room before retrying.
    • RTMP_STREAM_PUBLISH_ERROR_NOT_AUTHORIZED (8): Operation without permission. Common reason: Pushing media streams to a streaming URL that is being used by another host. Solution: Check the code logic.
    • RTMP_STREAM_PUBLISH_ERROR_FORMAT_NOT_SUPPORTED (10): The format of the streaming URL is not supported. Solution: Check and replace the streaming URL.
    • RTMP_STREAM_PUBLISH_ERROR_NOT_BROADCASTER (11): The user role is not host, so the user cannot use the Media Push function. Check your application code logic.
    • RTMP_STREAM_PUBLISH_ERROR_TRANSCODING_NO_MIX_STREAM (13): The updateRtmpTranscoding or setLiveTranscoding (deprecated) method is called to update the transcoding configuration in a scenario where there is streaming without transcoding. Check your application code logic.
    • RTMP_STREAM_PUBLISH_ERROR_INVALID_APPID (15): Your App ID does not have permission to use the Media Push function. Refer to Prerequisites to enable the Media Push permission.

    Repeatedly pushing the stream to the CDN on a timer

    Under extremely poor network conditions, you might not receive callbacks when the client is disconnected from the Agora streaming server. Therefore, Agora recommends that, in addition to listening for callbacks, you set a one-minute timer in your application layer to call start once every minute after the streaming starts. Using this strategy produces this result: If the current streaming is abnormal, you might receive the onRtmpStreamingStateChanged callback reporting other error codes, or you might not receive the callback. You can troubleshoot according to the error code you receive or retry pushing the stream.

    Agora recommends that you maintain an interval of at least 30 seconds between attempts to push a stream when retrying.

    Sample code to retry pushing streams

    The following sample code takes the C++ language as an example to show the code logic of calling stopRtmpStream and start in turn to retry pushing streams.


    _172
    LRESULT CAgoraRtmpStreamingDlg::OnEIDRtmpStateChanged(WPARAM wParam, LPARAM lParam)
    _172
    {
    _172
    PRtmpStreamStreamStateChanged rtmpState = (PRtmpStreamStreamStateChanged)wParam;
    _172
    CString strInfo;
    _172
    m_btnRemoveStream.EnableWindow(TRUE);
    _172
    switch (rtmpState->state)
    _172
    {
    _172
    case RTMP_STREAM_PUBLISH_STATE_IDLE:
    _172
    {
    _172
    strInfo.Format(_T("%s:%S��"), agoraRtmpStateIdle, rtmpState->url);
    _172
    CString strUrl;
    _172
    strUrl.Format(_T("%S"), rtmpState->url);
    _172
    int sel = m_cmbRtmpUrl.GetCurSel();
    _172
    m_cmbRtmpUrl.DeleteString(sel);
    _172
    m_cmbRtmpUrl.ResetContent();
    _172
    if (m_cmbRtmpUrl.GetCount() > 0) {
    _172
    m_cmbRtmpUrl.SetCurSel(0);
    _172
    }
    _172
    for (auto iter = m_urlSet.begin(); iter != m_urlSet.end(); ++iter)
    _172
    if (strUrl.Compare(*iter) == 0) {
    _172
    m_urlSet.erase(iter);
    _172
    break;
    _172
    }
    _172
    if (m_bRemoveAll) {
    _172
    m_removeUrlCount++;
    _172
    if (m_removeUrlCount == m_urlSet.size()) {//remove all url when leave channel
    _172
    m_urlSet.clear();
    _172
    m_bRemoveAll = false;
    _172
    m_rtcEngine->leaveChannel();
    _172
    m_lstInfo.InsertString(m_lstInfo.GetCount(), _T("leaveChannel"));
    _172
    }
    _172
    }
    _172
    _172
    }
    _172
    break;
    _172
    case RTMP_STREAM_PUBLISH_STATE_CONNECTING:
    _172
    {
    _172
    strInfo = agoraRtmpStateConnecting;
    _172
    }
    _172
    break;
    _172
    case RTMP_STREAM_PUBLISH_STATE_RUNNING:
    _172
    strInfo = agoraRtmpStateRunning;
    _172
    if (rtmpState->error == RTMP_STREAM_PUBLISH_ERROR_OK) {
    _172
    strInfo = agoraRtmpStateRunningSuccess;
    _172
    CString strUrl;
    _172
    strUrl.Format(_T("%S"), rtmpState->url);
    _172
    if (m_urlSet.find(strUrl) == m_urlSet.end()) {
    _172
    m_cmbRtmpUrl.AddString(strUrl);
    _172
    m_urlSet.insert(strUrl);
    _172
    if (m_cmbRtmpUrl.GetCurSel() < 0)
    _172
    m_cmbRtmpUrl.SetCurSel(0);
    _172
    }
    _172
    _172
    }
    _172
    break;
    _172
    case RTMP_STREAM_PUBLISH_STATE_RECOVERING:
    _172
    strInfo.Format(agoraRtmpStateRecovering);
    _172
    break;
    _172
    case RTMP_STREAM_PUBLISH_STATE_FAILURE:
    _172
    {
    _172
    strInfo = agoraRtmpStateRunningSuccess;
    _172
    CString strUrl;
    _172
    strUrl.Format(_T("%S"), rtmpState->url);
    _172
    std::string szUrl = cs2utf8(strUrl);
    _172
    m_rtcEngine->stopRtmpStream(szUrl.c_str());
    _172
    _172
    int error = lParam;
    _172
    if (error == RTMP_STREAM_PUBLISH_ERROR_CONNECTION_TIMEOUT
    _172
    || error == RTMP_STREAM_PUBLISH_ERROR_INTERNAL_SERVER_ERROR
    _172
    || error == RTMP_STREAM_PUBLISH_ERROR_STREAM_NOT_FOUND
    _172
    || error == RTMP_STREAM_PUBLISH_ERROR_RTMP_SERVER_ERROR
    _172
    || error == RTMP_STREAM_PUBLISH_ERROR_NET_DOWN) {
    _172
    if (m_mapRepublishFlag.find(szUrl.c_str()) != m_mapRepublishFlag.end()
    _172
    && m_mapRemoveFlag.find(szUrl.c_str()) != m_mapRemoveFlag.end()) {
    _172
    if (m_mapRepublishFlag[szUrl.c_str()]
    _172
    && !m_mapRemoveFlag[szUrl.c_str()]) {
    _172
    //republish, removePublish when error
    _172
    m_rtcEngine->startRtmpStreamWithoutTranscoding(szUrl.c_str());
    _172
    }
    _172
    }
    _172
    }
    _172
    else {
    _172
    // stop retrying
    _172
    m_mapRemoveFlag[szUrl.c_str()] = false;
    _172
    m_mapRepublishFlag[szUrl.c_str()] = true;
    _172
    CString strUrl;
    _172
    strUrl.Format(_T("%S"), szUrl.c_str());
    _172
    for (int i = 0; i < m_cmbRtmpUrl.GetCount(); ++i) {
    _172
    CString strText;
    _172
    m_cmbRtmpUrl.GetLBText(i, strText);
    _172
    if (strText.Compare(strUrl) == 0) {
    _172
    m_cmbRtmpUrl.DeleteString(i);
    _172
    break;
    _172
    }
    _172
    }
    _172
    _172
    if (m_urlSet.find(strUrl) != m_urlSet.end()) {
    _172
    m_urlSet.erase(strUrl);
    _172
    }
    _172
    _172
    if (m_cmbRtmpUrl.GetCurSel() < 0 && m_cmbRtmpUrl.GetCount() > 0)
    _172
    m_cmbRtmpUrl.SetCurSel(0);
    _172
    }
    _172
    _172
    _172
    switch (rtmpState->state)
    _172
    {
    _172
    case RTMP_STREAM_PUBLISH_ERROR_INVALID_ARGUMENT:
    _172
    {
    _172
    strInfo = agoraRtmpStateInvalidArg;
    _172
    }
    _172
    break;
    _172
    case RTMP_STREAM_PUBLISH_ERROR_ENCRYPTED_STREAM_NOT_ALLOWED:
    _172
    {
    _172
    strInfo = agoraRtmpStateEncrypted;
    _172
    }
    _172
    break;
    _172
    case RTMP_STREAM_PUBLISH_ERROR_CONNECTION_TIMEOUT:
    _172
    {
    _172
    strInfo = agoraRtmpStateConnTimeout;
    _172
    }
    _172
    break;
    _172
    case RTMP_STREAM_PUBLISH_ERROR_INTERNAL_SERVER_ERROR:
    _172
    {
    _172
    strInfo = agoraRtmpStateInrealErr;
    _172
    }
    _172
    break;
    _172
    case RTMP_STREAM_PUBLISH_ERROR_RTMP_SERVER_ERROR:
    _172
    {
    _172
    strInfo = agoraRtmpStateServerErr;
    _172
    }
    _172
    break;
    _172
    case RTMP_STREAM_PUBLISH_ERROR_TOO_OFTEN:
    _172
    {
    _172
    strInfo = agoraRtmpStateTooOften;
    _172
    }
    _172
    break;
    _172
    case RTMP_STREAM_PUBLISH_ERROR_REACH_LIMIT:
    _172
    {
    _172
    strInfo = agoraRtmpStateReachLimit;
    _172
    }
    _172
    break;
    _172
    case RTMP_STREAM_PUBLISH_ERROR_NOT_AUTHORIZED:
    _172
    {
    _172
    strInfo = agoraRtmpStateNotAuth;
    _172
    }
    _172
    break;
    _172
    case RTMP_STREAM_PUBLISH_ERROR_STREAM_NOT_FOUND:
    _172
    {
    _172
    strInfo = agoraRtmpStateNotFound;
    _172
    }
    _172
    break;
    _172
    case RTMP_STREAM_PUBLISH_ERROR_FORMAT_NOT_SUPPORTED:
    _172
    {
    _172
    strInfo = agoraRtmpStateNotSupported;
    _172
    }
    _172
    break;
    _172
    default:
    _172
    break;
    _172
    }
    _172
    }
    _172
    break;
    _172
    default:
    _172
    break;
    _172
    }
    _172
    m_lstInfo.InsertString(m_lstInfo.GetCount(), strInfo);
    _172
    delete[] rtmpState->url;
    _172
    rtmpState->url = NULL;
    _172
    delete[] rtmpState;
    _172
    rtmpState = NULL;
    _172
    return 0;
    _172
    }

    References

    The page takes the C++ language as an example. If you are using APIs in another language, refer to the following API comparison:

    C++Objective-CJava
    startRtmpStreamWithoutTranscodingstartRtmpStreamWithoutTranscodingstartRtmpStreamWithoutTranscoding
    startRtmpStreamWithTranscodingstartRtmpStreamWithTranscodingstartRtmpStreamWithTranscoding
    updateRtmpTranscodingupdateRtmpTranscodingupdateRtmpTranscoding
    stopRtmpStreamstopRtmpStreamstopRtmpStream
    onRtmpStreamingStateChangedrtmpStreamingChangedtoStateonRtmpStreamingStateChanged
    onRtmpStreamingEventrtmpStreamingEventWithUrlonRtmpStreamingEvent

    Page Content

    Interactive Live Streaming