ALSA audio output experiment
I think it's smart to rather use ALSA directly instead of PortAudio. ALSA is push AFAIK, and talking about it here at the hackspace, seems like the better choice. It's a bit lower level, but anyway everything speaks ALSA anyway. It's not like there's any reason to use PortAudio at all. It's just an extra abstraction. Coding for ALSA it'll also work with Pulseaudio and esd. Do people really use other sound systems than Pulseaudio, esd or plain ALSA? I can't think of it. I really the idea about building a small tool first. I'll do that. Also thought about making a small blikning cursor/text output, and syncing a BEEP-sound to that, so that I can test around with throwing in lots and lots of latency between "me" and the video, and try to sync it anyway. I should be able to read back from the sound card (or pulse audio underneath, it will just work with alsa as the abstraction) how long it takes for the bytes I'm pushing to reach the speakers, and do some buffer tuning on that.
This commit is contained in:
parent
37384f1b68
commit
29394345af
2 changed files with 175 additions and 0 deletions
148
src/tool/alsa.c
Normal file
148
src/tool/alsa.c
Normal file
|
|
@ -0,0 +1,148 @@
|
|||
#include <err.h>
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <alsa/asoundlib.h>
|
||||
|
||||
static snd_pcm_t* playback_handle = 0;
|
||||
static snd_pcm_sw_params_t* sw_params = 0;
|
||||
static snd_pcm_hw_params_t* hw_params = 0;
|
||||
static snd_pcm_sframes_t buffer_size = 0;
|
||||
|
||||
static snd_pcm_sframes_t written = 0;
|
||||
static snd_pcm_sframes_t delay = 0;
|
||||
|
||||
static unsigned int rate = 44100;
|
||||
|
||||
static int audio_initialized = 0;
|
||||
|
||||
size_t
|
||||
audio_offset()
|
||||
{
|
||||
snd_pcm_delay(playback_handle, &delay);
|
||||
|
||||
return written - delay;
|
||||
}
|
||||
|
||||
void
|
||||
audio_init()
|
||||
{
|
||||
unsigned int buffer_time = 50000;
|
||||
const char* device;
|
||||
int err;
|
||||
|
||||
if(audio_initialized)
|
||||
return;
|
||||
|
||||
audio_initialized = 1;
|
||||
|
||||
device = getenv("ALSA_DEVICE");
|
||||
|
||||
if(!device)
|
||||
device = "default";
|
||||
|
||||
if(0 > (err = snd_pcm_open(&playback_handle, device,
|
||||
SND_PCM_STREAM_PLAYBACK, 0/*SND_PCM_NONBLOCK*/)))
|
||||
errx(EXIT_FAILURE, "Audio: Cannot open device %s: %s", device, snd_strerror(err));
|
||||
|
||||
if(0 > (err = snd_pcm_sw_params_malloc(&sw_params)))
|
||||
errx(EXIT_FAILURE, "Audio: Could not allocate software parameter structure: %s",
|
||||
snd_strerror(err));
|
||||
|
||||
if(0 > (err = snd_pcm_hw_params_malloc(&hw_params)))
|
||||
errx(EXIT_FAILURE, "Audio: Could not allocate hardware parameter structure: %s",
|
||||
snd_strerror(err));
|
||||
|
||||
if(0 > (err = snd_pcm_hw_params_any(playback_handle, hw_params)))
|
||||
errx(EXIT_FAILURE, "Audio: Could not initializa hardware parameters: %s",
|
||||
snd_strerror(err));
|
||||
|
||||
if(0 > (err = snd_pcm_hw_params_set_access(playback_handle, hw_params,
|
||||
SND_PCM_ACCESS_RW_INTERLEAVED)))
|
||||
errx(EXIT_FAILURE, "Audio: Could not set access type: %s", snd_strerror(err));
|
||||
|
||||
if(0 > (err = snd_pcm_hw_params_set_format(playback_handle, hw_params,
|
||||
SND_PCM_FORMAT_S16)))
|
||||
errx(EXIT_FAILURE, "Audio: Could not set sample format to signed 16 bit "
|
||||
"native endian: %s", snd_strerror(err));
|
||||
|
||||
if(0 > (err = snd_pcm_hw_params_set_rate_near(playback_handle, hw_params,
|
||||
&rate, 0)))
|
||||
errx(EXIT_FAILURE, "Audio: Could not set sample rate %uHz: %s", rate,
|
||||
snd_strerror(err));
|
||||
|
||||
if(0 > (err = snd_pcm_hw_params_set_channels(playback_handle, hw_params, 2)))
|
||||
errx(EXIT_FAILURE, "Audio: Could not set channel count to %u: %s",
|
||||
2, snd_strerror(err));
|
||||
|
||||
snd_pcm_hw_params_set_buffer_time_near(playback_handle, hw_params, &buffer_time, 0);
|
||||
|
||||
if(0 > (err = snd_pcm_hw_params(playback_handle, hw_params)))
|
||||
errx(EXIT_FAILURE, "Audio: Could not set hardware parameters: %s", snd_strerror(err));
|
||||
|
||||
fprintf(stderr, "Buffer time is %.3f seconds\n", buffer_time / 1.0e6);
|
||||
|
||||
if(0 > (err = snd_pcm_sw_params_current(playback_handle, sw_params)))
|
||||
errx(EXIT_FAILURE, "Audio: Could not initialize software parameters: %s",
|
||||
snd_strerror(err));
|
||||
|
||||
snd_pcm_sw_params_set_start_threshold(playback_handle, sw_params, 0);
|
||||
snd_pcm_sw_params_set_avail_min(playback_handle, sw_params, 1024);
|
||||
|
||||
snd_pcm_uframes_t min;
|
||||
snd_pcm_sw_params_get_avail_min(sw_params, &min);
|
||||
fprintf(stderr, "Minimum %u\n", (unsigned) min);
|
||||
|
||||
if(0 > (err = snd_pcm_sw_params(playback_handle, sw_params)))
|
||||
errx(EXIT_FAILURE, "Audio: Could not set software parameters: %s",
|
||||
snd_strerror(err));
|
||||
|
||||
buffer_size = snd_pcm_avail_update(playback_handle);
|
||||
}
|
||||
|
||||
size_t
|
||||
audio_write(const void* data, size_t amount)
|
||||
{
|
||||
int err;
|
||||
|
||||
amount /= 4;
|
||||
|
||||
for(;;)
|
||||
{
|
||||
err = snd_pcm_writei(playback_handle, data, amount);
|
||||
|
||||
if(err == -EAGAIN)
|
||||
return 0;
|
||||
|
||||
if(err < 0)
|
||||
{
|
||||
err = snd_pcm_recover(playback_handle, err, 0);
|
||||
|
||||
if(err < 0)
|
||||
errx(EXIT_FAILURE, "Audio playback failed: %s", strerror(-err));
|
||||
}
|
||||
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
written += err;
|
||||
|
||||
err *= 4;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
void
|
||||
audio_start(unsigned int rate, unsigned int channel_count)
|
||||
{
|
||||
audio_init();
|
||||
|
||||
snd_pcm_prepare(playback_handle);
|
||||
}
|
||||
|
||||
void
|
||||
audio_stop()
|
||||
{
|
||||
snd_pcm_drain(playback_handle);
|
||||
}
|
||||
27
src/tool/main.c
Normal file
27
src/tool/main.c
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
#include <unistd.h>
|
||||
#include <stdint.h>
|
||||
#include "alsa.c"
|
||||
|
||||
#define SAMPLE_RATE 44100
|
||||
|
||||
int16_t quiet[SAMPLE_RATE], noisy[SAMPLE_RATE];
|
||||
|
||||
void main () {
|
||||
|
||||
for (int i=0; i<SAMPLE_RATE; i++)
|
||||
{
|
||||
quiet[i] = 0;
|
||||
noisy[i] = i%30000;
|
||||
}
|
||||
audio_start(44100, 2);
|
||||
|
||||
for (int i=0; i<10; i++)
|
||||
{
|
||||
audio_write(noisy, SAMPLE_RATE);
|
||||
printf("=================================\n");
|
||||
audio_write(quiet, SAMPLE_RATE);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
audio_stop();
|
||||
}
|
||||
Loading…
Reference in a new issue