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.
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.After you call startRtmpStreamWithTranscoding
or startRtmpStreamWithoutTranscoding
, you can troubleshoot using the error codes reported by the onRtmpStreamingStateChanged
callback.
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.RTMP_STREAM_PUBLISH_ERROR_OK (0)
: Streaming to CDN is successful.RTMP_STREAM_UNPUBLISH_ERROR_OK (100)
: The streaming is stopped normally.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.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.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.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.
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.
LRESULT CAgoraRtmpStreamingDlg::OnEIDRtmpStateChanged(WPARAM wParam, LPARAM lParam)
{
PRtmpStreamStreamStateChanged rtmpState = (PRtmpStreamStreamStateChanged)wParam;
CString strInfo;
m_btnRemoveStream.EnableWindow(TRUE);
switch (rtmpState->state)
{
case RTMP_STREAM_PUBLISH_STATE_IDLE:
{
strInfo.Format(_T("%s:%S��"), agoraRtmpStateIdle, rtmpState->url);
CString strUrl;
strUrl.Format(_T("%S"), rtmpState->url);
int sel = m_cmbRtmpUrl.GetCurSel();
m_cmbRtmpUrl.DeleteString(sel);
m_cmbRtmpUrl.ResetContent();
if (m_cmbRtmpUrl.GetCount() > 0) {
m_cmbRtmpUrl.SetCurSel(0);
}
for (auto iter = m_urlSet.begin(); iter != m_urlSet.end(); ++iter)
if (strUrl.Compare(*iter) == 0) {
m_urlSet.erase(iter);
break;
}
if (m_bRemoveAll) {
m_removeUrlCount++;
if (m_removeUrlCount == m_urlSet.size()) {//remove all url when leave channel
m_urlSet.clear();
m_bRemoveAll = false;
m_rtcEngine->leaveChannel();
m_lstInfo.InsertString(m_lstInfo.GetCount(), _T("leaveChannel"));
}
}
}
break;
case RTMP_STREAM_PUBLISH_STATE_CONNECTING:
{
strInfo = agoraRtmpStateConnecting;
}
break;
case RTMP_STREAM_PUBLISH_STATE_RUNNING:
strInfo = agoraRtmpStateRunning;
if (rtmpState->error == RTMP_STREAM_PUBLISH_ERROR_OK) {
strInfo = agoraRtmpStateRunningSuccess;
CString strUrl;
strUrl.Format(_T("%S"), rtmpState->url);
if (m_urlSet.find(strUrl) == m_urlSet.end()) {
m_cmbRtmpUrl.AddString(strUrl);
m_urlSet.insert(strUrl);
if (m_cmbRtmpUrl.GetCurSel() < 0)
m_cmbRtmpUrl.SetCurSel(0);
}
}
break;
case RTMP_STREAM_PUBLISH_STATE_RECOVERING:
strInfo.Format(agoraRtmpStateRecovering);
break;
case RTMP_STREAM_PUBLISH_STATE_FAILURE:
{
strInfo = agoraRtmpStateRunningSuccess;
CString strUrl;
strUrl.Format(_T("%S"), rtmpState->url);
std::string szUrl = cs2utf8(strUrl);
m_rtcEngine->stopRtmpStream(szUrl.c_str());
int error = lParam;
if (error == RTMP_STREAM_PUBLISH_ERROR_CONNECTION_TIMEOUT
|| error == RTMP_STREAM_PUBLISH_ERROR_INTERNAL_SERVER_ERROR
|| error == RTMP_STREAM_PUBLISH_ERROR_STREAM_NOT_FOUND
|| error == RTMP_STREAM_PUBLISH_ERROR_RTMP_SERVER_ERROR
|| error == RTMP_STREAM_PUBLISH_ERROR_NET_DOWN) {
if (m_mapRepublishFlag.find(szUrl.c_str()) != m_mapRepublishFlag.end()
&& m_mapRemoveFlag.find(szUrl.c_str()) != m_mapRemoveFlag.end()) {
if (m_mapRepublishFlag[szUrl.c_str()]
&& !m_mapRemoveFlag[szUrl.c_str()]) {
//republish, removePublish when error
m_rtcEngine->startRtmpStreamWithoutTranscoding(szUrl.c_str());
}
}
}
else {
// stop retrying
m_mapRemoveFlag[szUrl.c_str()] = false;
m_mapRepublishFlag[szUrl.c_str()] = true;
CString strUrl;
strUrl.Format(_T("%S"), szUrl.c_str());
for (int i = 0; i < m_cmbRtmpUrl.GetCount(); ++i) {
CString strText;
m_cmbRtmpUrl.GetLBText(i, strText);
if (strText.Compare(strUrl) == 0) {
m_cmbRtmpUrl.DeleteString(i);
break;
}
}
if (m_urlSet.find(strUrl) != m_urlSet.end()) {
m_urlSet.erase(strUrl);
}
if (m_cmbRtmpUrl.GetCurSel() < 0 && m_cmbRtmpUrl.GetCount() > 0)
m_cmbRtmpUrl.SetCurSel(0);
}
switch (rtmpState->state)
{
case RTMP_STREAM_PUBLISH_ERROR_INVALID_ARGUMENT:
{
strInfo = agoraRtmpStateInvalidArg;
}
break;
case RTMP_STREAM_PUBLISH_ERROR_ENCRYPTED_STREAM_NOT_ALLOWED:
{
strInfo = agoraRtmpStateEncrypted;
}
break;
case RTMP_STREAM_PUBLISH_ERROR_CONNECTION_TIMEOUT:
{
strInfo = agoraRtmpStateConnTimeout;
}
break;
case RTMP_STREAM_PUBLISH_ERROR_INTERNAL_SERVER_ERROR:
{
strInfo = agoraRtmpStateInrealErr;
}
break;
case RTMP_STREAM_PUBLISH_ERROR_RTMP_SERVER_ERROR:
{
strInfo = agoraRtmpStateServerErr;
}
break;
case RTMP_STREAM_PUBLISH_ERROR_TOO_OFTEN:
{
strInfo = agoraRtmpStateTooOften;
}
break;
case RTMP_STREAM_PUBLISH_ERROR_REACH_LIMIT:
{
strInfo = agoraRtmpStateReachLimit;
}
break;
case RTMP_STREAM_PUBLISH_ERROR_NOT_AUTHORIZED:
{
strInfo = agoraRtmpStateNotAuth;
}
break;
case RTMP_STREAM_PUBLISH_ERROR_STREAM_NOT_FOUND:
{
strInfo = agoraRtmpStateNotFound;
}
break;
case RTMP_STREAM_PUBLISH_ERROR_FORMAT_NOT_SUPPORTED:
{
strInfo = agoraRtmpStateNotSupported;
}
break;
default:
break;
}
}
break;
default:
break;
}
m_lstInfo.InsertString(m_lstInfo.GetCount(), strInfo);
delete[] rtmpState->url;
rtmpState->url = NULL;
delete[] rtmpState;
rtmpState = NULL;
return 0;
}
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-C | Java |
---|---|---|
startRtmpStreamWithoutTranscoding |
startRtmpStreamWithoutTranscoding |
startRtmpStreamWithoutTranscoding |
startRtmpStreamWithTranscoding |
startRtmpStreamWithTranscoding |
startRtmpStreamWithTranscoding |
updateRtmpTranscoding |
updateRtmpTranscoding |
updateRtmpTranscoding |
stopRtmpStream |
stopRtmpStream |
stopRtmpStream |
onRtmpStreamingStateChanged |
rtmpStreamingChangedtoState |
onRtmpStreamingStateChanged |
onRtmpStreamingEvent |
rtmpStreamingEventWithUrl |
onRtmpStreamingEvent |