summaryrefslogtreecommitdiff
path: root/ext/apexsink/gstapexraop.c
diff options
context:
space:
mode:
Diffstat (limited to 'ext/apexsink/gstapexraop.c')
-rw-r--r--ext/apexsink/gstapexraop.c798
1 files changed, 0 insertions, 798 deletions
diff --git a/ext/apexsink/gstapexraop.c b/ext/apexsink/gstapexraop.c
deleted file mode 100644
index af4f573c0..000000000
--- a/ext/apexsink/gstapexraop.c
+++ /dev/null
@@ -1,798 +0,0 @@
-/* GStreamer - Remote Audio Access Protocol (RAOP) as used in Apple iTunes to stream music to the Airport Express (ApEx) -
- *
- * RAOP is based on the Real Time Streaming Protocol (RTSP) but with an extra challenge-response RSA based authentication step.
- * This interface accepts RAW PCM data and set it as AES encrypted ALAC while performing emission.
- *
- * Copyright (C) 2008 Jérémie Bernard [GRemi] <gremimail@gmail.com>
- *
- * gstapexraop.c
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
- * Boston, MA 02110-1301, USA.
- *
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include <string.h>
-
-#include "gstapexraop.h"
-
-/* private constants */
-#define GST_APEX_RAOP_VOLUME_MIN -144
-#define GST_APEX_RAOP_VOLUME_MAX 0
-
-#define GST_APEX_RAOP_HDR_DEFAULT_LENGTH 1024
-#define GST_APEX_RAOP_SDP_DEFAULT_LENGTH 2048
-
-const static gchar GST_APEX_RAOP_RSA_PUBLIC_MOD[] =
- "59dE8qLieItsH1WgjrcFRKj6eUWqi+bGLOX1HL3U3GhC/j0Qg90u3sG/1CUtwC"
- "5vOYvfDmFI6oSFXi5ELabWJmT2dKHzBJKa3k9ok+8t9ucRqMd6DZHJ2YCCLlDR"
- "KSKv6kDqnw4UwPdpOMXziC/AMj3Z/lUVX1G7WSHCAWKf1zNS1eLvqr+boEjXuB"
- "OitnZ/bDzPHrTOZz0Dew0uowxf/+sG+NCK3eQJVxqcaJ/vEHKIVd2M+5qL71yJ"
- "Q+87X6oV3eaYvt3zWZYD6z5vYTcrtij2VZ9Zmni/UAaHqn9JdsBWLUEpVviYnh"
- "imNVvYFZeCXg/IdTQ+x4IRdiXNv5hEew==";
-
-const static gchar GST_APEX_RAOP_RSA_PUBLIC_EXP[] = "AQAB";
-
-const static gchar GST_APEX_RAOP_USER_AGENT[] =
- "iTunes/4.6 (Macintosh; U; PPC Mac OS X 10.3)";
-
-const static guchar GST_APEX_RAOP_FRAME_HEADER[] = { // Used by gen. 1
- 0x24, 0x00, 0x00, 0x00,
- 0xF0, 0xFF, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00
-};
-
-const static int GST_APEX_RAOP_FRAME_HEADER_SIZE = 16; // Used by gen. 1
-const static int GST_APEX_RTP_FRAME_HEADER_SIZE = 12; // Used by gen. 2
-
-const static int GST_APEX_RAOP_ALAC_HEADER_SIZE = 3;
-
-/* string extra utility */
-static gint
-g_strdel (gchar * str, gchar rc)
-{
- int i = 0, j = 0, len, num = 0;
- len = strlen (str);
- while (i < len) {
- if (str[i] == rc) {
- for (j = i; j < len; j++)
- str[j] = str[j + 1];
- len--;
- num++;
- } else {
- i++;
- }
- }
- return num;
-}
-
-/* socket utilities */
-static int
-gst_apexraop_send (int desc, void *data, size_t len)
-{
- int total = 0, bytesleft = len, n = 0;
-
- while (total < len) {
- n = send (desc, ((const char *) data) + total, bytesleft, 0);
- if (n == -1)
- break;
- total += n;
- bytesleft -= n;
- }
-
- return n == -1 ? -1 : total;
-}
-
-static int
-gst_apexraop_recv (int desc, void *data, size_t len)
-{
- memset (data, 0, len);
- return recv (desc, data, len, 0);
-}
-
-/* public opaque handle resolution */
-typedef struct
-{
- guchar aes_ky[AES_BLOCK_SIZE]; /* AES random key */
- guchar aes_iv[AES_BLOCK_SIZE]; /* AES random initial vector */
-
- guchar url_abspath[16]; /* header url random absolute path addon, ANNOUNCE id */
- gint cseq; /* header rtsp inc cseq */
- guchar cid[24]; /* header client instance id */
- gchar *session; /* header raop negotiated session id, once SETUP performed */
- gchar *ua; /* header user agent */
-
- GstApExJackType jack_type; /* APEX connected jack type, once ANNOUNCE performed */
- GstApExJackStatus jack_status; /* APEX connected jack status, once ANNOUNCE performed */
-
- GstApExGeneration generation; /* Different devices accept different audio streams */
- GstApExTransportProtocol transport_protocol; /* For media stream, not RAOP/RTSP */
-
- gchar *host; /* APEX target ip */
- guint ctrl_port; /* APEX target control port */
- guint data_port; /* APEX negotiated data port, once SETUP performed */
-
- int ctrl_sd; /* control socket */
- struct sockaddr_in ctrl_sd_in;
-
- int data_sd; /* data socket */
- struct sockaddr_in data_sd_in;
-
- short rtp_seq_num; /* RTP sequence number, used by gen. 2 */
- int rtp_timestamp; /* RTP timestamp, used by gen. 2 */
-}
-_GstApExRAOP;
-
-/* raop apex struct allocation */
-GstApExRAOP *
-gst_apexraop_new (const gchar * host,
- const guint16 port,
- const GstApExGeneration generation,
- const GstApExTransportProtocol transport_protocol)
-{
- _GstApExRAOP *apexraop;
-
- apexraop = (_GstApExRAOP *) g_malloc0 (sizeof (_GstApExRAOP));
-
- apexraop->host = g_strdup (host);
- apexraop->ctrl_port = port;
- apexraop->ua = g_strdup (GST_APEX_RAOP_USER_AGENT);
- apexraop->jack_type = GST_APEX_JACK_TYPE_UNDEFINED;
- apexraop->jack_status = GST_APEX_JACK_STATUS_DISCONNECTED;
- apexraop->generation = generation;
- apexraop->transport_protocol = transport_protocol;
- apexraop->rtp_seq_num = 0;
- apexraop->rtp_timestamp = 0;
-
- return (GstApExRAOP *) apexraop;
-}
-
-/* raop apex struct freeing */
-void
-gst_apexraop_free (GstApExRAOP * con)
-{
- _GstApExRAOP *conn;
- conn = (_GstApExRAOP *) con;
-
- g_free (conn->host);
- g_free (conn->session);
- g_free (conn->ua);
- g_free (conn);
-}
-
-/* host affectation */
-void
-gst_apexraop_set_host (GstApExRAOP * con, const gchar * host)
-{
- _GstApExRAOP *conn;
- conn = (_GstApExRAOP *) con;
-
- g_free (conn->host);
- conn->host = g_strdup (host);
-}
-
-/* host reader */
-gchar *
-gst_apexraop_get_host (GstApExRAOP * con)
-{
- _GstApExRAOP *conn;
- conn = (_GstApExRAOP *) con;
-
- return g_strdup (conn->host);
-}
-
-/* control port affectation */
-void
-gst_apexraop_set_port (GstApExRAOP * con, const guint16 port)
-{
- _GstApExRAOP *conn;
- conn = (_GstApExRAOP *) con;
-
- conn->ctrl_port = port;
-}
-
-/* control port reader */
-guint16
-gst_apexraop_get_port (GstApExRAOP * con)
-{
- _GstApExRAOP *conn;
- conn = (_GstApExRAOP *) con;
-
- return conn->ctrl_port;
-}
-
-/* user agent affectation */
-void
-gst_apexraop_set_useragent (GstApExRAOP * con, const gchar * useragent)
-{
- _GstApExRAOP *conn;
- conn = (_GstApExRAOP *) con;
-
- g_free (conn->ua);
- conn->ua = g_strdup (useragent);
-}
-
-/* user agent reader */
-gchar *
-gst_apexraop_get_useragent (GstApExRAOP * con)
-{
- _GstApExRAOP *conn;
- conn = (_GstApExRAOP *) con;
-
- return g_strdup (conn->ua);
-}
-
-/* raop apex connection sequence */
-GstRTSPStatusCode
-gst_apexraop_connect (GstApExRAOP * con)
-{
- gchar *ac, *ky, *iv, *s, inaddr[INET_ADDRSTRLEN],
- creq[GST_APEX_RAOP_SDP_DEFAULT_LENGTH],
- hreq[GST_APEX_RAOP_HDR_DEFAULT_LENGTH], *req;
- RSA *rsa;
- guchar *mod, *exp, rsakey[512];
- union gst_randbytes
- {
- struct asvals
- {
- guint32 url_key;
- guint64 conn_id;
- guchar challenge[16];
- } v;
- guchar buf[4 + 8 + 16];
- } randbuf;
- gsize size;
- struct sockaddr_in ioaddr;
- socklen_t iolen;
- GstRTSPStatusCode res;
- _GstApExRAOP *conn;
-
- conn = (_GstApExRAOP *) con;
-
- if ((conn->ctrl_sd = socket (AF_INET, SOCK_STREAM, 0)) < 0)
- return GST_RTSP_STS_DESTINATION_UNREACHABLE;
-
- conn->ctrl_sd_in.sin_family = AF_INET;
- conn->ctrl_sd_in.sin_port = htons (conn->ctrl_port);
-
- if (!inet_aton (conn->host, &conn->ctrl_sd_in.sin_addr)) {
- struct hostent *hp = (struct hostent *) gethostbyname (conn->host);
- if (hp == NULL)
- return GST_RTSP_STS_DESTINATION_UNREACHABLE;
- memcpy (&conn->ctrl_sd_in.sin_addr, hp->h_addr, hp->h_length);
- }
-
- if (connect (conn->ctrl_sd, (struct sockaddr *) &conn->ctrl_sd_in,
- sizeof (conn->ctrl_sd_in)) < 0)
- return GST_RTSP_STS_DESTINATION_UNREACHABLE;
-
- RAND_bytes (randbuf.buf, sizeof (randbuf));
- sprintf ((gchar *) conn->url_abspath, "%u", randbuf.v.url_key);
- sprintf ((char *) conn->cid, "%16" G_GINT64_MODIFIER "x", randbuf.v.conn_id);
-
- RAND_bytes (conn->aes_ky, AES_BLOCK_SIZE);
- RAND_bytes (conn->aes_iv, AES_BLOCK_SIZE);
-
- rsa = RSA_new ();
- mod = g_base64_decode (GST_APEX_RAOP_RSA_PUBLIC_MOD, &size);
- rsa->n = BN_bin2bn (mod, size, NULL);
- exp = g_base64_decode (GST_APEX_RAOP_RSA_PUBLIC_EXP, &size);
- rsa->e = BN_bin2bn (exp, size, NULL);
- size =
- RSA_public_encrypt (AES_BLOCK_SIZE, conn->aes_ky, rsakey, rsa,
- RSA_PKCS1_OAEP_PADDING);
-
- ky = g_base64_encode (rsakey, size);
- iv = g_base64_encode (conn->aes_iv, AES_BLOCK_SIZE);
- g_strdel (ky, '=');
- g_strdel (iv, '=');
-
- iolen = sizeof (struct sockaddr);
- getsockname (conn->ctrl_sd, (struct sockaddr *) &ioaddr, &iolen);
- inet_ntop (AF_INET, &(ioaddr.sin_addr), inaddr, INET_ADDRSTRLEN);
-
- ac = g_base64_encode (randbuf.v.challenge, 16);
- g_strdel (ac, '=');
-
- sprintf (creq,
- "v=0\r\n"
- "o=iTunes %s 0 IN IP4 %s\r\n"
- "s=iTunes\r\n"
- "c=IN IP4 %s\r\n"
- "t=0 0\r\n"
- "m=audio 0 RTP/AVP 96\r\n"
- "a=rtpmap:96 AppleLossless\r\n"
- "a=fmtp:96 %d 0 %d 40 10 14 %d 255 0 0 %d\r\n"
- "a=rsaaeskey:%s\r\n"
- "a=aesiv:%s\r\n",
- conn->url_abspath,
- inaddr,
- conn->host,
- conn->generation == GST_APEX_GENERATION_ONE
- ? GST_APEX_RAOP_V1_SAMPLES_PER_FRAME
- : GST_APEX_RAOP_V2_SAMPLES_PER_FRAME,
- GST_APEX_RAOP_BYTES_PER_CHANNEL * 8,
- GST_APEX_RAOP_CHANNELS, GST_APEX_RAOP_BITRATE, ky, iv);
-
- sprintf (hreq,
- "ANNOUNCE rtsp://%s/%s RTSP/1.0\r\n"
- "CSeq: %d\r\n"
- "Client-Instance: %s\r\n"
- "User-Agent: %s\r\n"
- "Content-Type: application/sdp\r\n"
- "Content-Length: %u\r\n"
- "Apple-Challenge: %s\r\n",
- conn->host,
- conn->url_abspath, ++conn->cseq, conn->cid, conn->ua,
- (guint) strlen (creq), ac);
-
- RSA_free (rsa);
- g_free (ky);
- g_free (iv);
- g_free (ac);
- g_free (mod);
- g_free (exp);
-
- req = g_strconcat (hreq, "\r\n", creq, NULL);
-
- if (gst_apexraop_send (conn->ctrl_sd, req, strlen (req)) <= 0) {
- g_free (req);
- return GST_RTSP_STS_GONE;
- }
-
- g_free (req);
-
- if (gst_apexraop_recv (conn->ctrl_sd, hreq,
- GST_APEX_RAOP_HDR_DEFAULT_LENGTH) <= 0)
- return GST_RTSP_STS_GONE;
-
- {
- int tmp;
- sscanf (hreq, "%*s %d", &tmp);
- res = (GstRTSPStatusCode) tmp;
- }
-
- if (res != GST_RTSP_STS_OK)
- return res;
-
- s = g_strrstr (hreq, "Audio-Jack-Status");
-
- if (s != NULL) {
- gchar status[128];
- sscanf (s, "%*s %s", status);
-
- if (strcmp (status, "connected;") == 0)
- conn->jack_status = GST_APEX_JACK_STATUS_CONNECTED;
- else if (strcmp (status, "disconnected;") == 0)
- conn->jack_status = GST_APEX_JACK_STATUS_DISCONNECTED;
- else
- conn->jack_status = GST_APEX_JACK_STATUS_UNDEFINED;
-
- s = g_strrstr (s, "type=");
-
- if (s != NULL) {
- strtok (s, "=");
- s = strtok (NULL, "\n");
-
- if (strcmp (s, "analog"))
- conn->jack_type = GST_APEX_JACK_TYPE_ANALOG;
- else if (strcmp (s, "digital"))
- conn->jack_type = GST_APEX_JACK_TYPE_DIGITAL;
- else
- conn->jack_type = GST_APEX_JACK_TYPE_UNDEFINED;
- }
- }
-
- sprintf (hreq,
- "SETUP rtsp://%s/%s RTSP/1.0\r\n"
- "CSeq: %d\r\n"
- "Client-Instance: %s\r\n"
- "User-Agent: %s\r\n"
- "Transport: RTP/AVP/TCP;unicast;interleaved=0-1;mode=record\r\n"
- "\r\n", conn->host, conn->url_abspath, ++conn->cseq, conn->cid, conn->ua);
-
- if (gst_apexraop_send (conn->ctrl_sd, hreq, strlen (hreq)) <= 0)
- return GST_RTSP_STS_GONE;
-
- if (gst_apexraop_recv (conn->ctrl_sd, hreq,
- GST_APEX_RAOP_HDR_DEFAULT_LENGTH) <= 0)
- return GST_RTSP_STS_GONE;
-
- {
- int tmp;
- sscanf (hreq, "%*s %d", &tmp);
- res = (GstRTSPStatusCode) tmp;
- }
-
- if (res != GST_RTSP_STS_OK)
- return res;
-
- s = g_strrstr (hreq, "Session");
-
- if (s != NULL) {
- gchar session[128];
- sscanf (s, "%*s %s", session);
- conn->session = g_strdup (session);
- } else
- return GST_RTSP_STS_PRECONDITION_FAILED;
-
- s = g_strrstr (hreq, "server_port");
- if (s != NULL) {
- sscanf (s, "server_port=%d", &conn->data_port);
- } else
- return GST_RTSP_STS_PRECONDITION_FAILED;
-
- sprintf (hreq,
- "RECORD rtsp://%s/%s RTSP/1.0\r\n"
- "CSeq: %d\r\n"
- "Client-Instance: %s\r\n"
- "User-Agent: %s\r\n"
- "Session: %s\r\n"
- "Range: npt=0-\r\n"
- "RTP-Info: seq=0;rtptime=0\r\n"
- "\r\n",
- conn->host,
- conn->url_abspath, ++conn->cseq, conn->cid, conn->ua, conn->session);
-
- if (gst_apexraop_send (conn->ctrl_sd, hreq, strlen (hreq)) <= 0)
- return GST_RTSP_STS_GONE;
-
- if (gst_apexraop_recv (conn->ctrl_sd, hreq,
- GST_APEX_RAOP_HDR_DEFAULT_LENGTH) <= 0)
- return GST_RTSP_STS_GONE;
-
- {
- int tmp;
- sscanf (hreq, "%*s %d", &tmp);
- res = (GstRTSPStatusCode) tmp;
- }
-
- if (res != GST_RTSP_STS_OK)
- return res;
-
- if (conn->transport_protocol == GST_APEX_TCP) {
- if ((conn->data_sd = socket (AF_INET, SOCK_STREAM, 0)) < 0)
- return GST_RTSP_STS_DESTINATION_UNREACHABLE;
- } else if (conn->transport_protocol == GST_APEX_UDP) {
- if ((conn->data_sd = socket (AF_INET, SOCK_DGRAM, 0)) < 0)
- return GST_RTSP_STS_DESTINATION_UNREACHABLE;
- } else
- return GST_RTSP_STS_METHOD_NOT_ALLOWED;
-
- conn->data_sd_in.sin_family = AF_INET;
- conn->data_sd_in.sin_port = htons (conn->data_port);
-
- memcpy (&conn->data_sd_in.sin_addr, &conn->ctrl_sd_in.sin_addr,
- sizeof (conn->ctrl_sd_in.sin_addr));
-
- if (connect (conn->data_sd, (struct sockaddr *) &conn->data_sd_in,
- sizeof (conn->data_sd_in)) < 0)
- return GST_RTSP_STS_DESTINATION_UNREACHABLE;
-
- return res;
-}
-
-/* raop apex jack type access */
-GstApExJackType
-gst_apexraop_get_jacktype (GstApExRAOP * con)
-{
- _GstApExRAOP *conn;
-
- conn = (_GstApExRAOP *) con;
-
- if (!conn)
- return GST_APEX_JACK_TYPE_UNDEFINED;
-
- return conn->jack_type;
-}
-
-/* raop apex jack status access */
-GstApExJackStatus
-gst_apexraop_get_jackstatus (GstApExRAOP * con)
-{
- _GstApExRAOP *conn;
-
- conn = (_GstApExRAOP *) con;
-
- if (!conn)
- return GST_APEX_JACK_STATUS_UNDEFINED;
-
- return conn->jack_status;
-}
-
-/* raop apex generation access */
-GstApExGeneration
-gst_apexraop_get_generation (GstApExRAOP * con)
-{
- _GstApExRAOP *conn;
-
- conn = (_GstApExRAOP *) con;
-
- if (!conn)
- return GST_APEX_GENERATION_ONE;
-
- return conn->generation;
-}
-
-/* raop apex transport protocol access */
-GstApExTransportProtocol
-gst_apexraop_get_transport_protocol (GstApExRAOP * con)
-{
- _GstApExRAOP *conn;
-
- conn = (_GstApExRAOP *) con;
-
- if (!conn)
- return GST_APEX_TCP;
-
- return conn->transport_protocol;
-}
-
-/* raop apex sockets close */
-void
-gst_apexraop_close (GstApExRAOP * con)
-{
- gchar hreq[GST_APEX_RAOP_HDR_DEFAULT_LENGTH];
- _GstApExRAOP *conn;
-
- conn = (_GstApExRAOP *) con;
-
- sprintf (hreq,
- "TEARDOWN rtsp://%s/%s RTSP/1.0\r\n"
- "CSeq: %d\r\n"
- "Client-Instance: %s\r\n"
- "User-Agent: %s\r\n"
- "Session: %s\r\n"
- "\r\n",
- conn->host,
- conn->url_abspath, ++conn->cseq, conn->cid, conn->ua, conn->session);
-
- gst_apexraop_send (conn->ctrl_sd, hreq, strlen (hreq));
- gst_apexraop_recv (conn->ctrl_sd, hreq, GST_APEX_RAOP_HDR_DEFAULT_LENGTH);
-
- if (conn->ctrl_sd != 0)
- close (conn->ctrl_sd);
- if (conn->data_sd != 0)
- close (conn->data_sd);
-}
-
-/* raop apex volume set */
-GstRTSPStatusCode
-gst_apexraop_set_volume (GstApExRAOP * con, const guint volume)
-{
- gint v;
- gchar creq[GST_APEX_RAOP_SDP_DEFAULT_LENGTH],
- hreq[GST_APEX_RAOP_HDR_DEFAULT_LENGTH], *req, vol[128];
- GstRTSPStatusCode res;
- _GstApExRAOP *conn;
-
- conn = (_GstApExRAOP *) con;
-
- v = GST_APEX_RAOP_VOLUME_MIN + (GST_APEX_RAOP_VOLUME_MAX -
- GST_APEX_RAOP_VOLUME_MIN) * volume / 100.;
- sprintf (vol, "volume: %d.000000\r\n", v);
-
- sprintf (creq, "%s\r\n", vol);
-
- sprintf (hreq,
- "SET_PARAMETER rtsp://%s/%s RTSP/1.0\r\n"
- "CSeq: %d\r\n"
- "Client-Instance: %s\r\n"
- "User-Agent: %s\r\n"
- "Session: %s\r\n"
- "Content-Type: text/parameters\r\n"
- "Content-Length: %u\r\n",
- conn->host,
- conn->url_abspath,
- ++conn->cseq, conn->cid, conn->ua, conn->session, (guint) strlen (creq)
- );
-
- req = g_strconcat (hreq, "\r\n", creq, NULL);
-
- if (gst_apexraop_send (conn->ctrl_sd, req, strlen (req)) <= 0) {
- g_free (req);
- return GST_RTSP_STS_GONE;
- }
-
- g_free (req);
-
- if (gst_apexraop_recv (conn->ctrl_sd, hreq,
- GST_APEX_RAOP_HDR_DEFAULT_LENGTH) <= 0)
- return GST_RTSP_STS_GONE;
-
- {
- int tmp;
- sscanf (hreq, "%*s %d", &tmp);
- res = (GstRTSPStatusCode) tmp;
- }
-
- return res;
-}
-
-/* raop apex raw data alac encapsulation, encryption and emission, http://wiki.multimedia.cx/index.php?title=Apple_Lossless_Audio_Coding */
-static void inline
-gst_apexraop_write_bits (guchar * buffer, int data, int numbits,
- int *bit_offset, int *byte_offset)
-{
- const static guchar masks[] =
- { 0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3F, 0x7F, 0xFF };
-
- if (((*bit_offset) != 0) && (((*bit_offset) + numbits) > 8)) {
- gint numwritebits;
- guchar bitstowrite;
-
- numwritebits = 8 - (*bit_offset);
- bitstowrite =
- (guchar) ((data >> (numbits - numwritebits)) << (8 - (*bit_offset) -
- numwritebits));
- buffer[(*byte_offset)] |= bitstowrite;
- numbits -= numwritebits;
- (*bit_offset) = 0;
- (*byte_offset)++;
- }
-
- while (numbits >= 8) {
- guchar bitstowrite;
-
- bitstowrite = (guchar) ((data >> (numbits - 8)) & 0xFF);
- buffer[(*byte_offset)] |= bitstowrite;
- numbits -= 8;
- (*bit_offset) = 0;
- (*byte_offset)++;
- }
-
- if (numbits > 0) {
- guchar bitstowrite;
- bitstowrite =
- (guchar) ((data & masks[numbits]) << (8 - (*bit_offset) - numbits));
- buffer[(*byte_offset)] |= bitstowrite;
- (*bit_offset) += numbits;
- if ((*bit_offset) == 8) {
- (*byte_offset)++;
- (*bit_offset) = 0;
- }
- }
-}
-
-guint
-gst_apexraop_write (GstApExRAOP * con, gpointer rawdata, guint length)
-{
- guchar *buffer, *frame_data;
- gushort len;
- gint bit_offset, byte_offset, i, out_len, res;
- EVP_CIPHER_CTX aes_ctx;
- _GstApExRAOP *conn = (_GstApExRAOP *) con;
- const int frame_header_size = conn->generation == GST_APEX_GENERATION_ONE
- ? GST_APEX_RAOP_FRAME_HEADER_SIZE : GST_APEX_RTP_FRAME_HEADER_SIZE;
-
- buffer =
- (guchar *) g_malloc0 (frame_header_size +
- GST_APEX_RAOP_ALAC_HEADER_SIZE + length);
-
- if (conn->generation == GST_APEX_GENERATION_ONE) {
- g_assert (frame_header_size == GST_APEX_RAOP_FRAME_HEADER_SIZE);
- memcpy (buffer, GST_APEX_RAOP_FRAME_HEADER, frame_header_size);
-
- len = length + frame_header_size + GST_APEX_RAOP_ALAC_HEADER_SIZE - 4;
-
- buffer[2] = len >> 8;
- buffer[3] = len & 0xff;
- } else {
- /* Gen. 2 uses RTP-like header (RFC 3550). */
- short network_seq_num;
- int network_timestamp, unknown_const;
- static gboolean first = TRUE;
-
- buffer[0] = 0x80;
- if (first) {
- buffer[1] = 0xe0;
- first = FALSE;
- } else
- buffer[1] = 0x60;
-
- network_seq_num = htons (conn->rtp_seq_num++);
- memcpy (buffer + 2, &network_seq_num, 2);
-
- network_timestamp = htons (conn->rtp_timestamp);
- memcpy (buffer + 4, &network_timestamp, 4);
- conn->rtp_timestamp += GST_APEX_RAOP_V2_SAMPLES_PER_FRAME;
-
- unknown_const = 0xdeadbeef;
- memcpy (buffer + 8, &unknown_const, 4);
- }
-
- bit_offset = 0;
- byte_offset = 0;
- frame_data = buffer + frame_header_size;
-
- gst_apexraop_write_bits (frame_data, 1, 3, &bit_offset, &byte_offset); /* channels, 0 mono, 1 stereo */
- gst_apexraop_write_bits (frame_data, 0, 4, &bit_offset, &byte_offset); /* unknown */
- gst_apexraop_write_bits (frame_data, 0, 8, &bit_offset, &byte_offset); /* unknown (12 bits) */
- gst_apexraop_write_bits (frame_data, 0, 4, &bit_offset, &byte_offset);
- gst_apexraop_write_bits (frame_data, 0, 1, &bit_offset, &byte_offset); /* has size flag */
- gst_apexraop_write_bits (frame_data, 0, 2, &bit_offset, &byte_offset); /* unknown */
- gst_apexraop_write_bits (frame_data, 1, 1, &bit_offset, &byte_offset); /* no compression flag */
-
- for (i = 0; i < length; i += 2) {
- gst_apexraop_write_bits (frame_data, ((guchar *) rawdata)[i + 1], 8,
- &bit_offset, &byte_offset);
- gst_apexraop_write_bits (frame_data, ((guchar *) rawdata)[i], 8,
- &bit_offset, &byte_offset);
- }
-
- EVP_CIPHER_CTX_init (&aes_ctx);
- EVP_CipherInit_ex (&aes_ctx, EVP_aes_128_cbc (), NULL, conn->aes_ky,
- conn->aes_iv, AES_ENCRYPT);
- EVP_CipherUpdate (&aes_ctx, frame_data, &out_len, frame_data, /*( */
- GST_APEX_RAOP_ALAC_HEADER_SIZE +
- length /*) / AES_BLOCK_SIZE * AES_BLOCK_SIZE */ );
- EVP_CIPHER_CTX_cleanup (&aes_ctx);
-
- res =
- gst_apexraop_send (conn->data_sd, buffer,
- frame_header_size + GST_APEX_RAOP_ALAC_HEADER_SIZE + length);
-
- g_free (buffer);
-
- return (guint) ((res >=
- (frame_header_size +
- GST_APEX_RAOP_ALAC_HEADER_SIZE)) ? (res -
- frame_header_size - GST_APEX_RAOP_ALAC_HEADER_SIZE) : 0);
-}
-
-/* raop apex buffer flush */
-GstRTSPStatusCode
-gst_apexraop_flush (GstApExRAOP * con)
-{
- gchar hreq[GST_APEX_RAOP_HDR_DEFAULT_LENGTH];
- GstRTSPStatusCode res;
- _GstApExRAOP *conn;
-
- conn = (_GstApExRAOP *) con;
-
- sprintf (hreq,
- "FLUSH rtsp://%s/%s RTSP/1.0\r\n"
- "CSeq: %d\r\n"
- "Client-Instance: %s\r\n"
- "User-Agent: %s\r\n"
- "Session: %s\r\n"
- "RTP-Info: seq=%d;rtptime=%d\r\n"
- "\r\n",
- conn->host,
- conn->url_abspath,
- ++conn->cseq,
- conn->cid,
- conn->ua, conn->session, conn->rtp_seq_num, conn->rtp_timestamp);
-
- if (gst_apexraop_send (conn->ctrl_sd, hreq, strlen (hreq)) <= 0)
- return GST_RTSP_STS_GONE;
-
- if (gst_apexraop_recv (conn->ctrl_sd, hreq,
- GST_APEX_RAOP_HDR_DEFAULT_LENGTH) <= 0)
- return GST_RTSP_STS_GONE;
-
- {
- int tmp;
- sscanf (hreq, "%*s %d", &tmp);
- res = (GstRTSPStatusCode) tmp;
- }
-
- return res;
-}