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