[pulseaudio-commits] r2365 - in /branches/coling/airtunes/src/modules/rtp: rtsp.c rtsp.h

svnmailer-noreply at 0pointer.de svnmailer-noreply at 0pointer.de
Mon May 5 17:17:18 PDT 2008


Author: coling
Date: Tue May  6 02:17:17 2008
New Revision: 2365

URL: http://0pointer.de/cgi-bin/viewcvs.cgi?rev=2365&root=pulseaudio&view=rev
Log:
Move closer to an asynchronous structure (still some parsing code to be converted).
Move type definition into .c file to keep it private
Add more utility functions to add/remove headers and return the serverport now the structure is private.
This commit will break the test application but I will fix that in due course

Modified:
    branches/coling/airtunes/src/modules/rtp/rtsp.c
    branches/coling/airtunes/src/modules/rtp/rtsp.h

Modified: branches/coling/airtunes/src/modules/rtp/rtsp.c
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/branches/coling/airtunes/src/modules/rtp/rtsp.c?rev=2365&root=pulseaudio&r1=2364&r2=2365&view=diff
==============================================================================
--- branches/coling/airtunes/src/modules/rtp/rtsp.c (original)
+++ branches/coling/airtunes/src/modules/rtp/rtsp.c Tue May  6 02:17:17 2008
@@ -48,6 +48,22 @@
 #include <pulsecore/poll.h>
 
 #include "rtsp.h"
+
+struct pa_rtsp_context {
+    pa_socket_client *sc;
+    pa_iochannel *io;
+    pa_rtsp_cb_t callback;
+    void* userdata;
+    const char* useragent;
+    pa_headerlist* headers;
+    char* localip;
+    char* url;
+    uint32_t port;
+    uint32_t cseq;
+    char* session;
+    char* transport;
+    pa_rtsp_state state;
+};
 
 /*
  * read one line from the file descriptor
@@ -112,18 +128,10 @@
 static int pa_rtsp_exec(pa_rtsp_context* c, const char* cmd,
                         const char* content_type, const char* content,
                         int expect_response,
-                        pa_headerlist* headers, pa_headerlist** response_headers) {
+                        pa_headerlist* headers) {
     pa_strbuf* buf;
     char* hdrs;
     ssize_t l;
-    char response[1024];
-    int timeout;
-    char* token;
-    const char* token_state;
-    char delimiters[2];
-    char* header;
-    char* delimpos;
-
 
     pa_assert(c);
     pa_assert(c->url);
@@ -167,91 +175,6 @@
     l = pa_iochannel_write(c->io, hdrs, strlen(hdrs));
     pa_xfree(hdrs);
 
-    /* Do we expect a response? */
-    if (!expect_response)
-        return 0;
-
-    timeout = 5000;
-    if (pa_read_line(c->io, response, sizeof(response), timeout) <= 0) {
-        /*ERRMSG("%s: request failed\n",__func__);*/
-        return -1;
-    }
-
-    delimiters[0] = ' ';
-    delimiters[1] = '\0';
-    token_state = NULL;
-    pa_xfree(pa_split(response, delimiters, &token_state));
-    token = pa_split(response, delimiters, &token_state);
-    if (!token || strcmp(token, "200")) {
-        pa_xfree(token);
-        /*ERRMSG("%s: request failed, error %s\n",__func__,token);*/
-        return -1;
-    }
-    pa_xfree(token);
-
-    /* We want to return the headers? */
-    if (!response_headers)
-    {
-        /* We have no storage, so just clear out the response. */
-        while (pa_read_line(c->io, response, sizeof(response), timeout) > 0) {
-            /* Reduce timeout for future requests */
-            timeout = 1000;
-        }
-        return 0;
-    }
-
-    /* TODO: Move header reading into the headerlist. */
-    header = NULL;
-    buf = pa_strbuf_new();
-    while (pa_read_line(c->io, response, sizeof(response), timeout) > 0) {
-        /* Reduce timeout for future requests */
-        timeout = 1000;
-
-        /* If the first character is a space, it's a continuation header */
-        if (header && ' ' == response[0]) {
-            /* Add this line to the buffer (sans the space. */
-            pa_strbuf_puts(buf, &(response[1]));
-            continue;
-        }
-
-        if (header) {
-            /* This is not a continuation header so let's dump the full
-               header/value into our proplist */
-            pa_headerlist_puts(*response_headers, header, pa_strbuf_tostring_free(buf));
-            pa_xfree(header);
-            buf = pa_strbuf_new();
-        }
-
-        delimpos = strstr(response, ":");
-        if (!delimpos) {
-            /*ERRMSG("%s: Request failed, bad header\n",__func__);*/
-            return -1;
-        }
-
-        if (strlen(delimpos) > 1) {
-            /* Cut our line off so we can copy the header name out */
-            *delimpos++ = '\0';
-
-            /* Trim the front of any spaces */
-            while (' ' == *delimpos)
-                ++delimpos;
-
-            pa_strbuf_puts(buf, delimpos);
-        } else {
-            /* Cut our line off so we can copy the header name out */
-            *delimpos = '\0';
-        }
-
-        /* Save the header name */
-        header = pa_xstrdup(response);
-    }
-    /* We will have a header left from our looping itteration, so add it in :) */
-    if (header) {
-        /* This is not a continuation header so let's dump it into our proplist */
-        pa_headerlist_puts(*response_headers, header, pa_strbuf_tostring(buf));
-    }
-    pa_strbuf_free(buf);
-
     return 0;
 }
 
@@ -286,6 +209,146 @@
 }
 
 
+static void io_callback(PA_GCC_UNUSED pa_iochannel *io, void *userdata) {
+    pa_strbuf* buf;
+    pa_headerlist* response_headers = NULL;
+    char response[1024];
+    int timeout;
+    char* token;
+    char* header;
+    char* delimpos;
+    char delimiters[] = " ";
+    pa_rtsp_context *c = userdata;
+    pa_assert(c);
+
+    /* TODO: convert this to a pa_ioline based reader */
+    if (STATE_CONNECT == c->state) {
+        response_headers = pa_headerlist_new();
+    }
+    timeout = 5000;
+    /* read in any response headers */
+    if (pa_read_line(c->io, response, sizeof(response), timeout) > 0) {
+        const char* token_state = NULL;
+
+        timeout = 1000;
+        pa_xfree(pa_split(response, delimiters, &token_state));
+        token = pa_split(response, delimiters, &token_state);
+        if (!token || strcmp(token, "200")) {
+            pa_xfree(token);
+            pa_log("Invalid Response");
+            /* TODO: Bail out completely */
+            return;
+        }
+        pa_xfree(token);
+
+        /* We want to return the headers? */
+        if (!response_headers) {
+            /* We have no storage, so just clear out the response. */
+            while (pa_read_line(c->io, response, sizeof(response), timeout) > 0);
+        } else {
+            /* TODO: Move header reading into the headerlist. */
+            header = NULL;
+            buf = pa_strbuf_new();
+            while (pa_read_line(c->io, response, sizeof(response), timeout) > 0) {
+                /* If the first character is a space, it's a continuation header */
+                if (header && ' ' == response[0]) {
+                    /* Add this line to the buffer (sans the space. */
+                    pa_strbuf_puts(buf, &(response[1]));
+                    continue;
+                }
+
+                if (header) {
+                    /* This is not a continuation header so let's dump the full
+                      header/value into our proplist */
+                    pa_headerlist_puts(response_headers, header, pa_strbuf_tostring_free(buf));
+                    pa_xfree(header);
+                    buf = pa_strbuf_new();
+                }
+
+                delimpos = strstr(response, ":");
+                if (!delimpos) {
+                    pa_log("Invalid response header");
+                    return;
+                }
+
+                if (strlen(delimpos) > 1) {
+                    /* Cut our line off so we can copy the header name out */
+                    *delimpos++ = '\0';
+
+                    /* Trim the front of any spaces */
+                    while (' ' == *delimpos)
+                        ++delimpos;
+
+                    pa_strbuf_puts(buf, delimpos);
+                } else {
+                    /* Cut our line off so we can copy the header name out */
+                    *delimpos = '\0';
+                }
+
+                /* Save the header name */
+                header = pa_xstrdup(response);
+            }
+            /* We will have a header left from our looping itteration, so add it in :) */
+            if (header) {
+                /* This is not a continuation header so let's dump it into our proplist */
+                pa_headerlist_puts(response_headers, header, pa_strbuf_tostring(buf));
+            }
+            pa_strbuf_free(buf);
+        }
+    }
+
+    /* Deal with a CONNECT response */
+    if (STATE_CONNECT == c->state) {
+        const char* token_state = NULL;
+        const char* pc = NULL;
+        c->session = pa_xstrdup(pa_headerlist_gets(response_headers, "Session"));
+        c->transport = pa_xstrdup(pa_headerlist_gets(response_headers, "Transport"));
+
+        if (!c->session || !c->transport) {
+            pa_headerlist_free(response_headers);
+            return;
+        }
+
+        /* Now parse out the server port component of the response. */
+        c->port = 0;
+        delimiters[0] = ';';
+        while ((token = pa_split(c->transport, delimiters, &token_state))) {
+            if ((pc = strstr(token, "="))) {
+                if (0 == strncmp(token, "server_port", 11)) {
+                    pa_atou(pc+1, &c->port);
+                    pa_xfree(token);
+                    break;
+                }
+            }
+            pa_xfree(token);
+        }
+        if (0 == c->port) {
+            /* Error no server_port in response */
+            pa_headerlist_free(response_headers);
+            return;
+        }
+    }
+
+    /* Call our callback */
+    if (c->callback)
+        c->callback(c, c->state, response_headers, c->userdata);
+
+
+    if (response_headers)
+        pa_headerlist_free(response_headers);
+
+    /*
+    if (do_read(u) < 0 || do_write(u) < 0) {
+
+        if (u->io) {
+            pa_iochannel_free(u->io);
+            u->io = NULL;
+        }
+
+       pa_module_unload_request(u->module);
+    }
+    */
+}
 
 static void on_connection(pa_socket_client *sc, pa_iochannel *io, void *userdata) {
     pa_rtsp_context *c = userdata;
@@ -309,6 +372,7 @@
     }
     pa_assert(!c->io);
     c->io = io;
+    pa_iochannel_set_callback(c->io, io_callback, c);
 
     /* Get the local IP address for use externally */
     if (0 == getsockname(pa_iochannel_get_recv_fd(io), &sa.sa, &sa_len)) {
@@ -337,9 +401,16 @@
     }
 
     pa_socket_client_set_callback(c->sc, on_connection, c);
+    c->state = STATE_CONNECT;
     return 0;
 }
 
+void pa_rtsp_set_callback(pa_rtsp_context *c, pa_rtsp_cb_t callback, void *userdata) {
+    pa_assert(c);
+
+    c->callback = callback;
+    c->userdata = userdata;
+}
 
 void pa_rtsp_disconnect(pa_rtsp_context *c) {
     pa_assert(c);
@@ -356,11 +427,33 @@
     return c->localip;
 }
 
+uint32_t pa_rtsp_serverport(pa_rtsp_context* c) {
+    pa_assert(c);
+
+    return c->port;
+}
 
 void pa_rtsp_set_url(pa_rtsp_context* c, const char* url) {
     pa_assert(c);
 
     c->url = pa_xstrdup(url);
+}
+
+void pa_rtsp_add_header(pa_rtsp_context *c, const char* key, const char* value)
+{
+    pa_assert(c);
+    pa_assert(key);
+    pa_assert(value);
+
+    pa_headerlist_puts(c->headers, key, value);
+}
+
+void pa_rtsp_remove_header(pa_rtsp_context *c, const char* key)
+{
+    pa_assert(c);
+    pa_assert(key);
+
+    pa_headerlist_remove(c->headers, key);
 }
 
 int pa_rtsp_announce(pa_rtsp_context *c, const char* sdp) {
@@ -368,62 +461,24 @@
     if (!sdp)
         return -1;
 
-    return pa_rtsp_exec(c, "ANNOUNCE", "application/sdp", sdp, 1, NULL, NULL);
-}
-
-
-int pa_rtsp_setup(pa_rtsp_context* c, pa_headerlist** response_headers) {
+    c->state = STATE_ANNOUNCE;
+    return pa_rtsp_exec(c, "ANNOUNCE", "application/sdp", sdp, 1, NULL);
+}
+
+
+int pa_rtsp_setup(pa_rtsp_context* c) {
     pa_headerlist* headers;
-    pa_headerlist* rheaders;
-    char delimiters[2];
-    char* token;
-    const char* token_state;
-    const char* pc;
+    int rv;
 
     pa_assert(c);
 
     headers = pa_headerlist_new();
-    rheaders = pa_headerlist_new();
     pa_headerlist_puts(headers, "Transport", "RTP/AVP/TCP;unicast;interleaved=0-1;mode=record");
 
-    if (pa_rtsp_exec(c, "SETUP", NULL, NULL, 1, headers, &rheaders)) {
-        pa_headerlist_free(headers);
-        pa_headerlist_free(rheaders);
-        return -1;
-    }
+    c->state = STATE_SETUP;
+    rv = pa_rtsp_exec(c, "SETUP", NULL, NULL, 1, headers);
     pa_headerlist_free(headers);
-
-    c->session = pa_xstrdup(pa_headerlist_gets(rheaders, "Session"));
-    c->transport = pa_xstrdup(pa_headerlist_gets(rheaders, "Transport"));
-
-    if (!c->session || !c->transport) {
-        pa_headerlist_free(rheaders);
-        return -1;
-    }
-
-    /* Now parse out the server port component of the response. */
-    c->port = 0;
-    delimiters[0] = ';';
-    delimiters[1] = '\0';
-    token_state = NULL;
-    while ((token = pa_split(c->transport, delimiters, &token_state))) {
-        if ((pc = strstr(token, "="))) {
-            if (0 == strncmp(token, "server_port", 11)) {
-                pa_atou(pc+1, &c->port);
-                pa_xfree(token);
-                break;
-            }
-        }
-        pa_xfree(token);
-    }
-    if (0 == c->port) {
-        /* Error no server_port in response */
-        pa_headerlist_free(rheaders);
-        return -1;
-    }
-
-    *response_headers = rheaders;
-    return 0;
+    return rv;
 }
 
 
@@ -441,7 +496,8 @@
     pa_headerlist_puts(headers, "Range", "npt=0-");
     pa_headerlist_puts(headers, "RTP-Info", "seq=0;rtptime=0");
 
-    rv = pa_rtsp_exec(c, "RECORD", NULL, NULL, 1, headers, NULL);
+    c->state = STATE_RECORD;
+    rv = pa_rtsp_exec(c, "RECORD", NULL, NULL, 1, headers);
     pa_headerlist_free(headers);
     return rv;
 }
@@ -450,7 +506,8 @@
 int pa_rtsp_teardown(pa_rtsp_context *c) {
     pa_assert(c);
 
-    return pa_rtsp_exec(c, "TEARDOWN", NULL, NULL, 0, NULL, NULL);
+    c->state = STATE_TEARDOWN;
+    return pa_rtsp_exec(c, "TEARDOWN", NULL, NULL, 0, NULL);
 }
 
 
@@ -459,7 +516,8 @@
     if (!param)
         return -1;
 
-    return pa_rtsp_exec(c, "SET_PARAMETER", "text/parameters", param, 1, NULL, NULL);
+    c->state = STATE_SET_PARAMETER;
+    return pa_rtsp_exec(c, "SET_PARAMETER", "text/parameters", param, 1, NULL);
 }
 
 
@@ -472,7 +530,8 @@
     headers = pa_headerlist_new();
     pa_headerlist_puts(headers, "RTP-Info", "seq=0;rtptime=0");
 
-    rv = pa_rtsp_exec(c, "FLUSH", NULL, NULL, 1, headers, NULL);
+    c->state = STATE_FLUSH;
+    rv = pa_rtsp_exec(c, "FLUSH", NULL, NULL, 1, headers);
     pa_headerlist_free(headers);
     return rv;
 }

Modified: branches/coling/airtunes/src/modules/rtp/rtsp.h
URL: http://0pointer.de/cgi-bin/viewcvs.cgi/branches/coling/airtunes/src/modules/rtp/rtsp.h?rev=2365&root=pulseaudio&r1=2364&r2=2365&view=diff
==============================================================================
--- branches/coling/airtunes/src/modules/rtp/rtsp.h (original)
+++ branches/coling/airtunes/src/modules/rtp/rtsp.h Tue May  6 02:17:17 2008
@@ -36,30 +36,35 @@
 
 #include "headerlist.h"
 
-typedef struct pa_rtsp_context {
-    pa_socket_client *sc;
-    pa_iochannel *io;
-    const char* useragent;
-    pa_headerlist* headers;
-    char* localip;
-    char* url;
-    uint32_t port;
-    uint32_t cseq;
-    char* session;
-    char* transport;
-} pa_rtsp_context;
+typedef struct pa_rtsp_context pa_rtsp_context;
+typedef enum {
+  STATE_CONNECT,
+  STATE_ANNOUNCE,
+  STATE_SETUP,
+  STATE_RECORD,
+  STATE_TEARDOWN,
+  STATE_SET_PARAMETER,
+  STATE_FLUSH
+} pa_rtsp_state;
+typedef void (*pa_rtsp_cb_t)(pa_rtsp_context *c, pa_rtsp_state state, pa_headerlist* hl, void *userdata);
 
 pa_rtsp_context* pa_rtsp_context_new(const char* useragent);
 void pa_rtsp_context_free(pa_rtsp_context* c);
 
 int pa_rtsp_connect(pa_rtsp_context* c, pa_mainloop_api *mainloop, const char* hostname, uint16_t port);
+void pa_rtsp_set_callback(pa_rtsp_context *c, pa_rtsp_cb_t callback, void *userdata);
+
 void pa_rtsp_disconnect(pa_rtsp_context* c);
 
 const char* pa_rtsp_localip(pa_rtsp_context* c);
+uint32_t pa_rtsp_serverport(pa_rtsp_context* c);
 void pa_rtsp_set_url(pa_rtsp_context* c, const char* url);
+void pa_rtsp_add_header(pa_rtsp_context *c, const char* key, const char* value);
+void pa_rtsp_remove_header(pa_rtsp_context *c, const char* key);
+
 int pa_rtsp_announce(pa_rtsp_context* c, const char* sdp);
 
-int pa_rtsp_setup(pa_rtsp_context* c, pa_headerlist** response_headers);
+int pa_rtsp_setup(pa_rtsp_context* c);
 int pa_rtsp_record(pa_rtsp_context* c);
 int pa_rtsp_teardown(pa_rtsp_context* c);
 




More information about the pulseaudio-commits mailing list