Give error when using an invalid audio input with pipewire

This commit is contained in:
dec05eba 2022-09-30 22:02:23 +02:00
parent 09ad7a1eb5
commit f7606a144b
4 changed files with 105 additions and 2 deletions

View File

@ -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.\ 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.\ 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 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/). There is also a gui for the gpu-screen-recorder called [gpu-screen-recorder-gtk](https://git.dec05eba.com/gpu-screen-recorder-gtk/).
# Demo # Demo

View File

@ -18,11 +18,19 @@
#ifndef GPU_SCREEN_RECORDER_H #ifndef GPU_SCREEN_RECORDER_H
#define GPU_SCREEN_RECORDER_H #define GPU_SCREEN_RECORDER_H
#include <vector>
#include <string>
typedef struct { typedef struct {
void *handle; void *handle;
unsigned int frames; unsigned int frames;
} SoundDevice; } SoundDevice;
struct AudioInput {
std::string name;
std::string description;
};
/* /*
Get a sound device by name, returning the device into the @device parameter. 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 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); int sound_device_read_next_chunk(SoundDevice *device, void **buffer);
std::vector<AudioInput> get_pulseaudio_inputs();
#endif /* GPU_SCREEN_RECORDER_H */ #endif /* GPU_SCREEN_RECORDER_H */

View File

@ -1073,6 +1073,28 @@ int main(int argc, char **argv) {
} }
Arg &audio_input_arg = args["-a"]; 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_x = 0;
uint32_t region_y = 0; uint32_t region_y = 0;

View File

@ -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); pa_handle *handle = pa_sound_device_new(nullptr, stream_name, name, stream_name, &ss, &buffer_attr, &error);
if(!handle) { 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; return -1;
} }
@ -299,3 +299,74 @@ int sound_device_read_next_chunk(SoundDevice *device, void **buffer) {
*buffer = pa->output_data; *buffer = pa->output_data;
return device->frames; 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);
}