/**
 * @brief Callback function called when the information on the
 *        context's sink is retrieved.
 * @param ctx Context which operation has succeeded
 * @param info Structure containing the sink's information
 * @param this_gen pulse_driver_t pointer for the PulseAudio output
 *        instance.
 *
 * This function saves the volume field of the passed structure to the
 * @c cvolume variable of the output instance and send an update volume
 * event to the frontend.
 */
static void __xine_pa_sink_info_callback(pa_context *c, const pa_sink_input_info *info,
                                         int is_last, void *userdata) {

  pulse_driver_t *const this = (pulse_driver_t *) userdata;

  if (is_last < 0) {
    xprintf (this->xine, XINE_VERBOSITY_DEBUG, "audio_pulse_out: Failed to get sink input info: %s\n",
             pa_strerror(pa_context_errno(this->context)));
    return;
  }

  if (!info)
      return;

  this->cvolume = info->volume;
  this->swvolume = pa_cvolume_avg(&info->volume);
#if PA_PROTOCOL_VERSION >= 11
  /* PulseAudio 0.9.7 and newer */
  this->muted = info->mute;
#else
  this->muted = pa_cvolume_is_muted (&this->cvolume);
#endif

  /* send update volume event to frontend */

  xine_event_t              event;
  xine_audio_level_data_t   data;
  xine_stream_t            *stream;
  xine_list_iterator_t      ite;

  data.right        = data.left = (int) (pa_sw_volume_to_linear(this->swvolume)*100);

  data.mute         = this->muted;

  event.type        = XINE_EVENT_AUDIO_LEVEL;
  event.data        = &data;
  event.data_length = sizeof(data);

  pthread_mutex_lock(&this->xine->streams_lock);
  for(ite = xine_list_front(this->xine->streams); ite; ite =
    xine_list_next(this->xine->streams, ite)) {
    stream = xine_list_get_value(this->xine->streams, ite);
    event.stream = stream;
    xine_event_send(stream, &event);
  }
  pthread_mutex_unlock(&this->xine->streams_lock);
}
  /* Each line sent is '\n' terminated */
  if((buf[strlen(buf)] == '\0') && (buf[strlen(buf) - 1] != '\n'))
      strcat(buf, "\n");

  return sock_data_write(xine, socket, buf, strlen(buf));
}

/*
 * this is the most important broadcaster function.
 * it sends data to every connected client (slaves).
 */
static void broadcaster_data_write(broadcaster_t *this, const void *buf, int len) {
  xine_list_iterator_t ite;

  ite = xine_list_front (this->connections);
  while (ite) {

    int *psock = xine_list_get_value(this->connections, ite);

    ite = xine_list_next(this->connections, ite);

    /* in case of failure remove from list */
    if( sock_data_write(this->stream->xine, *psock, buf, len) < 0 ) {

      xprintf(this->stream->xine, XINE_VERBOSITY_DEBUG, "broadcaster: closing socket %d\n", *psock);
      close(*psock);
      free(psock);

      xine_list_remove (this->connections, xine_list_prev(this->connections, ite));
    }