On Mon, 1 Sep 2003, James Courtier-Dutton wrote:
I have found two problems with using the dmix alsa device name. 1) snd_pcm_hw_params_can_pause (params) causes alsa-lib to assert!
2) Sound is broken up. a) It can only function with 2 periods, why is that? Having 8 periods might be better, although "front" works fine with 2 periods, but "dmix" with 2 periods fails.
See attachment dmix-fail.c compile with gcc -g -DDEBUG -lasound a.c
Shows problem (1) and (2)
I don't have a small compilable example for this yet. The problem application is the latest xine cvs. (xine.sf.net)b) Of the 2 periods, it sounds like sound is only being played from one of the periods, with silence for the other period.
Summary: - If I use device name "front", there are no problems with sound output. If I use device name "dmix", there are the above problems.
Show me your code, please (compilable example).
Jaroslav
Cheers James
/* * Copyright (C) 2000-2002 the xine project * * This file is part of xine, a free video player. * * xine is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * xine is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * * Credits go * - for the SPDIF A/52 sync part * - frame size calculation added (16-08-2001) * (c) 2001 Andy Lo A Foe <[EMAIL PROTECTED]> * for initial ALSA 0.9.x support. * adding MONO/STEREO/4CHANNEL/5CHANNEL/5.1CHANNEL analogue support. * (c) 2001 James Courtier-Dutton <[EMAIL PROTECTED]> * * * $Id: audio_alsa_out.c,v 1.106 2003/09/01 04:08:41 jcdutton Exp $ */
#ifdef HAVE_CONFIG_H #include "config.h" #endif #include <stdio.h> #include <stdarg.h> #include <errno.h> #include <string.h> #include <unistd.h> #include <stdlib.h> #include <fcntl.h> #include <math.h> #include <alloca.h> #define ALSA_PCM_NEW_HW_PARAMS_API #define ALSA_PCM_NEW_SW_PARAMS_API #include <alsa/asoundlib.h> #include <sys/ioctl.h> #include <inttypes.h> #include <pthread.h> /* #define ALSA_LOG */ /* #define LOG_DEBUG */ #define AO_OUT_ALSA_IFACE_VERSION 7 #define BUFFER_TIME 1000*1000 #define PERIOD_TIME 100*1000 #define GAP_TOLERANCE 5000 #define MIXER_MASK_LEFT (1 << 0) #define MIXER_MASK_RIGHT (1 << 1) #define MIXER_MASK_STEREO (MIXER_MASK_LEFT|MIXER_MASK_RIGHT) typedef struct alsa_driver_s { snd_pcm_t *audio_fd; int capabilities; int open_mode; int has_pause_resume; int32_t output_sample_rate, input_sample_rate; double sample_rate_factor; uint32_t num_channels; uint32_t bits_per_sample; uint32_t bytes_per_frame; uint32_t bytes_in_buffer; /* number of bytes writen to audio hardware */ snd_pcm_uframes_t buffer_size; int32_t mmap; } alsa_driver_t; static snd_output_t *jcd_out; /* * open the audio device for writing to */ int main (int argc, char **argv) { alsa_driver_t variables; alsa_driver_t *this = &variables; char *pcm_device; snd_pcm_stream_t direction = SND_PCM_STREAM_PLAYBACK; snd_pcm_hw_params_t *params; snd_pcm_sw_params_t *swparams; snd_pcm_access_mask_t *mask; snd_pcm_uframes_t period_size; uint32_t periods; uint32_t buffer_time=BUFFER_TIME; int err, dir; int open_mode=1; /* NONBLOCK */ /* int open_mode=0; BLOCK */ int rate = 48000; int bits = 16; snd_pcm_hw_params_alloca(¶ms); snd_pcm_sw_params_alloca(&swparams); err = snd_output_stdio_attach(&jcd_out, stdout, 0); pcm_device = "dmix"; #ifdef ALSA_LOG printf("audio_alsa_out: Audio Device name = %s\n",pcm_device); printf("audio_alsa_out: Number of channels = %d\n",this->num_channels); #endif this->audio_fd = NULL; this->open_mode = open_mode; this->input_sample_rate = rate; this->bits_per_sample = bits; this->num_channels = 2; this->bytes_in_buffer = 0; /* * open audio device */ err=snd_pcm_open(&this->audio_fd, pcm_device, direction, open_mode); if(err <0 ) { printf ("audio_alsa_out: snd_pcm_open() of %s failed: %s\n", pcm_device, snd_strerror(err)); printf ("audio_alsa_out: >>> check if another program don't already use PCM <<<\n"); return 0; } /* printf ("audio_alsa_out: snd_pcm_open() opened %s\n", pcm_device); */ /* We wanted non blocking open but now put it back to normal */ //snd_pcm_nonblock(this->audio_fd, 0); snd_pcm_nonblock(this->audio_fd, 1); /* * configure audio device */ err = snd_pcm_hw_params_any(this->audio_fd, params); if (err < 0) { printf ("audio_alsa_out: broken configuration for this PCM: no configurations available\n"); goto __close; } /* set interleaved access */ if (this->mmap != 0) { mask = alloca(snd_pcm_access_mask_sizeof()); snd_pcm_access_mask_none(mask); snd_pcm_access_mask_set(mask, SND_PCM_ACCESS_MMAP_INTERLEAVED); snd_pcm_access_mask_set(mask, SND_PCM_ACCESS_MMAP_NONINTERLEAVED); snd_pcm_access_mask_set(mask, SND_PCM_ACCESS_MMAP_COMPLEX); err = snd_pcm_hw_params_set_access_mask(this->audio_fd, params, mask); if (err < 0) { printf ("audio_alsa_out: mmap not availiable, falling back to compatiblity mode\n"); this->mmap=0; err = snd_pcm_hw_params_set_access(this->audio_fd, params, SND_PCM_ACCESS_RW_INTERLEAVED); } } else { err = snd_pcm_hw_params_set_access(this->audio_fd, params, SND_PCM_ACCESS_RW_INTERLEAVED); } if (err < 0) { printf ("audio_alsa_out: access type not available\n"); goto __close; } /* set the sample format ([SU]{8,16{LE,BE}})*/ err = snd_pcm_hw_params_set_format(this->audio_fd, params, (bits == 16) ? #ifdef WORDS_BIGENDIAN SND_PCM_FORMAT_S16_BE #else SND_PCM_FORMAT_S16_LE #endif : SND_PCM_FORMAT_U8); if (err < 0) { printf ("audio_alsa_out: sample format non available\n"); goto __close; } /* set the number of channels */ err = snd_pcm_hw_params_set_channels(this->audio_fd, params, this->num_channels); if (err < 0) { printf ("audio_alsa_out: Cannot set number of channels to %d (err=%d)\n", this->num_channels, err); goto __close; } /* set the stream rate [Hz] */ dir=0; err = snd_pcm_hw_params_set_rate_near(this->audio_fd, params, &rate, &dir); if (err < 0) { printf ("audio_alsa_out: rate not available\n"); goto __close; } this->output_sample_rate = (uint32_t)rate; if (this->input_sample_rate != this->output_sample_rate) { printf ("audio_alsa_out: audio rate : %d requested, %d provided by device/sec\n", this->input_sample_rate, this->output_sample_rate); } /* Set period to buffer size ratios at 8 periods to 1 buffer */ dir=-1; periods=8; err = snd_pcm_hw_params_set_periods_near(this->audio_fd, params, &periods ,&dir); if (err < 0) { printf ("audio_alsa_out: unable to set any periods\n"); goto __close; } printf ("audio_alsa_out: Requested 8 periods, got %d\n", periods); /* set the ring-buffer time [us] (large enough for x us|y samples ...) */ dir=0; err = snd_pcm_hw_params_set_buffer_time_near(this->audio_fd, params, &buffer_time, &dir); if (err < 0) { printf ("audio_alsa_out: buffer time not available\n"); goto __close; } err = snd_pcm_hw_params_get_buffer_size(params, &(this->buffer_size)); #if 0 /* set the period time [us] (interrupt every x us|y samples ...) */ dir=0; period_size=this->buffer_size/8; err = snd_pcm_hw_params_set_period_size_near(this->audio_fd, params, &period_size, &dir); if (err < 0) { printf ("audio_alsa_out: period time not available"); goto __close; } #endif dir=0; err = snd_pcm_hw_params_get_period_size(params, &period_size, &dir); if (2*period_size > this->buffer_size) { printf ("audio_alsa_out: buffer to small, could not use\n"); goto __close; } /* write the parameters to device */ err = snd_pcm_hw_params(this->audio_fd, params); if (err < 0) { printf ("audio_alsa_out: pcm hw_params failed: %s\n", snd_strerror(err)); goto __close; } /* Check for pause/resume support */ this->has_pause_resume = ( snd_pcm_hw_params_can_pause (params) && snd_pcm_hw_params_can_resume (params) ); this->sample_rate_factor = (double) this->output_sample_rate / (double) this->input_sample_rate; this->bytes_per_frame = snd_pcm_frames_to_bytes (this->audio_fd, 1); /* * audio buffer size handling */ /* Copy current parameters into swparams */ err = snd_pcm_sw_params_current(this->audio_fd, swparams); if (err < 0) { printf ("audio_alsa_out: Unable to determine current swparams: %s\n", snd_strerror(err)); goto __close; } /* align all transfers to 1 sample */ err = snd_pcm_sw_params_set_xfer_align(this->audio_fd, swparams, 1); if (err < 0) { printf ("audio_alsa_out: Unable to set transfer alignment: %s\n", snd_strerror(err)); goto __close; } /* allow the transfer when at least period_size samples can be processed */ err = snd_pcm_sw_params_set_avail_min(this->audio_fd, swparams, period_size); if (err < 0) { printf ("audio_alsa_out: Unable to set available min: %s\n", snd_strerror(err)); goto __close; } /* start the transfer when the buffer contains at least period_size samples */ err = snd_pcm_sw_params_set_start_threshold(this->audio_fd, swparams, period_size); if (err < 0) { printf ("audio_alsa_out: Unable to set start threshold: %s\n", snd_strerror(err)); goto __close; } /* never stop the transfer, even on xruns */ err = snd_pcm_sw_params_set_stop_threshold(this->audio_fd, swparams, this->buffer_size); if (err < 0) { printf ("audio_alsa_out: Unable to set stop threshold: %s\n", snd_strerror(err)); goto __close; } /* Install swparams into current parameters */ err = snd_pcm_sw_params(this->audio_fd, swparams); if (err < 0) { printf ("audio_alsa_out: Unable to set swparams: %s\n", snd_strerror(err)); goto __close; } #ifdef ALSA_LOG snd_pcm_dump_setup(this->audio_fd, jcd_out); snd_pcm_sw_params_dump(swparams, jcd_out); #endif // return this->output_sample_rate; __close: snd_pcm_close (this->audio_fd); this->audio_fd=NULL; return 0; }