On Wed, 6 Jun 2012, Martin Storsjö wrote:

There's one exception to this reasoning, though, which will require larger fixes within rtmpproto.c (actually this could be seen as a bug in the current code). When writing data to the server (as in, publishing a live stream), only rtmp_write is called, never rtmp_read. Given the way this function is implemented right now, we never ever read from the handle again after the initial setup.

First, the issue with the code for plain rtmp - if the server has any message to send to us, we won't read it and act upon it. If the server would require us to e.g. reply to some ping message regularly, we wouldn't know about it.

For rtmpt, an initial (but insufficient) solution would be the following:

Buffer the initial byte of the response. That is, in rtmp_http_send_cmd, after you've read the polling interval byte, you read another byte. If this succeeds, you store it and return it immediately at the next rtmp_http_read call. If it fails with EOF, you switch state back to the right one.

This allows you to continuously send data, as long as the server just replies with a 1-byte response (the polling byte) each time.

But if the server response contains more data than this, we will never be able to send any more data until we've read the rest of the response - since we're still in the state that we've got more data to read from the current request until we can send the next one, and we can't send any more data until someone actually consumes the pending input data.

I don't have a good solution off-hand for this problem right now, I'll try to think about how to solve it cleanly, given the current urlprotocol architecture (in other words - the minimal changes to the urlprotocol system needed for solving this properly).

Ok, I think I've got an idea on how to solve this pretty cleanly.

In rtmp_write, after writing all the data, set rt->stream into nonblocking mode:
  rt->stream->flags |= AVIO_FLAG_NONBLOCK;

Then try to read one byte from the stream. If this fails due to EAGAIN, there's no incoming data to handle, just return as normal. However, if this returns 1, indicating that one byte actually was read, switch the stream back into blocking mode (flags &= ~AVIO_FLAG_NONBLOCK), and try to read the whole packet of data. This will probably require you to split ff_rtmp_packet_read, into a separate version where you can provide the first byte as a parameter (since there's no 'ungetc' equivalent in this framework). Once you've read the packet, try to parse and handle it (or just free it and ignore it?).

This can all be implemented first with the straight normal tcp rtmp.

Then, you can add support for handling nonblocking mode in rtmp_http_read.

If the nonblock flag is set, check the state flag. If the state is ready (that is, no current http request ongoing), just return EAGAIN, indicating that there's currently no immediate data to return to the caller. If state is waiting, try to read the amount of bytes. (This will be a normal blocking read, since http itself doesn't support nonblocking mode.) If this returns EOF, just return EAGAIN to the caller - don't start any new request.

This should do quite precisely what we need here, and shouldn't be all that terribly complicated to implement - not the rtmphttp part at least.


For reference, librtmp solves this issue in a different way, by pipelining http requests (e.g. sending a second request before the previous one has completed), although I'm not sure that all servers support that.

// Martin
_______________________________________________
libav-devel mailing list
libav-devel@libav.org
https://lists.libav.org/mailman/listinfo/libav-devel

Reply via email to