]> git.sesse.net Git - ffmpeg/blobdiff - libavformat/rtmpproto.c
Merge commit '5dd9a4b88b287bf8c93520afda7becb1ad0d1894'
[ffmpeg] / libavformat / rtmpproto.c
index ae55a3328422f069b075d502255b1fc6cbb5ce92..7320b4f022a426530fdea11a4e4802ee9542c9f9 100644 (file)
@@ -93,7 +93,7 @@ typedef struct RTMPContext {
     int           flv_off;                    ///< number of bytes read from current buffer
     int           flv_nb_packets;             ///< number of flv packets published
     RTMPPacket    out_pkt;                    ///< rtmp packet, created from flv a/v or metadata (for output)
-    uint32_t      client_report_size;         ///< number of bytes after which client should report to server
+    uint32_t      receive_report_size;        ///< number of bytes after which we should report the number of received bytes to the peer
     uint64_t      bytes_read;                 ///< number of bytes read from server
     uint64_t      last_bytes_read;            ///< number of bytes read last reported to server
     uint32_t      last_timestamp;             ///< last timestamp received in a packet
@@ -114,7 +114,7 @@ typedef struct RTMPContext {
     char          swfverification[42];        ///< hash of the SWF verification
     char*         pageurl;                    ///< url of the web page
     char*         subscribe;                  ///< name of live stream to subscribe
-    int           server_bw;                  ///< server bandwidth
+    int           max_sent_unacked;           ///< max unacked sent bytes
     int           client_buffer_time;         ///< client buffer time in ms
     int           flush_interval;             ///< number of packets flushed in the same request (RTMPT only)
     int           encrypted;                  ///< use an encrypted connection (RTMPE only)
@@ -156,8 +156,8 @@ static const uint8_t rtmp_server_key[] = {
 };
 
 static int handle_chunk_size(URLContext *s, RTMPPacket *pkt);
-static int handle_server_bw(URLContext *s, RTMPPacket *pkt);
-static int handle_client_bw(URLContext *s, RTMPPacket *pkt);
+static int handle_window_ack_size(URLContext *s, RTMPPacket *pkt);
+static int handle_set_peer_bw(URLContext *s, RTMPPacket *pkt);
 
 static int add_tracked_method(RTMPContext *rt, const char *name, int id)
 {
@@ -438,13 +438,13 @@ static int read_connect(URLContext *s, RTMPContext *rt)
             return AVERROR_UNKNOWN;
         } else if (pkt.type == RTMP_PT_BYTES_READ) {
             av_log(s, AV_LOG_TRACE, "received acknowledgement\n");
-        } else if (pkt.type == RTMP_PT_SERVER_BW) {
-            if ((ret = handle_server_bw(s, &pkt)) < 0) {
+        } else if (pkt.type == RTMP_PT_WINDOW_ACK_SIZE) {
+            if ((ret = handle_window_ack_size(s, &pkt)) < 0) {
                 ff_rtmp_packet_destroy(&pkt);
                 return ret;
             }
-        } else if (pkt.type == RTMP_PT_CLIENT_BW) {
-            if ((ret = handle_client_bw(s, &pkt)) < 0) {
+        } else if (pkt.type == RTMP_PT_SET_PEER_BW) {
+            if ((ret = handle_set_peer_bw(s, &pkt)) < 0) {
                 ff_rtmp_packet_destroy(&pkt);
                 return ret;
             }
@@ -485,22 +485,26 @@ static int read_connect(URLContext *s, RTMPContext *rt)
 
     // Send Window Acknowledgement Size (as defined in specification)
     if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL,
-                                     RTMP_PT_SERVER_BW, 0, 4)) < 0)
+                                     RTMP_PT_WINDOW_ACK_SIZE, 0, 4)) < 0)
         return ret;
     p = pkt.data;
-    bytestream_put_be32(&p, rt->server_bw);
+    // Inform the peer about how often we want acknowledgements about what
+    // we send. (We don't check for the acknowledgements currently.)
+    bytestream_put_be32(&p, rt->max_sent_unacked);
     pkt.size = p - pkt.data;
     ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->out_chunk_size,
                                &rt->prev_pkt[1], &rt->nb_prev_pkt[1]);
     ff_rtmp_packet_destroy(&pkt);
     if (ret < 0)
         return ret;
-    // Send Peer Bandwidth
+    // Set Peer Bandwidth
     if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL,
-                                     RTMP_PT_CLIENT_BW, 0, 5)) < 0)
+                                     RTMP_PT_SET_PEER_BW, 0, 5)) < 0)
         return ret;
     p = pkt.data;
-    bytestream_put_be32(&p, rt->server_bw);
+    // Tell the peer to only send this many bytes unless it gets acknowledgements.
+    // This could be any arbitrary value we want here.
+    bytestream_put_be32(&p, rt->max_sent_unacked);
     bytestream_put_byte(&p, 2); // dynamic
     pkt.size = p - pkt.data;
     ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->out_chunk_size,
@@ -509,14 +513,14 @@ static int read_connect(URLContext *s, RTMPContext *rt)
     if (ret < 0)
         return ret;
 
-    // Ping request
+    // User control
     if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL,
-                                     RTMP_PT_PING, 0, 6)) < 0)
+                                     RTMP_PT_USER_CONTROL, 0, 6)) < 0)
         return ret;
 
     p = pkt.data;
     bytestream_put_be16(&p, 0); // 0 -> Stream Begin
-    bytestream_put_be32(&p, 0);
+    bytestream_put_be32(&p, 0); // Stream 0
     ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->out_chunk_size,
                                &rt->prev_pkt[1], &rt->nb_prev_pkt[1]);
     ff_rtmp_packet_destroy(&pkt);
@@ -742,12 +746,12 @@ static int gen_buffer_time(URLContext *s, RTMPContext *rt)
     uint8_t *p;
     int ret;
 
-    if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL, RTMP_PT_PING,
+    if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL, RTMP_PT_USER_CONTROL,
                                      1, 10)) < 0)
         return ret;
 
     p = pkt.data;
-    bytestream_put_be16(&p, 3);
+    bytestream_put_be16(&p, 3); // SetBuffer Length
     bytestream_put_be32(&p, rt->stream_id);
     bytestream_put_be32(&p, rt->client_buffer_time);
 
@@ -874,12 +878,12 @@ static int gen_pong(URLContext *s, RTMPContext *rt, RTMPPacket *ppkt)
         return AVERROR_INVALIDDATA;
     }
 
-    if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL, RTMP_PT_PING,
+    if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL,RTMP_PT_USER_CONTROL,
                                      ppkt->timestamp + 1, 6)) < 0)
         return ret;
 
     p = pkt.data;
-    bytestream_put_be16(&p, 7);
+    bytestream_put_be16(&p, 7); // PingResponse
     bytestream_put_be32(&p, AV_RB32(ppkt->data+2));
 
     return rtmp_send_packet(rt, &pkt, 0);
@@ -895,7 +899,7 @@ static int gen_swf_verification(URLContext *s, RTMPContext *rt)
     int ret;
 
     av_log(s, AV_LOG_DEBUG, "Sending SWF verification...\n");
-    if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL, RTMP_PT_PING,
+    if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL, RTMP_PT_USER_CONTROL,
                                      0, 44)) < 0)
         return ret;
 
@@ -907,20 +911,20 @@ static int gen_swf_verification(URLContext *s, RTMPContext *rt)
 }
 
 /**
- * Generate server bandwidth message and send it to the server.
+ * Generate window acknowledgement size message and send it to the server.
  */
-static int gen_server_bw(URLContext *s, RTMPContext *rt)
+static int gen_window_ack_size(URLContext *s, RTMPContext *rt)
 {
     RTMPPacket pkt;
     uint8_t *p;
     int ret;
 
-    if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL, RTMP_PT_SERVER_BW,
+    if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL, RTMP_PT_WINDOW_ACK_SIZE,
                                      0, 4)) < 0)
         return ret;
 
     p = pkt.data;
-    bytestream_put_be32(&p, rt->server_bw);
+    bytestream_put_be32(&p, rt->max_sent_unacked);
 
     return rtmp_send_packet(rt, &pkt, 0);
 }
@@ -1553,19 +1557,19 @@ static int handle_chunk_size(URLContext *s, RTMPPacket *pkt)
     return 0;
 }
 
-static int handle_ping(URLContext *s, RTMPPacket *pkt)
+static int handle_user_control(URLContext *s, RTMPPacket *pkt)
 {
     RTMPContext *rt = s->priv_data;
     int t, ret;
 
     if (pkt->size < 2) {
-        av_log(s, AV_LOG_ERROR, "Too short ping packet (%d)\n",
+        av_log(s, AV_LOG_ERROR, "Too short user control packet (%d)\n",
                pkt->size);
         return AVERROR_INVALIDDATA;
     }
 
     t = AV_RB16(pkt->data);
-    if (t == 6) {
+    if (t == 6) { // PingRequest
         if ((ret = gen_pong(s, rt, pkt)) < 0)
             return ret;
     } else if (t == 26) {
@@ -1580,48 +1584,55 @@ static int handle_ping(URLContext *s, RTMPPacket *pkt)
     return 0;
 }
 
-static int handle_client_bw(URLContext *s, RTMPPacket *pkt)
+static int handle_set_peer_bw(URLContext *s, RTMPPacket *pkt)
 {
     RTMPContext *rt = s->priv_data;
 
     if (pkt->size < 4) {
         av_log(s, AV_LOG_ERROR,
-               "Client bandwidth report packet is less than 4 bytes long (%d)\n",
+               "Peer bandwidth packet is less than 4 bytes long (%d)\n",
                pkt->size);
         return AVERROR_INVALIDDATA;
     }
 
-    rt->client_report_size = AV_RB32(pkt->data);
-    if (rt->client_report_size <= 0) {
-        av_log(s, AV_LOG_ERROR, "Incorrect client bandwidth %d\n",
-                rt->client_report_size);
+    // We currently don't check how much the peer has acknowledged of
+    // what we have sent. To do that properly, we should call
+    // gen_window_ack_size here, to tell the peer that we want an
+    // acknowledgement with (at least) that interval.
+    rt->max_sent_unacked = AV_RB32(pkt->data);
+    if (rt->max_sent_unacked <= 0) {
+        av_log(s, AV_LOG_ERROR, "Incorrect set peer bandwidth %d\n",
+               rt->max_sent_unacked);
         return AVERROR_INVALIDDATA;
 
     }
-    av_log(s, AV_LOG_DEBUG, "Client bandwidth = %d\n", rt->client_report_size);
-    rt->client_report_size >>= 1;
+    av_log(s, AV_LOG_DEBUG, "Max sent, unacked = %d\n", rt->max_sent_unacked);
 
     return 0;
 }
 
-static int handle_server_bw(URLContext *s, RTMPPacket *pkt)
+static int handle_window_ack_size(URLContext *s, RTMPPacket *pkt)
 {
     RTMPContext *rt = s->priv_data;
 
     if (pkt->size < 4) {
         av_log(s, AV_LOG_ERROR,
-               "Too short server bandwidth report packet (%d)\n",
+               "Too short window acknowledgement size packet (%d)\n",
                pkt->size);
         return AVERROR_INVALIDDATA;
     }
 
-    rt->server_bw = AV_RB32(pkt->data);
-    if (rt->server_bw <= 0) {
-        av_log(s, AV_LOG_ERROR, "Incorrect server bandwidth %d\n",
-               rt->server_bw);
+    rt->receive_report_size = AV_RB32(pkt->data);
+    if (rt->receive_report_size <= 0) {
+        av_log(s, AV_LOG_ERROR, "Incorrect window acknowledgement size %d\n",
+               rt->receive_report_size);
         return AVERROR_INVALIDDATA;
     }
-    av_log(s, AV_LOG_DEBUG, "Server bandwidth = %d\n", rt->server_bw);
+    av_log(s, AV_LOG_DEBUG, "Window acknowledgement size = %d\n", rt->receive_report_size);
+    // Send an Acknowledgement packet after receiving half the maximum
+    // size, to make sure the peer can keep on sending without waiting
+    // for acknowledgements.
+    rt->receive_report_size >>= 1;
 
     return 0;
 }
@@ -1863,7 +1874,7 @@ static int write_begin(URLContext *s)
 
     // Send Stream Begin 1
     if ((ret = ff_rtmp_packet_create(&spkt, RTMP_NETWORK_CHANNEL,
-                                     RTMP_PT_PING, 0, 6)) < 0) {
+                                     RTMP_PT_USER_CONTROL, 0, 6)) < 0) {
         av_log(s, AV_LOG_ERROR, "Unable to create response packet\n");
         return ret;
     }
@@ -2091,7 +2102,7 @@ static int handle_invoke_result(URLContext *s, RTMPPacket *pkt)
             if ((ret = gen_fcpublish_stream(s, rt)) < 0)
                 goto fail;
         } else {
-            if ((ret = gen_server_bw(s, rt)) < 0)
+            if ((ret = gen_window_ack_size(s, rt)) < 0)
                 goto fail;
         }
 
@@ -2340,16 +2351,16 @@ static int rtmp_parse_result(URLContext *s, RTMPContext *rt, RTMPPacket *pkt)
         if ((ret = handle_chunk_size(s, pkt)) < 0)
             return ret;
         break;
-    case RTMP_PT_PING:
-        if ((ret = handle_ping(s, pkt)) < 0)
+    case RTMP_PT_USER_CONTROL:
+        if ((ret = handle_user_control(s, pkt)) < 0)
             return ret;
         break;
-    case RTMP_PT_CLIENT_BW:
-        if ((ret = handle_client_bw(s, pkt)) < 0)
+    case RTMP_PT_SET_PEER_BW:
+        if ((ret = handle_set_peer_bw(s, pkt)) < 0)
             return ret;
         break;
-    case RTMP_PT_SERVER_BW:
-        if ((ret = handle_server_bw(s, pkt)) < 0)
+    case RTMP_PT_WINDOW_ACK_SIZE:
+        if ((ret = handle_window_ack_size(s, pkt)) < 0)
             return ret;
         break;
     case RTMP_PT_INVOKE:
@@ -2454,7 +2465,7 @@ static int get_packet(URLContext *s, int for_header)
         rt->last_timestamp = rpkt.timestamp;
 
         rt->bytes_read += ret;
-        if (rt->bytes_read - rt->last_bytes_read > rt->client_report_size) {
+        if (rt->bytes_read - rt->last_bytes_read > rt->receive_report_size) {
             av_log(s, AV_LOG_DEBUG, "Sending bytes read report\n");
             if ((ret = gen_bytes_read(s, rt, rpkt.timestamp + 1)) < 0)
                 return ret;
@@ -2507,7 +2518,7 @@ static int get_packet(URLContext *s, int for_header)
         } else if (rpkt.type == RTMP_PT_METADATA) {
             ret = handle_metadata(rt, &rpkt);
             ff_rtmp_packet_destroy(&rpkt);
-            return 0;
+            return ret;
         }
         ff_rtmp_packet_destroy(&rpkt);
     }
@@ -2818,13 +2829,13 @@ reconnect:
         }
     }
 
-    rt->client_report_size = 1048576;
+    rt->receive_report_size = 1048576;
     rt->bytes_read = 0;
     rt->has_audio = 0;
     rt->has_video = 0;
     rt->received_metadata = 0;
     rt->last_bytes_read = 0;
-    rt->server_bw = 2500000;
+    rt->max_sent_unacked = 2500000;
     rt->duration = 0;
 
     av_log(s, AV_LOG_DEBUG, "Proto = %s, path = %s, app = %s, fname = %s\n",