1 /* GUI_EnginePreferences.cpp */
2
3 /* Copyright (C) 2011-2020 Michael Lugmair (Lucio Carreras)
4 *
5 * This file is part of sayonara player
6 *
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21 #include "GUI_EnginePreferences.h"
22 #include "Gui/Preferences/ui_GUI_EnginePreferences.h"
23
24 #include "Utils/Utils.h"
25 #include "Utils/Settings/Settings.h"
26 #include "Utils/Logger/Logger.h"
27 #include "Utils/Language/Language.h"
28 #include "Utils/Playlist/PlaylistMode.h"
29
30 #include <QProcess>
31 #include <QMap>
32
33 struct GUI_EnginePreferences::Private
34 {
35 QString alsaBuffer;
36 };
37
GUI_EnginePreferences(const QString & identifier)38 GUI_EnginePreferences::GUI_EnginePreferences(const QString& identifier) :
39 Preferences::Base(identifier)
40 {
41 m = Pimpl::make<Private>();
42 }
43
~GUI_EnginePreferences()44 GUI_EnginePreferences::~GUI_EnginePreferences()
45 {
46 if(ui){
47 delete ui; ui = nullptr;
48 }
49 }
50
actionName() const51 QString GUI_EnginePreferences::actionName() const
52 {
53 return tr("Audio");
54 }
55
commit()56 bool GUI_EnginePreferences::commit()
57 {
58 if(ui->rbPulse->isChecked()){
59 SetSetting(Set::Engine_Sink, QString("pulse"));
60 }
61
62 else if(ui->rbAlsa->isChecked())
63 {
64 QString card = ui->comboAlsaDevices->currentData().toString();
65 SetSetting(Set::Engine_AlsaDevice, card);
66 SetSetting(Set::Engine_Sink, QString("alsa"));
67
68 SetSetting(Set::Engine_CrossFaderActive, false);
69
70 Playlist::Mode plm = GetSetting(Set::PL_Mode);
71 plm.setGapless(false, false);
72 SetSetting(Set::PL_Mode, plm);
73 }
74
75 else
76 {
77 SetSetting(Set::Engine_Sink, QString("auto"));
78 }
79
80 return true;
81 }
82
revert()83 void GUI_EnginePreferences::revert()
84 {
85 QString engineName = GetSetting(Set::Engine_Sink);
86 if(engineName == "pulse"){
87 ui->rbPulse->setChecked(true);
88 }
89
90 else if(engineName == "alsa"){
91 ui->rbAlsa->setChecked(true);
92 }
93
94 else{
95 ui->rbAuto->setChecked(true);
96 }
97 }
98
initUi()99 void GUI_EnginePreferences::initUi()
100 {
101 if(ui){
102 return;
103 }
104
105 setupParent(this, &ui);
106
107 connect(ui->rbAlsa, &QRadioButton::toggled, this, &GUI_EnginePreferences::radioButtonChanged);
108 connect(ui->rbPulse, &QRadioButton::toggled, this, &GUI_EnginePreferences::radioButtonChanged);
109
110 revert();
111
112 radioButtonChanged(ui->rbAlsa->isChecked());
113 ui->comboAlsaDevices->setVisible(false);
114
115 /*
116 auto* process = new QProcess(this);
117 m->alsa_buffer.clear();
118
119 Util::set_environment("LANGUAGE", "en_US");
120 connect(process, static_cast<void (QProcess::*)(int, QProcess::ExitStatus)>(&QProcess::finished), this, &GUI_EnginePreferences::alsa_process_finished);
121 connect(process, &QProcess::readyReadStandardOutput, this, &GUI_EnginePreferences::alsa_stdout_written);
122
123 QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
124 env.insert("LANGUAGE", "en_US");
125 env.insert("LANG", "en_US.UTF-8");
126 env.insert("LC_ALL", "en_US.UTF-8");
127 process->setProcessEnvironment(env);
128 process->start("aplay", QStringList{"-l"});
129 */
130 }
131
retranslate()132 void GUI_EnginePreferences::retranslate()
133 {
134 ui->retranslateUi(this);
135
136 ui->rbAuto->setText(Lang::get(Lang::Automatic));
137 }
138
radioButtonChanged(bool b)139 void GUI_EnginePreferences::radioButtonChanged(bool b)
140 {
141 Q_UNUSED(b)
142 ui->comboAlsaDevices->setVisible(false);
143 }
144
145 struct SubDevice
146 {
147 QString name;
148 int id=0;
149 };
150
151
alsaProcessFinished(int exit_code,QProcess::ExitStatus exit_status)152 void GUI_EnginePreferences::alsaProcessFinished(int exit_code, QProcess::ExitStatus exit_status)
153 {
154 Q_UNUSED(exit_code)
155 Q_UNUSED(exit_status)
156
157 auto* process = static_cast<QProcess*>(sender());
158 m->alsaBuffer.append
159 (
160 QString::fromLocal8Bit(process->readAllStandardOutput())
161 );
162
163 ui->comboAlsaDevices->clear();
164
165 if(exit_code != 0){
166 return;
167 }
168
169 QMap <int, QList<SubDevice>> device_map;
170
171 const QStringList splitted = m->alsaBuffer.split("\n");
172 for(const QString& line : splitted)
173 {
174 QRegExp re("card ([0-9]+): (.+device ([0-9]+).+)");
175 int idx = re.indexIn(line);
176 if(idx < 0){
177 continue;
178 }
179
180 int device_id = re.cap(1).toInt();
181 int subdevice_id = re.cap(3).toInt();
182 QString name = re.cap(2);
183
184 SubDevice sd;
185 sd.id = subdevice_id;
186 sd.name = name;
187
188 if(!device_map.contains(device_id))
189 {
190 device_map.insert(device_id, QList<SubDevice>{sd});
191 }
192
193 else
194 {
195 QList<SubDevice> subdevices = device_map[device_id];
196 subdevices << sd;
197 device_map[device_id] = subdevices;
198 }
199 }
200
201 for(auto it=device_map.begin(); it != device_map.end(); it++)
202 {
203 for(const SubDevice& subdevice : it.value())
204 {
205 QString device_identifier = QString("hw:%1").arg(it.key());
206 if(it.value().size() > 1){
207 device_identifier += QString(",%1").arg(subdevice.id);
208 }
209
210 ui->comboAlsaDevices->addItem(subdevice.name, device_identifier);
211 }
212 }
213 }
214
alsaProcessErrorOccured(QProcess::ProcessError error)215 void GUI_EnginePreferences::alsaProcessErrorOccured(QProcess::ProcessError error)
216 {
217 Q_UNUSED(error)
218 }
219
alsaStdoutWritten()220 void GUI_EnginePreferences::alsaStdoutWritten()
221 {
222 auto* process = static_cast<QProcess*>(sender());
223
224 m->alsaBuffer.append
225 (
226 QString::fromLocal8Bit(process->readAllStandardOutput())
227 );
228 }
229
230