Give error when using an invalid audio input with pipewire
This commit is contained in:
parent
09ad7a1eb5
commit
f7606a144b
@ -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
|
||||||
|
@ -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 */
|
||||||
|
22
src/main.cpp
22
src/main.cpp
@ -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;
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -298,4 +298,75 @@ 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);
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user