LCOV - code coverage report
Current view: top level - gst-plugins-bad/ext/apexsink - gstapexsink.c (source / functions) Hit Total Coverage
Test: GStreamer Lines: 91 194 46.9 %
Date: 2011-03-25 Functions: 12 24 50.0 %
Branches: 12 94 12.8 %

           Branch data     Line data    Source code
       1                 :            : /* GStreamer - AirPort Express Audio Sink -
       2                 :            :  *
       3                 :            :  * Remote Audio Access Protocol (RAOP) as used in Apple iTunes to stream music to the Airport Express (ApEx) -
       4                 :            :  * RAOP is based on the Real Time Streaming Protocol (RTSP) but with an extra challenge-response RSA based authentication step.
       5                 :            :  *
       6                 :            :  * RAW PCM input only as defined by the following GST_STATIC_PAD_TEMPLATE
       7                 :            :  *
       8                 :            :  * Copyright (C) 2008 Jérémie Bernard [GRemi] <gremimail@gmail.com>
       9                 :            :  *
      10                 :            :  * gstapexsink.c 
      11                 :            :  *
      12                 :            :  * This library is free software; you can redistribute it and/or
      13                 :            :  * modify it under the terms of the GNU Library General Public
      14                 :            :  * License as published by the Free Software Foundation; either
      15                 :            :  * version 2 of the License, or (at your option) any later version.
      16                 :            :  *
      17                 :            :  * This library is distributed in the hope that it will be useful,
      18                 :            :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      19                 :            :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      20                 :            :  * Library General Public License for more details.
      21                 :            :  *
      22                 :            :  * You should have received a copy of the GNU Library General Public
      23                 :            :  * License along with this library; if not, write to the
      24                 :            :  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
      25                 :            :  * Boston, MA 02111-1307, USA.
      26                 :            :  *
      27                 :            :  */
      28                 :            : 
      29                 :            : #ifdef HAVE_CONFIG_H
      30                 :            : #include "config.h"
      31                 :            : #endif
      32                 :            : 
      33                 :            : #include <string.h>
      34                 :            : 
      35                 :            : #include "gstapexsink.h"
      36                 :            : 
      37                 :            : GST_DEBUG_CATEGORY_STATIC (apexsink_debug);
      38                 :            : #define GST_CAT_DEFAULT apexsink_debug
      39                 :            : 
      40                 :            : static GstStaticPadTemplate gst_apexsink_sink_factory = GST_STATIC_PAD_TEMPLATE
      41                 :            :     ("sink",
      42                 :            :     GST_PAD_SINK,
      43                 :            :     GST_PAD_ALWAYS,
      44                 :            :     GST_STATIC_CAPS
      45                 :            :     (GST_APEX_RAOP_INPUT_TYPE ","
      46                 :            :         "width = (int) " GST_APEX_RAOP_INPUT_WIDTH ","
      47                 :            :         "depth = (int) " GST_APEX_RAOP_INPUT_DEPTH ","
      48                 :            :         "endianness = (int) " GST_APEX_RAOP_INPUT_ENDIAN ","
      49                 :            :         "channels = (int) " GST_APEX_RAOP_INPUT_CHANNELS ","
      50                 :            :         "rate = (int) " GST_APEX_RAOP_INPUT_BIT_RATE ","
      51                 :            :         "signed = (boolean) " GST_APEX_RAOP_INPUT_SIGNED)
      52                 :            :     );
      53                 :            : 
      54                 :            : 
      55                 :            : enum
      56                 :            : {
      57                 :            :   APEX_PROP_HOST = 1,
      58                 :            :   APEX_PROP_PORT,
      59                 :            :   APEX_PROP_VOLUME,
      60                 :            :   APEX_PROP_JACK_TYPE,
      61                 :            :   APEX_PROP_JACK_STATUS,
      62                 :            : };
      63                 :            : 
      64                 :            : #define DEFAULT_APEX_HOST   ""
      65                 :            : #define DEFAULT_APEX_PORT   5000
      66                 :            : #define DEFAULT_APEX_VOLUME   1.0
      67                 :            : #define DEFAULT_APEX_JACK_TYPE    GST_APEX_JACK_TYPE_UNDEFINED
      68                 :            : #define DEFAULT_APEX_JACK_STATUS  GST_APEX_JACK_STATUS_UNDEFINED
      69                 :            : 
      70                 :            : /* genum apex jack resolution */
      71                 :            : GType
      72                 :          3 : gst_apexsink_jackstatus_get_type (void)
      73                 :            : {
      74                 :            :   static GType jackstatus_type = 0;
      75                 :            :   static GEnumValue jackstatus[] = {
      76                 :            :     {GST_APEX_JACK_STATUS_UNDEFINED, "GST_APEX_JACK_STATUS_UNDEFINED",
      77                 :            :         "Jack status undefined"},
      78                 :            :     {GST_APEX_JACK_STATUS_DISCONNECTED, "GST_APEX_JACK_STATUS_DISCONNECTED",
      79                 :            :         "Jack disconnected"},
      80                 :            :     {GST_APEX_JACK_STATUS_CONNECTED, "GST_APEX_JACK_STATUS_CONNECTED",
      81                 :            :         "Jack connected"},
      82                 :            :     {0, NULL, NULL},
      83                 :            :   };
      84                 :            : 
      85         [ +  - ]:          3 :   if (!jackstatus_type) {
      86                 :          3 :     jackstatus_type = g_enum_register_static ("GstApExJackStatus", jackstatus);
      87                 :            :   }
      88                 :            : 
      89                 :          3 :   return jackstatus_type;
      90                 :            : }
      91                 :            : 
      92                 :            : GType
      93                 :          3 : gst_apexsink_jacktype_get_type (void)
      94                 :            : {
      95                 :            :   static GType jacktype_type = 0;
      96                 :            :   static GEnumValue jacktype[] = {
      97                 :            :     {GST_APEX_JACK_TYPE_UNDEFINED, "GST_APEX_JACK_TYPE_UNDEFINED",
      98                 :            :         "Undefined jack type"},
      99                 :            :     {GST_APEX_JACK_TYPE_ANALOG, "GST_APEX_JACK_TYPE_ANALOG", "Analog jack"},
     100                 :            :     {GST_APEX_JACK_TYPE_DIGITAL, "GST_APEX_JACK_TYPE_DIGITAL", "Digital jack"},
     101                 :            :     {0, NULL, NULL},
     102                 :            :   };
     103                 :            : 
     104         [ +  - ]:          3 :   if (!jacktype_type) {
     105                 :          3 :     jacktype_type = g_enum_register_static ("GstApExJackType", jacktype);
     106                 :            :   }
     107                 :            : 
     108                 :          3 :   return jacktype_type;
     109                 :            : }
     110                 :            : 
     111                 :            : 
     112                 :            : static void gst_apexsink_set_property (GObject * object, guint prop_id,
     113                 :            :     const GValue * value, GParamSpec * pspec);
     114                 :            : static void gst_apexsink_get_property (GObject * object, guint prop_id,
     115                 :            :     GValue * value, GParamSpec * pspec);
     116                 :            : static void gst_apexsink_finalise (GObject * object);
     117                 :            : 
     118                 :            : static gboolean gst_apexsink_open (GstAudioSink * asink);
     119                 :            : static gboolean gst_apexsink_prepare (GstAudioSink * asink,
     120                 :            :     GstRingBufferSpec * spec);
     121                 :            : static guint gst_apexsink_write (GstAudioSink * asink, gpointer data,
     122                 :            :     guint length);
     123                 :            : static gboolean gst_apexsink_unprepare (GstAudioSink * asink);
     124                 :            : static guint gst_apexsink_delay (GstAudioSink * asink);
     125                 :            : static void gst_apexsink_reset (GstAudioSink * asink);
     126                 :            : static gboolean gst_apexsink_close (GstAudioSink * asink);
     127                 :            : 
     128                 :            : /* mixer interface standard api */
     129                 :            : static void gst_apexsink_interfaces_init (GType type);
     130                 :            : static void gst_apexsink_implements_interface_init (GstImplementsInterfaceClass
     131                 :            :     * iface);
     132                 :            : static void gst_apexsink_mixer_interface_init (GstMixerClass * iface);
     133                 :            : 
     134                 :            : static gboolean gst_apexsink_interface_supported (GstImplementsInterface *
     135                 :            :     iface, GType iface_type);
     136                 :            : static const GList *gst_apexsink_mixer_list_tracks (GstMixer * mixer);
     137                 :            : static void gst_apexsink_mixer_set_volume (GstMixer * mixer,
     138                 :            :     GstMixerTrack * track, gint * volumes);
     139                 :            : static void gst_apexsink_mixer_get_volume (GstMixer * mixer,
     140                 :            :     GstMixerTrack * track, gint * volumes);
     141                 :            : 
     142         [ +  + ]:         12 : GST_BOILERPLATE_FULL (GstApExSink, gst_apexsink, GstAudioSink,
     143                 :         12 :     GST_TYPE_AUDIO_SINK, gst_apexsink_interfaces_init);
     144                 :            : 
     145                 :            : /* apex sink interface(s) stuff */
     146                 :            : static void
     147                 :          3 : gst_apexsink_interfaces_init (GType type)
     148                 :            : {
     149                 :            :   static const GInterfaceInfo implements_interface_info =
     150                 :            :       { (GInterfaceInitFunc) gst_apexsink_implements_interface_init, NULL,
     151                 :            :     NULL
     152                 :            :   };
     153                 :            :   static const GInterfaceInfo mixer_interface_info =
     154                 :            :       { (GInterfaceInitFunc) gst_apexsink_mixer_interface_init, NULL, NULL };
     155                 :            : 
     156                 :          3 :   g_type_add_interface_static (type, GST_TYPE_IMPLEMENTS_INTERFACE,
     157                 :            :       &implements_interface_info);
     158                 :          3 :   g_type_add_interface_static (type, GST_TYPE_MIXER, &mixer_interface_info);
     159                 :          3 : }
     160                 :            : 
     161                 :            : static void
     162                 :          3 : gst_apexsink_implements_interface_init (GstImplementsInterfaceClass * iface)
     163                 :            : {
     164                 :          3 :   iface->supported = gst_apexsink_interface_supported;
     165                 :          3 : }
     166                 :            : 
     167                 :            : static void
     168                 :          3 : gst_apexsink_mixer_interface_init (GstMixerClass * iface)
     169                 :            : {
     170                 :          3 :   GST_MIXER_TYPE (iface) = GST_MIXER_SOFTWARE;
     171                 :            : 
     172                 :          3 :   iface->list_tracks = gst_apexsink_mixer_list_tracks;
     173                 :          3 :   iface->set_volume = gst_apexsink_mixer_set_volume;
     174                 :          3 :   iface->get_volume = gst_apexsink_mixer_get_volume;
     175                 :          3 : }
     176                 :            : 
     177                 :            : static gboolean
     178                 :          0 : gst_apexsink_interface_supported (GstImplementsInterface * iface,
     179                 :            :     GType iface_type)
     180                 :            : {
     181         [ #  # ]:          0 :   g_return_val_if_fail (iface_type == GST_TYPE_MIXER, FALSE);
     182                 :            : 
     183                 :          0 :   return TRUE;
     184                 :            : }
     185                 :            : 
     186                 :            : static const GList *
     187                 :          0 : gst_apexsink_mixer_list_tracks (GstMixer * mixer)
     188                 :            : {
     189                 :          0 :   GstApExSink *apexsink = GST_APEX_SINK (mixer);
     190                 :            : 
     191                 :          0 :   return apexsink->tracks;
     192                 :            : }
     193                 :            : 
     194                 :            : static void
     195                 :          0 : gst_apexsink_mixer_set_volume (GstMixer * mixer, GstMixerTrack * track,
     196                 :            :     gint * volumes)
     197                 :            : {
     198                 :          0 :   GstApExSink *apexsink = GST_APEX_SINK (mixer);
     199                 :            : 
     200                 :          0 :   apexsink->volume = volumes[0];
     201                 :            : 
     202         [ #  # ]:          0 :   if (apexsink->gst_apexraop != NULL)
     203                 :          0 :     gst_apexraop_set_volume (apexsink->gst_apexraop, apexsink->volume);
     204                 :          0 : }
     205                 :            : 
     206                 :            : static void
     207                 :          0 : gst_apexsink_mixer_get_volume (GstMixer * mixer, GstMixerTrack * track,
     208                 :            :     gint * volumes)
     209                 :            : {
     210                 :          0 :   GstApExSink *apexsink = GST_APEX_SINK (mixer);
     211                 :            : 
     212                 :          0 :   volumes[0] = apexsink->volume;
     213                 :          0 : }
     214                 :            : 
     215                 :            : /* sink base init */
     216                 :            : static void
     217                 :          3 : gst_apexsink_base_init (gpointer g_class)
     218                 :            : {
     219                 :          3 :   GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
     220                 :            : 
     221                 :          3 :   gst_element_class_set_details_simple (element_class,
     222                 :            :       "Apple AirPort Express Audio Sink", "Sink/Audio/Wireless",
     223                 :            :       "Output stream to an AirPort Express",
     224                 :            :       "Jérémie Bernard [GRemi] <gremimail@gmail.com>");
     225                 :          3 :   gst_element_class_add_pad_template (element_class,
     226                 :            :       gst_static_pad_template_get (&gst_apexsink_sink_factory));
     227                 :          3 : }
     228                 :            : 
     229                 :            : /* sink class init */
     230                 :            : static void
     231                 :          3 : gst_apexsink_class_init (GstApExSinkClass * klass)
     232                 :            : {
     233         [ +  - ]:          3 :   GST_DEBUG_CATEGORY_INIT (apexsink_debug, GST_APEX_SINK_NAME, 0,
     234                 :            :       "AirPort Express sink");
     235                 :            : 
     236                 :          3 :   parent_class = g_type_class_peek_parent (klass);
     237                 :            : 
     238                 :          3 :   ((GObjectClass *) klass)->get_property =
     239                 :          3 :       GST_DEBUG_FUNCPTR (gst_apexsink_get_property);
     240                 :          3 :   ((GObjectClass *) klass)->set_property =
     241                 :          3 :       GST_DEBUG_FUNCPTR (gst_apexsink_set_property);
     242                 :          3 :   ((GObjectClass *) klass)->finalize =
     243                 :          3 :       GST_DEBUG_FUNCPTR (gst_apexsink_finalise);
     244                 :            : 
     245                 :          3 :   ((GstAudioSinkClass *) klass)->open = GST_DEBUG_FUNCPTR (gst_apexsink_open);
     246                 :          3 :   ((GstAudioSinkClass *) klass)->prepare =
     247                 :          3 :       GST_DEBUG_FUNCPTR (gst_apexsink_prepare);
     248                 :          3 :   ((GstAudioSinkClass *) klass)->write = GST_DEBUG_FUNCPTR (gst_apexsink_write);
     249                 :          3 :   ((GstAudioSinkClass *) klass)->unprepare =
     250                 :          3 :       GST_DEBUG_FUNCPTR (gst_apexsink_unprepare);
     251                 :          3 :   ((GstAudioSinkClass *) klass)->delay = GST_DEBUG_FUNCPTR (gst_apexsink_delay);
     252                 :          3 :   ((GstAudioSinkClass *) klass)->reset = GST_DEBUG_FUNCPTR (gst_apexsink_reset);
     253                 :          3 :   ((GstAudioSinkClass *) klass)->close = GST_DEBUG_FUNCPTR (gst_apexsink_close);
     254                 :            : 
     255                 :          3 :   g_object_class_install_property ((GObjectClass *) klass, APEX_PROP_HOST,
     256                 :            :       g_param_spec_string ("host", "Host", "AirPort Express target host",
     257                 :            :           DEFAULT_APEX_HOST, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
     258                 :          3 :   g_object_class_install_property ((GObjectClass *) klass, APEX_PROP_PORT,
     259                 :            :       g_param_spec_uint ("port", "Port", "AirPort Express target port", 0,
     260                 :            :           32000, DEFAULT_APEX_PORT,
     261                 :            :           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
     262                 :            :   /* we need to expose the volume as a double for playbin2. Internally we keep
     263                 :            :    * it as an int between 0 and 100, where 75 corresponds to 1.0.
     264                 :            :    * FIXME we should store the volume as a double. */
     265                 :          3 :   g_object_class_install_property ((GObjectClass *) klass, APEX_PROP_VOLUME,
     266                 :            :       g_param_spec_double ("volume", "Volume", "AirPort Express target volume",
     267                 :            :           0.0, 10.0, DEFAULT_APEX_VOLUME,
     268                 :            :           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
     269                 :          3 :   g_object_class_install_property ((GObjectClass *) klass, APEX_PROP_JACK_TYPE,
     270                 :            :       g_param_spec_enum ("jack-type", "Jack Type",
     271                 :            :           "AirPort Express connected jack type", GST_APEX_SINK_JACKTYPE_TYPE,
     272                 :            :           DEFAULT_APEX_JACK_TYPE, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
     273                 :          3 :   g_object_class_install_property ((GObjectClass *) klass,
     274                 :            :       APEX_PROP_JACK_STATUS, g_param_spec_enum ("jack-status", "Jack Status",
     275                 :            :           "AirPort Express jack connection status",
     276                 :            :           GST_APEX_SINK_JACKSTATUS_TYPE, DEFAULT_APEX_JACK_STATUS,
     277                 :            :           G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
     278                 :          3 : }
     279                 :            : 
     280                 :            : /* sink plugin instance init */
     281                 :            : static void
     282                 :          1 : gst_apexsink_init (GstApExSink * apexsink, GstApExSinkClass * g_class)
     283                 :            : {
     284                 :          1 :   GstMixerTrack *track = NULL;
     285                 :            : 
     286                 :          1 :   track = g_object_new (GST_TYPE_MIXER_TRACK, NULL);
     287                 :          1 :   track->label = g_strdup ("Airport Express");
     288                 :          1 :   track->num_channels = GST_APEX_RAOP_CHANNELS;
     289                 :          1 :   track->min_volume = 0;
     290                 :          1 :   track->max_volume = 100;
     291                 :          1 :   track->flags = GST_MIXER_TRACK_OUTPUT;
     292                 :            : 
     293                 :          1 :   apexsink->host = g_strdup (DEFAULT_APEX_HOST);
     294                 :          1 :   apexsink->port = DEFAULT_APEX_PORT;
     295                 :          1 :   apexsink->volume = CLAMP (DEFAULT_APEX_VOLUME * 75, 0, 100);
     296                 :          1 :   apexsink->gst_apexraop = NULL;
     297                 :          1 :   apexsink->tracks = g_list_append (apexsink->tracks, track);
     298                 :            : 
     299         [ -  + ]:          1 :   GST_INFO_OBJECT (apexsink,
     300                 :            :       "ApEx sink default initialization, target=\"%s\", port=\"%d\", volume=\"%d%%\"",
     301                 :            :       apexsink->host, apexsink->port, apexsink->volume);
     302                 :          1 : }
     303                 :            : 
     304                 :            : /* apex sink set property */
     305                 :            : static void
     306                 :          0 : gst_apexsink_set_property (GObject * object, guint prop_id,
     307                 :            :     const GValue * value, GParamSpec * pspec)
     308                 :            : {
     309                 :          0 :   GstApExSink *sink = GST_APEX_SINK (object);
     310                 :            : 
     311   [ #  #  #  # ]:          0 :   switch (prop_id) {
     312                 :            :     case APEX_PROP_HOST:
     313         [ #  # ]:          0 :       if (sink->gst_apexraop == NULL) {
     314                 :          0 :         g_free (sink->host);
     315                 :          0 :         sink->host = g_value_dup_string (value);
     316                 :            : 
     317         [ #  # ]:          0 :         GST_INFO_OBJECT (sink, "ApEx sink target set to \"%s\"", sink->host);
     318                 :            :       } else {
     319                 :          0 :         G_OBJECT_WARN_INVALID_PSPEC (object, "host", prop_id, pspec);
     320                 :            :       }
     321                 :          0 :       break;
     322                 :            :     case APEX_PROP_PORT:
     323         [ #  # ]:          0 :       if (sink->gst_apexraop == NULL) {
     324                 :          0 :         sink->port = g_value_get_uint (value);
     325                 :            : 
     326         [ #  # ]:          0 :         GST_INFO_OBJECT (sink, "ApEx port set to \"%d\"", sink->port);
     327                 :            :       } else {
     328                 :          0 :         G_OBJECT_WARN_INVALID_PSPEC (object, "port", prop_id, pspec);
     329                 :            :       }
     330                 :          0 :       break;
     331                 :            :     case APEX_PROP_VOLUME:
     332                 :            :     {
     333                 :            :       gdouble volume;
     334                 :            : 
     335                 :          0 :       volume = g_value_get_double (value);
     336                 :          0 :       volume *= 75.0;
     337                 :            : 
     338 [ #  # ][ #  # ]:          0 :       sink->volume = CLAMP (volume, 0, 100);
     339                 :            : 
     340         [ #  # ]:          0 :       if (sink->gst_apexraop != NULL)
     341                 :          0 :         gst_apexraop_set_volume (sink->gst_apexraop, sink->volume);
     342                 :            : 
     343         [ #  # ]:          0 :       GST_INFO_OBJECT (sink, "ApEx volume set to \"%d%%\"", sink->volume);
     344                 :          0 :       break;
     345                 :            :     }
     346                 :            :     default:
     347                 :          0 :       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
     348                 :          0 :       break;
     349                 :            :   }
     350                 :          0 : }
     351                 :            : 
     352                 :            : /* apex sink get property */
     353                 :            : static void
     354                 :          5 : gst_apexsink_get_property (GObject * object, guint prop_id, GValue * value,
     355                 :            :     GParamSpec * pspec)
     356                 :            : {
     357                 :          5 :   GstApExSink *sink = GST_APEX_SINK (object);
     358                 :            : 
     359   [ +  +  +  +  :          5 :   switch (prop_id) {
                   +  - ]
     360                 :            :     case APEX_PROP_HOST:
     361                 :          1 :       g_value_set_string (value, sink->host);
     362                 :          1 :       break;
     363                 :            :     case APEX_PROP_PORT:
     364                 :          1 :       g_value_set_uint (value, sink->port);
     365                 :          1 :       break;
     366                 :            :     case APEX_PROP_VOLUME:
     367                 :          1 :       g_value_set_double (value, ((gdouble) sink->volume) / 75.0);
     368                 :          1 :       break;
     369                 :            :     case APEX_PROP_JACK_TYPE:
     370                 :          1 :       g_value_set_enum (value, gst_apexraop_get_jacktype (sink->gst_apexraop));
     371                 :          1 :       break;
     372                 :            :     case APEX_PROP_JACK_STATUS:
     373                 :          1 :       g_value_set_enum (value,
     374                 :          1 :           gst_apexraop_get_jackstatus (sink->gst_apexraop));
     375                 :          1 :       break;
     376                 :            :     default:
     377                 :          0 :       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
     378                 :          0 :       break;
     379                 :            :   }
     380                 :          5 : }
     381                 :            : 
     382                 :            : /* apex sink finalize */
     383                 :            : static void
     384                 :          1 : gst_apexsink_finalise (GObject * object)
     385                 :            : {
     386                 :          1 :   GstApExSink *sink = GST_APEX_SINK (object);
     387                 :            : 
     388         [ +  - ]:          1 :   if (sink->tracks) {
     389                 :          1 :     g_list_foreach (sink->tracks, (GFunc) g_object_unref, NULL);
     390                 :          1 :     g_list_free (sink->tracks);
     391                 :          1 :     sink->tracks = NULL;
     392                 :            :   }
     393                 :            : 
     394                 :          1 :   g_free (sink->host);
     395                 :            : 
     396                 :          1 :   G_OBJECT_CLASS (parent_class)->finalize (object);
     397                 :          1 : }
     398                 :            : 
     399                 :            : /* sink open : open the device */
     400                 :            : static gboolean
     401                 :          0 : gst_apexsink_open (GstAudioSink * asink)
     402                 :            : {
     403                 :            :   int res;
     404                 :          0 :   GstApExSink *apexsink = (GstApExSink *) asink;
     405                 :            : 
     406                 :          0 :   apexsink->gst_apexraop = gst_apexraop_new (apexsink->host, apexsink->port);
     407                 :            : 
     408         [ #  # ]:          0 :   if ((res = gst_apexraop_connect (apexsink->gst_apexraop)) != GST_RTSP_STS_OK) {
     409         [ #  # ]:          0 :     GST_ERROR_OBJECT (apexsink,
     410                 :            :         "%s : network or RAOP failure, connection refused or timeout, RTSP code=%d",
     411                 :            :         apexsink->host, res);
     412                 :          0 :     return FALSE;
     413                 :            :   }
     414                 :            : 
     415         [ #  # ]:          0 :   GST_INFO_OBJECT (apexsink,
     416                 :            :       "OPEN : ApEx sink successfully connected to \"%s:%d\", ANNOUNCE, SETUP and RECORD requests performed",
     417                 :            :       apexsink->host, apexsink->port);
     418                 :            : 
     419      [ #  #  # ]:          0 :   switch (gst_apexraop_get_jackstatus (apexsink->gst_apexraop)) {
     420                 :            :     case GST_APEX_JACK_STATUS_CONNECTED:
     421         [ #  # ]:          0 :       GST_INFO_OBJECT (apexsink, "OPEN : ApEx jack is connected");
     422                 :          0 :       break;
     423                 :            :     case GST_APEX_JACK_STATUS_DISCONNECTED:
     424         [ #  # ]:          0 :       GST_WARNING_OBJECT (apexsink, "OPEN : ApEx jack is disconnected !");
     425                 :          0 :       break;
     426                 :            :     default:
     427         [ #  # ]:          0 :       GST_WARNING_OBJECT (apexsink, "OPEN : ApEx jack status is undefined !");
     428                 :          0 :       break;
     429                 :            :   }
     430                 :            : 
     431      [ #  #  # ]:          0 :   switch (gst_apexraop_get_jacktype (apexsink->gst_apexraop)) {
     432                 :            :     case GST_APEX_JACK_TYPE_ANALOG:
     433         [ #  # ]:          0 :       GST_INFO_OBJECT (apexsink, "OPEN : ApEx jack type is analog");
     434                 :          0 :       break;
     435                 :            :     case GST_APEX_JACK_TYPE_DIGITAL:
     436         [ #  # ]:          0 :       GST_INFO_OBJECT (apexsink, "OPEN : ApEx jack type is digital");
     437                 :          0 :       break;
     438                 :            :     default:
     439         [ #  # ]:          0 :       GST_WARNING_OBJECT (apexsink, "OPEN : ApEx jack type is undefined !");
     440                 :          0 :       break;
     441                 :            :   }
     442                 :            : 
     443         [ #  # ]:          0 :   if ((res =
     444                 :          0 :           gst_apexraop_set_volume (apexsink->gst_apexraop,
     445                 :            :               apexsink->volume)) != GST_RTSP_STS_OK) {
     446         [ #  # ]:          0 :     GST_WARNING_OBJECT (apexsink,
     447                 :            :         "%s : could not set initial volume to \"%d%%\", RTSP code=%d",
     448                 :            :         apexsink->host, apexsink->volume, res);
     449                 :            :   } else {
     450         [ #  # ]:          0 :     GST_INFO_OBJECT (apexsink,
     451                 :            :         "OPEN : ApEx sink successfully set volume to \"%d%%\"",
     452                 :            :         apexsink->volume);
     453                 :            :   }
     454                 :            : 
     455                 :          0 :   return TRUE;
     456                 :            : }
     457                 :            : 
     458                 :            : /* prepare sink : configure the device with the specified format */
     459                 :            : static gboolean
     460                 :          0 : gst_apexsink_prepare (GstAudioSink * asink, GstRingBufferSpec * spec)
     461                 :            : {
     462                 :          0 :   GstApExSink *apexsink = (GstApExSink *) asink;
     463                 :            : 
     464                 :          0 :   apexsink->latency_time = spec->latency_time;
     465                 :            : 
     466                 :          0 :   spec->segsize =
     467                 :            :       GST_APEX_RAOP_SAMPLES_PER_FRAME * GST_APEX_RAOP_BYTES_PER_SAMPLE;
     468                 :          0 :   spec->segtotal = 1;
     469                 :            : 
     470                 :          0 :   memset (spec->silence_sample, 0, sizeof (spec->silence_sample));
     471                 :            : 
     472         [ #  # ]:          0 :   GST_INFO_OBJECT (apexsink,
     473                 :            :       "PREPARE : ApEx sink ready to stream at %dHz, %d bytes per sample, %d channels, %d bytes segments (%dkB/s)",
     474                 :            :       spec->rate, spec->bytes_per_sample, spec->channels, spec->segsize,
     475                 :            :       spec->rate * spec->bytes_per_sample / 1000);
     476                 :            : 
     477                 :          0 :   return TRUE;
     478                 :            : }
     479                 :            : 
     480                 :            : /* sink write : write samples to the device */
     481                 :            : static guint
     482                 :          0 : gst_apexsink_write (GstAudioSink * asink, gpointer data, guint length)
     483                 :            : {
     484                 :          0 :   GstApExSink *apexsink = (GstApExSink *) asink;
     485                 :            : 
     486         [ #  # ]:          0 :   if (gst_apexraop_write (apexsink->gst_apexraop, data, length) != length) {
     487         [ #  # ]:          0 :     GST_INFO_OBJECT (apexsink,
     488                 :            :         "WRITE : %d bytes not fully sended, skipping frame samples...", length);
     489                 :            :   } else {
     490         [ #  # ]:          0 :     GST_INFO_OBJECT (apexsink, "WRITE : %d bytes sent", length);
     491                 :            : 
     492                 :            :     /* FIXME, sleeping is ugly and not interruptible */
     493                 :          0 :     usleep ((gulong) ((length * 1000000.) / (GST_APEX_RAOP_BITRATE *
     494                 :          0 :                 GST_APEX_RAOP_BYTES_PER_SAMPLE) - apexsink->latency_time));
     495                 :            :   }
     496                 :            : 
     497                 :          0 :   return length;
     498                 :            : }
     499                 :            : 
     500                 :            : /* unprepare sink : undo operations done by prepare */
     501                 :            : static gboolean
     502                 :          0 : gst_apexsink_unprepare (GstAudioSink * asink)
     503                 :            : {
     504         [ #  # ]:          0 :   GST_INFO_OBJECT (asink, "UNPREPARE");
     505                 :            : 
     506                 :          0 :   return TRUE;
     507                 :            : }
     508                 :            : 
     509                 :            : /* delay sink : get the estimated number of samples written but not played yet by the device */
     510                 :            : static guint
     511                 :          0 : gst_apexsink_delay (GstAudioSink * asink)
     512                 :            : {
     513         [ #  # ]:          0 :   GST_LOG_OBJECT (asink, "DELAY");
     514                 :            : 
     515                 :          0 :   return 0;
     516                 :            : }
     517                 :            : 
     518                 :            : /* reset sink : unblock writes and flush the device */
     519                 :            : static void
     520                 :          0 : gst_apexsink_reset (GstAudioSink * asink)
     521                 :            : {
     522                 :            :   int res;
     523                 :          0 :   GstApExSink *apexsink = (GstApExSink *) asink;
     524                 :            : 
     525         [ #  # ]:          0 :   GST_INFO_OBJECT (apexsink, "RESET : flushing buffer...");
     526                 :            : 
     527         [ #  # ]:          0 :   if ((res = gst_apexraop_flush (apexsink->gst_apexraop)) == GST_RTSP_STS_OK) {
     528         [ #  # ]:          0 :     GST_INFO_OBJECT (apexsink, "RESET : ApEx buffer flush success");
     529                 :            :   } else {
     530         [ #  # ]:          0 :     GST_WARNING_OBJECT (apexsink,
     531                 :            :         "RESET : could not flush ApEx buffer, RTSP code=%d", res);
     532                 :            :   }
     533                 :          0 : }
     534                 :            : 
     535                 :            : /* sink close : close the device */
     536                 :            : static gboolean
     537                 :          0 : gst_apexsink_close (GstAudioSink * asink)
     538                 :            : {
     539                 :          0 :   GstApExSink *apexsink = (GstApExSink *) asink;
     540                 :            : 
     541                 :          0 :   gst_apexraop_close (apexsink->gst_apexraop);
     542                 :          0 :   gst_apexraop_free (apexsink->gst_apexraop);
     543                 :            : 
     544         [ #  # ]:          0 :   GST_INFO_OBJECT (apexsink, "CLOSE : ApEx sink closed connection");
     545                 :            : 
     546                 :          0 :   return TRUE;
     547                 :            : }

Generated by: LCOV version 1.9