aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordec05eba <dec05eba@protonmail.com>2022-09-30 22:02:23 +0200
committerdec05eba <dec05eba@protonmail.com>2022-09-30 22:02:23 +0200
commitf7606a144b7147e493304278d321ab2ed7996bb8 (patch)
tree0571a158e1da5824749958fc5db68a5bf02a4a82
parent09ad7a1eb5ff4a1d00776396c4582252e4bd83fc (diff)
Give error when using an invalid audio input with pipewire
-rw-r--r--README.md2
-rw-r--r--include/sound.hpp10
-rw-r--r--src/main.cpp22
-rw-r--r--src/sound.cpp73
4 files changed, 105 insertions, 2 deletions
diff --git a/README.md b/README.md
index 9cd1ac3..5c3df22 100644
--- a/README.md
+++ b/README.md
@@ -27,7 +27,7 @@ Run `scripts/interactive.sh` or run gpu-screen-recorder directly, for example: `
Then stop the screen recorder with Ctrl+C, which will also save the recording.\
Send signal SIGUSR1 (`killall -SIGUSR1 gpu-screen-recorder`) to gpu-screen-recorder when in replay mode to save the replay. The paths to the saved files is output to stdout after the recording is saved.\
You can find the default output audio device (headset, speakers) with the command `pactl get-default-sink`. Add `monitor` to the end of that to use that as an audio input in gpu-screen-recorder.\
-You can find the default input audio device (microphone) with the command `pactl get-default-source`.\
+You can find the default input audio device (microphone) with the command `pactl get-default-source`. This input should not have `monitor` added to the end when used in gpu-screen-recorder.\
There is also a gui for the gpu-screen-recorder called [gpu-screen-recorder-gtk](https://git.dec05eba.com/gpu-screen-recorder-gtk/).
# Demo
diff --git a/include/sound.hpp b/include/sound.hpp
index 39d9248..d8ad322 100644
--- a/include/sound.hpp
+++ b/include/sound.hpp
@@ -18,11 +18,19 @@
#ifndef GPU_SCREEN_RECORDER_H
#define GPU_SCREEN_RECORDER_H
+#include <vector>
+#include <string>
+
typedef struct {
void *handle;
unsigned int frames;
} SoundDevice;
+struct AudioInput {
+ std::string name;
+ std::string description;
+};
+
/*
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
@@ -39,4 +47,6 @@ void sound_device_close(SoundDevice *device);
*/
int sound_device_read_next_chunk(SoundDevice *device, void **buffer);
+std::vector<AudioInput> get_pulseaudio_inputs();
+
#endif /* GPU_SCREEN_RECORDER_H */
diff --git a/src/main.cpp b/src/main.cpp
index caea9b6..61eb5cf 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -1073,6 +1073,28 @@ int main(int argc, char **argv) {
}
Arg &audio_input_arg = args["-a"];
+ const std::vector<AudioInput> audio_inputs = get_pulseaudio_inputs();
+
+ // Manually check if the audio inputs we give exist. This is only needed for pipewire, not pulseaudio.
+ // Pipewire instead DEFAULTS TO THE DEFAULT AUDIO INPUT. THAT'S RETARDED.
+ // OH, YOU MISSPELLED THE AUDIO INPUT? FUCK YOU
+ for(const char *audio_input : audio_input_arg.values) {
+ bool match = false;
+ for(const auto &existing_audio_input : audio_inputs) {
+ if(strcmp(audio_input, existing_audio_input.name.c_str()) == 0) {
+ match = true;
+ break;
+ }
+ }
+
+ if(!match) {
+ fprintf(stderr, "Error: Audio input device '%s' is not a valid input device. Expected one of:\n", audio_input);
+ for(const auto &existing_audio_input : audio_inputs) {
+ fprintf(stderr, " %s\n", existing_audio_input.name.c_str());
+ }
+ exit(2);
+ }
+ }
uint32_t region_x = 0;
uint32_t region_y = 0;
diff --git a/src/sound.cpp b/src/sound.cpp
index abd2e65..0fd1333 100644
--- a/src/sound.cpp
+++ b/src/sound.cpp
@@ -277,7 +277,7 @@ int sound_device_get_by_name(SoundDevice *device, const char *name, unsigned int
pa_handle *handle = pa_sound_device_new(nullptr, stream_name, name, stream_name, &ss, &buffer_attr, &error);
if(!handle) {
- fprintf(stderr, "pa_simple_new() failed: %s. Audio input device %s might not be valid\n", pa_strerror(error), name);
+ fprintf(stderr, "pa_sound_device_new() failed: %s. Audio input device %s might not be valid\n", pa_strerror(error), name);
return -1;
}
@@ -298,4 +298,75 @@ int sound_device_read_next_chunk(SoundDevice *device, void **buffer) {
}
*buffer = pa->output_data;
return device->frames;
+}
+
+static void pa_state_cb(pa_context *c, void *userdata) {
+ pa_context_state state = pa_context_get_state(c);
+ int *pa_ready = (int*)userdata;
+ switch(state) {
+ case PA_CONTEXT_UNCONNECTED:
+ case PA_CONTEXT_CONNECTING:
+ case PA_CONTEXT_AUTHORIZING:
+ case PA_CONTEXT_SETTING_NAME:
+ default:
+ break;
+ case PA_CONTEXT_FAILED:
+ case PA_CONTEXT_TERMINATED:
+ *pa_ready = 2;
+ break;
+ case PA_CONTEXT_READY:
+ *pa_ready = 1;
+ break;
+ }
+}
+
+static void pa_sourcelist_cb(pa_context *ctx, const pa_source_info *source_info, int eol, void *userdata) {
+ if(eol > 0)
+ return;
+
+ std::vector<AudioInput> *inputs = (std::vector<AudioInput>*)userdata;
+ inputs->push_back({ source_info->name, source_info->description });
+}
+
+std::vector<AudioInput> get_pulseaudio_inputs() {
+ std::vector<AudioInput> inputs;
+ pa_mainloop *main_loop = pa_mainloop_new();
+
+ pa_context *ctx = pa_context_new(pa_mainloop_get_api(main_loop), "gpu-screen-recorder");
+ pa_context_connect(ctx, NULL, PA_CONTEXT_NOFLAGS, NULL);
+ int state = 0;
+ int pa_ready = 0;
+ pa_context_set_state_callback(ctx, pa_state_cb, &pa_ready);
+
+ pa_operation *pa_op = NULL;
+
+ for(;;) {
+ // Not ready
+ if(pa_ready == 0) {
+ pa_mainloop_iterate(main_loop, 1, NULL);
+ continue;
+ }
+
+ switch(state) {
+ case 0: {
+ pa_op = pa_context_get_source_info_list(ctx, pa_sourcelist_cb, &inputs);
+ ++state;
+ break;
+ }
+ }
+
+ // Couldn't get connection to the server
+ if(pa_ready == 2 || (state == 1 && pa_op && pa_operation_get_state(pa_op) == PA_OPERATION_DONE)) {
+ if(pa_op)
+ pa_operation_unref(pa_op);
+ pa_context_disconnect(ctx);
+ pa_context_unref(ctx);
+ pa_mainloop_free(main_loop);
+ return inputs;
+ }
+
+ pa_mainloop_iterate(main_loop, 1, NULL);
+ }
+
+ pa_mainloop_free(main_loop);
} \ No newline at end of file