Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add basic pulseaudio source (microphone etc.) support #1154

Merged
merged 2 commits into from
Feb 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions doc/variables.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -951,6 +951,15 @@ values:
desc: |-
If Pulseaudio's default sink is muted, display everything
between $if_pa_sink_muted and the corresponding $else or $endif.
- name: if_pa_source_running
desc: |-
If Pulseaudio's default source is running (e.g. a program is accessing
your microphone), display everything between $if_pa_source_running and
the corresponding $else or $endif.
- name: if_pa_source_muted
desc: |-
If Pulseaudio's default source (e.g. your microphone) is muted, display
everything between $if_pa_source_muted and the corresponding $else or $endif.
- name: if_running
desc:
"If PROCESS is running, display everything between\n$if_running and the corresponding\
Expand Down
15 changes: 9 additions & 6 deletions src/core.cc
Original file line number Diff line number Diff line change
Expand Up @@ -660,12 +660,8 @@ struct text_object *construct_text_object(char *s, const char *arg, long line,
EQUAL) {
obj->data.i = PB_BATT_STATUS;
}
else if (strcmp(arg, "percent") == EQUAL) {
obj->data.i = PB_BATT_PERCENT;
}
else if (strcmp(arg, "time") == EQUAL) {
obj->data.i = PB_BATT_TIME;
}
else if (strcmp(arg, "percent") == EQUAL) { obj->data.i = PB_BATT_PERCENT; }
else if (strcmp(arg, "time") == EQUAL) { obj->data.i = PB_BATT_TIME; }
else {
NORM_ERR("pb_battery: illegal argument '%s', defaulting to status", arg);
obj->data.i = PB_BATT_STATUS;
Expand Down Expand Up @@ -2013,6 +2009,13 @@ struct text_object *construct_text_object(char *s, const char *arg, long line,
END OBJ(pa_card_name, 0) obj->callbacks.print = &print_puau_card_name;
obj->callbacks.free = &free_pulseaudio;
init_pulseaudio(obj);
END OBJ_IF(if_pa_source_running, 0) obj->callbacks.iftest =
&puau_source_running;
obj->callbacks.free = &free_pulseaudio;
init_pulseaudio(obj);
END OBJ_IF(if_pa_source_muted, 0) obj->callbacks.iftest = &puau_source_muted;
obj->callbacks.free = &free_pulseaudio;
init_pulseaudio(obj);
#endif /* BUILD_PULSEAUDIO */
#ifdef BUILD_INTEL_BACKLIGHT
END OBJ(intel_backlight, 0) obj->callbacks.print = &print_intel_backlight;
Expand Down
68 changes: 57 additions & 11 deletions src/pulseaudio.cc
Original file line number Diff line number Diff line change
Expand Up @@ -40,17 +40,21 @@

struct pulseaudio_default_results get_result_copy();

const struct pulseaudio_default_results pulseaudio_result0 = {std::string(),
std::string(),
std::string(),
std::string(),
0,
0,
0,
0,
std::string(),
std::string(),
0};
const struct pulseaudio_default_results pulseaudio_result0 = {
std::string(),
std::string(),
std::string(),
std::string(),
0,
0,
0,
0,
std::string(),
PA_SOURCE_SUSPENDED,
0,
std::string(),
std::string(),
0};
pulseaudio_c *pulseaudio = nullptr;

void pa_sink_info_callback(pa_context *c, const pa_sink_info *i, int eol,
Expand All @@ -77,12 +81,26 @@ void pa_sink_info_callback(pa_context *c, const pa_sink_info *i, int eol,
++eol;
}

void pa_source_info_callback(pa_context *c, const pa_source_info *i, int eol,
void *data) {
if (i != nullptr && data) {
struct pulseaudio_default_results *pdr =
(struct pulseaudio_default_results *)data;
pdr->source_state = i->state;
pdr->source_mute = i->mute;
pa_threaded_mainloop_signal(pulseaudio->mainloop, 0);
}
(void)c;
++eol;
}

void pa_server_info_callback(pa_context *c, const pa_server_info *i,
void *userdata) {
if (i != nullptr) {
struct pulseaudio_default_results *pdr =
(struct pulseaudio_default_results *)userdata;
pdr->sink_name.assign(i->default_sink_name);
pdr->source_name.assign(i->default_source_name);
pa_threaded_mainloop_signal(pulseaudio->mainloop, 0);
}
(void)c;
Expand Down Expand Up @@ -165,6 +183,15 @@ void subscribe_cb(pa_context *c, pa_subscription_event_type_t t, uint32_t index,
"pa_context_get_sink_info_by_name failed");
} break;

case PA_SUBSCRIPTION_EVENT_SOURCE: {
if (res->source_name.empty()) return;
pa_operation *op;
PULSEAUDIO_OP(
pa_context_get_source_info_by_name(c, res->source_name.c_str(),
pa_source_info_callback, res),
"pa_context_get_source_info_by_name failed");
} break;

case PA_SUBSCRIPTION_EVENT_CARD:
if (index == res->card_index && res->card_index != (uint32_t)-1) {
pa_operation *op;
Expand Down Expand Up @@ -252,6 +279,16 @@ void init_pulseaudio(struct text_object *obj) {
return;
}

if (pulseaudio->result.source_name.empty()) return;

PULSEAUDIO_WAIT(pa_context_get_source_info_by_name(
pulseaudio->context, pulseaudio->result.source_name.c_str(),
pa_source_info_callback, &pulseaudio->result));

if (pulseaudio->result.source_name.empty()) {
NORM_ERR("Incorrect pulseaudio source information.");
return;
}
if (pulseaudio->result.sink_card != (uint32_t)-1)
PULSEAUDIO_WAIT(pa_context_get_card_info_by_index(
pulseaudio->context, pulseaudio->result.sink_card,
Expand All @@ -264,6 +301,7 @@ void init_pulseaudio(struct text_object *obj) {
if (!(op = pa_context_subscribe(
pulseaudio->context,
(pa_subscription_mask_t)(PA_SUBSCRIPTION_MASK_SINK |
PA_SUBSCRIPTION_MASK_SOURCE |
PA_SUBSCRIPTION_MASK_SERVER |
PA_SUBSCRIPTION_MASK_CARD),
nullptr, NULL))) {
Expand Down Expand Up @@ -313,6 +351,14 @@ int puau_muted(struct text_object *obj) {
return get_pulseaudio(obj).sink_mute;
}

int puau_source_running(struct text_object *obj) {
return get_pulseaudio(obj).source_state == PA_SOURCE_RUNNING;
}

int puau_source_muted(struct text_object *obj) {
return get_pulseaudio(obj).source_mute;
}

void print_puau_sink_description(struct text_object *obj, char *p,
unsigned int p_max_size) {
snprintf(p, p_max_size, "%s", get_pulseaudio(obj).sink_description.c_str());
Expand Down
11 changes: 10 additions & 1 deletion src/pulseaudio.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
#define _PULSEAUDIO_H

#include <pulse/pulseaudio.h>
#include <string>
#include "text_object.h"

void init_pulseaudio(struct text_object *obj);
Expand All @@ -48,6 +49,8 @@ void print_puau_card_active_profile(struct text_object *obj, char *p,
unsigned int p_max_size);
double puau_volumebarval(struct text_object *obj);
int puau_muted(struct text_object *obj);
int puau_source_running(struct text_object *obj);
int puau_source_muted(struct text_object *obj);

struct pulseaudio_default_results {
// default sink
Expand All @@ -60,6 +63,11 @@ struct pulseaudio_default_results {
uint32_t sink_index;
unsigned int sink_volume; // percentage

// default source
std::string source_name;
pa_source_state source_state;
int source_mute;

// default card
std::string card_active_profile_description;
std::string card_name;
Expand Down Expand Up @@ -87,7 +95,8 @@ class pulseaudio_c {
cstate(PULSE_CONTEXT_INITIALIZING),
ninits(0),
result({std::string(), std::string(), std::string(), std::string(), 0,
0, 0, 0, std::string(), std::string(), 0}){};
0, 0, 0, std::string(), PA_SOURCE_SUSPENDED, 0, std::string(),
std::string(), 0}){};
};

#endif /* _PULSEAUDIO_H */
4 changes: 1 addition & 3 deletions src/top.cc
Original file line number Diff line number Diff line change
Expand Up @@ -99,9 +99,7 @@ static void unhash_all_processes() {
}
}

struct process *get_first_process() {
return first_process;
}
struct process *get_first_process() { return first_process; }

void free_all_processes() {
struct process *next = nullptr, *pr = first_process;
Expand Down