static int get_chmap(snd_pcm_t *pcm, int format, int channels, int rate) { snd_pcm_chmap_t *map; if (setup_pcm(pcm, format, channels, rate)) return 1; map = snd_pcm_get_chmap(pcm); if (!map) { printf("Cannot get chmap\n"); return 1; } printf("Channels = %d\n", map->channels); print_channels(map); free(map); return 0; }
static int set_chmap(snd_pcm_t *pcm, int format, int channels, int rate, int nargs, char **arg) { int i; snd_pcm_chmap_t *map; if (channels && channels != nargs) { printf("Inconsistent channels %d vs %d\n", channels, nargs); return 1; } if (!channels) { if (!nargs) { printf("No channels are given\n"); return 1; } channels = nargs; } if (setup_pcm(pcm, format, channels, rate)) return 1; map = malloc(sizeof(int) * (channels + 1)); if (!map) { printf("cannot malloc\n"); return 1; } map->channels = channels; for (i = 0; i < channels; i++) { int val = snd_pcm_chmap_from_string(arg[i]); if (val < 0) val = SND_CHMAP_UNKNOWN; map->pos[i] = val; } if (snd_pcm_set_chmap(pcm, map) < 0) { printf("Cannot set chmap\n"); return 1; } free(map); map = snd_pcm_get_chmap(pcm); if (!map) { printf("Cannot get chmap\n"); return 1; } printf("Get channels = %d\n", map->channels); print_channels(map); free(map); return 0; }
snd_pcm_chmap_t *snd_pcm_generic_get_chmap(snd_pcm_t *pcm) { snd_pcm_generic_t *generic = pcm->private_data; return snd_pcm_get_chmap(generic->slave); }
bool OutputALSA::initialize(quint32 freq, ChannelMap map, Qmmp::AudioFormat format) { m_inited = false; if (pcm_handle) return false; if (snd_pcm_open(&pcm_handle, pcm_name, SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK) < 0) { qWarning ("OutputALSA: Error opening PCM device %s", pcm_name); return false; } // we need to configure uint rate = freq; /* Sample rate */ uint exact_rate = freq; /* Sample rate returned by */ /* load settings from config */ QSettings settings(Qmmp::configFile(), QSettings::IniFormat); settings.beginGroup("ALSA"); uint buffer_time = settings.value("buffer_time",500).toUInt()*1000; uint period_time = settings.value("period_time",100).toUInt()*1000; bool use_pause = settings.value("use_snd_pcm_pause", false).toBool(); settings.endGroup(); snd_pcm_hw_params_t *hwparams = 0; snd_pcm_sw_params_t *swparams = 0; int err; //alsa error code //hw params snd_pcm_hw_params_alloca(&hwparams); if ((err = snd_pcm_hw_params_any(pcm_handle, hwparams)) < 0) { qWarning("OutputALSA: Can not read configuration for PCM device: %s", snd_strerror(err)); return false; } if (m_use_mmap) { if ((err = snd_pcm_hw_params_set_access(pcm_handle, hwparams, SND_PCM_ACCESS_MMAP_INTERLEAVED)) < 0) { qWarning("OutputALSA: Error setting mmap access: %s", snd_strerror(err)); m_use_mmap = false; } } if (!m_use_mmap) { if ((err = snd_pcm_hw_params_set_access(pcm_handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) { qWarning("OutputALSA: Error setting access: %s", snd_strerror(err)); return false; } } snd_pcm_format_t alsa_format = SND_PCM_FORMAT_UNKNOWN; switch (format) { case Qmmp::PCM_S8: alsa_format = SND_PCM_FORMAT_S8; break; case Qmmp::PCM_S16LE: alsa_format = SND_PCM_FORMAT_S16_LE; break; case Qmmp::PCM_S24LE: alsa_format = SND_PCM_FORMAT_S24_LE; break; case Qmmp::PCM_S32LE: alsa_format = SND_PCM_FORMAT_S32_LE; break; default: qWarning("OutputALSA: unsupported format detected"); return false; } if ((err = snd_pcm_hw_params_set_format(pcm_handle, hwparams, alsa_format)) < 0) { qDebug("OutputALSA: Error setting format: %s", snd_strerror(err)); return false; } exact_rate = rate; if ((err = snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams, &exact_rate, 0)) < 0) { qWarning("OutputALSA: Error setting rate: %s", snd_strerror(err)); return false; } if (rate != exact_rate) { qWarning("OutputALSA: The rate %d Hz is not supported by your hardware.\n==> Using %d Hz instead.", rate, exact_rate); rate = exact_rate; } uint c = map.count(); if ((err = snd_pcm_hw_params_set_channels_near(pcm_handle, hwparams, &c)) < 0) { qWarning("OutputALSA: Error setting channels: %s", snd_strerror(err)); return false; } if (c != (uint)map.count()) { qWarning("OutputALSA: The channel number %d is not supported by your hardware", map.count()); qWarning("==> Using %d instead.", c); } if ((err = snd_pcm_hw_params_set_period_time_near(pcm_handle, hwparams, &period_time ,0)) < 0) { qWarning("OutputALSA: Error setting period time: %s", snd_strerror(err)); return false; } if ((err = snd_pcm_hw_params_set_buffer_time_near(pcm_handle, hwparams, &buffer_time ,0)) < 0) { qWarning("OutputALSA: Error setting buffer time: %s", snd_strerror(err)); return false; } if ((err = snd_pcm_hw_params(pcm_handle, hwparams)) < 0) { qWarning("OutputALSA: Error setting HW params: %s", snd_strerror(err)); return false; } //read some alsa parameters snd_pcm_uframes_t buffer_size = 0; snd_pcm_uframes_t period_size = 0; if ((err = snd_pcm_hw_params_get_buffer_size(hwparams, &buffer_size)) < 0) { qWarning("OutputALSA: Error reading buffer size: %s", snd_strerror(err)); return false; } if ((err = snd_pcm_hw_params_get_period_size(hwparams, &period_size, 0)) < 0) { qWarning("OutputALSA: Error reading period size: %s", snd_strerror(err)); return false; } //swparams snd_pcm_sw_params_alloca(&swparams); snd_pcm_sw_params_current(pcm_handle, swparams); if ((err = snd_pcm_sw_params_set_start_threshold(pcm_handle, swparams, buffer_size - period_size)) < 0) qWarning("OutputALSA: Error setting threshold: %s", snd_strerror(err)); if ((err = snd_pcm_sw_params(pcm_handle, swparams)) < 0) { qWarning("OutputALSA: Error setting SW params: %s", snd_strerror(err)); return false; } //setup needed values m_chunk_size = period_size; m_can_pause = snd_pcm_hw_params_can_pause(hwparams) && use_pause; qDebug("OutputALSA: can pause: %d", m_can_pause); ChannelMap out_map = map; #if (SND_LIB_VERSION >= 0x01001B) //channel map configuration snd_pcm_chmap_t *chmap = snd_pcm_get_chmap(pcm_handle); if(chmap) { out_map.clear(); char tmp[256]; memset(tmp,0,256); snd_pcm_chmap_print(chmap, 256, tmp); qDebug("OutputALSA: received channel map: %s",tmp); for(uint i = 0; i < chmap->channels; ++i) { if(m_alsa_channels.keys().contains(chmap->pos[i])) out_map.append(m_alsa_channels.value(chmap->pos[i])); else out_map.append(Qmmp::CHAN_NULL); } free(chmap); } else qWarning("OutputALSA: Unable to receive current channel map"); #endif configure(exact_rate, out_map, format); //apply configuration //create alsa prebuffer; m_prebuf_size = 2 * snd_pcm_frames_to_bytes(pcm_handle, m_chunk_size); //buffer for two periods m_prebuf = (uchar *)malloc(m_prebuf_size); m_inited = true; return true; }
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_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; } }