Support RTSP protocol via NSURLProtocol?

Hi,


I'm trying to develop a simple client for the RTSP protocol. I'm only interested in exchanging messages such as OPTIONS, DESCRIBE, SETUP, etc. with the server, not actually streaming any media.


Because RTSP is similar to HTTP, I hoped I could use an NSURLSession to talk to the server if I provided a protocol handler for RTSP. So I created a class that extends NSURLProtocol, implemented the +canInitWithRequest method, and registered the class with [NSURLProtocol registerClass:]. Then I put a breakpoint in my canInitWithRequest method and tried to send a dataTask to an rtsp:// URL.


The result is simply an error message "unsupported URL". I'm totally confused by this result, because my canInitWithRequest method was never even called. I expected that it would be, regardless of what ever else happened.


Can someone explain why this is? Also, is it even possible to do what I want to do, without writing a bunch of low-level socket code to talk to the server? I'm willing to write the socket code if I have to, but I was hoping to find a shortcut (and if I have to write the socket code, I don't care whether or not it is integrated with the URL loading system).


Thanks,

Frank

Accepted Reply

I got past this first issue by using the shared NSURLSession instead of creating a new one.

Right. NSURLSession does support NSURLProtocol but that support varies by session type:

  • The shared session picks up protocols registered via

    +registerClass:
    .
  • For other standard sessions you have to opt into them by setting the

    protocolClasses
    property on the NSURLSessionConfiguration object you use to create the session.
  • Background sessions don’t support NSURLProtocol at all.

However, I don’t think that this will help you with this:

is it even possible to do what I want to do, without writing a bunch of low-level socket code to talk to the server?

The HTTP protocol that lurks within NSURLSession will only accept

http
and
http
URLs. You can’t change that by adding an NSURLProtocol. Specifically:

It seems like I should be able to have my protocol class extend the one that implements the HTTP protocol, but I don't know the name of that class.

Indeed. That class is not public. In fact, it’s not even written in Objective-C (-:

CFNetwork was not designed to facilitate what you’re trying to do. Even if it were, it’s likely that it wouldn’t be possible. While HTTP and RTSP are superficially similar, they’re nowhere near close enough to for this to work. Section 1.8 of RFC 2326 is pretty clear about this.

Using an NSURLProtocol here will have two effects:

  • You still have to write the code that implements the on-the-wire protocol, but now it’s inside an NSURLProtocol subclass

  • Clients will be able to access your protocol via the NSURLSession API

The first point is a wash. The second point might be a benefit; ultimately you get to decide whether it’s enough of a benefit to justify the work involved.

Are you implementing RTSP over UDP or TCP? If you’re targeting UDP then, alas, low-level sockets code is the order of the day. If you’re targeting TCP, you should use CFSocketStream (typically via the NSStream API) to get all the benefits it provides (nicer API, TLS support, proxy support).

Also, depending on how close the RTSP protocol is to HTTP, you may be able to use CFHTTPMessage to format and parse messages.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

Replies

I got past this first issue by using the shared NSURLSession instead of creating a new one.


I'm not sure what to do next or if what I want to do is even possible.


I'd like to essentially override the HTTP protocol and be able to change the first line of text that is sent to the server. Instead of HTTP/1.1, it needs to say RTSP/1.0. Beyond that, everything else is the same as an HTTP request.


Is there an easy way to do this without having to resort to opening my own sockets and doing everything at a byte-by-byte level?


It seems like I should be able to have my protocol class extend the one that implements the HTTP protocol, but I don't know the name of that class.


Thanks,

Frank

I got past this first issue by using the shared NSURLSession instead of creating a new one.

Right. NSURLSession does support NSURLProtocol but that support varies by session type:

  • The shared session picks up protocols registered via

    +registerClass:
    .
  • For other standard sessions you have to opt into them by setting the

    protocolClasses
    property on the NSURLSessionConfiguration object you use to create the session.
  • Background sessions don’t support NSURLProtocol at all.

However, I don’t think that this will help you with this:

is it even possible to do what I want to do, without writing a bunch of low-level socket code to talk to the server?

The HTTP protocol that lurks within NSURLSession will only accept

http
and
http
URLs. You can’t change that by adding an NSURLProtocol. Specifically:

It seems like I should be able to have my protocol class extend the one that implements the HTTP protocol, but I don't know the name of that class.

Indeed. That class is not public. In fact, it’s not even written in Objective-C (-:

CFNetwork was not designed to facilitate what you’re trying to do. Even if it were, it’s likely that it wouldn’t be possible. While HTTP and RTSP are superficially similar, they’re nowhere near close enough to for this to work. Section 1.8 of RFC 2326 is pretty clear about this.

Using an NSURLProtocol here will have two effects:

  • You still have to write the code that implements the on-the-wire protocol, but now it’s inside an NSURLProtocol subclass

  • Clients will be able to access your protocol via the NSURLSession API

The first point is a wash. The second point might be a benefit; ultimately you get to decide whether it’s enough of a benefit to justify the work involved.

Are you implementing RTSP over UDP or TCP? If you’re targeting UDP then, alas, low-level sockets code is the order of the day. If you’re targeting TCP, you should use CFSocketStream (typically via the NSStream API) to get all the benefits it provides (nicer API, TLS support, proxy support).

Also, depending on how close the RTSP protocol is to HTTP, you may be able to use CFHTTPMessage to format and parse messages.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

Thanks for all the help. In retrospect I can see where extending the HTTP protocol is not likely to be something that the framework would support.


I've got some POSIX socket code from an old project that I should be able to repurpose for this, so I'll give that a try.


Frank