Exemple #1
0
/** XXX: duplicated from ALSA output */
static void Dump (vlc_object_t *obj, const char *msg,
                  int (*cb)(void *, snd_output_t *), void *p)
{
    snd_output_t *output;
    char *str;

    if (unlikely(snd_output_buffer_open (&output)))
        return;

    int val = cb (p, output);
    if (val)
    {
        msg_Warn (obj, "cannot get info: %s", snd_strerror (val));
        return;
    }

    size_t len = snd_output_buffer_string (output, &str);
    if (len > 0 && str[len - 1])
        len--; /* strip trailing newline */
    msg_Dbg (obj, "%s%.*s", msg, (int)len, str);
    snd_output_close (output);
}
Exemple #2
0
static gboolean
gst_alsasink_prepare (GstAudioSink * asink, GstRingBufferSpec * spec)
{
    GstAlsaSink *alsa;
    gint err;

    alsa = GST_ALSA_SINK (asink);

    if (alsa->iec958) {
        snd_pcm_close (alsa->handle);
        alsa->handle = gst_alsa_open_iec958_pcm (GST_OBJECT (alsa), alsa->device);
        if (G_UNLIKELY (!alsa->handle)) {
            goto no_iec958;
        }
    }

    if (!alsasink_parse_spec (alsa, spec))
        goto spec_parse;

    CHECK (set_hwparams (alsa), hw_params_failed);
    CHECK (set_swparams (alsa), sw_params_failed);

    alsa->bytes_per_sample = spec->bytes_per_sample;
    spec->segsize = alsa->period_size * spec->bytes_per_sample;
    spec->segtotal = alsa->buffer_size / alsa->period_size;

    {
        snd_output_t *out_buf = NULL;
        char *msg = NULL;

        snd_output_buffer_open (&out_buf);
        snd_pcm_dump_hw_setup (alsa->handle, out_buf);
        snd_output_buffer_string (out_buf, &msg);
        GST_DEBUG_OBJECT (alsa, "Hardware setup: \n%s", msg);
        snd_output_close (out_buf);
        snd_output_buffer_open (&out_buf);
        snd_pcm_dump_sw_setup (alsa->handle, out_buf);
        snd_output_buffer_string (out_buf, &msg);
        GST_DEBUG_OBJECT (alsa, "Software setup: \n%s", msg);
        snd_output_close (out_buf);
    }

    return TRUE;

    /* ERRORS */
no_iec958:
    {
        GST_ELEMENT_ERROR (alsa, RESOURCE, OPEN_WRITE, (NULL),
                           ("Could not open IEC958 (SPDIF) device for playback"));
        return FALSE;
    }
spec_parse:
    {
        GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL),
                           ("Error parsing spec"));
        return FALSE;
    }
hw_params_failed:
    {
        GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL),
                           ("Setting of hwparams failed: %s", snd_strerror (err)));
        return FALSE;
    }
sw_params_failed:
    {
        GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL),
                           ("Setting of swparams failed: %s", snd_strerror (err)));
        return FALSE;
    }
}
static gboolean
gst_alsasrc_prepare (GstAudioSrc * asrc, GstAudioRingBufferSpec * spec)
{
  GstAlsaSrc *alsa;
  gint err;

  alsa = GST_ALSA_SRC (asrc);

  if (!alsasrc_parse_spec (alsa, spec))
    goto spec_parse;

  CHECK (snd_pcm_nonblock (alsa->handle, 0), non_block);

  CHECK (set_hwparams (alsa), hw_params_failed);
  CHECK (set_swparams (alsa), sw_params_failed);
  CHECK (snd_pcm_prepare (alsa->handle), prepare_failed);

  alsa->bpf = GST_AUDIO_INFO_BPF (&spec->info);
  spec->segsize = alsa->period_size * alsa->bpf;
  spec->segtotal = alsa->buffer_size / alsa->period_size;

  {
    snd_output_t *out_buf = NULL;
    char *msg = NULL;

    snd_output_buffer_open (&out_buf);
    snd_pcm_dump_hw_setup (alsa->handle, out_buf);
    snd_output_buffer_string (out_buf, &msg);
    GST_DEBUG_OBJECT (alsa, "Hardware setup: \n%s", msg);
    snd_output_close (out_buf);
    snd_output_buffer_open (&out_buf);
    snd_pcm_dump_sw_setup (alsa->handle, out_buf);
    snd_output_buffer_string (out_buf, &msg);
    GST_DEBUG_OBJECT (alsa, "Software setup: \n%s", msg);
    snd_output_close (out_buf);
  }

#ifdef SND_CHMAP_API_VERSION
  if (spec->type == GST_AUDIO_RING_BUFFER_FORMAT_TYPE_RAW && alsa->channels < 9) {
    snd_pcm_chmap_t *chmap = snd_pcm_get_chmap (alsa->handle);
    if (chmap && chmap->channels == alsa->channels) {
      GstAudioChannelPosition pos[8];
      if (alsa_chmap_to_channel_positions (chmap, pos))
        gst_audio_ring_buffer_set_channel_positions (GST_AUDIO_BASE_SRC
            (alsa)->ringbuffer, pos);
    }
    free (chmap);
  }
#endif /* SND_CHMAP_API_VERSION */

  return TRUE;

  /* ERRORS */
spec_parse:
  {
    GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL),
        ("Error parsing spec"));
    return FALSE;
  }
non_block:
  {
    GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL),
        ("Could not set device to blocking: %s", snd_strerror (err)));
    return FALSE;
  }
hw_params_failed:
  {
    GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL),
        ("Setting of hwparams failed: %s", snd_strerror (err)));
    return FALSE;
  }
sw_params_failed:
  {
    GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL),
        ("Setting of swparams failed: %s", snd_strerror (err)));
    return FALSE;
  }
prepare_failed:
  {
    GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL),
        ("Prepare failed: %s", snd_strerror (err)));
    return FALSE;
  }
}
static gboolean
gst_alsasrc_prepare (GstAudioSrc * asrc, GstAudioRingBufferSpec * spec)
{
  GstAlsaSrc *alsa;
  gint err;

  alsa = GST_ALSA_SRC (asrc);

  if (!alsasrc_parse_spec (alsa, spec))
    goto spec_parse;

  CHECK (snd_pcm_nonblock (alsa->handle, 0), non_block);

  CHECK (set_hwparams (alsa), hw_params_failed);
  CHECK (set_swparams (alsa), sw_params_failed);
  CHECK (snd_pcm_prepare (alsa->handle), prepare_failed);

  alsa->bpf = GST_AUDIO_INFO_BPF (&spec->info);
  spec->segsize = alsa->period_size * alsa->bpf;
  spec->segtotal = alsa->buffer_size / alsa->period_size;

  {
    snd_output_t *out_buf = NULL;
    char *msg = NULL;

    snd_output_buffer_open (&out_buf);
    snd_pcm_dump_hw_setup (alsa->handle, out_buf);
    snd_output_buffer_string (out_buf, &msg);
    GST_DEBUG_OBJECT (alsa, "Hardware setup: \n%s", msg);
    snd_output_close (out_buf);
    snd_output_buffer_open (&out_buf);
    snd_pcm_dump_sw_setup (alsa->handle, out_buf);
    snd_output_buffer_string (out_buf, &msg);
    GST_DEBUG_OBJECT (alsa, "Software setup: \n%s", msg);
    snd_output_close (out_buf);
  }

#ifdef SND_CHMAP_API_VERSION
  alsa_detect_channels_mapping (GST_OBJECT (alsa), alsa->handle, spec,
      alsa->channels, GST_AUDIO_BASE_SRC (alsa)->ringbuffer);
#endif /* SND_CHMAP_API_VERSION */

  return TRUE;

  /* ERRORS */
spec_parse:
  {
    GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL),
        ("Error parsing spec"));
    return FALSE;
  }
non_block:
  {
    GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL),
        ("Could not set device to blocking: %s", snd_strerror (err)));
    return FALSE;
  }
hw_params_failed:
  {
    GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL),
        ("Setting of hwparams failed: %s", snd_strerror (err)));
    return FALSE;
  }
sw_params_failed:
  {
    GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL),
        ("Setting of swparams failed: %s", snd_strerror (err)));
    return FALSE;
  }
prepare_failed:
  {
    GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL),
        ("Prepare failed: %s", snd_strerror (err)));
    return FALSE;
  }
}
static int
laudio_alsa_start(uint64_t cur_pos, uint64_t next_pkt)
{
  snd_output_t *output;
  char *debug_pcm_cfg;
  int ret;

  ret = snd_pcm_prepare(hdl);
  if (ret < 0)
    {
      DPRINTF(E_LOG, L_LAUDIO, "Could not prepare PCM device: %s\n", snd_strerror(ret));

      return -1;
    }

  DPRINTF(E_DBG, L_LAUDIO, "Start local audio curpos %" PRIu64 ", next_pkt %" PRIu64 "\n", cur_pos, next_pkt);

  /* Make pcm_pos the rtptime of the packet containing cur_pos */
  pcm_pos = next_pkt;
  while (pcm_pos > cur_pos)
    pcm_pos -= AIRTUNES_V2_PACKET_SAMPLES;

  pcm_start_pos = next_pkt + pcm_period_size;

  /* Compensate period size, otherwise get_pos won't be correct */
  pcm_pos += pcm_period_size;

  DPRINTF(E_DBG, L_LAUDIO, "PCM pos %" PRIu64 ", start pos %" PRIu64 "\n", pcm_pos, pcm_start_pos);

  pcm_pkt_head = NULL;
  pcm_pkt_tail = NULL;

  pcm_last_error = 0;
  pcm_recovery = 0;

  // alsa doesn't actually seem to wait for this threshold?
  ret = laudio_alsa_set_start_threshold(pcm_buf_threshold);
  if (ret < 0)
    {
      DPRINTF(E_LOG, L_LAUDIO, "Could not set PCM start threshold for local audio start\n");

      return -1;
    }

  // Dump PCM config data for E_DBG logging
  ret = snd_output_buffer_open(&output);
  if (ret == 0)
    {
      if (snd_pcm_dump_setup(hdl, output) == 0)
	{
	  snd_output_buffer_string(output, &debug_pcm_cfg);
	  DPRINTF(E_DBG, L_LAUDIO, "Dump of sound device config:\n%s\n", debug_pcm_cfg);
	}

      snd_output_close(output);
    }

  update_status(LAUDIO_STARTED);

  return 0;
}
int
sa_stream_open(sa_stream_t *s) {
  snd_output_t* out;
  char* buf;
  size_t bufsz;
  snd_pcm_hw_params_t* hwparams;
  snd_pcm_sw_params_t* swparams;
  int dir;
  snd_pcm_uframes_t period;

  if (s == NULL) {
    return SA_ERROR_NO_INIT;
  }
  if (s->output_unit != NULL) {
    return SA_ERROR_INVALID;
  }

  pthread_mutex_lock(&sa_alsa_mutex);

  /* Turn off debug output to stderr */
  snd_lib_error_set_handler(quiet_error_handler);

  if (snd_pcm_open(&s->output_unit, 
                   "default", 
                   SND_PCM_STREAM_PLAYBACK, 
                   0) < 0) {
    pthread_mutex_unlock(&sa_alsa_mutex);
    return SA_ERROR_NO_DEVICE;
  }
  
  if (snd_pcm_set_params(s->output_unit,
#ifdef SA_LITTLE_ENDIAN
                         SND_PCM_FORMAT_S16_LE,
#else
                         SND_PCM_FORMAT_S16_BE,
#endif
                         SND_PCM_ACCESS_RW_INTERLEAVED,
                         s->n_channels,
                         s->rate,
                         1,
                         500000) < 0) {
    snd_pcm_close(s->output_unit);
    s->output_unit = NULL;
    pthread_mutex_unlock(&sa_alsa_mutex);
    return SA_ERROR_NOT_SUPPORTED;
  }
  
  /* ugly alsa-pulse plugin detection */
  snd_output_buffer_open(&out);
  snd_pcm_dump(s->output_unit, out);
  bufsz = snd_output_buffer_string(out, &buf);
  s->pulseaudio = bufsz >= strlen(ALSA_PA_PLUGIN) &&
                  strncmp(buf, ALSA_PA_PLUGIN, strlen(ALSA_PA_PLUGIN)) == 0;
  snd_output_close(out);

  snd_pcm_hw_params_alloca(&hwparams);
  snd_pcm_hw_params_current(s->output_unit, hwparams);
  snd_pcm_hw_params_get_period_size(hwparams, &period, &dir);

  pthread_mutex_unlock(&sa_alsa_mutex);

  return SA_SUCCESS;
}
static gboolean
gst_alsasink_prepare (GstAudioSink * asink, GstAudioRingBufferSpec * spec)
{
  GstAlsaSink *alsa;
  gint err;

  alsa = GST_ALSA_SINK (asink);

  if (alsa->iec958) {
    snd_pcm_close (alsa->handle);
    alsa->handle = gst_alsa_open_iec958_pcm (GST_OBJECT (alsa), alsa->device);
    if (G_UNLIKELY (!alsa->handle)) {
      goto no_iec958;
    }
  }

  if (!alsasink_parse_spec (alsa, spec))
    goto spec_parse;

  CHECK (set_hwparams (alsa), hw_params_failed);
  CHECK (set_swparams (alsa), sw_params_failed);

  alsa->bpf = GST_AUDIO_INFO_BPF (&spec->info);
  spec->segsize = alsa->period_size * alsa->bpf;
  spec->segtotal = alsa->buffer_size / alsa->period_size;

  {
    snd_output_t *out_buf = NULL;
    char *msg = NULL;

    snd_output_buffer_open (&out_buf);
    snd_pcm_dump_hw_setup (alsa->handle, out_buf);
    snd_output_buffer_string (out_buf, &msg);
    GST_DEBUG_OBJECT (alsa, "Hardware setup: \n%s", msg);
    snd_output_close (out_buf);
    snd_output_buffer_open (&out_buf);
    snd_pcm_dump_sw_setup (alsa->handle, out_buf);
    snd_output_buffer_string (out_buf, &msg);
    GST_DEBUG_OBJECT (alsa, "Software setup: \n%s", msg);
    snd_output_close (out_buf);
  }

#ifdef SND_CHMAP_API_VERSION
  if (spec->type == GST_AUDIO_RING_BUFFER_FORMAT_TYPE_RAW && alsa->channels < 9) {
    snd_pcm_chmap_t *chmap = snd_pcm_get_chmap (alsa->handle);
    if (chmap && chmap->channels == alsa->channels) {
      GstAudioChannelPosition pos[8];
      if (alsa_chmap_to_channel_positions (chmap, pos))
        gst_audio_ring_buffer_set_channel_positions (GST_AUDIO_BASE_SINK
            (alsa)->ringbuffer, pos);
    }
    free (chmap);
  }
#endif /* SND_CHMAP_API_VERSION */

  return TRUE;

  /* ERRORS */
no_iec958:
  {
    GST_ELEMENT_ERROR (alsa, RESOURCE, OPEN_WRITE, (NULL),
        ("Could not open IEC958 (SPDIF) device for playback"));
    return FALSE;
  }
spec_parse:
  {
    GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL),
        ("Error parsing spec"));
    return FALSE;
  }
hw_params_failed:
  {
    GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL),
        ("Setting of hwparams failed: %s", snd_strerror (err)));
    return FALSE;
  }
sw_params_failed:
  {
    GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL),
        ("Setting of swparams failed: %s", snd_strerror (err)));
    return FALSE;
  }
}