LCOV - code coverage report
Current view: top level - gst-plugins-bad/ext/apexsink - gstapexraop.c (source / functions) Hit Total Coverage
Test: GStreamer Lines: 10 282 3.5 %
Date: 2011-03-25 Functions: 2 19 10.5 %
Branches: 2 88 2.3 %

           Branch data     Line data    Source code
       1                 :            : /* GStreamer - Remote Audio Access Protocol (RAOP) as used in Apple iTunes to stream music to the Airport Express (ApEx) -
       2                 :            :  *
       3                 :            :  * RAOP is based on the Real Time Streaming Protocol (RTSP) but with an extra challenge-response RSA based authentication step.
       4                 :            :  * This interface accepts RAW PCM data and set it as AES encrypted ALAC while performing emission.
       5                 :            :  *
       6                 :            :  * Copyright (C) 2008 Jérémie Bernard [GRemi] <gremimail@gmail.com>
       7                 :            :  *
       8                 :            :  * gstapexraop.c
       9                 :            :  *
      10                 :            :  * This library is free software; you can redistribute it and/or
      11                 :            :  * modify it under the terms of the GNU Library General Public
      12                 :            :  * License as published by the Free Software Foundation; either
      13                 :            :  * version 2 of the License, or (at your option) any later version.
      14                 :            :  *
      15                 :            :  * This library is distributed in the hope that it will be useful,
      16                 :            :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      17                 :            :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      18                 :            :  * Library General Public License for more details.
      19                 :            :  *
      20                 :            :  * You should have received a copy of the GNU Library General Public
      21                 :            :  * License along with this library; if not, write to the
      22                 :            :  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
      23                 :            :  * Boston, MA 02111-1307, USA.
      24                 :            :  *
      25                 :            :  */
      26                 :            : 
      27                 :            : #ifdef HAVE_CONFIG_H
      28                 :            : #include "config.h"
      29                 :            : #endif
      30                 :            : 
      31                 :            : #include <string.h>
      32                 :            : 
      33                 :            : #include "gstapexraop.h"
      34                 :            : 
      35                 :            : /* private constants */
      36                 :            : #define GST_APEX_RAOP_VOLUME_MIN  -144
      37                 :            : #define GST_APEX_RAOP_VOLUME_MAX     0
      38                 :            : 
      39                 :            : #define GST_APEX_RAOP_HDR_DEFAULT_LENGTH 1024
      40                 :            : #define GST_APEX_RAOP_SDP_DEFAULT_LENGTH 2048
      41                 :            : 
      42                 :            : const static gchar GST_APEX_RAOP_RSA_PUBLIC_MOD[] =
      43                 :            :     "59dE8qLieItsH1WgjrcFRKj6eUWqi+bGLOX1HL3U3GhC/j0Qg90u3sG/1CUtwC"
      44                 :            :     "5vOYvfDmFI6oSFXi5ELabWJmT2dKHzBJKa3k9ok+8t9ucRqMd6DZHJ2YCCLlDR"
      45                 :            :     "KSKv6kDqnw4UwPdpOMXziC/AMj3Z/lUVX1G7WSHCAWKf1zNS1eLvqr+boEjXuB"
      46                 :            :     "OitnZ/bDzPHrTOZz0Dew0uowxf/+sG+NCK3eQJVxqcaJ/vEHKIVd2M+5qL71yJ"
      47                 :            :     "Q+87X6oV3eaYvt3zWZYD6z5vYTcrtij2VZ9Zmni/UAaHqn9JdsBWLUEpVviYnh"
      48                 :            :     "imNVvYFZeCXg/IdTQ+x4IRdiXNv5hEew==";
      49                 :            : 
      50                 :            : const static gchar GST_APEX_RAOP_RSA_PUBLIC_EXP[] = "AQAB";
      51                 :            : 
      52                 :            : const static gchar GST_APEX_RAOP_USER_AGENT[] =
      53                 :            :     "iTunes/4.6 (Macintosh; U; PPC Mac OS X 10.3)";
      54                 :            : 
      55                 :            : const static guchar GST_APEX_RAOP_FRAME_HEADER[] = {
      56                 :            :   0x24, 0x00, 0x00, 0x00,
      57                 :            :   0xF0, 0xFF, 0x00, 0x00,
      58                 :            :   0x00, 0x00, 0x00, 0x00,
      59                 :            :   0x00, 0x00, 0x00, 0x00
      60                 :            : };
      61                 :            : 
      62                 :            : const static int GST_APEX_RAOP_FRAME_HEADER_SIZE = 16;
      63                 :            : 
      64                 :            : const static int GST_APEX_RAOP_ALAC_HEADER_SIZE = 3;
      65                 :            : 
      66                 :            : /* string extra utility */
      67                 :            : static gint
      68                 :          0 : g_strdel (gchar * str, gchar rc)
      69                 :            : {
      70                 :          0 :   int i = 0, j = 0, len, num = 0;
      71                 :          0 :   len = strlen (str);
      72         [ #  # ]:          0 :   while (i < len) {
      73         [ #  # ]:          0 :     if (str[i] == rc) {
      74         [ #  # ]:          0 :       for (j = i; j < len; j++)
      75                 :          0 :         str[j] = str[j + 1];
      76                 :          0 :       len--;
      77                 :          0 :       num++;
      78                 :            :     } else {
      79                 :          0 :       i++;
      80                 :            :     }
      81                 :            :   }
      82                 :          0 :   return num;
      83                 :            : }
      84                 :            : 
      85                 :            : /* socket utilities */
      86                 :            : static int
      87                 :          0 : gst_apexraop_send (int desc, void *data, size_t len)
      88                 :            : {
      89                 :          0 :   int total = 0, bytesleft = len, n = 0;
      90                 :            : 
      91         [ #  # ]:          0 :   while (total < len) {
      92                 :          0 :     n = send (desc, ((const char *) data) + total, bytesleft, 0);
      93         [ #  # ]:          0 :     if (n == -1)
      94                 :          0 :       break;
      95                 :          0 :     total += n;
      96                 :          0 :     bytesleft -= n;
      97                 :            :   }
      98                 :            : 
      99         [ #  # ]:          0 :   return n == -1 ? -1 : total;
     100                 :            : }
     101                 :            : 
     102                 :            : static int
     103                 :          0 : gst_apexraop_recv (int desc, void *data, size_t len)
     104                 :            : {
     105                 :          0 :   memset (data, 0, len);
     106                 :          0 :   return recv (desc, data, len, 0);
     107                 :            : }
     108                 :            : 
     109                 :            : /* public opaque handle resolution */
     110                 :            : typedef struct
     111                 :            : {
     112                 :            :   guchar aes_ky[AES_BLOCK_SIZE];        /* AES random key */
     113                 :            :   guchar aes_iv[AES_BLOCK_SIZE];        /* AES random initial vector */
     114                 :            : 
     115                 :            :   guchar url_abspath[16];       /* header url random absolute path addon, ANNOUNCE id */
     116                 :            :   gint cseq;                    /* header rtsp inc cseq */
     117                 :            :   guchar cid[24];               /* header client instance id */
     118                 :            :   gchar *session;               /* header raop negotiated session id, once SETUP performed */
     119                 :            :   gchar *ua;                    /* header user agent */
     120                 :            : 
     121                 :            :   GstApExJackType jack_type;    /* APEX connected jack type, once ANNOUNCE performed */
     122                 :            :   GstApExJackStatus jack_status;        /* APEX connected jack status, once ANNOUNCE performed */
     123                 :            : 
     124                 :            :   gchar *host;                  /* APEX target ip */
     125                 :            :   guint ctrl_port;              /* APEX target control port */
     126                 :            :   guint data_port;              /* APEX negotiated data port, once SETUP performed */
     127                 :            : 
     128                 :            :   int ctrl_sd;                  /* control socket */
     129                 :            :   struct sockaddr_in ctrl_sd_in;
     130                 :            : 
     131                 :            :   int data_sd;                  /* data socket */
     132                 :            :   struct sockaddr_in data_sd_in;
     133                 :            : }
     134                 :            : _GstApExRAOP;
     135                 :            : 
     136                 :            : /* raop apex struct allocation */
     137                 :            : GstApExRAOP *
     138                 :          0 : gst_apexraop_new (const gchar * host, const guint16 port)
     139                 :            : {
     140                 :            :   _GstApExRAOP *apexraop;
     141                 :            : 
     142                 :          0 :   apexraop = (_GstApExRAOP *) g_malloc0 (sizeof (_GstApExRAOP));
     143                 :            : 
     144                 :          0 :   apexraop->host = g_strdup (host);
     145                 :          0 :   apexraop->ctrl_port = port;
     146                 :          0 :   apexraop->ua = g_strdup (GST_APEX_RAOP_USER_AGENT);
     147                 :          0 :   apexraop->jack_type = GST_APEX_JACK_TYPE_UNDEFINED;
     148                 :          0 :   apexraop->jack_status = GST_APEX_JACK_STATUS_DISCONNECTED;
     149                 :            : 
     150                 :          0 :   return (GstApExRAOP *) apexraop;
     151                 :            : }
     152                 :            : 
     153                 :            : /* raop apex struct freeing */
     154                 :            : void
     155                 :          0 : gst_apexraop_free (GstApExRAOP * con)
     156                 :            : {
     157                 :            :   _GstApExRAOP *conn;
     158                 :          0 :   conn = (_GstApExRAOP *) con;
     159                 :            : 
     160                 :          0 :   g_free (conn->host);
     161                 :          0 :   g_free (conn->session);
     162                 :          0 :   g_free (conn->ua);
     163                 :          0 :   g_free (conn);
     164                 :          0 : }
     165                 :            : 
     166                 :            : /* host affectation */
     167                 :            : void
     168                 :          0 : gst_apexraop_set_host (GstApExRAOP * con, const gchar * host)
     169                 :            : {
     170                 :            :   _GstApExRAOP *conn;
     171                 :          0 :   conn = (_GstApExRAOP *) con;
     172                 :            : 
     173                 :          0 :   g_free (conn->host);
     174                 :          0 :   conn->host = g_strdup (host);
     175                 :          0 : }
     176                 :            : 
     177                 :            : /* host reader */
     178                 :            : gchar *
     179                 :          0 : gst_apexraop_get_host (GstApExRAOP * con)
     180                 :            : {
     181                 :            :   _GstApExRAOP *conn;
     182                 :          0 :   conn = (_GstApExRAOP *) con;
     183                 :            : 
     184                 :          0 :   return g_strdup (conn->host);
     185                 :            : }
     186                 :            : 
     187                 :            : /* control port affectation */
     188                 :            : void
     189                 :          0 : gst_apexraop_set_port (GstApExRAOP * con, const guint16 port)
     190                 :            : {
     191                 :            :   _GstApExRAOP *conn;
     192                 :          0 :   conn = (_GstApExRAOP *) con;
     193                 :            : 
     194                 :          0 :   conn->ctrl_port = port;
     195                 :          0 : }
     196                 :            : 
     197                 :            : /* control port reader */
     198                 :            : guint16
     199                 :          0 : gst_apexraop_get_port (GstApExRAOP * con)
     200                 :            : {
     201                 :            :   _GstApExRAOP *conn;
     202                 :          0 :   conn = (_GstApExRAOP *) con;
     203                 :            : 
     204                 :          0 :   return conn->ctrl_port;
     205                 :            : }
     206                 :            : 
     207                 :            : /* user agent affectation */
     208                 :            : void
     209                 :          0 : gst_apexraop_set_useragent (GstApExRAOP * con, const gchar * useragent)
     210                 :            : {
     211                 :            :   _GstApExRAOP *conn;
     212                 :          0 :   conn = (_GstApExRAOP *) con;
     213                 :            : 
     214                 :          0 :   g_free (conn->ua);
     215                 :          0 :   conn->ua = g_strdup (useragent);
     216                 :          0 : }
     217                 :            : 
     218                 :            : /* user agent reader */
     219                 :            : gchar *
     220                 :          0 : gst_apexraop_get_useragent (GstApExRAOP * con)
     221                 :            : {
     222                 :            :   _GstApExRAOP *conn;
     223                 :          0 :   conn = (_GstApExRAOP *) con;
     224                 :            : 
     225                 :          0 :   return g_strdup (conn->ua);
     226                 :            : }
     227                 :            : 
     228                 :            : /* raop apex connection sequence */
     229                 :            : GstRTSPStatusCode
     230                 :          0 : gst_apexraop_connect (GstApExRAOP * con)
     231                 :            : {
     232                 :            :   gchar *ac, *ky, *iv, *s, inaddr[INET_ADDRSTRLEN],
     233                 :            :       creq[GST_APEX_RAOP_SDP_DEFAULT_LENGTH],
     234                 :            :       hreq[GST_APEX_RAOP_HDR_DEFAULT_LENGTH], *req;
     235                 :            :   RSA *rsa;
     236                 :            :   guchar *mod, *exp, rsakey[512];
     237                 :            :   union gst_randbytes
     238                 :            :   {
     239                 :            :     struct asvals
     240                 :            :     {
     241                 :            :       gulong url_key;
     242                 :            :       guint64 conn_id;
     243                 :            :       guchar challenge[16];
     244                 :            :     } v;
     245                 :            :     guchar buf[4 + 8 + 16];
     246                 :            :   } randbuf;
     247                 :            :   gsize size;
     248                 :            :   struct sockaddr_in ioaddr;
     249                 :            :   socklen_t iolen;
     250                 :            :   GstRTSPStatusCode res;
     251                 :            :   _GstApExRAOP *conn;
     252                 :            : 
     253                 :          0 :   conn = (_GstApExRAOP *) con;
     254                 :            : 
     255         [ #  # ]:          0 :   if ((conn->ctrl_sd = socket (AF_INET, SOCK_STREAM, 0)) < 0)
     256                 :          0 :     return GST_RTSP_STS_DESTINATION_UNREACHABLE;
     257                 :            : 
     258                 :          0 :   conn->ctrl_sd_in.sin_family = AF_INET;
     259                 :          0 :   conn->ctrl_sd_in.sin_port = htons (conn->ctrl_port);
     260                 :            : 
     261         [ #  # ]:          0 :   if (!inet_aton (conn->host, &conn->ctrl_sd_in.sin_addr)) {
     262                 :          0 :     struct hostent *hp = (struct hostent *) gethostbyname (conn->host);
     263         [ #  # ]:          0 :     if (hp == NULL)
     264                 :          0 :       return GST_RTSP_STS_DESTINATION_UNREACHABLE;
     265                 :          0 :     memcpy (&conn->ctrl_sd_in.sin_addr, hp->h_addr, hp->h_length);
     266                 :            :   }
     267                 :            : 
     268         [ #  # ]:          0 :   if (connect (conn->ctrl_sd, (struct sockaddr *) &conn->ctrl_sd_in,
     269                 :            :           sizeof (conn->ctrl_sd_in)) < 0)
     270                 :          0 :     return GST_RTSP_STS_DESTINATION_UNREACHABLE;
     271                 :            : 
     272                 :          0 :   RAND_bytes (randbuf.buf, sizeof (randbuf));
     273                 :          0 :   sprintf ((gchar *) conn->url_abspath, "%lu", randbuf.v.url_key);
     274                 :          0 :   sprintf ((char *) conn->cid, "%16" G_GINT64_MODIFIER "x", randbuf.v.conn_id);
     275                 :            : 
     276                 :          0 :   RAND_bytes (conn->aes_ky, AES_BLOCK_SIZE);
     277                 :          0 :   RAND_bytes (conn->aes_iv, AES_BLOCK_SIZE);
     278                 :            : 
     279                 :          0 :   rsa = RSA_new ();
     280                 :          0 :   mod = g_base64_decode (GST_APEX_RAOP_RSA_PUBLIC_MOD, &size);
     281                 :          0 :   rsa->n = BN_bin2bn (mod, size, NULL);
     282                 :          0 :   exp = g_base64_decode (GST_APEX_RAOP_RSA_PUBLIC_EXP, &size);
     283                 :          0 :   rsa->e = BN_bin2bn (exp, size, NULL);
     284                 :          0 :   size =
     285                 :          0 :       RSA_public_encrypt (AES_BLOCK_SIZE, conn->aes_ky, rsakey, rsa,
     286                 :            :       RSA_PKCS1_OAEP_PADDING);
     287                 :            : 
     288                 :          0 :   ky = g_base64_encode (rsakey, size);
     289                 :          0 :   iv = g_base64_encode (conn->aes_iv, AES_BLOCK_SIZE);
     290                 :          0 :   g_strdel (ky, '=');
     291                 :          0 :   g_strdel (iv, '=');
     292                 :            : 
     293                 :          0 :   iolen = sizeof (struct sockaddr);
     294                 :          0 :   getsockname (conn->ctrl_sd, (struct sockaddr *) &ioaddr, &iolen);
     295                 :          0 :   inet_ntop (AF_INET, &(ioaddr.sin_addr), inaddr, INET_ADDRSTRLEN);
     296                 :            : 
     297                 :          0 :   ac = g_base64_encode (randbuf.v.challenge, 16);
     298                 :          0 :   g_strdel (ac, '=');
     299                 :            : 
     300                 :          0 :   sprintf (creq,
     301                 :            :       "v=0\r\n"
     302                 :            :       "o=iTunes %s 0 IN IP4 %s\r\n"
     303                 :            :       "s=iTunes\r\n"
     304                 :            :       "c=IN IP4 %s\r\n"
     305                 :            :       "t=0 0\r\n"
     306                 :            :       "m=audio 0 RTP/AVP 96\r\n"
     307                 :            :       "a=rtpmap:96 AppleLossless\r\n"
     308                 :            :       "a=fmtp:96 %d 0 %d 40 10 14 %d 255 0 0 %d\r\n"
     309                 :            :       "a=rsaaeskey:%s\r\n"
     310                 :            :       "a=aesiv:%s\r\n",
     311                 :          0 :       conn->url_abspath,
     312                 :            :       inaddr,
     313                 :            :       conn->host,
     314                 :            :       GST_APEX_RAOP_SAMPLES_PER_FRAME,
     315                 :            :       GST_APEX_RAOP_BYTES_PER_CHANNEL * 8,
     316                 :            :       GST_APEX_RAOP_CHANNELS, GST_APEX_RAOP_BITRATE, ky, iv);
     317                 :            : 
     318                 :          0 :   sprintf (hreq,
     319                 :            :       "ANNOUNCE rtsp://%s/%s RTSP/1.0\r\n"
     320                 :            :       "CSeq: %d\r\n"
     321                 :            :       "Client-Instance: %s\r\n"
     322                 :            :       "User-Agent: %s\r\n"
     323                 :            :       "Content-Type: application/sdp\r\n"
     324                 :            :       "Content-Length: %u\r\n"
     325                 :            :       "Apple-Challenge: %s\r\n",
     326                 :            :       conn->host,
     327                 :          0 :       conn->url_abspath, ++conn->cseq, conn->cid, conn->ua,
     328                 :          0 :       (guint) strlen (creq), ac);
     329                 :            : 
     330                 :          0 :   RSA_free (rsa);
     331                 :          0 :   g_free (ky);
     332                 :          0 :   g_free (iv);
     333                 :          0 :   g_free (ac);
     334                 :          0 :   g_free (mod);
     335                 :          0 :   g_free (exp);
     336                 :            : 
     337                 :          0 :   req = g_strconcat (hreq, "\r\n", creq, NULL);
     338                 :            : 
     339         [ #  # ]:          0 :   if (gst_apexraop_send (conn->ctrl_sd, req, strlen (req)) <= 0) {
     340                 :          0 :     g_free (req);
     341                 :          0 :     return GST_RTSP_STS_GONE;
     342                 :            :   }
     343                 :            : 
     344                 :          0 :   g_free (req);
     345                 :            : 
     346         [ #  # ]:          0 :   if (gst_apexraop_recv (conn->ctrl_sd, hreq,
     347                 :            :           GST_APEX_RAOP_HDR_DEFAULT_LENGTH) <= 0)
     348                 :          0 :     return GST_RTSP_STS_GONE;
     349                 :            : 
     350                 :            :   {
     351                 :            :     int tmp;
     352                 :          0 :     sscanf (hreq, "%*s %d", &tmp);
     353                 :          0 :     res = (GstRTSPStatusCode) tmp;
     354                 :            :   }
     355                 :            : 
     356         [ #  # ]:          0 :   if (res != GST_RTSP_STS_OK)
     357                 :          0 :     return res;
     358                 :            : 
     359                 :          0 :   s = g_strrstr (hreq, "Audio-Jack-Status");
     360                 :            : 
     361         [ #  # ]:          0 :   if (s != NULL) {
     362                 :            :     gchar status[128];
     363                 :          0 :     sscanf (s, "%*s %s", status);
     364                 :            : 
     365         [ #  # ]:          0 :     if (strcmp (status, "connected;") == 0)
     366                 :          0 :       conn->jack_status = GST_APEX_JACK_STATUS_CONNECTED;
     367         [ #  # ]:          0 :     else if (strcmp (status, "disconnected;") == 0)
     368                 :          0 :       conn->jack_status = GST_APEX_JACK_STATUS_DISCONNECTED;
     369                 :            :     else
     370                 :          0 :       conn->jack_status = GST_APEX_JACK_STATUS_UNDEFINED;
     371                 :            : 
     372                 :          0 :     s = g_strrstr (s, "type=");
     373                 :            : 
     374         [ #  # ]:          0 :     if (s != NULL) {
     375                 :          0 :       strtok (s, "=");
     376                 :          0 :       s = strtok (NULL, "\n");
     377                 :            : 
     378         [ #  # ]:          0 :       if (strcmp (s, "analog"))
     379                 :          0 :         conn->jack_type = GST_APEX_JACK_TYPE_ANALOG;
     380         [ #  # ]:          0 :       else if (strcmp (s, "digital"))
     381                 :          0 :         conn->jack_type = GST_APEX_JACK_TYPE_DIGITAL;
     382                 :            :       else
     383                 :          0 :         conn->jack_type = GST_APEX_JACK_TYPE_UNDEFINED;
     384                 :            :     }
     385                 :            :   }
     386                 :            : 
     387                 :          0 :   sprintf (hreq,
     388                 :            :       "SETUP rtsp://%s/%s RTSP/1.0\r\n"
     389                 :            :       "CSeq: %d\r\n"
     390                 :            :       "Client-Instance: %s\r\n"
     391                 :            :       "User-Agent: %s\r\n"
     392                 :            :       "Transport: RTP/AVP/TCP;unicast;interleaved=0-1;mode=record\r\n"
     393                 :          0 :       "\r\n", conn->host, conn->url_abspath, ++conn->cseq, conn->cid, conn->ua);
     394                 :            : 
     395         [ #  # ]:          0 :   if (gst_apexraop_send (conn->ctrl_sd, hreq, strlen (hreq)) <= 0)
     396                 :          0 :     return GST_RTSP_STS_GONE;
     397                 :            : 
     398         [ #  # ]:          0 :   if (gst_apexraop_recv (conn->ctrl_sd, hreq,
     399                 :            :           GST_APEX_RAOP_HDR_DEFAULT_LENGTH) <= 0)
     400                 :          0 :     return GST_RTSP_STS_GONE;
     401                 :            : 
     402                 :            :   {
     403                 :            :     int tmp;
     404                 :          0 :     sscanf (hreq, "%*s %d", &tmp);
     405                 :          0 :     res = (GstRTSPStatusCode) tmp;
     406                 :            :   }
     407                 :            : 
     408         [ #  # ]:          0 :   if (res != GST_RTSP_STS_OK)
     409                 :          0 :     return res;
     410                 :            : 
     411                 :          0 :   s = g_strrstr (hreq, "Session");
     412                 :            : 
     413         [ #  # ]:          0 :   if (s != NULL) {
     414                 :            :     gchar session[128];
     415                 :          0 :     sscanf (s, "%*s %s", session);
     416                 :          0 :     conn->session = g_strdup (session);
     417                 :            :   } else
     418                 :          0 :     return GST_RTSP_STS_PRECONDITION_FAILED;
     419                 :            : 
     420                 :          0 :   s = g_strrstr (hreq, "server_port");
     421         [ #  # ]:          0 :   if (s != NULL) {
     422                 :          0 :     sscanf (s, "server_port=%d", &conn->data_port);
     423                 :            :   } else
     424                 :          0 :     return GST_RTSP_STS_PRECONDITION_FAILED;
     425                 :            : 
     426                 :          0 :   sprintf (hreq,
     427                 :            :       "RECORD rtsp://%s/%s RTSP/1.0\r\n"
     428                 :            :       "CSeq: %d\r\n"
     429                 :            :       "Client-Instance: %s\r\n"
     430                 :            :       "User-Agent: %s\r\n"
     431                 :            :       "Session: %s\r\n"
     432                 :            :       "Range: npt=0-\r\n"
     433                 :            :       "RTP-Info: seq=0;rtptime=0\r\n"
     434                 :            :       "\r\n",
     435                 :            :       conn->host,
     436                 :          0 :       conn->url_abspath, ++conn->cseq, conn->cid, conn->ua, conn->session);
     437                 :            : 
     438         [ #  # ]:          0 :   if (gst_apexraop_send (conn->ctrl_sd, hreq, strlen (hreq)) <= 0)
     439                 :          0 :     return GST_RTSP_STS_GONE;
     440                 :            : 
     441         [ #  # ]:          0 :   if (gst_apexraop_recv (conn->ctrl_sd, hreq,
     442                 :            :           GST_APEX_RAOP_HDR_DEFAULT_LENGTH) <= 0)
     443                 :          0 :     return GST_RTSP_STS_GONE;
     444                 :            : 
     445                 :            :   {
     446                 :            :     int tmp;
     447                 :          0 :     sscanf (hreq, "%*s %d", &tmp);
     448                 :          0 :     res = (GstRTSPStatusCode) tmp;
     449                 :            :   }
     450                 :            : 
     451         [ #  # ]:          0 :   if (res != GST_RTSP_STS_OK)
     452                 :          0 :     return res;
     453                 :            : 
     454         [ #  # ]:          0 :   if ((conn->data_sd = socket (AF_INET, SOCK_STREAM, 0)) < 0)
     455                 :          0 :     return GST_RTSP_STS_DESTINATION_UNREACHABLE;
     456                 :            : 
     457                 :          0 :   conn->data_sd_in.sin_family = AF_INET;
     458                 :          0 :   conn->data_sd_in.sin_port = htons (conn->data_port);
     459                 :            : 
     460                 :          0 :   memcpy (&conn->data_sd_in.sin_addr, &conn->ctrl_sd_in.sin_addr,
     461                 :            :       sizeof (conn->ctrl_sd_in.sin_addr));
     462                 :            : 
     463         [ #  # ]:          0 :   if (connect (conn->data_sd, (struct sockaddr *) &conn->data_sd_in,
     464                 :            :           sizeof (conn->data_sd_in)) < 0)
     465                 :          0 :     return GST_RTSP_STS_DESTINATION_UNREACHABLE;
     466                 :            : 
     467                 :          0 :   return res;
     468                 :            : }
     469                 :            : 
     470                 :            : /* raop apex jack type access */
     471                 :            : GstApExJackType
     472                 :          1 : gst_apexraop_get_jacktype (GstApExRAOP * con)
     473                 :            : {
     474                 :            :   _GstApExRAOP *conn;
     475                 :            : 
     476                 :          1 :   conn = (_GstApExRAOP *) con;
     477                 :            : 
     478         [ +  - ]:          1 :   if (!conn)
     479                 :          1 :     return GST_APEX_JACK_TYPE_UNDEFINED;
     480                 :            : 
     481                 :          1 :   return conn->jack_type;
     482                 :            : }
     483                 :            : 
     484                 :            : /* raop apex jack status access */
     485                 :            : GstApExJackStatus
     486                 :          1 : gst_apexraop_get_jackstatus (GstApExRAOP * con)
     487                 :            : {
     488                 :            :   _GstApExRAOP *conn;
     489                 :            : 
     490                 :          1 :   conn = (_GstApExRAOP *) con;
     491                 :            : 
     492         [ +  - ]:          1 :   if (!conn)
     493                 :          1 :     return GST_APEX_JACK_STATUS_UNDEFINED;
     494                 :            : 
     495                 :          1 :   return conn->jack_status;
     496                 :            : }
     497                 :            : 
     498                 :            : /* raop apex sockets close */
     499                 :            : void
     500                 :          0 : gst_apexraop_close (GstApExRAOP * con)
     501                 :            : {
     502                 :            :   gchar hreq[GST_APEX_RAOP_HDR_DEFAULT_LENGTH];
     503                 :            :   _GstApExRAOP *conn;
     504                 :            : 
     505                 :          0 :   conn = (_GstApExRAOP *) con;
     506                 :            : 
     507                 :          0 :   sprintf (hreq,
     508                 :            :       "TEARDOWN rtsp://%s/%s RTSP/1.0\r\n"
     509                 :            :       "CSeq: %d\r\n"
     510                 :            :       "Client-Instance: %s\r\n"
     511                 :            :       "User-Agent: %s\r\n"
     512                 :            :       "Session: %s\r\n"
     513                 :            :       "\r\n",
     514                 :            :       conn->host,
     515                 :          0 :       conn->url_abspath, ++conn->cseq, conn->cid, conn->ua, conn->session);
     516                 :            : 
     517                 :          0 :   gst_apexraop_send (conn->ctrl_sd, hreq, strlen (hreq));
     518                 :          0 :   gst_apexraop_recv (conn->ctrl_sd, hreq, GST_APEX_RAOP_HDR_DEFAULT_LENGTH);
     519                 :            : 
     520         [ #  # ]:          0 :   if (conn->ctrl_sd != 0)
     521                 :          0 :     close (conn->ctrl_sd);
     522         [ #  # ]:          0 :   if (conn->data_sd != 0)
     523                 :          0 :     close (conn->data_sd);
     524                 :          0 : }
     525                 :            : 
     526                 :            : /* raop apex volume set */
     527                 :            : GstRTSPStatusCode
     528                 :          0 : gst_apexraop_set_volume (GstApExRAOP * con, const guint volume)
     529                 :            : {
     530                 :            :   gint v;
     531                 :            :   gchar creq[GST_APEX_RAOP_SDP_DEFAULT_LENGTH],
     532                 :            :       hreq[GST_APEX_RAOP_HDR_DEFAULT_LENGTH], *req, vol[128];
     533                 :            :   GstRTSPStatusCode res;
     534                 :            :   _GstApExRAOP *conn;
     535                 :            : 
     536                 :          0 :   conn = (_GstApExRAOP *) con;
     537                 :            : 
     538                 :          0 :   v = GST_APEX_RAOP_VOLUME_MIN + (GST_APEX_RAOP_VOLUME_MAX -
     539                 :          0 :       GST_APEX_RAOP_VOLUME_MIN) * volume / 100.;
     540                 :          0 :   sprintf (vol, "volume: %d.000000\r\n", v);
     541                 :            : 
     542                 :          0 :   sprintf (creq, "%s\r\n", vol);
     543                 :            : 
     544                 :          0 :   sprintf (hreq,
     545                 :            :       "SET_PARAMETER rtsp://%s/%s RTSP/1.0\r\n"
     546                 :            :       "CSeq: %d\r\n"
     547                 :            :       "Client-Instance: %s\r\n"
     548                 :            :       "User-Agent: %s\r\n"
     549                 :            :       "Session: %s\r\n"
     550                 :            :       "Content-Type: text/parameters\r\n"
     551                 :            :       "Content-Length: %u\r\n",
     552                 :            :       conn->host,
     553                 :          0 :       conn->url_abspath,
     554                 :          0 :       ++conn->cseq, conn->cid, conn->ua, conn->session, (guint) strlen (creq)
     555                 :            :       );
     556                 :            : 
     557                 :          0 :   req = g_strconcat (hreq, "\r\n", creq, NULL);
     558                 :            : 
     559         [ #  # ]:          0 :   if (gst_apexraop_send (conn->ctrl_sd, req, strlen (req)) <= 0) {
     560                 :          0 :     g_free (req);
     561                 :          0 :     return GST_RTSP_STS_GONE;
     562                 :            :   }
     563                 :            : 
     564                 :          0 :   g_free (req);
     565                 :            : 
     566         [ #  # ]:          0 :   if (gst_apexraop_recv (conn->ctrl_sd, hreq,
     567                 :            :           GST_APEX_RAOP_HDR_DEFAULT_LENGTH) <= 0)
     568                 :          0 :     return GST_RTSP_STS_GONE;
     569                 :            : 
     570                 :            :   {
     571                 :            :     int tmp;
     572                 :          0 :     sscanf (hreq, "%*s %d", &tmp);
     573                 :          0 :     res = (GstRTSPStatusCode) tmp;
     574                 :            :   }
     575                 :            : 
     576                 :          0 :   return res;
     577                 :            : }
     578                 :            : 
     579                 :            : /* raop apex raw data alac encapsulation, encryption and emission, http://wiki.multimedia.cx/index.php?title=Apple_Lossless_Audio_Coding */
     580                 :            : static void inline
     581                 :          0 : gst_apexraop_write_bits (guchar * buffer, int data, int numbits,
     582                 :            :     int *bit_offset, int *byte_offset)
     583                 :            : {
     584                 :            :   const static guchar masks[] =
     585                 :            :       { 0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3F, 0x7F, 0xFF };
     586                 :            : 
     587 [ #  # ][ #  # ]:          0 :   if (((*bit_offset) != 0) && (((*bit_offset) + numbits) > 8)) {
     588                 :            :     gint numwritebits;
     589                 :            :     guchar bitstowrite;
     590                 :            : 
     591                 :          0 :     numwritebits = 8 - (*bit_offset);
     592                 :          0 :     bitstowrite =
     593                 :          0 :         (guchar) ((data >> (numbits - numwritebits)) << (8 - (*bit_offset) -
     594                 :            :             numwritebits));
     595                 :          0 :     buffer[(*byte_offset)] |= bitstowrite;
     596                 :          0 :     numbits -= numwritebits;
     597                 :          0 :     (*bit_offset) = 0;
     598                 :          0 :     (*byte_offset)++;
     599                 :            :   }
     600                 :            : 
     601         [ #  # ]:          0 :   while (numbits >= 8) {
     602                 :            :     guchar bitstowrite;
     603                 :            : 
     604                 :          0 :     bitstowrite = (guchar) ((data >> (numbits - 8)) & 0xFF);
     605                 :          0 :     buffer[(*byte_offset)] |= bitstowrite;
     606                 :          0 :     numbits -= 8;
     607                 :          0 :     (*bit_offset) = 0;
     608                 :          0 :     (*byte_offset)++;
     609                 :            :   }
     610                 :            : 
     611         [ #  # ]:          0 :   if (numbits > 0) {
     612                 :            :     guchar bitstowrite;
     613                 :          0 :     bitstowrite =
     614                 :          0 :         (guchar) ((data & masks[numbits]) << (8 - (*bit_offset) - numbits));
     615                 :          0 :     buffer[(*byte_offset)] |= bitstowrite;
     616                 :          0 :     (*bit_offset) += numbits;
     617         [ #  # ]:          0 :     if ((*bit_offset) == 8) {
     618                 :          0 :       (*byte_offset)++;
     619                 :          0 :       (*bit_offset) = 0;
     620                 :            :     }
     621                 :            :   }
     622                 :          0 : }
     623                 :            : 
     624                 :            : guint
     625                 :          0 : gst_apexraop_write (GstApExRAOP * con, gpointer rawdata, guint length)
     626                 :            : {
     627                 :            :   guchar *buffer, *frame_data;
     628                 :            :   gushort len;
     629                 :            :   gint bit_offset, byte_offset, i, out_len, res;
     630                 :            :   EVP_CIPHER_CTX aes_ctx;
     631                 :            :   _GstApExRAOP *conn;
     632                 :            : 
     633                 :          0 :   conn = (_GstApExRAOP *) con;
     634                 :            : 
     635                 :          0 :   buffer =
     636                 :          0 :       (guchar *) g_malloc0 (GST_APEX_RAOP_FRAME_HEADER_SIZE +
     637                 :          0 :       GST_APEX_RAOP_ALAC_HEADER_SIZE + length);
     638                 :            : 
     639                 :          0 :   memcpy (buffer, GST_APEX_RAOP_FRAME_HEADER, GST_APEX_RAOP_FRAME_HEADER_SIZE);
     640                 :            : 
     641                 :          0 :   len =
     642                 :            :       length + GST_APEX_RAOP_FRAME_HEADER_SIZE +
     643                 :            :       GST_APEX_RAOP_ALAC_HEADER_SIZE - 4;
     644                 :          0 :   buffer[2] = len >> 8;
     645                 :          0 :   buffer[3] = len & 0xff;
     646                 :            : 
     647                 :          0 :   bit_offset = 0;
     648                 :          0 :   byte_offset = 0;
     649                 :          0 :   frame_data = buffer + GST_APEX_RAOP_FRAME_HEADER_SIZE;
     650                 :            : 
     651                 :          0 :   gst_apexraop_write_bits (frame_data, 1, 3, &bit_offset, &byte_offset);        /* channels, 0 mono, 1 stereo */
     652                 :          0 :   gst_apexraop_write_bits (frame_data, 0, 4, &bit_offset, &byte_offset);        /* unknown */
     653                 :          0 :   gst_apexraop_write_bits (frame_data, 0, 8, &bit_offset, &byte_offset);        /* unknown (12 bits) */
     654                 :          0 :   gst_apexraop_write_bits (frame_data, 0, 4, &bit_offset, &byte_offset);
     655                 :          0 :   gst_apexraop_write_bits (frame_data, 0, 1, &bit_offset, &byte_offset);        /* has size flag */
     656                 :          0 :   gst_apexraop_write_bits (frame_data, 0, 2, &bit_offset, &byte_offset);        /* unknown */
     657                 :          0 :   gst_apexraop_write_bits (frame_data, 1, 1, &bit_offset, &byte_offset);        /* no compression flag */
     658                 :            : 
     659         [ #  # ]:          0 :   for (i = 0; i < length; i += 2) {
     660                 :          0 :     gst_apexraop_write_bits (frame_data, ((guchar *) rawdata)[i + 1], 8,
     661                 :            :         &bit_offset, &byte_offset);
     662                 :          0 :     gst_apexraop_write_bits (frame_data, ((guchar *) rawdata)[i], 8,
     663                 :            :         &bit_offset, &byte_offset);
     664                 :            :   }
     665                 :            : 
     666                 :          0 :   EVP_CIPHER_CTX_init (&aes_ctx);
     667                 :          0 :   EVP_CipherInit_ex (&aes_ctx, EVP_aes_128_cbc (), NULL, conn->aes_ky,
     668                 :          0 :       conn->aes_iv, AES_ENCRYPT);
     669                 :          0 :   EVP_CipherUpdate (&aes_ctx, frame_data, &out_len, frame_data, /*( */
     670                 :          0 :       GST_APEX_RAOP_ALAC_HEADER_SIZE +
     671                 :            :       length /*) / AES_BLOCK_SIZE * AES_BLOCK_SIZE */ );
     672                 :          0 :   EVP_CIPHER_CTX_cleanup (&aes_ctx);
     673                 :            : 
     674                 :          0 :   res =
     675                 :          0 :       gst_apexraop_send (conn->data_sd, buffer,
     676                 :          0 :       GST_APEX_RAOP_FRAME_HEADER_SIZE + GST_APEX_RAOP_ALAC_HEADER_SIZE +
     677                 :            :       length);
     678                 :            : 
     679                 :          0 :   g_free (buffer);
     680                 :            : 
     681         [ #  # ]:          0 :   return (guint) ((res >=
     682                 :          0 :           (GST_APEX_RAOP_FRAME_HEADER_SIZE +
     683                 :          0 :               GST_APEX_RAOP_ALAC_HEADER_SIZE)) ? (res -
     684                 :          0 :           GST_APEX_RAOP_FRAME_HEADER_SIZE -
     685                 :            :           GST_APEX_RAOP_ALAC_HEADER_SIZE) : 0);
     686                 :            : }
     687                 :            : 
     688                 :            : /* raop apex buffer flush */
     689                 :            : GstRTSPStatusCode
     690                 :          0 : gst_apexraop_flush (GstApExRAOP * con)
     691                 :            : {
     692                 :            :   gchar hreq[GST_APEX_RAOP_HDR_DEFAULT_LENGTH];
     693                 :            :   GstRTSPStatusCode res;
     694                 :            :   _GstApExRAOP *conn;
     695                 :            : 
     696                 :          0 :   conn = (_GstApExRAOP *) con;
     697                 :            : 
     698                 :          0 :   sprintf (hreq,
     699                 :            :       "FLUSH rtsp://%s/%s RTSP/1.0\r\n"
     700                 :            :       "CSeq: %d\r\n"
     701                 :            :       "Client-Instance: %s\r\n"
     702                 :            :       "User-Agent: %s\r\n"
     703                 :            :       "Session: %s\r\n"
     704                 :            :       "RTP-Info: seq=0;rtptime=0\r\n"
     705                 :            :       "\r\n",
     706                 :            :       conn->host,
     707                 :          0 :       conn->url_abspath, ++conn->cseq, conn->cid, conn->ua, conn->session);
     708                 :            : 
     709         [ #  # ]:          0 :   if (gst_apexraop_send (conn->ctrl_sd, hreq, strlen (hreq)) <= 0)
     710                 :          0 :     return GST_RTSP_STS_GONE;
     711                 :            : 
     712         [ #  # ]:          0 :   if (gst_apexraop_recv (conn->ctrl_sd, hreq,
     713                 :            :           GST_APEX_RAOP_HDR_DEFAULT_LENGTH) <= 0)
     714                 :          0 :     return GST_RTSP_STS_GONE;
     715                 :            : 
     716                 :            :   {
     717                 :            :     int tmp;
     718                 :          0 :     sscanf (hreq, "%*s %d", &tmp);
     719                 :          0 :     res = (GstRTSPStatusCode) tmp;
     720                 :            :   }
     721                 :            : 
     722                 :          0 :   return res;
     723                 :            : }

Generated by: LCOV version 1.9