Add Microphone support

This commit adds a new widget for the bar: A Microphone widget. It is
disabled by default and can can
be enabled with AudioInput: true.
Implements a flyin as well.

https://github.com/scorpion-26/gBar/issues/5 for the ping
This commit is contained in:
scorpion-26 2023-02-22 16:45:29 +01:00
parent f5adfebfe9
commit 3c8c93d774
14 changed files with 376 additions and 129 deletions

View file

@ -44,6 +44,10 @@ gBar bar 0
```
gBar audio [monitor]
```
*Open microphone flyin, this is equivalent to the audio flyin*
```
gBar mic [monitor]
```
*Open bluetooth widget*
```
gBar bluetooth [monitor]
@ -68,6 +72,7 @@ Bar:
- Time
- Bluetooth (BlueZ only)
- Audio control
- Microphone control
- Power control
- Shutdown
- Restart
@ -87,6 +92,7 @@ Bluetooth:
Audio Flyin:
- Audio control
- Microphone control
## Configuration for your system
Copy the example config (found under data/config) into ~/.config/gBar/config and modify it to your needs.

View file

@ -42,12 +42,65 @@
margin-right: 6px;
}
trough {
border-radius: 3px;
border-width: 1px;
border-style: none;
background-color: #44475a;
margin-top: 2px;
min-width: 4px;
min-height: 4px;
}
slider {
border-radius: 0%;
border-width: 1px;
border-style: none;
margin: -9px -9px -9px -9px;
min-width: 16px;
min-height: 16px;
background-color: transparent;
}
highlight {
border-radius: 3px;
border-width: 1px;
border-style: none;
min-height: 6px;
}
.audio-icon {
font-size: 24px;
color: #ffb86c;
margin-right: 12px;
}
.audio-volume trough {
background-color: #44475a;
}
.audio-volume slider {
background-color: transparent;
}
.audio-volume highlight {
background-color: #ffb86c;
}
.mic-icon {
font-size: 24px;
color: #bd93f9;
margin-right: 0px;
}
.mic-volume trough {
background-color: #44475a;
}
.mic-volume slider {
background-color: transparent;
}
.mic-volume highlight {
background-color: #bd93f9;
}
.bt-num {
font-size: 16px;
color: #1793D1;
@ -325,32 +378,4 @@
animation-fill-mode: forwards;
}
trough {
border-radius: 3px;
border-width: 1px;
border-style: none;
background-color: #44475a;
margin-top: 2px;
min-width: 4px;
min-height: 4px;
}
slider {
border-radius: 0%;
border-width: 1px;
border-style: none;
margin: -9px -9px -9px -9px;
min-width: 16px;
min-height: 16px;
background-color: transparent;
}
highlight {
border-radius: 3px;
border-width: 1px;
border-style: none;
min-height: 6px;
background-color: #ffb86c;
}
/*# sourceMappingURL=style.css.map */

View file

@ -1 +1 @@
{"version":3,"sourceRoot":"","sources":["style.scss"],"names":[],"mappings":"AAmBA;EACI;EACA;;;AASJ;EACI,kBA7BC;EA8BD;;;AAGJ;EACI;EACA;;;AAGJ;EACI,WAxBO;;;AA2BX;EACI;EAEA;EAEA,OA5CO;;;AA8CX;EACI;EAGA,OAlDO;;;AAoDX;EACI;EAGA,OAxDO;;;AA2DX;EACI;EAGA,OAzDE;;;AA+DN;EACI;;;AAGJ;EACI;EACA,OAxEK;EAyEL;;;AAGJ;EACI,WApEO;EAqEP,OAvEK;EAwEL;;;AAEJ;EACI;EACA,OA5EK;EA6EL;;;AAEJ;EACI;EACA,OAjFK;EAkFL;;;AAEJ;EACI;EACA,OAtFK;EAuFL;;;AAGJ;EACI,OAhGK;EAiGL,kBAvGO;EAwGP,WA3FO;;;AA6FX;EACI,OArGK;EAsGL;EACA,WAhGO;;;AAmGX;EACI,OA7GK;EA8GL,kBAlHO;;;AAoHX;EACI,OAjHK;EAkHL;EACA,WA1GO;;;AA6GX;EACI,OAnHK;EAoHL,kBA5HO;;;AA8HX;EACI,OAvHK;EAwHL;EACA,WApHO;;;AAuHX;EACI,OAnIG;EAoIH,kBAtIO;;;AAwIX;EACI,OAvIG;EAwIH;EACA,WA9HO;;;AAiIX;EACI,OA5II;EA6IJ,kBAhJO;EAiJP,WApIO;;;AAsIX;EACI,OAjJI;EAkJJ;EACA,WAzIO;;;AA4IX;EACI,OArJG;EAsJH,kBA3JO;EA4JP,WA/IO;;;AAiJX;EACI,OA1JG;EA2JH;EACA,WApJO;;;AAuJX;EACI,OAlKI;EAmKJ;EACA,WA1JO;;;AA8JX;EACI,OA5KO;;;AA+KX;EACI,OA7KI;;;AAgLR;EACI,OA5KK;;;AA+KT;EACI,OApLK;;;AAuLT;EACI,OAtLK;;;AAyLT;EACI,OAzLE;;;AA6LN;EACI,OArMO;;;AAwMX;EACI,OAtMI;;;AAyMR;EACI,OArMK;;;AAwMT;EACI,OA7MK;;;AAgNT;EACI,OA/MK;;;AAkNT;EACI,OAlNE;;;AAqNN;EACI,OA7NO;EA8NP,WAjNO;;;AAmNX;EACI,OAhOO;EAiOP,WArNO;;;AAuNX;EACI,OAnOG;EAoOH,WAzNO;;;AA2NX;EACI,OAjOK;EAkOL,WA7NO;;;AA+NX;EACI,OA1OI;EA2OJ,WAjOO;;;AAqOX;EACI;IACI;;EAEJ;IACI;;;AAGR;EACI;IACI;;EAEJ;IACI;;;AAIR;EACI;IACI,OA7PC;;EA+PL;IACI,OArQA;;;AAwQR;EACI;IACI,OA1QA;;EA4QJ;IACI,OAxQC;;;AA4QT;EACI,kBAvRC;EAwRD;;;AAEJ;EACI;EACA;EACA;EACA;EACA,OAlRK;;;AAoRT;EACI;EACA;;;AAEJ;EAgBI;EACA;EACA;EACA;EACA;EAEA;EACA;EAEA;;AAxBA;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAEJ;EACI,OA1SF;;;AAwTN;EACI,OAzTE;EA0TF,kBAjUO;EAkUP;EACH;EACA;;;AAED;EAaI,OA3UK;EA4UL,kBApVO;EAqVP;EACA;EACH;EACG;;AAjBA;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;;AAWR;EACI;EACA;EACH;EACG,kBAhWO;EAiWP;EACH;EACA;;;AAGD;EAEC;EACG;EACH;EACA;EACA;EACA;EACA;;;AAGD;EACC;EACG;EACH;EACG;EACH,kBAlXQ","file":"style.css"}
{"version":3,"sourceRoot":"","sources":["style.scss"],"names":[],"mappings":"AAmBA;EACI;EACA;;;AASJ;EACI,kBA7BC;EA8BD;;;AAGJ;EACI;EACA;;;AAGJ;EACI,WAxBO;;;AA2BX;EACI;EAEA;EAEA,OA5CO;;;AA8CX;EACI;EAGA,OAlDO;;;AAoDX;EACI;EAGA,OAxDO;;;AA2DX;EACI;EAGA,OAzDE;;;AA+DN;EACI;;;AAIJ;EACI;EACA;EACA;EACA,kBA/EO;EAgFP;EACA;EACA;;;AAGJ;EAEI;EACA;EACA;EACA;EACA;EACA;EACA;;;AAGJ;EACI;EACA;EACA;EACA;;;AAGJ;EACI;EACA,OArGK;EAsGL;;;AAIA;EACI,kBA/GG;;AAkHP;EACI;;AAGJ;EACI,kBAnHC;;;AAuHT;EACI;EACA,OAvHK;EAwHL;;;AAIA;EACI,kBAnIG;;AAsIP;EACI;;AAGJ;EACI,kBArIC;;;AAyIT;EACI,WAnIO;EAoIP,OAtIK;EAuIL;;;AAEJ;EACI;EACA,OA3IK;EA4IL;;;AAEJ;EACI;EACA,OAhJK;EAiJL;;;AAEJ;EACI;EACA,OArJK;EAsJL;;;AAGJ;EACI,OA/JK;EAgKL,kBAtKO;EAuKP,WA1JO;;;AA4JX;EACI,OApKK;EAqKL;EACA,WA/JO;;;AAkKX;EACI,OA5KK;EA6KL,kBAjLO;;;AAmLX;EACI,OAhLK;EAiLL;EACA,WAzKO;;;AA4KX;EACI,OAlLK;EAmLL,kBA3LO;;;AA6LX;EACI,OAtLK;EAuLL;EACA,WAnLO;;;AAsLX;EACI,OAlMG;EAmMH,kBArMO;;;AAuMX;EACI,OAtMG;EAuMH;EACA,WA7LO;;;AAgMX;EACI,OA3MI;EA4MJ,kBA/MO;EAgNP,WAnMO;;;AAqMX;EACI,OAhNI;EAiNJ;EACA,WAxMO;;;AA2MX;EACI,OApNG;EAqNH,kBA1NO;EA2NP,WA9MO;;;AAgNX;EACI,OAzNG;EA0NH;EACA,WAnNO;;;AAsNX;EACI,OAjOI;EAkOJ;EACA,WAzNO;;;AA6NX;EACI,OA3OO;;;AA8OX;EACI,OA5OI;;;AA+OR;EACI,OA3OK;;;AA8OT;EACI,OAnPK;;;AAsPT;EACI,OArPK;;;AAwPT;EACI,OAxPE;;;AA4PN;EACI,OApQO;;;AAuQX;EACI,OArQI;;;AAwQR;EACI,OApQK;;;AAuQT;EACI,OA5QK;;;AA+QT;EACI,OA9QK;;;AAiRT;EACI,OAjRE;;;AAoRN;EACI,OA5RO;EA6RP,WAhRO;;;AAkRX;EACI,OA/RO;EAgSP,WApRO;;;AAsRX;EACI,OAlSG;EAmSH,WAxRO;;;AA0RX;EACI,OAhSK;EAiSL,WA5RO;;;AA8RX;EACI,OAzSI;EA0SJ,WAhSO;;;AAoSX;EACI;IACI;;EAEJ;IACI;;;AAGR;EACI;IACI;;EAEJ;IACI;;;AAIR;EACI;IACI,OA5TC;;EA8TL;IACI,OApUA;;;AAuUR;EACI;IACI,OAzUA;;EA2UJ;IACI,OAvUC;;;AA2UT;EACI,kBAtVC;EAuVD;;;AAEJ;EACI;EACA;EACA;EACA;EACA,OAjVK;;;AAmVT;EACI;EACA;;;AAEJ;EAgBI;EACA;EACA;EACA;EACA;EAEA;EACA;EAEA;;AAxBA;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAEJ;EACI,OAzWF;;;AAuXN;EACI,OAxXE;EAyXF,kBAhYO;EAiYP;EACH;EACA;;;AAED;EAaI,OA1YK;EA2YL,kBAnZO;EAoZP;EACA;EACH;EACG;;AAjBA;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA","file":"style.css"}

View file

@ -76,12 +76,75 @@ $textsize: 16px;
margin-right: 6px;
}
// Common slider settings
trough {
border-radius: 3px;
border-width: 1px;
border-style: none;
background-color: $inactive;
margin-top: 2px;
min-width: 4px;
min-height: 4px;
}
slider {
// Controls the size of the control area (set border-style to solid to see)
border-radius: 0%;
border-width: 1px;
border-style: none;
margin: -9px -9px -9px -9px;
min-width: 16px;
min-height: 16px;
background-color: transparent;
}
highlight {
border-radius: 3px;
border-width: 1px;
border-style: none;
min-height: 6px;
}
.audio-icon {
font-size: 24px;
color: $orange;
margin-right: 12px;
}
.audio-volume {
trough {
background-color: $inactive;
}
slider {
background-color: transparent;
}
highlight {
background-color: $orange;
}
}
.mic-icon {
font-size: 24px;
color: $purple;
margin-right: 0px;
}
.mic-volume {
trough {
background-color: $inactive;
}
slider {
background-color: transparent;
}
highlight {
background-color: $purple;
}
}
.bt-num {
font-size: $textsize;
color: $btblue;
@ -348,34 +411,3 @@ $textsize: 16px;
margin: 0px 0px 0px 10px;
font-size: 18px;
}
// Sliders
trough {
border-radius: 3px;
border-width: 1px;
border-style: none;
background-color: $inactive;
margin-top: 2px;
min-width: 4px;
min-height: 4px;
}
slider {
// Controls the size of the control area (set border-style to solid to see)
border-radius: 0%;
border-width: 1px;
border-style: none;
margin: -9px -9px -9px -9px;
min-width: 16px;
min-height: 16px;
background-color: transparent;
}
highlight {
border-radius: 3px;
border-width: 1px;
border-style: none;
min-height: 6px;
background-color: $orange;
}

View file

@ -38,6 +38,9 @@ WorkspaceScrollInvert: false
# This can cause issues, if there is not enough space on screen (e.g. when opening the text)
CenterTime: true
# Adds a audio input(aka. microphone) widget
AudioInput: false
# Sets the audio slider to be on reveal (Just like the sensors) when true. Only affects the bar.
AudioRevealer: false

View file

@ -5,6 +5,8 @@ namespace AudioFlyin
{
namespace DynCtx
{
Type type;
Window* win;
Slider* slider;
Text* icon;
@ -19,28 +21,59 @@ namespace AudioFlyin
void OnChangeVolume(Slider&, double value)
{
System::SetVolume(value);
if (type == Type::Speaker)
{
System::SetVolumeSink(value);
}
else if (type == Type::Microphone)
{
System::SetVolumeSource(value);
}
}
TimerResult Main(Box&)
{
System::AudioInfo info = System::GetAudioInfo();
if (sliderVal != info.volume || muted != info.muted)
if (type == Type::Speaker)
{
// Extend timer
curCloseTime = msOpen + closeTime;
sliderVal = info.volume;
slider->SetValue(info.volume);
muted = info.muted;
if (info.muted)
if (sliderVal != info.sinkVolume || muted != info.sinkMuted)
{
icon->SetText("");
// Extend timer
curCloseTime = msOpen + closeTime;
sliderVal = info.sinkVolume;
slider->SetValue(info.sinkVolume);
muted = info.sinkMuted;
if (info.sinkMuted)
{
icon->SetText("");
}
else
{
icon->SetText("");
}
}
else
}
else if (type == Type::Microphone)
{
if (sliderVal != info.sourceVolume || muted != info.sourceMuted)
{
icon->SetText("");
// Extend timer
curCloseTime = msOpen + closeTime;
sliderVal = info.sourceVolume;
slider->SetValue(info.sourceVolume);
muted = info.sourceMuted;
if (info.sourceMuted)
{
icon->SetText("󰍭");
}
else
{
icon->SetText("󰍬");
}
}
}
@ -66,23 +99,40 @@ namespace AudioFlyin
slider->SetOrientation(Orientation::Horizontal);
slider->SetHorizontalTransform({100, true, Alignment::Fill});
slider->SetInverted(true);
slider->SetClass("audio-volume");
if (DynCtx::type == Type::Speaker)
{
slider->SetClass("audio-volume");
}
else if (DynCtx::type == Type::Microphone)
{
slider->SetClass("mic-volume");
}
slider->OnValueChange(DynCtx::OnChangeVolume);
slider->SetRange({0, 1, 0.01});
DynCtx::slider = slider.get();
auto icon = Widget::Create<Text>();
icon->SetClass("audio-icon");
icon->SetText("");
if (DynCtx::type == Type::Speaker)
{
icon->SetClass("audio-icon");
icon->SetText("󰕾 ");
}
else if (DynCtx::type == Type::Microphone)
{
icon->SetClass("mic-icon");
icon->SetText("󰍬");
}
DynCtx::icon = icon.get();
parent.AddChild(std::move(slider));
parent.AddChild(std::move(icon));
}
void Create(Window& window, int32_t monitor)
void Create(Window& window, int32_t monitor, Type type)
{
DynCtx::win = &window;
DynCtx::type = type;
auto mainWidget = Widget::Create<Box>();
mainWidget->SetSpacing({8, false});
mainWidget->SetVerticalTransform({16, true, Alignment::Fill});

View file

@ -4,5 +4,10 @@
namespace AudioFlyin
{
void Create(Window& window, int32_t monitor);
enum class Type
{
Speaker,
Microphone
};
void Create(Window& window, int32_t monitor, Type type);
}

View file

@ -134,23 +134,43 @@ namespace Bar
}
#endif
void OnChangeVolume(Slider&, double value)
void OnChangeVolumeSink(Slider&, double value)
{
System::SetVolume(value);
System::SetVolumeSink(value);
}
void OnChangeVolumeSource(Slider&, double value)
{
System::SetVolumeSource(value);
}
Slider* audioSlider;
Slider* micSlider;
Text* audioIcon;
TimerResult UpdateAudio(Slider& slider)
Text* micIcon;
TimerResult UpdateAudio(Widget&)
{
System::AudioInfo info = System::GetAudioInfo();
slider.SetValue(info.volume);
if (info.muted)
audioSlider->SetValue(info.sinkVolume);
if (info.sinkMuted)
{
audioIcon->SetText("");
audioIcon->SetText("󰝟");
}
else
{
audioIcon->SetText("");
audioIcon->SetText("󰕾");
}
if (Config::Get().audioInput)
{
micSlider->SetValue(info.sourceVolume);
if (info.sourceMuted)
{
micIcon->SetText("󰍭");
}
else
{
micIcon->SetText("󰍬");
}
}
return TimerResult::Ok;
}
@ -256,33 +276,59 @@ namespace Bar
parent.AddChild(std::move(eventBox));
}
// Handles in and out
void WidgetAudio(Widget& parent)
{
auto widgetAudioSlider = [](Widget& parent)
enum class AudioType
{
Input,
Output
};
auto widgetAudioSlider = [](Widget& parent, AudioType type)
{
auto slider = Widget::Create<Slider>();
slider->SetOrientation(Orientation::Horizontal);
slider->SetHorizontalTransform({100, true, Alignment::Fill});
slider->SetInverted(true);
slider->SetClass("audio-volume");
slider->AddTimer<Slider>(DynCtx::UpdateAudio, DynCtx::updateTimeFast);
slider->OnValueChange(DynCtx::OnChangeVolume);
switch (type)
{
case AudioType::Input:
slider->SetClass("mic-volume");
slider->OnValueChange(DynCtx::OnChangeVolumeSource);
DynCtx::micSlider = slider.get();
break;
case AudioType::Output:
slider->SetClass("audio-volume");
slider->OnValueChange(DynCtx::OnChangeVolumeSink);
DynCtx::audioSlider = slider.get();
break;
}
slider->SetRange({0, 1, 0.01});
slider->SetScrollSpeed((double)Config::Get().audioScrollSpeed / 100.);
parent.AddChild(std::move(slider));
};
auto widgetAudioBody = [&widgetAudioSlider](Widget& parent)
auto widgetAudioBody = [&widgetAudioSlider](Widget& parent, AudioType type)
{
auto box = Widget::Create<Box>();
box->SetSpacing({8, false});
box->SetHorizontalTransform({-1, true, Alignment::Right});
{
auto icon = Widget::Create<Text>();
icon->SetClass("audio-icon");
icon->SetText("");
DynCtx::audioIcon = icon.get();
switch (type)
{
case AudioType::Input:
icon->SetClass("mic-icon");
icon->SetText("󰍬");
DynCtx::micIcon = icon.get();
break;
case AudioType::Output:
icon->SetClass("audio-icon");
icon->SetText("󰕾 ");
DynCtx::audioIcon = icon.get();
break;
}
if (Config::Get().audioRevealer)
{
@ -296,7 +342,7 @@ namespace Bar
slideRevealer->SetRevealed(hovered);
});
{
widgetAudioSlider(*revealer);
widgetAudioSlider(*revealer, type);
}
box->AddChild(std::move(revealer));
@ -304,7 +350,7 @@ namespace Bar
else
{
// Straight forward
widgetAudioSlider(*box);
widgetAudioSlider(*box, type);
}
box->AddChild(std::move(icon));
@ -314,16 +360,28 @@ namespace Bar
if (Config::Get().audioRevealer)
{
// Need an EventBox
if (Config::Get().audioInput)
{
auto eventBox = Widget::Create<EventBox>();
widgetAudioBody(*eventBox, AudioType::Input);
parent.AddChild(std::move(eventBox));
}
// Need an EventBox
auto eventBox = Widget::Create<EventBox>();
widgetAudioBody(*eventBox);
widgetAudioBody(*eventBox, AudioType::Output);
parent.AddChild(std::move(eventBox));
}
else
{
// Just invoke it.
widgetAudioBody(parent);
if (Config::Get().audioInput)
{
widgetAudioBody(parent, AudioType::Input);
}
widgetAudioBody(parent, AudioType::Output);
}
parent.AddTimer<Widget>(DynCtx::UpdateAudio, DynCtx::updateTimeFast);
}
#ifdef WITH_BLUEZ

View file

@ -132,6 +132,7 @@ void Config::Load()
}
AddConfigVar("CenterTime", config.centerTime, lineView, foundProperty);
AddConfigVar("AudioInput", config.audioInput, lineView, foundProperty);
AddConfigVar("AudioRevealer", config.audioRevealer, lineView, foundProperty);
AddConfigVar("NetworkWidget", config.networkWidget, lineView, foundProperty);
AddConfigVar("WorkspaceScrollOnMonitor", config.workspaceScrollOnMonitor, lineView, foundProperty);

View file

@ -16,9 +16,10 @@ public:
bool centerTime = true;
bool audioRevealer = false;
bool audioInput = false;
bool networkWidget = true;
bool workspaceScrollOnMonitor = true; // Scroll through workspaces on monitor instead of all
bool workspaceScrollInvert = false; // Up = +1, instead of Up = -1
bool workspaceScrollInvert = false; // Up = +1, instead of Up = -1
// Controls for color progression of the network widget
uint32_t minUploadBytes = 0; // Bottom limit of the network widgets upload. Everything below it is considered "under"

View file

@ -2,6 +2,7 @@
#include "System.h"
#include "Common.h"
#include <cmath>
#include <pulse/pulseaudio.h>
#include <stdlib.h>
#include <algorithm>
@ -77,20 +78,36 @@ namespace PulseAudio
ASSERT(res >= 0, "pa_context_connect failed!");
}
inline double PAVolumeToDouble(const pa_cvolume* volume)
{
double vol = (double)pa_cvolume_avg(volume) / (double)PA_VOLUME_NORM;
// Just round to 1% precision, should be enough
constexpr double precision = 0.01;
double volRounded = std::round(vol * 1 / precision) * precision;
return volRounded;
}
inline System::AudioInfo GetInfo()
{
const char* defaultSink = nullptr;
struct ServerInfo
{
const char* defaultSink = nullptr;
const char* defaultSource = nullptr;
} serverInfo;
System::AudioInfo info{};
// 1. Get default sink
auto serverInfo = [](pa_context*, const pa_server_info* info, void* sink)
auto getServerInfo = [](pa_context*, const pa_server_info* info, void* out)
{
if (!info)
return;
*(const char**)sink = info->default_sink_name;
ServerInfo* serverInfo = (ServerInfo*)out;
serverInfo->defaultSink = info->default_sink_name;
serverInfo->defaultSource = info->default_source_name;
};
pa_operation* op = pa_context_get_server_info(context, +serverInfo, &defaultSink);
pa_operation* op = pa_context_get_server_info(context, +getServerInfo, &serverInfo);
pa_operation_ref(op);
pendingOperations.push_back(op);
@ -103,22 +120,43 @@ namespace PulseAudio
System::AudioInfo* out = (System::AudioInfo*)audioInfo;
double vol = (double)pa_cvolume_avg(&info->volume) / (double)PA_VOLUME_NORM;
out->volume = vol;
out->muted = info->mute;
double vol = PAVolumeToDouble(&info->volume);
out->sinkVolume = vol;
out->sinkMuted = info->mute;
};
op = pa_context_get_sink_info_by_name(context, defaultSink, +sinkInfo, &info);
if (serverInfo.defaultSink)
{
op = pa_context_get_sink_info_by_name(context, serverInfo.defaultSink, +sinkInfo, &info);
pa_operation_ref(op);
pendingOperations.push_back(op);
pa_operation_ref(op);
pendingOperations.push_back(op);
FlushLoop();
}
FlushLoop();
auto sourceInfo = [](pa_context*, const pa_source_info* info, int, void* audioInfo)
{
if (!info)
return;
System::AudioInfo* out = (System::AudioInfo*)audioInfo;
double vol = PAVolumeToDouble(&info->volume);
out->sourceVolume = vol;
out->sourceMuted = info->mute;
};
if (serverInfo.defaultSource)
{
op = pa_context_get_source_info_by_name(context, serverInfo.defaultSource, +sourceInfo, &info);
pa_operation_ref(op);
pendingOperations.push_back(op);
FlushLoop();
}
return info;
}
inline void SetVolume(double value)
inline void SetVolumeSink(double value)
{
double valClamped = std::clamp(value, 0., 1.);
// I'm too lazy to implement the c api for this. Since it will only be called when needed and doesn't pipe, it shouldn't be a problem to
@ -127,6 +165,15 @@ namespace PulseAudio
system(cmd.c_str());
}
inline void SetVolumeSource(double value)
{
double valClamped = std::clamp(value, 0., 1.);
// I'm too lazy to implement the c api for this. Since it will only be called when needed and doesn't pipe, it shouldn't be a problem to
// fallback for a command
std::string cmd = "pamixer --default-source --set-volume " + std::to_string((uint32_t)(valClamped * 100));
system(cmd.c_str());
}
inline void Shutdown()
{
pa_mainloop_free(mainLoop);

View file

@ -437,9 +437,13 @@ namespace System
{
return PulseAudio::GetInfo();
}
void SetVolume(double volume)
void SetVolumeSink(double volume)
{
PulseAudio::SetVolume(volume);
PulseAudio::SetVolumeSink(volume);
}
void SetVolumeSource(double volume)
{
PulseAudio::SetVolumeSource(volume);
}
#ifdef WITH_HYPRLAND

View file

@ -73,11 +73,15 @@ namespace System
struct AudioInfo
{
double volume;
bool muted;
double sinkVolume;
bool sinkMuted;
double sourceVolume;
bool sourceMuted;
};
AudioInfo GetAudioInfo();
void SetVolume(double volume);
void SetVolumeSink(double volume);
void SetVolumeSource(double volume);
#ifdef WITH_HYPRLAND
enum class WorkspaceStatus

View file

@ -13,6 +13,24 @@
const char* audioTmpFileOpen = "/tmp/gBar__audio";
static bool flyin = false;
void OpenAudioFlyin(Window& window, int32_t monitor, AudioFlyin::Type type)
{
flyin = true;
if (access(audioTmpFileOpen, F_OK) != 0)
{
FILE* audioTempFile = fopen(audioTmpFileOpen, "w");
AudioFlyin::Create(window, monitor, type);
fclose(audioTempFile);
}
else
{
// Already open, close
LOG("Audio flyin already open");
exit(0);
}
}
int main(int argc, char** argv)
{
System::Init();
@ -31,18 +49,11 @@ int main(int argc, char** argv)
}
else if (strcmp(argv[1], "audio") == 0)
{
if (access(audioTmpFileOpen, F_OK) != 0)
{
FILE* audioTempFile = fopen(audioTmpFileOpen, "w");
AudioFlyin::Create(window, monitor);
fclose(audioTempFile);
}
else
{
// Already open, close
LOG("Audio already open");
exit(0);
}
OpenAudioFlyin(window, monitor, AudioFlyin::Type::Speaker);
}
else if (strcmp(argv[1], "mic") == 0)
{
OpenAudioFlyin(window, monitor, AudioFlyin::Type::Microphone);
}
#ifdef WITH_BLUEZ
else if (strcmp(argv[1], "bluetooth") == 0)
@ -66,7 +77,7 @@ int main(int argc, char** argv)
window.Run(argc, argv);
System::FreeResources();
if (strcmp(argv[1], "audio") == 0)
if (flyin)
{
remove(audioTmpFileOpen);
}