Board index » kylix » Problem with Alsa
|
Dean
kylix Developer |
Problem with Alsa2004-10-18 05:08:46 AM kylix2 Further to the above post, I found a really good reasource on using ALSA and built the following routines. I wonder if anyone here knows what's wrong? I get output from the soundcard, but it isn't what's expected ;-) Sounds a bit like a saw-wave........ Audio packets are PCM 8khz signed 16 bit little-endian. They're sitting in a TQueue derivative that I built which is receiving packets from a TCP/IP Socket. I basically have two functions, one to initialise the soundcard and one to buffer the audio packets to is (160 bytes at a time). "F" is a pointer to my 160 byte PCM buffer. I also get a few "buffer underruns" and I'm not sure of the reason. Thanks, Dean Code is:- unit SoundCardOut; interface uses pcm_ordinary, asoundlib, Libc, SysUtils; type TByteArray = Array[0..0] of Byte; PByteArray = ^TByteArray; function OutputPCM(F : Pointer; H : Psnd_pcm_t) : boolean; function InitSoundCard : Psnd_pcm_t; //--Soundcard handle implementation function InitSoundCard : Psnd_pcm_t; var { Handle for the PCM device } pcm_handle: Psnd_pcm_t; hwparams: Psnd_pcm_hw_params_t; pcm_name: Pchar; rate, periods, periodsize: longint; data: PByteArray; l1, l2: longint; s1, s2: smallint; num_frames: longint; const { Playback stream } stream: snd_pcm_stream_t = SND_PCM_STREAM_PLAYBACK; begin pcm_name := 'plughw:0,0'; { Allocate the snd_pcm_hw_params_t structure } snd_pcm_hw_params_malloc(hwparams); if (snd_pcm_open(pcm_handle, pcm_name, stream, 0) < 0) then begin WriteLn('Error opening PCM device ', pcm_name); Sleep(2000); Halt(1); end; { Init hwparams with full configuration space } if (snd_pcm_hw_params_any(pcm_handle, hwparams) < 0) then begin WriteLn('Can not configure this PCM device.'); Sleep(2000); Halt(1); end; rate := 8000; { Sample rate } periods := 8; { Number of periods } periodsize := 160; { Periodsize (bytes) } if (snd_pcm_hw_params_set_access(pcm_handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED) < 0) then begin WriteLn('Error setting access.'); Sleep(2000); Halt(1); end; { Set sample format } if (snd_pcm_hw_params_set_format(pcm_handle, hwparams, SND_PCM_FORMAT_S16_LE) < 0) then begin WriteLn('Error setting format.'); Sleep(2000); Halt(1); end; {$ifdef ALSA_PCM_NEW_HW_PARAMS_API} if (snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams, @rate, nil) < 0) then {$else} if (snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams, rate, nil) < 0) then {$endif} begin WriteLn('Error setting rate.'); Sleep(2000); Halt(1); end; { Set number of channels } if (snd_pcm_hw_params_set_channels(pcm_handle, hwparams, 2) < 0) then begin WriteLn('Error setting channels.'); Sleep(2000); Halt(1); end; { Set number of periods. Periods used to be called fragments. } if (snd_pcm_hw_params_set_periods(pcm_handle, hwparams, periods, 0) < 0) then begin WriteLn('Error setting periods.'); Sleep(2000); Halt(1); end; { Set buffer size (in frames). The resulting latency is given by latency = periodsize * periods / (rate * bytes_per_frame) } if (snd_pcm_hw_params_set_buffer_size(pcm_handle, hwparams, (periodsize * periods) shr 2) < 0) then begin WriteLn('Error setting buffersize.'); Sleep(2000); Halt(1); end; if (snd_pcm_hw_params(pcm_handle, hwparams) < 0) then begin WriteLn('Error setting HW params.'); Sleep(2000); Halt(1); end; snd_pcm_prepare(pcm_handle); Result := pcm_handle; end; function OutputPCM(F : Pointer; H : Psnd_pcm_t) : boolean; var num_frames: longint; begin num_frames := 160; while (snd_pcm_writei(H, F, num_frames) < 0) do begin snd_pcm_prepare(H); WriteLn('<<<<<<<<<<<<<<< Buffer Underrun>>>>>>>>>>>>>>>'); end; end; end. |
