diff options
author | dec05eba <dec05eba@protonmail.com> | 2020-03-29 09:10:24 +0200 |
---|---|---|
committer | dec05eba <dec05eba@protonmail.com> | 2020-03-29 09:10:24 +0200 |
commit | 7c8c97b1a8f844d7e0e682abe0dcba01c2973a66 (patch) | |
tree | 8f7a34dad700a44a866475fd0a7e24ffe829dbf9 /src | |
parent | bcb79582c511706358e85d95c003e4feb85c66df (diff) |
add alsa
Diffstat (limited to 'src')
-rw-r--r-- | src/sound.cpp | 84 |
1 files changed, 84 insertions, 0 deletions
diff --git a/src/sound.cpp b/src/sound.cpp new file mode 100644 index 0000000..fcfa7ae --- /dev/null +++ b/src/sound.cpp @@ -0,0 +1,84 @@ +#include "../include/sound.hpp" + +#include <stdlib.h> +#include <stdio.h> + +#define ALSA_PCM_NEW_HW_PARAMS_API +#include <alsa/asoundlib.h> + +int sound_device_get_by_name(SoundDevice *device, const char *name, unsigned int num_channels, unsigned int period_frame_size) { + int rc; + snd_pcm_t *handle; + + rc = snd_pcm_open(&handle, name, SND_PCM_STREAM_CAPTURE, 0); + if(rc < 0) { + fprintf(stderr, "unable to open pcm device 'default', reason: %s\n", snd_strerror(rc)); + return rc; + } + + snd_pcm_hw_params_t *params; + snd_pcm_hw_params_alloca(¶ms); + // Fill the params with default values + snd_pcm_hw_params_any(handle, params); + // Interleaved mode + snd_pcm_hw_params_set_access(handle, params, SND_PCM_ACCESS_RW_INTERLEAVED); + // Signed 16--bit little-endian format + snd_pcm_hw_params_set_format(handle, params, SND_PCM_FORMAT_S16_LE); + snd_pcm_hw_params_set_channels(handle, params, num_channels); + + // 44100 bits/second samling rate (CD quality) + unsigned int val = 44100; + int dir; + snd_pcm_hw_params_set_rate_near(handle, params, &val, &dir); + + snd_pcm_uframes_t frames = period_frame_size; + snd_pcm_hw_params_set_period_size_near(handle, params, &frames, &dir); + + // Write the parmeters to the driver + rc = snd_pcm_hw_params(handle, params); + if(rc < 0) { + fprintf(stderr, "unable to set hw parameters, reason: %s\n", snd_strerror(rc)); + snd_pcm_close(handle); + return rc; + } + + // Use a buffer large enough to hold one period + snd_pcm_hw_params_get_period_size(params, &frames, &dir); + int buffer_size = frames * 2 * num_channels; // 2 bytes/sample, @num_channels channels + char *buffer = (char*)malloc(buffer_size); + if(!buffer) { + fprintf(stderr, "failed to allocate buffer for audio\n"); + snd_pcm_close(handle); + return -1; + } + + device->handle = (void*)handle; + device->buffer = buffer; + device->buffer_size = buffer_size; + device->frames = frames; + return 0; +} + +int sound_device_close(SoundDevice *device) { + /* TODO: Is this also needed in @sound_device_get_by_name on failure? */ + snd_pcm_drain((snd_pcm_t*)device->handle); + snd_pcm_close((snd_pcm_t*)device->handle); + free(device->buffer); +} + +int sound_device_read_next_chunk(SoundDevice *device, char **buffer) { + int rc = snd_pcm_readi((snd_pcm_t*)device->handle, device->buffer, device->frames); + if (rc == -EPIPE) { + /* overrun */ + fprintf(stderr, "overrun occured\n"); + snd_pcm_prepare((snd_pcm_t*)device->handle); + return 0; + } else if(rc < 0) { + fprintf(stderr, "failed to read from sound device, reason: %s\n", snd_strerror(rc)); + return rc; + } else if (rc != (int)device->frames) { + fprintf(stderr, "short read, read %d frames\n", rc); + } + *buffer = device->buffer; + return rc; +} |