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
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)
};
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)
{
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;
}
// 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,
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);
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);
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);
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;
}
/**
- * 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);
}
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) {
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;
}
// 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;
}
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;
}
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:
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;
} 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);
}
}
}
- 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",