/* Return the best matching sample format for the requested format and * available format mask. */ static long sfmt_best_matching (const long formats_with_endian, const long req_with_endian) { long formats = formats_with_endian & SFMT_MASK_FORMAT; long req = req_with_endian & SFMT_MASK_FORMAT; long best = 0; #ifdef DEBUG char fmt_name1[SFMT_STR_MAX]; char fmt_name2[SFMT_STR_MAX]; #endif if (formats & req) best = req; else if (req == SFMT_S8 || req == SFMT_U8) { if (formats & SFMT_S8) best = SFMT_S8; else if (formats & SFMT_U8) best = SFMT_U8; else if (formats & SFMT_S16) best = SFMT_S16; else if (formats & SFMT_U16) best = SFMT_U16; else if (formats & SFMT_S32) best = SFMT_S32; else if (formats & SFMT_U32) best = SFMT_U32; else if (formats & SFMT_FLOAT) best = SFMT_FLOAT; } else if (req == SFMT_S16 || req == SFMT_U16) { if (formats & SFMT_S16) best = SFMT_S16; else if (formats & SFMT_U16) best = SFMT_U16; else if (formats & SFMT_S32) best = SFMT_S32; else if (formats & SFMT_U32) best = SFMT_U32; else if (formats & SFMT_FLOAT) best = SFMT_FLOAT; else if (formats & SFMT_S8) best = SFMT_S8; else if (formats & SFMT_U8) best = SFMT_U8; } else if (req == SFMT_S32 || req == SFMT_U32 || req == SFMT_FLOAT) { if (formats & SFMT_S32) best = SFMT_S32; else if (formats & SFMT_U32) best = SFMT_U32; else if (formats & SFMT_S16) best = SFMT_S16; else if (formats & SFMT_U16) best = SFMT_U16; else if (formats & SFMT_FLOAT) best = SFMT_FLOAT; else if (formats & SFMT_S8) best = SFMT_S8; else if (formats & SFMT_U8) best = SFMT_U8; } assert (best != 0); if (!(best & (SFMT_S8 | SFMT_U8))) { if ((formats_with_endian & SFMT_LE) && (formats_with_endian & SFMT_BE)) best |= SFMT_NE; else best |= formats_with_endian & SFMT_MASK_ENDIANNESS; } #ifdef DEBUG debug ("Chose %s as the best matching %s", sfmt_str(best, fmt_name1, sizeof(fmt_name1)), sfmt_str(req_with_endian, fmt_name2, sizeof(fmt_name2))); #endif return best; }
static int alsa_open (struct sound_params *sound_params) { snd_pcm_hw_params_t *hw_params; int err; unsigned int period_time; unsigned int buffer_time; snd_pcm_uframes_t chunk_frames; snd_pcm_uframes_t buffer_frames; char fmt_name[128]; switch (sound_params->fmt & SFMT_MASK_FORMAT) { case SFMT_S8: params.format = SND_PCM_FORMAT_S8; break; case SFMT_U8: params.format = SND_PCM_FORMAT_U8; break; case SFMT_S16: params.format = SND_PCM_FORMAT_S16; break; case SFMT_U16: params.format = SND_PCM_FORMAT_U16; break; case SFMT_S32: params.format = SND_PCM_FORMAT_S32; break; case SFMT_U32: params.format = SND_PCM_FORMAT_U32; break; default: error ("Unknown sample format: %s", sfmt_str(sound_params->fmt, fmt_name, sizeof(fmt_name))); params.format = SND_PCM_FORMAT_UNKNOWN; return 0; } if ((err = snd_pcm_open(&handle, options_get_str("AlsaDevice"), SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK)) < 0) { error ("Can't open audio: %s", snd_strerror(err)); return 0; } if ((err = snd_pcm_hw_params_malloc(&hw_params)) < 0) { error ("Can't allocate alsa hardware parameters structure: %s", snd_strerror(err)); return 0; } if ((err = snd_pcm_hw_params_any (handle, hw_params)) < 0) { error ("Can't initialize hardware parameters structure: %s", snd_strerror(err)); snd_pcm_hw_params_free (hw_params); return 0; } if ((err = snd_pcm_hw_params_set_access (handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) { error ("Can't set alsa access type: %s", snd_strerror(err)); snd_pcm_hw_params_free (hw_params); return 0; } if ((err = snd_pcm_hw_params_set_format (handle, hw_params, params.format)) < 0) { error ("Can't set sample format: %s", snd_strerror(err)); snd_pcm_hw_params_free (hw_params); return 0; } params.rate = sound_params->rate; if ((err = snd_pcm_hw_params_set_rate_near (handle, hw_params, ¶ms.rate, 0)) < 0) { error ("Can't set sample rate: %s", snd_strerror(err)); snd_pcm_hw_params_free (hw_params); return 0; } logit ("Set rate to %d", params.rate); if ((err = snd_pcm_hw_params_set_channels (handle, hw_params, sound_params->channels)) < 0) { error ("Can't set number of channels: %s", snd_strerror(err)); snd_pcm_hw_params_free (hw_params); return 0; } if ((err = snd_pcm_hw_params_get_buffer_time_max(hw_params, &buffer_time, 0)) < 0) { error ("Can't get maximum buffer time: %s", snd_strerror(err)); snd_pcm_hw_params_free (hw_params); return 0; } if (buffer_time > BUFFER_MAX_USEC) buffer_time = BUFFER_MAX_USEC; period_time = buffer_time / 4; if ((err = snd_pcm_hw_params_set_period_time_near(handle, hw_params, &period_time, 0)) < 0) { error ("Can't set period time: %s", snd_strerror(err)); snd_pcm_hw_params_free (hw_params); return 0; } if ((err = snd_pcm_hw_params_set_buffer_time_near(handle, hw_params, &buffer_time, 0)) < 0) { error ("Can't set buffer time: %s", snd_strerror(err)); snd_pcm_hw_params_free (hw_params); return 0; } if ((err = snd_pcm_hw_params (handle, hw_params)) < 0) { error ("Can't set audio parameters: %s", snd_strerror(err)); snd_pcm_hw_params_free (hw_params); return 0; } snd_pcm_hw_params_get_period_size (hw_params, &chunk_frames, 0); snd_pcm_hw_params_get_buffer_size (hw_params, &buffer_frames); bytes_per_frame = sound_params->channels * sfmt_Bps(sound_params->fmt); logit ("Buffer time: %ldus", buffer_frames * bytes_per_frame); if (chunk_frames == buffer_frames) { error ("Can't use period equal to buffer size (%lu == %lu)", chunk_frames, buffer_frames); snd_pcm_hw_params_free (hw_params); return 0; } chunk_size = chunk_frames * bytes_per_frame; debug ("Chunk size: %d", chunk_size); snd_pcm_hw_params_free (hw_params); if ((err = snd_pcm_prepare(handle)) < 0) { error ("Can't prepare audio interface for use: %s", snd_strerror(err)); return 0; } debug ("ALSA device initialized"); params.channels = sound_params->channels; alsa_buf_fill = 0; return 1; }