diff options
-rw-r--r-- | include/sound.hpp | 27 | ||||
-rw-r--r-- | project.conf | 5 | ||||
-rw-r--r-- | src/sound.cpp | 84 |
3 files changed, 115 insertions, 1 deletions
diff --git a/include/sound.hpp b/include/sound.hpp new file mode 100644 index 0000000..41dd043 --- /dev/null +++ b/include/sound.hpp @@ -0,0 +1,27 @@ +#ifndef GPU_SCREEN_RECORDER_H +#define GPU_SCREEN_RECORDER_H + +typedef struct { + void *handle; + char *buffer; + int buffer_size; + unsigned int frames; +} SoundDevice; + +/* + Get a sound device by name, returning the device into the @device parameter. + The device should be closed with @sound_device_close after it has been used + to clean up internal resources. + Returns 0 on success, or a negative value on failure. +*/ +int sound_device_get_by_name(SoundDevice *device, const char *name = "default", unsigned int num_channels = 1, unsigned int period_frame_size = 32); + +int sound_device_close(SoundDevice *device); + +/* + Returns the next chunk of audio into @buffer. + Returns the size of the buffer, or a negative value on failure. +*/ +int sound_device_read_next_chunk(SoundDevice *device, char **buffer); + +#endif /* GPU_SCREEN_RECORDER_H */ diff --git a/project.conf b/project.conf index bc30fab..f7a8e64 100644 --- a/project.conf +++ b/project.conf @@ -6,6 +6,7 @@ platforms = ["posix"] [config] include_dirs = ["/opt/cuda/targets/x86_64-linux/include"] +libs = ["/usr/lib/libcuda.so"] [dependencies] ffnvcodec = ">=9" @@ -20,4 +21,6 @@ xcomposite = ">=0.2" xdamage = "1" # TODO: Remove this dependency, this is needed right now for glfwMakeContextCurrent -glfw3 = "3"
\ No newline at end of file +glfw3 = "3" + +alsa = "1"
\ No newline at end of file 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; +} |