aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordec05eba <dec05eba@protonmail.com>2020-03-29 09:10:24 +0200
committerdec05eba <dec05eba@protonmail.com>2020-03-29 09:10:24 +0200
commit7c8c97b1a8f844d7e0e682abe0dcba01c2973a66 (patch)
tree8f7a34dad700a44a866475fd0a7e24ffe829dbf9
parentbcb79582c511706358e85d95c003e4feb85c66df (diff)
add alsa
-rw-r--r--include/sound.hpp27
-rw-r--r--project.conf5
-rw-r--r--src/sound.cpp84
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(&params);
+ // 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;
+}