1 |
# Copyright (C) 2005-2008 by Pieter Palmers |
---|
2 |
# 2007-2009 by Arnold Krille |
---|
3 |
# |
---|
4 |
# This file is part of FFADO |
---|
5 |
# FFADO = Free FireWire (pro-)audio drivers for linux |
---|
6 |
# |
---|
7 |
# FFADO is based upon FreeBoB. |
---|
8 |
# |
---|
9 |
# This program is free software: you can redistribute it and/or modify |
---|
10 |
# it under the terms of the GNU General Public License as published by |
---|
11 |
# the Free Software Foundation, either version 3 of the License, or |
---|
12 |
# (at your option) any later version. |
---|
13 |
# |
---|
14 |
# This program is distributed in the hope that it will be useful, |
---|
15 |
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
16 |
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
---|
17 |
# GNU General Public License for more details. |
---|
18 |
# |
---|
19 |
# You should have received a copy of the GNU General Public License |
---|
20 |
# along with this program. If not, see <http://www.gnu.org/licenses/>. |
---|
21 |
# |
---|
22 |
|
---|
23 |
import ctypes |
---|
24 |
import datetime |
---|
25 |
import os |
---|
26 |
|
---|
27 |
from ffado.config import * |
---|
28 |
|
---|
29 |
import subprocess |
---|
30 |
|
---|
31 |
# from PyQt4.QtCore import QObject, QTimer, Qt |
---|
32 |
# from PyQt4.QtGui import * |
---|
33 |
from ffado.import_pyqt import * |
---|
34 |
|
---|
35 |
from ffado.dbus_util import * |
---|
36 |
|
---|
37 |
from ffado.panelmanager import PanelManager |
---|
38 |
|
---|
39 |
from ffado.logginghandler import * |
---|
40 |
|
---|
41 |
"""Just a small helper to ask the retry-question without a blocking messagebox""" |
---|
42 |
class StartDialog(QWidget): |
---|
43 |
def __init__(self, parent): |
---|
44 |
QWidget.__init__(self, parent) |
---|
45 |
self.setObjectName("Restart Dialog") |
---|
46 |
self.label = QLabel("<qt>Somehow the connection to the dbus-service of FFADO couldn't be established.<p>\nShall we take another try?</qt>",self) |
---|
47 |
self.button = QPushButton("Retry", self) |
---|
48 |
self.layout = QGridLayout(self) |
---|
49 |
self.layout.setContentsMargins( 50, 10, 50, 10 ) |
---|
50 |
self.layout.addWidget(self.label, 0, 0, Qt.AlignHCenter|Qt.AlignBottom) |
---|
51 |
self.layout.addWidget(self.button, 1, 0, Qt.AlignHCenter|Qt.AlignTop) |
---|
52 |
|
---|
53 |
class FFADOWindow(QMainWindow): |
---|
54 |
def __init__(self, parent): |
---|
55 |
QMainWindow.__init__(self, parent) |
---|
56 |
|
---|
57 |
self.textlogger = QTextLogger(self) |
---|
58 |
dock = QDockWidget("Log Messages",self) |
---|
59 |
dock.setWidget(self.textlogger.textedit) |
---|
60 |
logging.getLogger('').addHandler(self.textlogger) |
---|
61 |
self.addDockWidget(Qt.BottomDockWidgetArea, dock) |
---|
62 |
|
---|
63 |
self.statuslogger = QStatusLogger(self, self.statusBar(), 20) |
---|
64 |
logging.getLogger('').addHandler(self.statuslogger) |
---|
65 |
|
---|
66 |
self.manager = PanelManager(self) |
---|
67 |
self.manager.connectionLost.connect(self.connectToDBUS) |
---|
68 |
|
---|
69 |
filemenu = self.menuBar().addMenu("&File") |
---|
70 |
self.openaction = QAction(QIcon.fromTheme("document-open"),"&Open", self) |
---|
71 |
self.openaction.setShortcut(self.tr("Ctrl+O")) |
---|
72 |
self.openaction.setEnabled(False) |
---|
73 |
self.openaction.triggered.connect(self.manager.readSettings) |
---|
74 |
filemenu.addAction(self.openaction) |
---|
75 |
self.saveaction = QAction(QIcon.fromTheme("document-save-as"),"&Save as...", self) |
---|
76 |
self.saveaction.setShortcut(self.tr("Ctrl+S")) |
---|
77 |
self.saveaction.setEnabled(False) |
---|
78 |
self.saveaction.triggered.connect(self.manager.saveSettings) |
---|
79 |
filemenu.addAction(self.saveaction) |
---|
80 |
self.quitaction = QAction(QIcon.fromTheme("application-exit"),"&Quit", self) |
---|
81 |
self.quitaction.setShortcut(self.tr("Ctrl+q")) |
---|
82 |
self.quitaction.triggered.connect(self.close) |
---|
83 |
filemenu.addAction(self.quitaction) |
---|
84 |
|
---|
85 |
self.editmenu = self.menuBar().addMenu("&View") |
---|
86 |
|
---|
87 |
self.thememenu = self.editmenu.addMenu("Theme") |
---|
88 |
themes = QStyleFactory.keys() |
---|
89 |
self.menuTheme = {} |
---|
90 |
for theme in themes: |
---|
91 |
self.menuTheme[theme] = QAction(QIcon.fromTheme("preferences-desktop-theme"), theme, self ) |
---|
92 |
self.menuTheme[theme].setCheckable(True) |
---|
93 |
|
---|
94 |
if (ffado_python3 and (self.style().objectName().lower() == theme.lower()) or |
---|
95 |
not(ffado_python3) and (self.style().objectName().toLower() == theme.toLower() if ffado_pyqt_version == 4 else |
---|
96 |
self.style().objectName().lower() == theme.lower())): |
---|
97 |
self.menuTheme[theme].setDisabled(True) |
---|
98 |
self.menuTheme[theme].setChecked(True) |
---|
99 |
self.menuTheme[theme].triggered.connect(self.switchTheme ) |
---|
100 |
self.thememenu.addAction( self.menuTheme[theme] ) |
---|
101 |
|
---|
102 |
self.updateaction = QAction(QIcon.fromTheme("view-refresh"),"&Update Mixer Panels", self) |
---|
103 |
self.updateaction.setEnabled(False) |
---|
104 |
self.updateaction.triggered.connect(self.manager.updatePanels) |
---|
105 |
self.editmenu.addAction(self.updateaction) |
---|
106 |
self.refreshaction = QAction(QIcon.fromTheme("view-refresh"),"&Refresh Current Panels", self) |
---|
107 |
self.refreshaction.triggered.connect(self.manager.refreshPanels) |
---|
108 |
self.editmenu.addAction(self.refreshaction) |
---|
109 |
self.editmenu.addSeparator() |
---|
110 |
self.devices = {} |
---|
111 |
|
---|
112 |
helpmenu = self.menuBar().addMenu( "&Help" ) |
---|
113 |
self.aboutaction = QAction(QIcon.fromTheme("help-about"), "About &FFADO", self ) |
---|
114 |
self.aboutaction.triggered.connect(self.aboutFFADO) |
---|
115 |
helpmenu.addAction( self.aboutaction ) |
---|
116 |
self.aboutqtaction = QAction(QIcon.fromTheme("help-about"), "About &Qt", self ) |
---|
117 |
self.aboutqtaction.triggered.connect(QApplication.instance().aboutQt) |
---|
118 |
helpmenu.addAction( self.aboutqtaction ) |
---|
119 |
|
---|
120 |
log.info( "Starting up" ) |
---|
121 |
|
---|
122 |
QTimer.singleShot( 1, self.tryStartDBUSServer ) |
---|
123 |
|
---|
124 |
def __del__(self): |
---|
125 |
log.info("__del__") |
---|
126 |
del self.manager |
---|
127 |
log.info("__del__ finished") |
---|
128 |
|
---|
129 |
def switchTheme(self, checked) : |
---|
130 |
for theme in self.menuTheme : |
---|
131 |
if not self.menuTheme[theme].isEnabled() : |
---|
132 |
self.menuTheme[theme].setChecked(False) |
---|
133 |
self.menuTheme[theme].setDisabled(False) |
---|
134 |
for theme in self.menuTheme : |
---|
135 |
if self.menuTheme[theme].isChecked() : |
---|
136 |
self.menuTheme[theme].setDisabled(True) |
---|
137 |
QApplication.setStyle(QStyleFactory.create(theme)) |
---|
138 |
|
---|
139 |
def closeEvent(self, event): |
---|
140 |
log.info("closeEvent()") |
---|
141 |
event.accept() |
---|
142 |
|
---|
143 |
def connectToDBUS(self): |
---|
144 |
log.info("connectToDBUS") |
---|
145 |
try: |
---|
146 |
self.setupDeviceManager() |
---|
147 |
except dbus.DBusException as ex: |
---|
148 |
log.error("Could not communicate with the FFADO DBus service...") |
---|
149 |
if not hasattr(self,"retry"): |
---|
150 |
self.retry = StartDialog(self) |
---|
151 |
self.retry.button.clicked.connect(self.tryStartDBUSServer) |
---|
152 |
if hasattr(self, "retry"): |
---|
153 |
self.manager.setParent(None) |
---|
154 |
self.setCentralWidget(self.retry) |
---|
155 |
self.retry.setEnabled(True) |
---|
156 |
|
---|
157 |
def tryStartDBUSServer(self): |
---|
158 |
try: |
---|
159 |
self.setupDeviceManager() |
---|
160 |
except dbus.DBusException as ex: |
---|
161 |
if hasattr(self, "retry"): |
---|
162 |
self.retry.setEnabled(False) |
---|
163 |
subprocess.Popen(['ffado-dbus-server', '-v3'], close_fds=True).pid |
---|
164 |
QTimer.singleShot(5000, self.connectToDBUS) |
---|
165 |
|
---|
166 |
def setupDeviceManager(self): |
---|
167 |
devmgr = DeviceManagerInterface(FFADO_DBUS_SERVER, FFADO_DBUS_BASEPATH) |
---|
168 |
self.manager.setManager(devmgr) |
---|
169 |
if hasattr(self, "retry"): |
---|
170 |
self.retry.setParent(None) |
---|
171 |
self.setCentralWidget(self.manager) |
---|
172 |
self.updateaction.setEnabled(True) |
---|
173 |
|
---|
174 |
def aboutFFADO(self): |
---|
175 |
QMessageBox.about( self, "About FFADO", """ |
---|
176 |
<h1><a href="http://ffado.org">ffado.org</a></h1> |
---|
177 |
|
---|
178 |
<p>{ffado_version}</p> |
---|
179 |
|
---|
180 |
<p><a href="http://ffado.org">FFADO</a> is the new approach to have firewire audio on linux.</p> |
---|
181 |
|
---|
182 |
<p>© 2006-2021 by the FFADO developers<br />ffado is licensed under the GPLv3, for the full license text see <a href="http://www.gnu.org/licenses/">www.gnu.org/licenses</a> or the LICENSE.* files shipped with ffado.</p> |
---|
183 |
|
---|
184 |
<p>FFADO developers are:<ul> |
---|
185 |
<li>Pieter Palmers |
---|
186 |
<li>Daniel Wagner |
---|
187 |
<li>Jonathan Woithe |
---|
188 |
<li>Arnold Krille |
---|
189 |
<li>Philippe Carriere |
---|
190 |
<li>Takashi Sakamoto |
---|
191 |
</ul> |
---|
192 |
with contributions from:<ul> |
---|
193 |
<li>Adrian Knoth |
---|
194 |
<li>Stefan Richter |
---|
195 |
<li>Jano Svitok |
---|
196 |
</ul> |
---|
197 |
""".format(ffado_version=get_ffado_version(), thisyear=datetime.datetime.now().year)) |
---|
198 |
|
---|
199 |
def get_ffado_version(): |
---|
200 |
try: |
---|
201 |
# call the C function ffado_get_version() to figure out the version |
---|
202 |
lib = ctypes.cdll.LoadLibrary('libffado.so') |
---|
203 |
func = ctypes.CFUNCTYPE(ctypes.c_char_p) |
---|
204 |
ffado_get_version = func(('ffado_get_version', lib)) |
---|
205 |
return ffado_get_version() |
---|
206 |
except: |
---|
207 |
return "libffado" |
---|
208 |
|
---|
209 |
def get_lock(process_name): |
---|
210 |
import socket |
---|
211 |
import sys |
---|
212 |
|
---|
213 |
global lock_socket |
---|
214 |
lock_socket = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM) |
---|
215 |
try: |
---|
216 |
lock_socket.bind('\0' + process_name) |
---|
217 |
# Lock acquired |
---|
218 |
except socket.error: |
---|
219 |
print( 'ffado-mixer instance is already running' ) |
---|
220 |
sys.exit() |
---|
221 |
|
---|
222 |
|
---|
223 |
def ffadomain(args): |
---|
224 |
#set up logging |
---|
225 |
import logging |
---|
226 |
logging.basicConfig( datefmt="%H:%M:%S", format="%(asctime)s %(name)-16s %(levelname)-8s %(message)s" ) |
---|
227 |
|
---|
228 |
if DEBUG: |
---|
229 |
debug_level = logging.DEBUG |
---|
230 |
else: |
---|
231 |
debug_level = logging.INFO |
---|
232 |
|
---|
233 |
get_lock('ffado-mixer') |
---|
234 |
|
---|
235 |
# Very simple command line option parser |
---|
236 |
if (len(args) > 1) and (args[1] == "-b" or args[1] == "--bypassdbus"): |
---|
237 |
ffado.config.bypassdbus = True |
---|
238 |
|
---|
239 |
# main loggers: |
---|
240 |
logging.getLogger('main').setLevel(debug_level) |
---|
241 |
logging.getLogger('dbus').setLevel(debug_level) |
---|
242 |
logging.getLogger('registration').setLevel(debug_level) |
---|
243 |
logging.getLogger('panelmanager').setLevel(debug_level) |
---|
244 |
logging.getLogger('configparser').setLevel(logging.INFO) |
---|
245 |
|
---|
246 |
# widgets: |
---|
247 |
logging.getLogger('matrixmixer').setLevel(debug_level) |
---|
248 |
logging.getLogger('crossbarrouter').setLevel(debug_level) |
---|
249 |
|
---|
250 |
# mixers: |
---|
251 |
logging.getLogger('audiofire').setLevel(debug_level) |
---|
252 |
logging.getLogger('bridgeco').setLevel(debug_level) |
---|
253 |
logging.getLogger('edirolfa101').setLevel(debug_level) |
---|
254 |
logging.getLogger('edirolfa66').setLevel(debug_level) |
---|
255 |
logging.getLogger('motu').setLevel(debug_level) |
---|
256 |
logging.getLogger('rme').setLevel(debug_level) |
---|
257 |
logging.getLogger('phase24').setLevel(debug_level) |
---|
258 |
logging.getLogger('phase88').setLevel(debug_level) |
---|
259 |
logging.getLogger('quatafire').setLevel(debug_level) |
---|
260 |
logging.getLogger('saffirebase').setLevel(debug_level) |
---|
261 |
logging.getLogger('saffire').setLevel(debug_level) |
---|
262 |
logging.getLogger('saffirepro').setLevel(debug_level) |
---|
263 |
|
---|
264 |
logging.getLogger('global').setLevel(debug_level) |
---|
265 |
|
---|
266 |
log = logging.getLogger('main') |
---|
267 |
log.debug("Using %s with Qt: %s PyQt: %s" % (get_ffado_version(), QtCore.QT_VERSION_STR, QtCore.PYQT_VERSION_STR)) |
---|
268 |
|
---|
269 |
app = QApplication(args) |
---|
270 |
app.setWindowIcon( QIcon( SHAREDIR + "/icons/hi64-apps-ffado.png" ) ) |
---|
271 |
|
---|
272 |
app.setOrganizationName("FFADO") |
---|
273 |
app.setOrganizationDomain("ffado.org") |
---|
274 |
app.setApplicationName("ffado-mixer") |
---|
275 |
|
---|
276 |
mainwindow = FFADOWindow(None) |
---|
277 |
|
---|
278 |
|
---|
279 |
# rock & roll |
---|
280 |
mainwindow.show() |
---|
281 |
return app.exec_() |
---|
282 |
|
---|
283 |
if __name__ == "__main__": |
---|
284 |
import sys |
---|
285 |
sys.exit(ffadomain(sys.argv)) |
---|
286 |
|
---|
287 |
# |
---|
288 |
# vim: ts=4 sw=4 et |
---|