summaryrefslogtreecommitdiffstats
path: root/plugins/alsa-sound
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/alsa-sound')
-rw-r--r--plugins/alsa-sound/CMakeL10n.txt6
-rw-r--r--plugins/alsa-sound/Makefile.am20
-rw-r--r--plugins/alsa-sound/alsa-config-mixer-setting.cpp67
-rw-r--r--plugins/alsa-sound/alsa-config-mixer-setting.h45
-rw-r--r--plugins/alsa-sound/alsa-mixer-element-ui.ui270
-rw-r--r--plugins/alsa-sound/alsa-mixer-element.cpp139
-rw-r--r--plugins/alsa-sound/alsa-mixer-element.h63
-rw-r--r--plugins/alsa-sound/alsa-sound-configuration-ui.ui319
-rw-r--r--plugins/alsa-sound/alsa-sound-configuration.cpp353
-rw-r--r--plugins/alsa-sound/alsa-sound-configuration.h84
-rw-r--r--plugins/alsa-sound/alsa-sound.cpp1562
-rw-r--r--plugins/alsa-sound/alsa-sound.h297
-rw-r--r--plugins/alsa-sound/icons/Makefile.am7
-rw-r--r--plugins/alsa-sound/icons/alsa.pngbin0 -> 3322 bytes
-rw-r--r--plugins/alsa-sound/icons/alsa2.pngbin0 -> 2389 bytes
-rw-r--r--plugins/alsa-sound/icons/hi16-action-tderadio_alsa.pngbin0 -> 392 bytes
-rw-r--r--plugins/alsa-sound/icons/hi16-action-tderadio_alsa2.pngbin0 -> 603 bytes
-rw-r--r--plugins/alsa-sound/icons/hi22-action-tderadio_alsa.pngbin0 -> 464 bytes
-rw-r--r--plugins/alsa-sound/icons/hi22-action-tderadio_alsa2.pngbin0 -> 918 bytes
-rw-r--r--plugins/alsa-sound/icons/hi32-action-tderadio_alsa.pngbin0 -> 607 bytes
-rw-r--r--plugins/alsa-sound/icons/hi32-action-tderadio_alsa2.pngbin0 -> 1360 bytes
-rw-r--r--plugins/alsa-sound/icons/hi48-action-tderadio_alsa.pngbin0 -> 905 bytes
-rw-r--r--plugins/alsa-sound/icons/hi48-action-tderadio_alsa2.pngbin0 -> 1954 bytes
-rw-r--r--plugins/alsa-sound/icons/hi64-action-tderadio_alsa.pngbin0 -> 1280 bytes
-rw-r--r--plugins/alsa-sound/icons/hi64-action-tderadio_alsa2.pngbin0 -> 2583 bytes
-rw-r--r--plugins/alsa-sound/po/Makefile.am3
-rw-r--r--plugins/alsa-sound/po/de.po285
-rw-r--r--plugins/alsa-sound/po/ru.po284
-rw-r--r--plugins/alsa-sound/po/tderadio-alsa-sound.pot275
29 files changed, 4079 insertions, 0 deletions
diff --git a/plugins/alsa-sound/CMakeL10n.txt b/plugins/alsa-sound/CMakeL10n.txt
new file mode 100644
index 0000000..cf48935
--- /dev/null
+++ b/plugins/alsa-sound/CMakeL10n.txt
@@ -0,0 +1,6 @@
+##### create translation templates ##############
+
+tde_l10n_create_template(
+ CATALOG "tderadio-alsa-sound"
+ DESTINATION "po"
+)
diff --git a/plugins/alsa-sound/Makefile.am b/plugins/alsa-sound/Makefile.am
new file mode 100644
index 0000000..dfc2b0b
--- /dev/null
+++ b/plugins/alsa-sound/Makefile.am
@@ -0,0 +1,20 @@
+SUBDIRS = po icons .
+
+INCLUDES = $(all_includes)
+METASOURCES = AUTO
+
+libtderadio_LTLIBRARIES = libalsa-sound.la
+libalsa_sound_la_LDFLAGS = -module -avoid-version $(KDE_RPATH) $(all_libraries)
+noinst_HEADERS = alsa-sound.h alsa-sound-configuration.h alsa-mixer-element.h \
+ alsa-config-mixer-setting.h
+libalsa_sound_la_SOURCES = alsa-sound.cpp alsa-sound-configuration-ui.ui \
+ alsa-sound-configuration.cpp alsa-mixer-element-ui.ui alsa-mixer-element.cpp \
+ alsa-config-mixer-setting.cpp
+libalsa_sound_la_LIBADD = $(LIB_ALSA)
+
+#messages: rc.cpp
+# $(XGETTEXT) *.cpp *.h -o po/tderadio-alsa-sound.pot
+
+messages: rc.cpp
+ $(EXTRACTRC) *.rc *.ui >> rc.cpp
+ $(XGETTEXT) rc.cpp *.h *.cpp -o po/tderadio-alsa-sound.pot
diff --git a/plugins/alsa-sound/alsa-config-mixer-setting.cpp b/plugins/alsa-sound/alsa-config-mixer-setting.cpp
new file mode 100644
index 0000000..4c39ff9
--- /dev/null
+++ b/plugins/alsa-sound/alsa-config-mixer-setting.cpp
@@ -0,0 +1,67 @@
+/***************************************************************************
+ alsa-config-mixer-setting.cpp - description
+ -------------------
+ begin : Mon Aug 15 2005
+ copyright : (C) 2005 by Martin Witte
+ email : witte@kawo1.rwth-aachen.de
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include "alsa-config-mixer-setting.h"
+
+#include <tdeconfig.h>
+
+AlsaConfigMixerSetting::AlsaConfigMixerSetting()
+ : m_card(-1),
+ m_name(TQString()),
+ m_use(false),
+ m_active(false),
+ m_volume(-1)
+{
+}
+
+AlsaConfigMixerSetting::AlsaConfigMixerSetting(TDEConfig *c, const TQString &prefix)
+{
+ m_card = c->readNumEntry (prefix+"card", -1);
+ m_name = c->readEntry (prefix+"name", TQString());
+ m_use = c->readBoolEntry (prefix+"use", false);
+ m_active = c->readBoolEntry (prefix+"active", false);
+ m_volume = c->readDoubleNumEntry(prefix+"volume", 0);
+}
+
+AlsaConfigMixerSetting::AlsaConfigMixerSetting(int card, const TQString &name, bool use, bool active, float volume)
+ : m_card(card),
+ m_name(name),
+ m_use(use),
+ m_active(active),
+ m_volume(volume)
+{
+}
+
+AlsaConfigMixerSetting::~AlsaConfigMixerSetting()
+{
+}
+
+TQString AlsaConfigMixerSetting::getIDString(int card, const TQString &name)
+{
+ return TQString::number(card) + "-" + name;
+}
+
+void AlsaConfigMixerSetting::saveState(TDEConfig *c, const TQString &prefix) const
+{
+ c->writeEntry(prefix+"card", m_card);
+ c->writeEntry(prefix+"name", m_name);
+ c->writeEntry(prefix+"use", m_use);
+ c->writeEntry(prefix+"active", m_active);
+ c->writeEntry(prefix+"volume", m_volume);
+}
+
+
diff --git a/plugins/alsa-sound/alsa-config-mixer-setting.h b/plugins/alsa-sound/alsa-config-mixer-setting.h
new file mode 100644
index 0000000..94a995f
--- /dev/null
+++ b/plugins/alsa-sound/alsa-config-mixer-setting.h
@@ -0,0 +1,45 @@
+/***************************************************************************
+ alsa-config-mixer-setting.h - description
+ -------------------
+ begin : Mon Aug 15 2005
+ copyright : (C) 2005 by Martin Witte
+ email : witte@kawo1.rwth-aachen.de
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef __KRADIO_ALSA_CONFIG_MIXER_SETTING_H
+#define __KRADIO_ALSA_CONFIG_MIXER_SETTING_H
+
+#include <tqstring.h>
+
+class TDEConfig;
+
+class AlsaConfigMixerSetting
+{
+public:
+ AlsaConfigMixerSetting();
+ AlsaConfigMixerSetting(TDEConfig *c, const TQString &prefix);
+ AlsaConfigMixerSetting(int card, const TQString &name, bool use, bool active, float volume);
+ ~AlsaConfigMixerSetting();
+
+ TQString getIDString() const { return getIDString(m_card, m_name); }
+ static TQString getIDString(int card, const TQString &m_name);
+
+ void saveState(TDEConfig *c, const TQString &prefix) const;
+
+ int m_card;
+ TQString m_name;
+ bool m_use;
+ bool m_active;
+ float m_volume;
+};
+
+#endif
diff --git a/plugins/alsa-sound/alsa-mixer-element-ui.ui b/plugins/alsa-sound/alsa-mixer-element-ui.ui
new file mode 100644
index 0000000..87cdfa5
--- /dev/null
+++ b/plugins/alsa-sound/alsa-mixer-element-ui.ui
@@ -0,0 +1,270 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>AlsaMixerElementUI</class>
+<widget class="TQWidget">
+ <property name="name">
+ <cstring>AlsaMixerElementUI</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>124</width>
+ <height>153</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>Form1</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="TQLayoutWidget">
+ <property name="name">
+ <cstring>layout16</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <spacer>
+ <property name="name">
+ <cstring>spacer1</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>16</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <spacer>
+ <property name="name">
+ <cstring>spacer23</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>1</width>
+ <height>40</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="TQSlider">
+ <property name="name">
+ <cstring>m_sliderVolume</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="maxValue">
+ <number>100</number>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer23_2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>1</width>
+ <height>40</height>
+ </size>
+ </property>
+ </spacer>
+ <spacer>
+ <property name="name">
+ <cstring>spacer1_2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </hbox>
+ </widget>
+ <widget class="TQLayoutWidget">
+ <property name="name">
+ <cstring>layout7</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <spacer>
+ <property name="name">
+ <cstring>spacer3_3</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>11</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="KIntSpinBox">
+ <property name="name">
+ <cstring>m_spinboxVolume</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="maxValue">
+ <number>100</number>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer3_4</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>11</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </hbox>
+ </widget>
+ <widget class="TQLayoutWidget">
+ <property name="name">
+ <cstring>layout5</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <spacer>
+ <property name="name">
+ <cstring>spacer3</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>16</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="TQLayoutWidget">
+ <property name="name">
+ <cstring>layout4</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="TQCheckBox">
+ <property name="name">
+ <cstring>m_checkboxActive</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>O&amp;n</string>
+ </property>
+ <property name="accel">
+ <string>Alt+N</string>
+ </property>
+ </widget>
+ <widget class="TQCheckBox">
+ <property name="name">
+ <cstring>m_checkboxOverride</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Use</string>
+ </property>
+ <property name="accel">
+ <string>Alt+U</string>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer3_2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>16</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </hbox>
+ </widget>
+ <widget class="TQLabel">
+ <property name="name">
+ <cstring>m_labelMixerElementName</cstring>
+ </property>
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ <property name="text">
+ <string>MixerName</string>
+ </property>
+ <property name="alignment">
+ <set>AlignCenter</set>
+ </property>
+ </widget>
+ </vbox>
+</widget>
+<customwidgets>
+</customwidgets>
+<layoutdefaults spacing="6" margin="2"/>
+<includes>
+ <include location="global" impldecl="in implementation">knuminput.h</include>
+</includes>
+</UI>
diff --git a/plugins/alsa-sound/alsa-mixer-element.cpp b/plugins/alsa-sound/alsa-mixer-element.cpp
new file mode 100644
index 0000000..53a7216
--- /dev/null
+++ b/plugins/alsa-sound/alsa-mixer-element.cpp
@@ -0,0 +1,139 @@
+/***************************************************************************
+ alsa-mixer-element.cpp - description
+ -------------------
+ begin : Mon Aug 15 2005
+ copyright : (C) 2005 by Martin Witte
+ email : witte@kawo1.rwth-aachen.de
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include "alsa-mixer-element.h"
+
+#include <knuminput.h>
+#include <tqslider.h>
+#include <tqlabel.h>
+#include <tqcheckbox.h>
+
+#include <math.h>
+
+QAlsaMixerElement::QAlsaMixerElement(TQWidget *parent, const TQString &label, bool has_switch, bool has_volume)
+ : AlsaMixerElementUI(parent),
+ m_HasVolume(has_volume),
+ m_HasSwitch(has_switch),
+ m_dirty(false),
+ m_ignore_updates(false)
+{
+ setLabel(label);
+ setVolume(0);
+
+ TQObject::connect(m_spinboxVolume, TQT_SIGNAL(valueChanged(int)),
+ this, TQT_SLOT (slotSpinboxValueChanged(int)));
+ TQObject::connect(m_sliderVolume, TQT_SIGNAL(valueChanged(int)),
+ this, TQT_SLOT (slotSliderValueChanged(int)));
+
+ if (m_HasVolume) {
+ TQObject::connect(m_checkboxOverride, TQT_SIGNAL(toggled(bool)),
+ m_spinboxVolume, TQT_SLOT (setEnabled(bool)));
+ TQObject::connect(m_checkboxOverride, TQT_SIGNAL(toggled(bool)),
+ m_sliderVolume, TQT_SLOT (setEnabled(bool)));
+ } else {
+ m_spinboxVolume->hide();
+ m_sliderVolume->hide();
+ }
+ if (m_HasSwitch) {
+ TQObject::connect(m_checkboxOverride, TQT_SIGNAL(toggled(bool)),
+ m_checkboxActive, TQT_SLOT (setEnabled(bool)));
+ } else {
+ //m_checkboxActive->hide();
+ m_checkboxActive->setEnabled(false);
+ m_checkboxActive->setChecked(true);
+ }
+
+ connect(m_checkboxOverride, TQT_SIGNAL(toggled(bool)), this, TQT_SLOT(slotSetDirty()));
+ connect(m_checkboxActive, TQT_SIGNAL(toggled(bool)), this, TQT_SLOT(slotSetDirty()));
+ connect(m_spinboxVolume, TQT_SIGNAL(valueChanged(int)), this, TQT_SLOT(slotSetDirty()));
+ connect(m_sliderVolume, TQT_SIGNAL(valueChanged(int)), this, TQT_SLOT(slotSetDirty()));
+}
+
+
+QAlsaMixerElement::~QAlsaMixerElement()
+{
+}
+
+float QAlsaMixerElement::getVolume() const
+{
+ return ((float)m_spinboxVolume->value())/100.0;
+}
+
+bool QAlsaMixerElement::getActive() const
+{
+ return m_checkboxActive->isChecked();
+}
+
+bool QAlsaMixerElement::getOverride() const
+{
+ return m_checkboxOverride->isChecked();
+}
+
+void QAlsaMixerElement::setLabel(const TQString &label)
+{
+ m_labelMixerElementName->setText(label);
+}
+
+void QAlsaMixerElement::setOverride(bool ov)
+{
+ m_ignore_updates = true;
+ m_checkboxOverride->setChecked(ov);
+ m_ignore_updates = false;
+}
+
+void QAlsaMixerElement::setActive(bool active)
+{
+ m_ignore_updates = true;
+ m_checkboxActive->setChecked(active);
+ m_ignore_updates = false;
+}
+
+void QAlsaMixerElement::setVolume(float vol)
+{
+ m_ignore_updates = true;
+ int v = (int)rint(vol*100 + 0.5);
+ m_sliderVolume->setValue(100 - v);
+ m_spinboxVolume->setValue(v);
+ m_ignore_updates = false;
+}
+
+void QAlsaMixerElement::slotSpinboxValueChanged(int v)
+{
+ m_sliderVolume->setValue(100-v);
+}
+
+void QAlsaMixerElement::slotSliderValueChanged(int v)
+{
+ m_spinboxVolume->setValue(100-v);
+}
+
+
+void QAlsaMixerElement::slotSetDirty()
+{
+ if (!m_dirty && !m_ignore_updates) {
+ m_dirty = true;
+ emit sigDirty();
+ }
+}
+
+
+void QAlsaMixerElement::slotResetDirty()
+{
+ m_dirty = false;
+}
+
+#include "alsa-mixer-element.moc"
diff --git a/plugins/alsa-sound/alsa-mixer-element.h b/plugins/alsa-sound/alsa-mixer-element.h
new file mode 100644
index 0000000..f72e78e
--- /dev/null
+++ b/plugins/alsa-sound/alsa-mixer-element.h
@@ -0,0 +1,63 @@
+/***************************************************************************
+ alsa-mixer-element.h - description
+ -------------------
+ begin : Mon Aug 15 2005
+ copyright : (C) 2005 by Martin Witte
+ email : witte@kawo1.rwth-aachen.de
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef __KRADIO_ALSA_MIXER_ELEMENT_H
+#define __KRADIO_ALSA_MIXER_ELEMENT_H
+
+#include "alsa-mixer-element-ui.h"
+
+class QAlsaMixerElement : public AlsaMixerElementUI
+{
+Q_OBJECT
+
+public:
+ QAlsaMixerElement(TQWidget *parent, const TQString &label, bool has_switch, bool has_volume);
+ ~QAlsaMixerElement();
+
+
+ float getVolume() const;
+ bool getActive() const;
+ bool getOverride() const;
+
+ bool isDirty() const { return m_dirty; }
+
+public slots:
+
+ void setLabel(const TQString &label);
+ void setOverride(bool ov);
+ void setActive(bool active);
+ void setVolume(float vol);
+ void slotResetDirty();
+ void slotSetDirty();
+
+protected slots:
+ void slotSpinboxValueChanged(int v);
+ void slotSliderValueChanged(int v);
+
+signals:
+
+ void sigDirty();
+
+protected:
+
+ bool m_HasVolume;
+ bool m_HasSwitch;
+ bool m_dirty;
+ bool m_ignore_updates;
+};
+
+#endif
diff --git a/plugins/alsa-sound/alsa-sound-configuration-ui.ui b/plugins/alsa-sound/alsa-sound-configuration-ui.ui
new file mode 100644
index 0000000..9484f18
--- /dev/null
+++ b/plugins/alsa-sound/alsa-sound-configuration-ui.ui
@@ -0,0 +1,319 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>AlsaSoundConfigurationUI</class>
+<widget class="TQWidget">
+ <property name="name">
+ <cstring>AlsaSoundConfigurationUI</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>475</width>
+ <height>260</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>AlsaSoundConfigurationUI</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <widget class="TQTabWidget" row="0" column="0">
+ <property name="name">
+ <cstring>kTabWidget8</cstring>
+ </property>
+ <widget class="TQWidget">
+ <property name="name">
+ <cstring>TabPage</cstring>
+ </property>
+ <attribute name="title">
+ <string>Devices</string>
+ </attribute>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>11</number>
+ </property>
+ <spacer row="1" column="0">
+ <property name="name">
+ <cstring>spacer114</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>5</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="TQLayoutWidget" row="0" column="0">
+ <property name="name">
+ <cstring>layout58</cstring>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="TQLabel" row="2" column="0">
+ <property name="name">
+ <cstring>textLabel2</cstring>
+ </property>
+ <property name="text">
+ <string>PCM Capture Card</string>
+ </property>
+ </widget>
+ <widget class="KComboBox" row="2" column="1">
+ <property name="name">
+ <cstring>m_comboCaptureCard</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>3</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ <widget class="TQLabel" row="4" column="0">
+ <property name="name">
+ <cstring>textLabel2_2_2</cstring>
+ </property>
+ <property name="text">
+ <string>Hardware Buffer Size</string>
+ </property>
+ </widget>
+ <widget class="KComboBox" row="3" column="1">
+ <property name="name">
+ <cstring>m_comboCaptureDevice</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>3</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ <widget class="KIntSpinBox" row="5" column="1">
+ <property name="name">
+ <cstring>editBufferSize</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>3</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="suffix">
+ <string> kB</string>
+ </property>
+ <property name="maxValue">
+ <number>1024</number>
+ </property>
+ <property name="minValue">
+ <number>1</number>
+ </property>
+ </widget>
+ <widget class="KIntSpinBox" row="4" column="1">
+ <property name="name">
+ <cstring>editHWBufferSize</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>3</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="suffix">
+ <string> kB</string>
+ </property>
+ <property name="maxValue">
+ <number>1024</number>
+ </property>
+ <property name="minValue">
+ <number>1</number>
+ </property>
+ </widget>
+ <widget class="KComboBox" row="0" column="1">
+ <property name="name">
+ <cstring>m_comboPlaybackCard</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>3</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ <widget class="TQLabel" row="5" column="0">
+ <property name="name">
+ <cstring>textLabel2_2_2_2</cstring>
+ </property>
+ <property name="text">
+ <string>Buffer Size</string>
+ </property>
+ </widget>
+ <widget class="KComboBox" row="1" column="1">
+ <property name="name">
+ <cstring>m_comboPlaybackDevice</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>3</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ <widget class="TQLabel" row="1" column="0">
+ <property name="name">
+ <cstring>textLabel2_3</cstring>
+ </property>
+ <property name="text">
+ <string>PCM Playback Device</string>
+ </property>
+ </widget>
+ <widget class="TQLabel" row="3" column="0">
+ <property name="name">
+ <cstring>textLabel2_4</cstring>
+ </property>
+ <property name="text">
+ <string>PCM Capture Device</string>
+ </property>
+ </widget>
+ <widget class="TQLabel" row="0" column="0">
+ <property name="name">
+ <cstring>textLabel2</cstring>
+ </property>
+ <property name="text">
+ <string>PCM Playback Card</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="TQWidget">
+ <property name="name">
+ <cstring>TabPage</cstring>
+ </property>
+ <attribute name="title">
+ <string>E&amp;xtended Options</string>
+ </attribute>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>11</number>
+ </property>
+ <widget class="TQCheckBox" row="0" column="0">
+ <property name="name">
+ <cstring>chkDisablePlayback</cstring>
+ </property>
+ <property name="text">
+ <string>Disable Pla&amp;yback</string>
+ </property>
+ <property name="accel">
+ <string>Alt+Y</string>
+ </property>
+ </widget>
+ <widget class="TQCheckBox" row="1" column="0">
+ <property name="name">
+ <cstring>chkDisableCapture</cstring>
+ </property>
+ <property name="text">
+ <string>Disa&amp;ble Capture</string>
+ </property>
+ <property name="accel">
+ <string>Alt+B</string>
+ </property>
+ </widget>
+ <spacer row="2" column="0">
+ <property name="name">
+ <cstring>spacer113</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>40</height>
+ </size>
+ </property>
+ </spacer>
+ </grid>
+ </widget>
+ <widget class="TQWidget">
+ <property name="name">
+ <cstring>TabPage</cstring>
+ </property>
+ <attribute name="title">
+ <string>Capture Mixer Settings</string>
+ </attribute>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>11</number>
+ </property>
+ <widget class="TQGroupBox" row="0" column="0">
+ <property name="name">
+ <cstring>m_groupMixer</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>5</hsizetype>
+ <vsizetype>7</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="frameShape">
+ <enum>NoFrame</enum>
+ </property>
+ <property name="lineWidth">
+ <number>0</number>
+ </property>
+ <property name="title">
+ <string></string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ </widget>
+ </grid>
+</widget>
+<customwidgets>
+</customwidgets>
+<layoutdefaults spacing="6" margin="0"/>
+<includes>
+ <include location="global" impldecl="in implementation">kcombobox.h</include>
+ <include location="global" impldecl="in implementation">knuminput.h</include>
+</includes>
+</UI>
diff --git a/plugins/alsa-sound/alsa-sound-configuration.cpp b/plugins/alsa-sound/alsa-sound-configuration.cpp
new file mode 100644
index 0000000..9a29e43
--- /dev/null
+++ b/plugins/alsa-sound/alsa-sound-configuration.cpp
@@ -0,0 +1,353 @@
+/***************************************************************************
+ alsa-sound-configuration.cpp - description
+ -------------------
+ begin : Thu Sep 30 2004
+ copyright : (C) 2004 by Martin Witte
+ email : witte@kawo1.rwth-aachen.de
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include <tqcheckbox.h>
+#include <tqgroupbox.h>
+#include <tqlayout.h>
+#include <tqscrollview.h>
+
+#include <kurlrequester.h>
+#include <knuminput.h>
+#include <klineedit.h>
+#include <kcombobox.h>
+#include <ktabwidget.h>
+#include <tdelocale.h>
+
+#include "alsa-mixer-element.h"
+#include "alsa-sound-configuration.h"
+#include "alsa-sound.h"
+
+
+AlsaSoundConfiguration::AlsaSoundConfiguration (TQWidget *parent, AlsaSoundDevice *dev)
+ : AlsaSoundConfigurationUI(parent),
+ m_SoundDevice (dev),
+ m_groupMixerLayout(NULL),
+ m_groupMixerScrollView(NULL),
+ m_groupMixerSubFrame(NULL),
+ m_dirty(true),
+ m_ignore_updates(false)
+{
+ TQObject::connect(m_comboPlaybackCard, TQT_SIGNAL(activated(int)), this, TQT_SLOT(slotSetDirty()));
+ TQObject::connect(m_comboCaptureCard, TQT_SIGNAL(activated(int)), this, TQT_SLOT(slotSetDirty()));
+ TQObject::connect(m_comboPlaybackDevice, TQT_SIGNAL(activated(int)), this, TQT_SLOT(slotSetDirty()));
+ TQObject::connect(m_comboCaptureDevice, TQT_SIGNAL(activated(int)), this, TQT_SLOT(slotSetDirty()));
+ TQObject::connect(editHWBufferSize, TQT_SIGNAL(valueChanged(int)), this, TQT_SLOT(slotSetDirty()));
+ TQObject::connect(editBufferSize, TQT_SIGNAL(valueChanged(int)), this, TQT_SLOT(slotSetDirty()));
+ TQObject::connect(chkDisablePlayback, TQT_SIGNAL(toggled(bool)), this, TQT_SLOT(slotSetDirty()));
+ TQObject::connect(chkDisableCapture, TQT_SIGNAL(toggled(bool)), this, TQT_SLOT(slotSetDirty()));
+
+ TQObject::connect(m_comboPlaybackCard, TQT_SIGNAL(activated(const TQString &)),
+ this, TQT_SLOT(slotPlaybackCardSelected(const TQString &)));
+ TQObject::connect(m_comboCaptureCard, TQT_SIGNAL(activated(const TQString &)),
+ this, TQT_SLOT(slotCaptureCardSelected(const TQString &)));
+
+ m_groupMixer->setColumnLayout(0, Qt::Horizontal );
+
+ TQHBoxLayout *tmp_layout = new TQHBoxLayout( m_groupMixer->layout() );
+
+ m_groupMixerScrollView = new TQScrollView (m_groupMixer);
+ m_groupMixerScrollView->setFrameShape(TQFrame::NoFrame);
+ m_groupMixerScrollView->setFrameShadow(TQFrame::Plain);
+ m_groupMixerScrollView->enableClipper(true);
+ m_groupMixerScrollView->setResizePolicy(TQScrollView::AutoOneFit);
+ //m_groupMixerScrollView->setHScrollBarMode(TQScrollView::AlwaysOn);
+
+ tmp_layout->addWidget(m_groupMixerScrollView);
+
+
+ int card = -1;
+ int ret = 0;
+ int idx_playback = 0;
+ int idx_capture = 0;
+ while ((ret = snd_card_next(&card)) == 0) {
+ char *name = NULL;
+ if (card >= 0 && snd_card_get_longname(card, &name) == 0) {
+ if (name) {
+ m_name2card[name] = card;
+ m_card2name[card] = name;
+ if (listSoundDevices(NULL, NULL, NULL, NULL, card, SND_PCM_STREAM_PLAYBACK)) {
+ m_comboPlaybackCard->insertItem(name);
+ m_playbackCard2idx[card] = idx_playback++;
+ }
+ if (listSoundDevices(NULL, NULL, NULL, NULL, card, SND_PCM_STREAM_CAPTURE)) {
+ m_comboCaptureCard->insertItem(name);
+ m_captureCard2idx[card] = idx_capture++;
+ }
+ }
+ } else {
+ break;
+ }
+ }
+
+ slotCancel();
+}
+
+
+AlsaSoundConfiguration::~AlsaSoundConfiguration ()
+{
+}
+
+
+void AlsaSoundConfiguration::slotPlaybackCardSelected(const TQString &cardname)
+{
+ if (!m_name2card.contains(cardname))
+ return;
+
+ listSoundDevices(m_comboPlaybackDevice, &m_playbackDeviceName2dev, &m_dev2playbackDeviceName, &m_playbackDevice2idx, m_name2card[cardname], SND_PCM_STREAM_PLAYBACK);
+}
+
+
+void AlsaSoundConfiguration::slotCaptureCardSelected(const TQString &cardname)
+{
+ if (!m_name2card.contains(cardname))
+ return;
+
+ saveCaptureMixerSettings();
+
+ listSoundDevices(m_comboCaptureDevice, &m_captureDeviceName2dev, &m_dev2captureDeviceName, &m_captureDevice2idx, m_name2card[cardname], SND_PCM_STREAM_CAPTURE);
+
+ m_currentCaptureCard = m_name2card[cardname];
+
+ TQStringList vol_list, sw_list, all_list;
+ TQMap<TQString, AlsaMixerElement> vol_ch2id, sw_ch2id;
+ AlsaSoundDevice::getCaptureMixerChannels(m_name2card[cardname], NULL, vol_list, vol_ch2id, sw_list, sw_ch2id, &all_list);
+
+ for (TQMapIterator<TQString, QAlsaMixerElement*> it = m_MixerElements.begin(); it != m_MixerElements.end(); ++it) {
+ delete *it;
+ }
+ m_MixerElements.clear();
+
+ if (m_groupMixerSubFrame)
+ delete m_groupMixerSubFrame;
+
+ m_groupMixerSubFrame = new TQFrame(m_groupMixerScrollView->viewport());
+ m_groupMixerSubFrame->setSizePolicy(TQSizePolicy::Maximum, TQSizePolicy::Maximum);
+ m_groupMixerScrollView->addChild(m_groupMixerSubFrame);
+
+ int rows = 1;
+ int cols = (all_list.count()+rows-1)/rows;
+ m_groupMixerLayout = new TQGridLayout( m_groupMixerSubFrame, rows, cols, 0, 0 );
+ m_groupMixerLayout->setAlignment( TQt::AlignBottom );
+
+ int idx = 0;
+ for (TQValueListConstIterator<TQString> it = all_list.begin(); it != all_list.end(); ++it, ++idx) {
+ QAlsaMixerElement *e = new QAlsaMixerElement(m_groupMixerSubFrame, *it,
+ sw_list.contains(*it), vol_list.contains(*it));
+ TQObject::connect(e, TQT_SIGNAL(sigDirty()), this, TQT_SLOT(slotSetDirty()));
+ m_groupMixerLayout->addWidget(e, idx > cols, idx % cols);
+ e->show();
+ m_MixerElements.insert(*it, e);
+ }
+ restoreCaptureMixerSettings();
+ m_groupMixerSubFrame->show();
+}
+
+void AlsaSoundConfiguration::saveCaptureMixerSettings()
+{
+ for (TQMapIterator<TQString, QAlsaMixerElement*> it = m_MixerElements.begin(); it != m_MixerElements.end(); ++it) {
+ const TQString &name = it.key();
+ int card = m_currentCaptureCard;
+ TQString id = AlsaConfigMixerSetting::getIDString(card, name);
+ QAlsaMixerElement *e = *it;
+ float vol = e->getVolume();
+ bool use = e->getOverride();
+ bool active = e->getActive();
+ e->slotResetDirty();
+ m_MixerSettings[id] = AlsaConfigMixerSetting(card,name,use,active,vol);
+ }
+}
+
+void AlsaSoundConfiguration::restoreCaptureMixerSettings()
+{
+ for (TQMapIterator<TQString, QAlsaMixerElement*> it = m_MixerElements.begin(); it != m_MixerElements.end(); ++it) {
+ const TQString &name = it.key();
+ int card = m_currentCaptureCard;
+ TQString id = AlsaConfigMixerSetting::getIDString(card, name);
+ QAlsaMixerElement *e = *it;
+
+ if (m_MixerSettings.contains(id)) {
+ const AlsaConfigMixerSetting &s = m_MixerSettings[id];
+ e->setVolume(s.m_volume);
+ e->setOverride(s.m_use);
+ e->setActive(s.m_active);
+ e->slotResetDirty();
+ } else {
+ if (name == "ADC") {
+ e->setOverride(true);
+ e->setActive(true);
+ e->setVolume(1.0);
+ }
+ else if (name == "Digital") {
+ e->setOverride(true);
+ e->setActive(true);
+ e->setVolume(1.0);
+ }
+ else if (name == "Wave") {
+ e->setOverride(true);
+ e->setActive(false);
+ e->setVolume(0);
+ }
+ else if (name == "Capture") {
+ e->setOverride(true);
+ e->setActive(true);
+ e->setVolume(0.01);
+ }
+ e->slotSetDirty();
+ }
+ }
+}
+
+int AlsaSoundConfiguration::listSoundDevices(KComboBox *combobox, TQMap<TQString, int> *devname2dev, TQMap<int, TQString> *dev2devname, TQMap<int, int> *dev2idx, int card, snd_pcm_stream_t stream)
+{
+ snd_ctl_t *handle = NULL;
+ int dev = -1;
+ snd_ctl_card_info_t *info = NULL;
+ snd_pcm_info_t *pcminfo = NULL;
+
+ snd_ctl_card_info_alloca(&info);
+ snd_pcm_info_alloca (&pcminfo);
+
+ TQString ctlname = "hw:"+TQString::number(card);
+
+ if (combobox)
+ combobox->clear();
+ if (devname2dev)
+ devname2dev->clear();
+ if (dev2devname)
+ dev2devname->clear();
+ if (dev2idx)
+ dev2idx->clear();
+
+ int count = 0;
+
+ if (snd_ctl_open (&handle, ctlname.ascii(), 0) == 0) {
+ if (snd_ctl_card_info(handle, info) == 0) {
+
+ dev = -1;
+ while (1) {
+ if (snd_ctl_pcm_next_device(handle, &dev) < 0) {
+ //logError("snd_ctl_pcm_next_device");
+ }
+ if (dev < 0)
+ break;
+ snd_pcm_info_set_device(pcminfo, dev);
+ snd_pcm_info_set_subdevice(pcminfo, 0);
+ snd_pcm_info_set_stream(pcminfo, stream);
+ int err = 0;
+ if ((err = snd_ctl_pcm_info(handle, pcminfo)) < 0) {
+ if (err != -ENOENT) {
+ //logError(TQString("control digital audio info (%1): %2").arg(card).arg(snd_strerror(err)));
+ }
+ continue;
+ }
+ const char *dev_name = snd_pcm_info_get_name(pcminfo);
+ TQString devname = i18n("context-card-plus-device-number", "%1 device %2").arg(dev_name).arg(dev);
+ if (combobox)
+ combobox->insertItem(devname);
+ if (devname2dev)
+ (*devname2dev)[devname] = dev;
+ if (dev2devname)
+ (*dev2devname)[dev] = devname;
+ if (dev2idx)
+ (*dev2idx)[dev] = count;
+ ++count;
+ }
+ }
+ snd_ctl_close(handle);
+ }
+ return count;
+}
+
+void AlsaSoundConfiguration::slotOK()
+{
+ if (!m_dirty)
+ return;
+
+ if (m_SoundDevice) {
+ m_SoundDevice->setHWBufferSize ( editHWBufferSize ->value() * 1024);
+ m_SoundDevice->setBufferSize ( editBufferSize ->value() * 1024);
+ m_SoundDevice->enablePlayback (!chkDisablePlayback->isChecked());
+ m_SoundDevice->enableCapture (!chkDisableCapture ->isChecked());
+
+ int card = m_name2card[m_comboPlaybackCard->currentText()];
+ int device = m_playbackDeviceName2dev[m_comboPlaybackDevice->currentText()];
+ m_SoundDevice->setPlaybackDevice( card, device);
+ card = m_name2card[m_comboCaptureCard->currentText()];
+ device = m_captureDeviceName2dev[m_comboCaptureDevice->currentText()];
+ m_SoundDevice->setCaptureDevice ( card, device);
+
+ saveCaptureMixerSettings();
+ m_SoundDevice->setCaptureMixerSettings(m_MixerSettings);
+ }
+ m_dirty = false;
+}
+
+
+void AlsaSoundConfiguration::slotCancel()
+{
+ if (!m_dirty)
+ return;
+ m_ignore_updates = true;
+
+ int card = m_SoundDevice ? m_SoundDevice->getPlaybackCard() : 0;
+ int dev = m_SoundDevice ? m_SoundDevice->getPlaybackDevice() : 0;
+ m_comboPlaybackCard ->setCurrentItem(m_playbackCard2idx[card]);
+ slotPlaybackCardSelected(m_comboPlaybackCard->currentText());
+ m_comboPlaybackDevice->setCurrentItem(m_playbackDevice2idx[dev]);
+
+ card = m_SoundDevice ? m_SoundDevice->getCaptureCard() : 0;
+ dev = m_SoundDevice ? m_SoundDevice->getCaptureDevice() : 0;
+ m_comboCaptureCard ->setCurrentItem(m_captureCard2idx[card]);
+ slotCaptureCardSelected(m_comboCaptureCard->currentText());
+ m_comboCaptureDevice->setCurrentItem(m_captureDevice2idx[dev]);
+
+ //IErrorLogClient::staticLogDebug(TQString("capture: card = %1(%2), dev = %3").arg(card).arg(m_captureCard2idx[card]).arg(dev));
+
+ editHWBufferSize ->setValue (m_SoundDevice ? m_SoundDevice->getHWBufferSize()/1024 : 4);
+ editBufferSize ->setValue (m_SoundDevice ? m_SoundDevice->getBufferSize()/1024 : 4);
+ chkDisablePlayback->setChecked(m_SoundDevice ? !m_SoundDevice->isPlaybackEnabled() : false);
+ chkDisableCapture ->setChecked(m_SoundDevice ? !m_SoundDevice->isCaptureEnabled() : false);
+
+ //IErrorLogClient::staticLogDebug(TQString("capture: card = %1").arg(m_comboCaptureCard->currentText()));
+
+
+ if (m_SoundDevice)
+ m_MixerSettings = m_SoundDevice->getCaptureMixerSettings();
+ else
+ m_MixerSettings.clear();
+ restoreCaptureMixerSettings();
+
+ m_ignore_updates = false;
+ m_dirty = false;
+}
+
+
+void AlsaSoundConfiguration::slotUpdateConfig()
+{
+ slotSetDirty();
+ slotCancel();
+}
+
+void AlsaSoundConfiguration::slotSetDirty()
+{
+ if (!m_dirty && !m_ignore_updates) {
+ m_dirty = true;
+ //emit sigDirty();
+ }
+}
+
+#include "alsa-sound-configuration.moc"
diff --git a/plugins/alsa-sound/alsa-sound-configuration.h b/plugins/alsa-sound/alsa-sound-configuration.h
new file mode 100644
index 0000000..a626544
--- /dev/null
+++ b/plugins/alsa-sound/alsa-sound-configuration.h
@@ -0,0 +1,84 @@
+/***************************************************************************
+ alsa-sound-configuration.h - description
+ -------------------
+ begin : Thu Sep 30 2004
+ copyright : (C) 2004 by Martin Witte
+ email : witte@kawo1.rwth-aachen.de
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef KRADIO_ALSA_SOUND_CONFIGURATION_H
+#define KRADIO_ALSA_SOUND_CONFIGURATION_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "alsa-sound-configuration-ui.h"
+#include "alsa-sound.h"
+#include "alsa-config-mixer-setting.h"
+
+class TQHBoxLayout;
+class TQGridLayout;
+class QAlsaMixerElement;
+class TQScrollView;
+class TQFrame;
+
+class AlsaSoundConfiguration : public AlsaSoundConfigurationUI
+{
+Q_OBJECT
+
+public :
+ AlsaSoundConfiguration (TQWidget *parent, AlsaSoundDevice *);
+ ~AlsaSoundConfiguration ();
+
+protected slots:
+
+ void slotOK();
+ void slotCancel();
+
+ void slotSetDirty();
+
+ void slotUpdateConfig();
+
+ void slotPlaybackCardSelected(const TQString &cardname);
+ void slotCaptureCardSelected(const TQString &cardname);
+
+protected:
+ int listSoundDevices(KComboBox *combobox, TQMap<TQString, int> *devname2dev, TQMap<int, TQString> *dev2devname, TQMap<int, int> *dev2idx, int card, snd_pcm_stream_t stream);
+ void saveCaptureMixerSettings();
+ void restoreCaptureMixerSettings();
+
+ AlsaSoundDevice *m_SoundDevice;
+ int m_currentCaptureCard;
+ TQMap<TQString, int> m_name2card,
+ m_name2capturedevice,
+ m_playbackDeviceName2dev,
+ m_captureDeviceName2dev;
+ TQMap<int, TQString> m_card2name,
+ m_dev2playbackDeviceName,
+ m_dev2captureDeviceName;
+ TQMap<int, int> m_captureCard2idx,
+ m_captureDevice2idx,
+ m_playbackCard2idx,
+ m_playbackDevice2idx;
+ TQGridLayout *m_groupMixerLayout;
+ TQScrollView *m_groupMixerScrollView;
+ TQFrame *m_groupMixerSubFrame;
+ TQMap<TQString, QAlsaMixerElement*> m_MixerElements;
+
+ TQMap<TQString, AlsaConfigMixerSetting> m_MixerSettings;
+
+ bool m_dirty;
+ bool m_ignore_updates;
+};
+
+#endif
diff --git a/plugins/alsa-sound/alsa-sound.cpp b/plugins/alsa-sound/alsa-sound.cpp
new file mode 100644
index 0000000..746eacf
--- /dev/null
+++ b/plugins/alsa-sound/alsa-sound.cpp
@@ -0,0 +1,1562 @@
+/***************************************************************************
+ alsa-sound.cpp - description
+ -------------------
+ begin : Thu May 26 2005
+ copyright : (C) 2005 by Martin Witte
+ email : witte@kawo1.rwth-aachen.de
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include <tdelocale.h>
+#include <tdeaboutdata.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <math.h>
+#include <errno.h>
+
+#include <sys/soundcard.h>
+#include <alsa/asoundlib.h>
+
+#include "alsa-sound.h"
+#include "alsa-sound-configuration.h"
+// #include "capture-thread.h"
+#include "../../src/include/aboutwidget.h"
+#include "../../src/include/utils.h"
+
+///////////////////////////////////////////////////////////////////////
+//// plugin library functions
+
+PLUGIN_LIBRARY_FUNCTIONS(AlsaSoundDevice, "tderadio-alsa-sound", i18n("Advanced Linux Sound Architecture (ALSA) Support"));
+
+/////////////////////////////////////////////////////////////////////////////
+
+struct _lrvol { unsigned char l, r; short dummy; };
+
+AlsaSoundDevice::AlsaSoundDevice(const TQString &name)
+ : TQObject(NULL, NULL),
+ PluginBase(name, i18n("TDERadio ALSA Sound Plugin")),
+ m_hPlayback(NULL),
+ m_hCapture(NULL),
+ m_hPlaybackMixer(NULL),
+ m_hCaptureMixer(NULL),
+ m_PlaybackFormat(),
+ m_CaptureFormat(),
+ m_PlaybackCard(-1),
+ m_PlaybackDevice(-1),
+ m_CaptureCard(-1),
+ m_CaptureDevice(-1),
+ m_PlaybackLatency(50),
+ m_CaptureLatency(50),
+ m_PassivePlaybackStreams(),
+ m_PlaybackStreamID(),
+ m_CaptureStreamID(),
+ m_HWBufferSize(2048),
+ m_BufferSize(16384),
+ m_PlaybackBuffer(m_BufferSize),
+ m_CaptureBuffer(m_BufferSize),
+ m_CaptureRequestCounter(0),
+ m_CapturePos(0),
+ m_CaptureStartTime(0),
+// m_PlaybackSkipCount(0),
+ m_CaptureSkipCount(0),
+ m_EnablePlayback(true),
+ m_EnableCapture(true)//,
+// m_captureThread(NULL)
+{
+ TQObject::connect(&m_PlaybackPollingTimer, TQT_SIGNAL(timeout()), this, TQT_SLOT(slotPollPlayback()));
+ TQObject::connect(&m_CapturePollingTimer, TQT_SIGNAL(timeout()), this, TQT_SLOT(slotPollCapture()));
+}
+
+
+AlsaSoundDevice::~AlsaSoundDevice()
+{
+ stopCapture(m_CaptureStreamID);
+ stopPlayback(m_PlaybackStreamID);
+ closePlaybackDevice();
+ closeCaptureDevice();
+ closePlaybackMixerDevice();
+ closeCaptureMixerDevice();
+}
+
+
+bool AlsaSoundDevice::connectI(Interface *i)
+{
+ bool a = PluginBase::connectI(i);
+ bool b = ISoundStreamClient::connectI(i);
+ return a || b;
+}
+
+
+bool AlsaSoundDevice::disconnectI(Interface *i)
+{
+ bool a = PluginBase::disconnectI(i);
+ bool b = ISoundStreamClient::disconnectI(i);
+ return a || b;
+}
+
+void AlsaSoundDevice::noticeConnectedI (ISoundStreamServer *s, bool pointer_valid)
+{
+ ISoundStreamClient::noticeConnectedI(s, pointer_valid);
+ if (s && pointer_valid) {
+ s->register4_sendReleasePlayback(this);
+ s->register4_sendReleaseCapture(this);
+ s->register4_sendPlaybackVolume(this);
+ s->register4_sendMute(this);
+ s->register4_sendUnmute(this);
+ s->register4_sendCaptureVolume(this);
+ s->register4_queryPlaybackVolume(this);
+ s->register4_queryCaptureVolume(this);
+ s->register4_sendStartPlayback(this);
+ s->register4_sendPausePlayback(this);
+ s->register4_sendStopPlayback(this);
+ s->register4_queryIsPlaybackRunning(this);
+ s->register4_sendStartCaptureWithFormat(this);
+ s->register4_sendStopCapture(this);
+ s->register4_queryIsCaptureRunning(this);
+ s->register4_notifySoundStreamClosed(this);
+ s->register4_notifySoundStreamRedirected(this);
+ s->register4_notifySoundStreamData(this);
+ }
+}
+
+// PluginBase
+
+void AlsaSoundDevice::saveState (TDEConfig *c) const
+{
+ c->setGroup(TQString("alsa-sound-") + PluginBase::name());
+
+ c->writeEntry("playback-card", m_PlaybackCard);
+ c->writeEntry("playback-device", m_PlaybackDevice);
+ c->writeEntry("capture-card", m_CaptureCard);
+ c->writeEntry("capture-device", m_CaptureDevice);
+ c->writeEntry("enable-playback", m_EnablePlayback);
+ c->writeEntry("enable-capture", m_EnableCapture);
+ c->writeEntry("hwbuffer-size", m_HWBufferSize);
+ c->writeEntry("buffer-size", m_BufferSize);
+ c->writeEntry("soundstreamclient-id", m_SoundStreamClientID);
+
+ c->writeEntry("mixer-settings", m_CaptureMixerSettings.count());
+ int i = 0;
+ for (TQMapConstIterator<TQString, AlsaConfigMixerSetting> it = m_CaptureMixerSettings.begin(); it != m_CaptureMixerSettings.end(); ++it, ++i) {
+
+ TQString prefix = TQString("mixer-setting-%1-").arg(i);
+ (*it).saveState(c, prefix);
+ }
+
+}
+
+
+void AlsaSoundDevice::restoreState (TDEConfig *c)
+{
+ c->setGroup(TQString("alsa-sound-") + PluginBase::name());
+
+ m_EnablePlayback = c->readBoolEntry("enable-playback", true);
+ m_EnableCapture = c->readBoolEntry("enable-capture", true);
+ m_HWBufferSize = c->readNumEntry ("hwbuffer-size", 2048);
+ m_BufferSize = c->readNumEntry ("buffer-size", 16384);
+ int card = c->readNumEntry ("playback-card", 0);
+ int dev = c->readNumEntry ("playback-device", 0);
+ setPlaybackDevice(card, dev);
+ card = c->readNumEntry ("capture-card", 0);
+ dev = c->readNumEntry ("capture-device", 0);
+ setCaptureDevice(card, dev);
+
+ m_PlaybackBuffer.resize(m_BufferSize);
+ m_CaptureBuffer.resize(m_BufferSize);
+
+ setSoundStreamClientID(c->readEntry("soundstreamclient-id", getSoundStreamClientID()));
+
+ int n = c->readNumEntry("mixer-settings", 0);
+ for (int i = 0; i < n; ++i) {
+ TQString prefix = TQString("mixer-setting-%1-").arg(i);
+ AlsaConfigMixerSetting s(c, prefix);
+ m_CaptureMixerSettings.insert(s.getIDString(), s);
+ }
+
+ emit sigUpdateConfig();
+}
+
+
+ConfigPageInfo AlsaSoundDevice::createConfigurationPage()
+{
+ AlsaSoundConfiguration *conf = new AlsaSoundConfiguration(NULL, this);
+ TQObject::connect(this, TQT_SIGNAL(sigUpdateConfig()), conf, TQT_SLOT(slotUpdateConfig()));
+ return ConfigPageInfo (conf,
+ i18n("ALSA Sound"),
+ i18n("ALSA Sound Device Options"),
+ "tderadio_alsa2");
+}
+
+
+AboutPageInfo AlsaSoundDevice::createAboutPage()
+{
+/* TDEAboutData aboutData("tderadio",
+ NULL,
+ NULL,
+ I18N_NOOP("ALSA Sound Plugin for TDERadio"),
+ TDEAboutData::License_GPL,
+ "(c) 2005 Martin Witte",
+ 0,
+ "http://sourceforge.net/projects/tderadio",
+ 0);
+ aboutData.addAuthor("Martin Witte", "", "witte@kawo1.rwth-aachen.de");
+
+ return AboutPageInfo(
+ new TDERadioAboutWidget(aboutData, TDERadioAboutWidget::AbtTabbed),
+ i18n("ALSA Sound"),
+ i18n("ALSA Sound"),
+ "tderadio_alsa_sound"
+ );
+*/
+ return AboutPageInfo();
+}
+
+
+
+bool AlsaSoundDevice::preparePlayback(SoundStreamID id, const TQString &channel, bool active_mode, bool start_immediately)
+{
+ if (id.isValid()) {
+ m_PlaybackStreams.insert(id, SoundStreamConfig(channel, active_mode));
+ if (start_immediately)
+ startPlayback(id);
+ return true;
+ // FIXME: what to do if stream is already playing?
+ }
+ return false;
+}
+
+bool AlsaSoundDevice::prepareCapture(SoundStreamID id, const TQString &channel)
+{
+ if (id.isValid()) {
+ m_CaptureStreams.insert(id, SoundStreamConfig(channel));
+ return true;
+ // FIXME: what to do if stream is already playing?
+ }
+ return false;
+}
+
+bool AlsaSoundDevice::releasePlayback(SoundStreamID id)
+{
+ if (id.isValid() && m_PlaybackStreams.contains(id)) {
+ if (m_PlaybackStreamID == id || m_PassivePlaybackStreams.contains(id)) {
+ stopPlayback(id);
+ }
+ m_PlaybackStreams.remove(id);
+ return true;
+ }
+ return false;
+}
+
+bool AlsaSoundDevice::releaseCapture(SoundStreamID id)
+{
+ if (id.isValid() && m_CaptureStreams.contains(id)) {
+ if (m_CaptureStreamID == id) {
+ stopCapture(id);
+ }
+ m_CaptureStreams.remove(id);
+ return true;
+ }
+ return false;
+}
+
+bool AlsaSoundDevice::supportsPlayback() const
+{
+ return m_EnablePlayback;
+}
+
+
+bool AlsaSoundDevice::supportsCapture() const
+{
+ return m_EnableCapture;
+}
+
+
+bool AlsaSoundDevice::startPlayback(SoundStreamID id)
+{
+ if (id.isValid() && m_PlaybackStreams.contains(id) && m_EnablePlayback) {
+
+ SoundStreamConfig &cfg = m_PlaybackStreams[id];
+
+ bool ok = false;
+ if (cfg.m_ActiveMode) {
+ if (!m_PlaybackStreamID.isValid()) {
+ m_PlaybackStreamID = id;
+ ok = true;
+ }
+ } else {
+ if (!m_PassivePlaybackStreams.contains(id))
+ m_PassivePlaybackStreams.append(id);
+ ok = true;
+ }
+
+ if (ok) {
+ openPlaybackMixerDevice();
+ if (cfg.m_Volume >= 0 && writePlaybackMixerVolume(cfg.m_Channel, cfg.m_Volume, cfg.m_Muted)) {
+ notifyPlaybackVolumeChanged(id, cfg.m_Volume);
+ notifyMuted(id, cfg.m_Volume);
+ }
+ m_PlaybackPollingTimer.start(m_PlaybackLatency);
+ }
+
+ // error handling?
+ return true;
+ } else {
+ return false;
+ }
+}
+
+
+bool AlsaSoundDevice::pausePlayback(SoundStreamID /*id*/)
+{
+ //return stopPlayback(id);
+ return false;
+}
+
+
+bool AlsaSoundDevice::stopPlayback(SoundStreamID id)
+{
+ if (id.isValid() && m_PlaybackStreams.contains(id)) {
+
+ SoundStreamConfig &cfg = m_PlaybackStreams[id];
+
+ if (!cfg.m_ActiveMode) {
+ if (m_PassivePlaybackStreams.contains(id)) {
+/* float tmp = 0;
+ writePlaybackMixerVolume(cfg.m_Channel, tmp, true);*/
+ m_PassivePlaybackStreams.remove(id);
+ }
+ } else if (m_PlaybackStreamID == id) {
+ m_PlaybackStreamID = SoundStreamID::InvalidID;
+ m_PlaybackBuffer.clear();
+ closePlaybackDevice();
+ }
+
+ closePlaybackMixerDevice();
+ return true;
+ } else {
+ return false;
+ }
+}
+
+bool AlsaSoundDevice::isPlaybackRunning(SoundStreamID id, bool &b) const
+{
+ if (id.isValid() && m_PlaybackStreamID == id || m_PassivePlaybackStreams.contains(id)) {
+ b = true;
+ return true;
+ } else {
+ return false;
+ }
+}
+
+bool AlsaSoundDevice::startCaptureWithFormat(SoundStreamID id,
+ const SoundFormat &proposed_format,
+ SoundFormat &real_format,
+ bool force_format)
+{
+ if (m_CaptureStreams.contains(id) && m_EnableCapture) {
+
+ if (m_CaptureStreamID != id) {
+ m_CapturePos = 0;
+ m_CaptureStartTime = time(NULL);
+ }
+
+ if (m_CaptureStreamID != id || (force_format && proposed_format != m_CaptureFormat)) {
+
+ m_CaptureStreamID = id;
+ SoundStreamConfig &cfg = m_CaptureStreams[id];
+
+ openCaptureMixerDevice();
+ selectCaptureChannel(cfg.m_Channel);
+ if (cfg.m_Volume >= 0 && writeCaptureMixerVolume(cfg.m_Channel, cfg.m_Volume)) {
+ notifyCaptureVolumeChanged(m_CaptureStreamID, cfg.m_Volume);
+ }
+
+ openCaptureDevice(proposed_format);
+
+ // FIXME: error handling?
+ }
+
+ real_format = m_CaptureFormat;
+ m_CaptureRequestCounter++;
+
+// m_captureThread = new AlsaCaptureThread(this, m_hCapture, m_CaptureFormat, 5, m_BufferSize);
+// m_captureThread->start();
+
+ slotPollCapture();
+
+ return true;
+ } else {
+ return false;
+ }
+}
+
+
+bool AlsaSoundDevice::stopCapture(SoundStreamID id)
+{
+ if (id.isValid() && m_CaptureStreamID == id) {
+
+ if (--m_CaptureRequestCounter == 0) {
+
+// m_captureThread->setDone();
+// if (!m_captureThread->wait(4000)) { //wait at maximum 4 seconds
+// logError("AlsaPlugin: capture thread did not terminate. Killing it.");
+// m_captureThread->terminate();
+// m_captureThread->wait();
+// }
+
+ slotPollCapture();
+
+// if (m_captureThread->error()) {
+// logError(i18n("ALSA Plugin, device plughw:%1,%2: %3").arg(m_CaptureCard)
+// .arg(m_CaptureDevice)
+// .arg(i18n("unknown error")));
+// }
+//
+// delete m_captureThread;
+// m_captureThread = NULL;
+
+ m_CaptureStreamID = SoundStreamID::InvalidID;
+ m_CaptureBuffer.clear();
+
+ closeCaptureMixerDevice();
+ closeCaptureDevice();
+ }
+ return true;
+ } else {
+ return false;
+ }
+}
+
+
+bool AlsaSoundDevice::isCaptureRunning(SoundStreamID id, bool &b, SoundFormat &sf) const
+{
+ if (id.isValid() && m_CaptureStreamID == id) {
+ b = true;
+ sf = m_CaptureFormat;
+ return true;
+ } else {
+ return false;
+ }
+}
+
+
+bool AlsaSoundDevice::noticeSoundStreamClosed(SoundStreamID id)
+{
+ bool found = false;
+ if (m_PlaybackStreamID == id || m_PassivePlaybackStreams.contains(id)) {
+ stopPlayback(id);
+ found = true;
+ }
+ if (m_CaptureStreamID == id) {
+ stopCapture(id);
+ found = true;
+ }
+ m_PlaybackStreams.remove(id);
+ m_CaptureStreams.remove(id);
+ return found;
+}
+
+
+bool AlsaSoundDevice::noticeSoundStreamRedirected(SoundStreamID oldID, SoundStreamID newID)
+{
+ bool found = false;
+ if (m_PlaybackStreams.contains(oldID)) {
+ m_PlaybackStreams.insert(newID, m_PlaybackStreams[oldID]);
+ if (newID != oldID)
+ m_PlaybackStreams.remove(oldID);
+ found = true;
+ }
+ if (m_CaptureStreams.contains(oldID)) {
+ m_CaptureStreams.insert(newID, m_CaptureStreams[oldID]);
+ if (newID != oldID)
+ m_CaptureStreams.remove(oldID);
+ found = true;
+ }
+
+ if (m_PlaybackStreamID == oldID)
+ m_PlaybackStreamID = newID;
+ if (m_CaptureStreamID == oldID)
+ m_CaptureStreamID = newID;
+ if (m_PassivePlaybackStreams.contains(oldID)) {
+ m_PassivePlaybackStreams.remove(oldID);
+ m_PassivePlaybackStreams.append(newID);
+ }
+ return found;
+}
+
+
+bool AlsaSoundDevice::noticeSoundStreamData(SoundStreamID id,
+ const SoundFormat &format,
+ const char *data, size_t size, size_t &consumed_size,
+ const SoundMetaData &/*md*/
+ )
+{
+ if (!id.isValid() || id != m_PlaybackStreamID)
+ return false;
+
+ if (!m_hPlayback) {
+ openPlaybackDevice(format);
+ } else if (format != m_PlaybackFormat) {
+ // flush playback buffer
+ size_t buffersize = 0;
+ char *buffer = m_PlaybackBuffer.getData(buffersize);
+
+ snd_pcm_writei(m_hPlayback, buffer, buffersize / m_PlaybackFormat.sampleSize());
+
+ // if not all could be written, it must be discarded
+ m_PlaybackBuffer.clear();
+ closePlaybackDevice();
+ openPlaybackDevice(format);
+ // error handling ?
+ }
+
+ size_t n = m_PlaybackBuffer.addData(data, size);
+ consumed_size = (consumed_size == SIZE_T_DONT_CARE) ? n : min (consumed_size, n);
+/* if (n < size) {
+ m_PlaybackSkipCount += size - n;
+ } else if (m_PlaybackSkipCount > 0) {
+ logWarning(i18n("plughw:%1,%2: Playback buffer overflow. Skipped %3 bytes").arg(m_PlaybackCard).arg(m_PlaybackDevice).arg(TQString::number(m_PlaybackSkipCount)));
+ m_PlaybackSkipCount = 0;
+ }
+ return m_PlaybackSkipCount == 0;*/
+ return true;
+}
+
+
+
+void AlsaSoundDevice::slotPollPlayback()
+{
+ if (m_PlaybackStreamID.isValid()) {
+
+ if (m_PlaybackBuffer.getFillSize() > 0 && m_hPlayback) {
+
+ size_t buffersize = 0;
+ int frameSize = m_CaptureFormat.frameSize();
+ char *buffer = m_PlaybackBuffer.getData(buffersize);
+ int framesWritten = snd_pcm_writei(m_hPlayback, buffer, buffersize / frameSize);
+ int bytesWritten = framesWritten * frameSize;
+
+ if (framesWritten > 0) {
+ m_PlaybackBuffer.removeData(bytesWritten);
+ } else if (framesWritten == 0) {
+ logError(i18n("ALSA Plugin: cannot write data for device plughw:%1,%2").arg(m_PlaybackCard).arg(m_PlaybackDevice));
+ } else if (framesWritten == -EAGAIN) {
+ // do nothing
+ } else {
+ snd_pcm_prepare(m_hPlayback);
+ logWarning(i18n("ALSA Plugin: buffer underrun for device plughw:%1,%2").arg(m_PlaybackCard).arg(m_PlaybackDevice));
+ }
+ }
+
+ if (m_PlaybackBuffer.getFreeSize() > m_PlaybackBuffer.getSize() / 3) {
+ notifyReadyForPlaybackData(m_PlaybackStreamID, m_PlaybackBuffer.getFreeSize());
+ }
+
+ checkMixerVolume(m_PlaybackStreamID);
+ }
+
+ TQValueListConstIterator<SoundStreamID> end = m_PassivePlaybackStreams.end();
+ for (TQValueListConstIterator<SoundStreamID> it = m_PassivePlaybackStreams.begin(); it != end; ++it)
+ checkMixerVolume(*it);
+}
+
+
+void AlsaSoundDevice::slotPollCapture()
+{
+ if (m_CaptureStreamID.isValid() && m_hCapture) {
+
+// while (m_captureThread && m_captureThread->getAvailableReadBuffers()) {
+// TQString dev = TQString("alsa://plughw:%1,%2").arg(m_CaptureCard).arg(m_CaptureDevice);
+// size_t size = 0;
+// char *buffer = m_captureThread->getReadBuffer(size);
+// time_t cur_time = time(NULL);
+// notifySoundStreamData(m_CaptureStreamID, m_CaptureFormat, buffer, size, SoundMetaData(m_CapturePos, cur_time - m_CaptureStartTime, cur_time, dev));
+// m_CapturePos += size;
+// }
+
+ size_t bufferSize = 0;
+ char *buffer = m_CaptureBuffer.getFreeSpace(bufferSize);
+
+ if (bufferSize) {
+
+ size_t frameSize = m_CaptureFormat.frameSize();
+ int framesRead = snd_pcm_readi(m_hCapture, buffer, bufferSize / frameSize);
+ size_t bytesRead = framesRead > 0 ? framesRead * frameSize : 0;
+
+// //BEGIN DEBUG
+// static unsigned int debug_val = 0;
+// short *debug_buf = (short*)buffer;
+// for (int i = 0; i < bytesRead / 2 / sizeof(short); ++i) {
+// debug_buf[2*i] = debug_val >> 10;
+// debug_buf[2*i+1] = debug_val >> 10;
+// ++debug_val;
+// }
+// //END DEBUG
+
+ if (framesRead > 0) {
+ m_CaptureBuffer.removeFreeSpace(bytesRead);
+ } else if (framesRead == 0) {
+ snd_pcm_prepare(m_hCapture);
+ logError(i18n("ALSA Plugin: cannot read data from device plughw:%1,%2").arg(m_CaptureCard).arg(m_CaptureDevice));
+ } else if (framesRead == -EAGAIN) {
+ // do nothing
+ } else {
+ snd_pcm_prepare(m_hCapture);
+ logWarning(i18n("ALSA Plugin: buffer overrun for device plughw:%1,%2 (buffersize=%3, buffer=%4)").arg(m_CaptureCard).arg(m_CaptureDevice).arg(bufferSize).arg((long long unsigned)buffer));
+ }
+
+ TQString dev = TQString("alsa://plughw:%1,%2").arg(m_CaptureCard).arg(m_CaptureDevice);
+ while (m_CaptureBuffer.getFillSize() > m_CaptureBuffer.getSize() / 3) {
+ size_t size = 0;
+ buffer = m_CaptureBuffer.getData(size);
+ time_t cur_time = time(NULL);
+ size_t consumed_size = SIZE_T_DONT_CARE;
+
+ notifySoundStreamData(m_CaptureStreamID, m_CaptureFormat, buffer, size, consumed_size, SoundMetaData(m_CapturePos, cur_time - m_CaptureStartTime, cur_time, i18n("internal stream, not stored (%1)").arg(dev)));
+
+ if (consumed_size == SIZE_T_DONT_CARE)
+ consumed_size = size;
+ m_CaptureBuffer.removeData(consumed_size);
+ m_CapturePos += consumed_size;
+ if (consumed_size < size)
+ break;
+ }
+ }
+ }
+ if (m_CaptureStreamID.isValid())
+ checkMixerVolume(m_CaptureStreamID);
+}
+
+
+bool AlsaSoundDevice::openPlaybackDevice(const SoundFormat &format, bool reopen)
+{
+ if (m_PlaybackCard < 0 || m_PlaybackDevice < 0)
+ return false;
+
+ if (m_hPlayback) {
+
+ if (reopen) {
+
+ closePlaybackDevice ( /* force = */ true);
+
+ } else {
+
+ if (format != m_PlaybackFormat)
+ return false;
+
+ return true;
+ }
+ } else {
+ if (reopen) // FIXME: emw: please check if this makes sense !?!?
+ return true;
+ }
+
+ m_PlaybackFormat = format;
+
+ TQString dev = TQString("plughw:%1,%2").arg(m_PlaybackCard).arg(m_PlaybackDevice);
+ bool error = !openAlsaDevice(m_hPlayback, m_PlaybackFormat, dev.ascii(), SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK, m_PlaybackLatency);
+
+ if (!error) {
+ m_PlaybackPollingTimer.start(m_PlaybackLatency);
+ } else {
+ closePlaybackDevice();
+ }
+
+// m_PlaybackSkipCount = 0;
+
+ return !error;
+}
+
+
+bool AlsaSoundDevice::openCaptureDevice(const SoundFormat &format, bool reopen)
+{
+ if (m_PlaybackCard < 0 || m_PlaybackDevice < 0)
+ return false;
+
+ if (m_hCapture) {
+
+ if (reopen) {
+
+ closeCaptureDevice ( /* force = */ true);
+
+ } else {
+
+ if (format != m_CaptureFormat)
+ return false;
+
+ return true;
+ }
+ } else {
+ if (reopen) // FIXME: emw: please check if this makes sense !?!?
+ return true;
+ }
+
+ m_CaptureFormat = format;
+
+ TQString dev = TQString("plughw:%1,%2").arg(m_CaptureCard).arg(m_CaptureDevice);
+// bool error = !openAlsaDevice(m_hCapture, m_CaptureFormat, dev.ascii(), SND_PCM_STREAM_CAPTURE, /*flags = block*/0, m_CaptureLatency);
+ bool error = !openAlsaDevice(m_hCapture, m_CaptureFormat, dev.ascii(), SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK, m_CaptureLatency);
+
+ if (!error) {
+ m_CapturePollingTimer.start(m_CaptureLatency);
+ } else {
+ closeCaptureDevice();
+ }
+
+ m_CaptureSkipCount = 0;
+
+ return !error;
+}
+
+
+bool AlsaSoundDevice::openAlsaDevice(snd_pcm_t *&alsa_handle, SoundFormat &format, const char *pcm_name, snd_pcm_stream_t stream, int flags, unsigned &latency)
+{
+ bool error = false;
+ int dir = 0;
+
+ snd_pcm_hw_params_t *hwparams = NULL;
+
+ snd_pcm_hw_params_alloca(&hwparams);
+
+
+ /* OPEN */
+
+ if (!error && snd_pcm_open(&alsa_handle, pcm_name, stream, flags) < 0) {
+ logError(i18n("ALSA Plugin: Error opening PCM device %1").arg(pcm_name));
+ error = true;
+ }
+
+ if (!error && snd_pcm_hw_params_any(alsa_handle, hwparams) < 0) {
+ logError(i18n("ALSA Plugin: Can not configure PCM device %1").arg(pcm_name));
+ error = true;
+ }
+
+ /* interleaved access type */
+
+ if (!error && snd_pcm_hw_params_set_access(alsa_handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED) < 0) {
+ logError(i18n("ALSA Plugin: Error setting access for %1").arg(pcm_name));
+ error = true;
+ }
+
+ /* sample format */
+ snd_pcm_format_t sample_format = snd_pcm_build_linear_format(format.m_SampleBits,
+ format.m_SampleBits,
+ !format.m_IsSigned,
+ format.m_Endianess == BIG_ENDIAN);
+ if (!error && snd_pcm_hw_params_set_format(alsa_handle, hwparams, sample_format) < 0) {
+ logError(i18n("ALSA Plugin: Error setting sample format for %1").arg(pcm_name));
+ error = true;
+ }
+
+ /* channels */
+ if (!error && snd_pcm_hw_params_set_channels(alsa_handle, hwparams, format.m_Channels) < 0) {
+ logError(i18n("ALSA Plugin: Error setting channels for %1").arg(pcm_name));
+ error = true;
+ }
+
+ /* sample rate */
+ int rate = format.m_SampleRate;
+ if (!error && snd_pcm_hw_params_set_rate_near(alsa_handle, hwparams, &format.m_SampleRate, &dir) < 0) {
+ logError(i18n("ALSA Plugin: Error setting rate for %1").arg(pcm_name));
+ error = true;
+ }
+ if (!error && format.m_SampleRate != format.m_SampleRate) {
+ logWarning(i18n("ALSA Plugin: The rate %1 Hz is not supported by your hardware %2. Using %3 Hz instead").arg(rate).arg(pcm_name).arg(format.m_SampleRate));
+ }
+
+
+ snd_pcm_uframes_t period_size = m_HWBufferSize / format.frameSize();
+ if (!error && snd_pcm_hw_params_set_period_size_near(alsa_handle, hwparams, &period_size, &dir) < 0) {
+ logError(i18n("ALSA Plugin: Error setting period size for %1").arg(pcm_name));
+ error = true;
+ }
+
+// size_t buffersize_frames = m_HWBufferSize / format.frameSize();
+// int periods = 4;
+// //int period_size = m_BufferSize / periods;
+//
+// /* fragments */
+// if (!error && snd_pcm_hw_params_set_periods(alsa_handle, hwparams, periods, 0) < 0) {
+// logError(i18n("ALSA Plugin: Error setting periods for %1").arg(pcm_name));
+// error = true;
+// }
+
+// /* Set buffer size (in frames). */
+//
+// snd_pcm_uframes_t exact_buffersize_frames = buffersize_frames;
+// if (!error && snd_pcm_hw_params_set_buffer_size_near(alsa_handle, hwparams, &exact_buffersize_frames) < 0) {
+// exact_buffersize_frames = 4096;
+// if (!error && snd_pcm_hw_params_set_buffer_size_near(alsa_handle, hwparams, &exact_buffersize_frames) < 0) {
+// logError(i18n("ALSA Plugin: Error setting buffersize for %1").arg(pcm_name));
+// error = true;
+// }
+// }
+
+// size_t exact_buffersize = exact_buffersize_frames * format.frameSize();
+// if (!error && m_HWBufferSize != exact_buffersize) {
+// logWarning(i18n("ALSA Plugin: Hardware %1 does not support buffer size of %2. Using buffer size of %3 instead.").arg(pcm_name).arg(m_HWBufferSize).arg(exact_buffersize));
+// size_t tmp = (((m_HWBufferSize - 1) / exact_buffersize) + 1) * exact_buffersize;
+// setHWBufferSize(tmp);
+// logInfo(i18n("ALSA Plugin: adjusted buffer size for %1 to %2 bytes").arg(pcm_name).arg(TQString::number(tmp)));
+// }
+
+ /* set all params */
+
+ if (!error && snd_pcm_hw_params(alsa_handle, hwparams) < 0) {
+ logError(i18n("ALSA Plugin: Error setting HW params"));
+ error = true;
+ }
+
+ if (!error && snd_pcm_hw_params_get_period_size(hwparams, &period_size, &dir) < 0) {
+ logError(i18n("ALSA Plugin: Error getting period size for %1").arg(pcm_name));
+ error = true;
+ }
+
+// latency = (exact_buffersize_frames * 1000) / format.m_SampleRate / periods; /* in milli seconds */
+ latency = (period_size * format.frameSize() * 1000) / format.m_SampleRate; /* in milli seconds */
+
+ if (!error) {
+ snd_pcm_prepare(alsa_handle);
+ }
+
+ return !error;
+}
+
+
+bool AlsaSoundDevice::closePlaybackDevice(bool force)
+{
+ if (!m_PlaybackStreamID.isValid() || force) {
+
+ if (!m_hPlaybackMixer)
+ m_PlaybackPollingTimer.stop();
+
+ if (m_hPlayback) {
+ snd_pcm_drop(m_hPlayback);
+ snd_pcm_close(m_hPlayback);
+ }
+
+ m_hPlayback = NULL;
+
+ m_PlaybackBuffer.clear();
+ return true;
+ }
+ return false;
+}
+
+
+bool AlsaSoundDevice::closeCaptureDevice(bool force)
+{
+ if (!m_CaptureStreamID.isValid() || force) {
+
+ if (!m_hCaptureMixer)
+ m_CapturePollingTimer.stop();
+
+ if (m_hCapture) {
+ snd_pcm_drop(m_hCapture);
+ snd_pcm_close(m_hCapture);
+ }
+
+ m_hCapture = NULL;
+
+ m_CaptureBuffer.clear();
+ return true;
+ }
+ return false;
+}
+
+
+bool AlsaSoundDevice::openPlaybackMixerDevice(bool reopen)
+{
+ return openMixerDevice(m_hPlaybackMixer, m_PlaybackCard, reopen, &m_PlaybackPollingTimer, m_PlaybackLatency);
+}
+
+
+bool AlsaSoundDevice::openCaptureMixerDevice(bool reopen)
+{
+// logDebug("AlsaSoundDevice::openCaptureMixerDevice: card == " + TQString::number(m_CaptureCard));
+ return openMixerDevice(m_hCaptureMixer, m_CaptureCard, reopen, &m_CapturePollingTimer, m_CaptureLatency);
+}
+
+
+bool AlsaSoundDevice::closePlaybackMixerDevice(bool force)
+{
+ return closeMixerDevice(m_hPlaybackMixer, m_PlaybackCard, m_PlaybackStreamID, m_hPlayback, force, &m_PlaybackPollingTimer);
+}
+
+bool AlsaSoundDevice::closeCaptureMixerDevice(bool force)
+{
+ return closeMixerDevice(m_hCaptureMixer, m_CaptureCard, m_CaptureStreamID, m_hCapture, force, &m_CapturePollingTimer);
+}
+
+
+static int mixer_dummy_callback(snd_mixer_t *, unsigned int /*mask*/, snd_mixer_elem_t */*elem*/)
+{
+ return 0;
+}
+
+bool AlsaSoundDevice::openMixerDevice(snd_mixer_t *&mixer_handle, int card, bool reopen, TQTimer *timer, int timer_latency)
+{
+ if (reopen) {
+ if (mixer_handle != NULL)
+ closeMixerDevice(mixer_handle, card, SoundStreamID::InvalidID, NULL, /* force = */ true, timer);
+ else
+ return true;
+ }
+
+ if (!mixer_handle) {
+ bool error = false;
+ if (snd_mixer_open (&mixer_handle, 0) < 0) {
+ staticLogError(i18n("ALSA Plugin: Error opening mixer"));
+ error = true;
+ }
+ TQString cardid = "hw:" + TQString::number(card);
+ bool attached = false;
+ if (!error) {
+ if (snd_mixer_attach (mixer_handle, cardid.ascii()) < 0) {
+ staticLogError(i18n("ALSA Plugin: ERROR: snd_mixer_attach for card %1").arg(card));
+ error = true;
+ } else {
+ attached = true;
+ }
+ }
+ if (!error && snd_mixer_selem_register(mixer_handle, NULL, NULL) < 0) {
+ staticLogError(i18n("ALSA Plugin: Error: snd_mixer_selem_register for card %1").arg(card));
+ error = true;
+ }
+ if (!error && snd_mixer_load (mixer_handle) < 0) {
+ staticLogError(i18n("ALSA Plugin: Error: snd_mixer_load for card %1").arg(card));
+ error = true;
+ }
+ if (mixer_handle) {
+ snd_mixer_set_callback (mixer_handle, mixer_dummy_callback);
+ }
+
+ if (error) {
+ if (attached) {
+ snd_mixer_detach(mixer_handle, cardid.ascii());
+ }
+ snd_mixer_close(mixer_handle);
+ mixer_handle = NULL;
+ }
+ }
+
+ if (mixer_handle && timer) {
+ timer->start(timer_latency);
+ }
+ return mixer_handle != NULL;
+}
+
+
+bool AlsaSoundDevice::closeMixerDevice(snd_mixer_t *&mixer_handle, int card, SoundStreamID id, snd_pcm_t *pcm_handle, bool force, TQTimer *timer)
+{
+ if (!id.isValid() || force) {
+
+ if (!pcm_handle && timer)
+ timer->stop();
+
+ if (mixer_handle) {
+ TQString cardid = "hw:" + TQString::number(card);
+ snd_mixer_free(mixer_handle);
+ snd_mixer_detach(mixer_handle, cardid.ascii());
+ snd_mixer_close (mixer_handle);
+ }
+ mixer_handle = NULL;
+ }
+ return mixer_handle == NULL;
+}
+
+void AlsaSoundDevice::getPlaybackMixerChannels(
+ int card,
+ snd_mixer_t *__mixer_handle,
+ TQStringList &retval, TQMap<TQString, AlsaMixerElement> &ch2id)
+{
+ retval.clear();
+ ch2id.clear();
+
+ snd_mixer_t *mixer_handle = __mixer_handle/*m_hPlaybackMixer*/;
+ bool use_tmp_handle = false;
+
+ if (!mixer_handle) {
+ openMixerDevice(mixer_handle, card/*m_PlaybackCard*/, false, NULL, 0);
+ use_tmp_handle = true;
+ }
+
+ if (mixer_handle) {
+ snd_mixer_elem_t *elem = NULL;
+
+ for (elem = snd_mixer_first_elem(mixer_handle); elem; elem = snd_mixer_elem_next(elem)) {
+ AlsaMixerElement sid;
+ if (!snd_mixer_selem_is_active(elem))
+ continue;
+ snd_mixer_selem_get_id(elem, sid);
+ TQString name = snd_mixer_selem_id_get_name(sid);
+ int idx = snd_mixer_selem_id_get_index(sid);
+ if (idx)
+ name = i18n("context-mixername-number", "%1 %2").arg(name).arg(idx);
+ if (snd_mixer_selem_has_playback_volume(elem)) {
+ ch2id[name] = sid;
+ retval.append(name);
+ }
+ }
+ }
+
+ if (use_tmp_handle && mixer_handle) {
+ closeMixerDevice(mixer_handle, card /*m_PlaybackCard*/, SoundStreamID::InvalidID, NULL, true, NULL);
+ }
+}
+
+void AlsaSoundDevice::getCaptureMixerChannels(
+ int card,
+ snd_mixer_t *__mixer_handle,
+ TQStringList &vol_list, TQMap<TQString, AlsaMixerElement> &vol_ch2id,
+ TQStringList &sw_list, TQMap<TQString, AlsaMixerElement> &sw_ch2id,
+ TQStringList *all_list
+)
+{
+ vol_list.clear();
+ sw_list.clear();
+ if (all_list) all_list->clear();
+ vol_ch2id.clear();
+ sw_ch2id.clear();
+
+ snd_mixer_t *mixer_handle = __mixer_handle /*m_hCaptureMixer*/;
+ bool use_tmp_handle = false;
+
+ if (!mixer_handle) {
+// staticLogDebug("AlsaSoundDevice::getCaptureMixerChannels: card == " + TQString::number(card/*m_CaptureCard*/));
+ openMixerDevice(mixer_handle, card /*m_CaptureCard*/, false, NULL, 0);
+ use_tmp_handle = true;
+ }
+
+ if (mixer_handle) {
+ snd_mixer_elem_t *elem = NULL;
+
+ for (elem = snd_mixer_first_elem(mixer_handle); elem; elem = snd_mixer_elem_next(elem)) {
+ AlsaMixerElement sid;
+ if (!snd_mixer_selem_is_active(elem))
+ continue;
+ snd_mixer_selem_get_id(elem, sid);
+ TQString name = snd_mixer_selem_id_get_name(sid);
+ int idx = snd_mixer_selem_id_get_index(sid);
+ if (idx)
+ name = i18n("context-mixerelement-name-number", "%1 %2").arg(name).arg(idx);
+
+ bool add2all = false;
+ if (snd_mixer_selem_has_capture_switch(elem)) {
+ sw_ch2id[name] = sid;
+ sw_list.append(name);
+ add2all = true;
+ }
+ if (snd_mixer_selem_has_capture_volume(elem)) {
+ vol_ch2id[name] = sid;
+ vol_list.append(name);
+ add2all = true;
+ }
+ if (add2all && all_list) {
+ all_list->append(name);
+ }
+ }
+ }
+
+ if (use_tmp_handle && mixer_handle) {
+ closeMixerDevice(mixer_handle, card /*m_CaptureCard*/, SoundStreamID::InvalidID, NULL, true, NULL);
+ }
+}
+
+const TQStringList &AlsaSoundDevice::getPlaybackChannels() const
+{
+ return m_PlaybackChannels;
+}
+
+
+const TQStringList &AlsaSoundDevice::getCaptureChannels() const
+{
+ return m_CaptureChannelsSwitch;
+}
+
+
+bool AlsaSoundDevice::setPlaybackVolume(SoundStreamID id, float volume)
+{
+ if (id.isValid() && (m_PlaybackStreamID == id || m_PassivePlaybackStreams.contains(id))) {
+ SoundStreamConfig &cfg = m_PlaybackStreams[id];
+
+ if (rint(100*volume) != rint(100*cfg.m_Volume)) {
+ if (writePlaybackMixerVolume(cfg.m_Channel, cfg.m_Volume = volume, cfg.m_Muted)) {
+ notifyPlaybackVolumeChanged(id, cfg.m_Volume);
+ }
+ }
+ return true;
+ }
+ return false;
+}
+
+
+bool AlsaSoundDevice::setCaptureVolume(SoundStreamID id, float volume)
+{
+ if (id.isValid() && m_CaptureStreamID == id) {
+ SoundStreamConfig &cfg = m_CaptureStreams[id];
+
+ if (rint(100*volume) != rint(100*cfg.m_Volume)) {
+ if (writeCaptureMixerVolume(cfg.m_Channel, cfg.m_Volume = volume)) {
+ notifyCaptureVolumeChanged(id, cfg.m_Volume);
+ }
+ }
+ return true;
+ }
+ return false;
+}
+
+
+bool AlsaSoundDevice::getPlaybackVolume(SoundStreamID id, float &volume) const
+{
+ if (id.isValid() && (m_PlaybackStreamID == id || m_PassivePlaybackStreams.contains(id))) {
+ const SoundStreamConfig &cfg = m_PlaybackStreams[id];
+ volume = cfg.m_Volume;
+ return true;
+ }
+ return false;
+}
+
+
+bool AlsaSoundDevice::getCaptureVolume(SoundStreamID id, float &volume) const
+{
+ if (id.isValid() && m_CaptureStreamID == id) {
+ const SoundStreamConfig &cfg = m_CaptureStreams[id];
+ volume = cfg.m_Volume;
+ return true;
+ }
+ return false;
+}
+
+
+void AlsaSoundDevice::checkMixerVolume(SoundStreamID id)
+{
+ if (id.isValid()) {
+
+ if (m_hPlaybackMixer && m_PassivePlaybackStreams.contains(id) || m_PlaybackStreamID == id) {
+ snd_mixer_handle_events(m_hPlaybackMixer);
+ SoundStreamConfig &cfg = m_PlaybackStreams[id];
+
+ bool m = false;
+ float v = readPlaybackMixerVolume(cfg.m_Channel, m);
+ if (rint(100*cfg.m_Volume) != rint(100*v)) {
+ cfg.m_Volume = v;
+ notifyPlaybackVolumeChanged(id, v);
+ }
+ if (m != cfg.m_Muted) {
+ cfg.m_Muted = m;
+ notifyMuted(id, m);
+ }
+ }
+
+ if (m_hCaptureMixer && m_CaptureStreamID == id) {
+ snd_mixer_handle_events(m_hCaptureMixer);
+ SoundStreamConfig &cfg = m_CaptureStreams[id];
+
+ if (m_CaptureChannels2ID.contains(cfg.m_Channel)) {
+ float v = readCaptureMixerVolume(cfg.m_Channel);
+ if (rint(100*cfg.m_Volume) != rint(100*v)) {
+ cfg.m_Volume = v;
+ notifyCaptureVolumeChanged(id, v);
+ }
+ }
+ }
+ }
+}
+
+
+float AlsaSoundDevice::readPlaybackMixerVolume(const TQString &channel, bool &muted) const
+{
+ if (!m_hPlaybackMixer)
+ return 0; // without error
+
+ if (m_PlaybackChannels2ID.contains(channel) && m_hPlaybackMixer) {
+ AlsaMixerElement sid = m_PlaybackChannels2ID[channel];
+ snd_mixer_elem_t *elem = snd_mixer_find_selem(m_hPlaybackMixer, sid);
+ if (elem) {
+ long min = 0;
+ long max = 0;
+ snd_mixer_selem_get_playback_volume_range(elem, &min, &max);
+ if (min != max) {
+ long val = min;
+
+ muted = false;
+ int m = false;
+ if (snd_mixer_selem_get_playback_switch(elem, SND_MIXER_SCHN_FRONT_LEFT, &m) == 0) {
+ muted = !m;
+ }
+ if (snd_mixer_selem_get_playback_volume(elem, SND_MIXER_SCHN_FRONT_LEFT, &val) == 0) {
+ return ((float)(val - min)) / (float)(max - min);
+ }
+ }
+ }
+ }
+ logError("AlsaSound::readPlaybackMixerVolume: " +
+ i18n("error while reading volume from hwplug:%1,%2")
+ .arg(m_PlaybackCard)
+ .arg(m_PlaybackDevice));
+ return 0;
+}
+
+
+float AlsaSoundDevice::readCaptureMixerVolume(const TQString &channel) const
+{
+ if (!m_hCaptureMixer)
+ return 0; // without error
+
+ if (m_CaptureChannels2ID.contains(channel) && m_hCaptureMixer) {
+ AlsaMixerElement sid = m_CaptureChannels2ID[channel];
+ snd_mixer_elem_t *elem = snd_mixer_find_selem(m_hCaptureMixer, sid);
+ if (elem) {
+ if (!snd_mixer_selem_has_capture_volume(elem))
+ return 0;
+ long min = 0;
+ long max = 0;
+ snd_mixer_selem_get_capture_volume_range(elem, &min, &max);
+ if (min != max) {
+ long val = min;
+ if (snd_mixer_selem_get_capture_volume(elem, SND_MIXER_SCHN_FRONT_LEFT, &val) == 0) {
+ return ((float)(val - min)) / (float)(max - min);
+ }
+ }
+ }
+ }
+ logError("AlsaSound::readCaptureMixerVolume: " +
+ i18n("error while reading volume from hwplug:%1,%2")
+ .arg(m_CaptureCard)
+ .arg(m_CaptureDevice));
+ return 0;
+}
+
+
+bool AlsaSoundDevice::writePlaybackMixerVolume (const TQString &channel, float &vol, bool muted)
+{
+ if (vol > 1.0) vol = 1.0;
+ if (vol < 0) vol = 0.0;
+
+ if (!m_hPlaybackMixer)
+ return false;
+
+ if (m_PlaybackChannels2ID.contains(channel) && m_hPlaybackMixer) {
+ AlsaMixerElement sid = m_PlaybackChannels2ID[channel];
+ snd_mixer_elem_t *elem = snd_mixer_find_selem(m_hPlaybackMixer, sid);
+ if (elem) {
+ long min = 0;
+ long max = 0;
+ snd_mixer_selem_get_playback_volume_range(elem, &min, &max);
+ if (min != max) {
+ long val = (int)rint(min + (max - min) * vol);
+ vol = (float)(val - min) / (float)(max - min);
+ snd_mixer_selem_set_playback_switch_all(elem, !muted);
+ if (snd_mixer_selem_set_playback_volume_all(elem, val) == 0) {
+ return true;
+ }
+ }
+ }
+ }
+ logError("AlsaSound::writePlaybackMixerVolume: " +
+ i18n("error while writing volume %1 to hwplug:%2,%3")
+ .arg(vol)
+ .arg(m_PlaybackCard)
+ .arg(m_PlaybackDevice));
+ return false;
+}
+
+
+
+
+bool AlsaSoundDevice::writeCaptureMixerVolume (const TQString &channel, float &vol)
+{
+ if (vol > 1.0) vol = 1.0;
+ if (vol < 0) vol = 0.0;
+
+ if (!m_hCaptureMixer)
+ return false;
+
+ if (m_CaptureChannels2ID.contains(channel) && m_hCaptureMixer) {
+ AlsaMixerElement sid = m_CaptureChannels2ID[channel];
+ snd_mixer_elem_t *elem = snd_mixer_find_selem(m_hCaptureMixer, sid);
+ if (elem) {
+ long min = 0;
+ long max = 0;
+ snd_mixer_selem_get_capture_volume_range(elem, &min, &max);
+ if (min != max) {
+ long val = (int)rint(min + (max - min) * vol);
+ vol = (float)(val - min) / (float)(max - min);
+ if (snd_mixer_selem_set_capture_volume_all(elem, val) == 0) {
+ return true;
+ }
+ }
+ }
+ }
+ logError("AlsaSound::writeCaptureMixerVolume: " +
+ i18n("error while writing volume %1 to hwplug:%2,%3")
+ .arg(vol)
+ .arg(m_CaptureCard)
+ .arg(m_CaptureDevice));
+ return false;
+}
+
+
+bool AlsaSoundDevice::writeCaptureMixerSwitch (const TQString &channel, bool capture)
+{
+ if (!m_hCaptureMixer)
+ return false;
+
+ if (m_CaptureChannelsSwitch2ID.contains(channel) && m_hCaptureMixer) {
+ AlsaMixerElement sid = m_CaptureChannelsSwitch2ID[channel];
+ snd_mixer_elem_t *elem = snd_mixer_find_selem(m_hCaptureMixer, sid);
+ if (elem) {
+ if (snd_mixer_selem_set_capture_switch_all(elem, capture) == 0) {
+ return true;
+ }
+ }
+ }
+ logError("AlsaSound::writeCaptureMixerSwitch: " +
+ i18n("error while setting capture switch %1 for hwplug:%2,%3")
+ .arg(channel)
+ .arg(m_CaptureCard)
+ .arg(m_CaptureDevice));
+ return false;
+}
+
+
+void AlsaSoundDevice::selectCaptureChannel (const TQString &channel)
+{
+ writeCaptureMixerSwitch(channel, true);
+
+ const TQString ADC = "ADC";
+ if (m_CaptureChannels2ID.contains(ADC)) {
+ float v = readCaptureMixerVolume(ADC);
+ if (rint(v*100) == 0) {
+ float tmp_vol = 1.0;
+ writeCaptureMixerVolume(ADC, tmp_vol);
+ }
+ }
+ const TQString Digital = "Digital";
+ if (m_CaptureChannels2ID.contains(Digital)) {
+ float v = readCaptureMixerVolume(Digital);
+ if (rint(v*100) == 0) {
+ float tmp_vol = 1.0;
+ writeCaptureMixerVolume(Digital, tmp_vol);
+ }
+ }
+ const TQString WAVE = "Wave";
+ if (m_CaptureChannels2ID.contains(WAVE)) {
+ float x = 0;
+ writeCaptureMixerVolume(WAVE, x);
+ }
+ const TQString Capture = "Capture";
+ if (m_CaptureChannelsSwitch2ID.contains(Capture)) {
+ writeCaptureMixerSwitch(Capture, true);
+ }
+
+ for (TQMapConstIterator<TQString, AlsaConfigMixerSetting> it = m_CaptureMixerSettings.begin(); it != m_CaptureMixerSettings.end(); ++it) {
+ const AlsaConfigMixerSetting &s = *it;
+ if (s.m_card == m_CaptureCard && s.m_use) {
+ float vol = s.m_volume;
+ if (m_CaptureChannels2ID.contains(s.m_name))
+ writeCaptureMixerVolume(s.m_name, vol);
+ if (m_CaptureChannelsSwitch2ID.contains(s.m_name))
+ writeCaptureMixerSwitch(s.m_name, s.m_active);
+ }
+ }
+}
+
+
+void AlsaSoundDevice::setHWBufferSize(int s)
+{
+ m_HWBufferSize = s;
+}
+
+
+void AlsaSoundDevice::setBufferSize(int s)
+{
+ m_BufferSize = s;
+ m_PlaybackBuffer.resize(m_BufferSize);
+ m_CaptureBuffer.resize(m_BufferSize);
+}
+
+
+void AlsaSoundDevice::enablePlayback(bool on)
+{
+ m_EnablePlayback = on;
+}
+
+
+void AlsaSoundDevice::enableCapture(bool on)
+{
+ m_EnableCapture = on;
+}
+
+
+void AlsaSoundDevice::setPlaybackDevice(int card, int dev)
+{
+ if (m_PlaybackCard == card && m_PlaybackDevice == dev)
+ return;
+
+ m_PlaybackCard = card;
+ m_PlaybackDevice = dev;
+ SoundFormat f = m_PlaybackFormat;
+ if (m_hPlayback)
+ openPlaybackDevice(f, /* reopen = */ true);
+ if (m_hPlaybackMixer)
+ openPlaybackMixerDevice(/* reopen = */ true);
+
+ getPlaybackMixerChannels(m_PlaybackCard,
+ m_hPlaybackMixer,
+ m_PlaybackChannels, m_PlaybackChannels2ID);
+ notifyPlaybackChannelsChanged(m_SoundStreamClientID, m_PlaybackChannels);
+}
+
+
+void AlsaSoundDevice::setCaptureDevice(int card, int dev)
+{
+// logDebug("AlsaSoundDevice::setCaptureDevice-1: m_CaptureCard == " + TQString::number(m_CaptureCard) + ", card == " + TQString::number(card));
+ if (m_CaptureCard == card && m_CaptureDevice == dev)
+ return;
+// logDebug("AlsaSoundDevice::setCaptureDevice-2: m_CaptureCard == " + TQString::number(m_CaptureCard) + ", card == " + TQString::number(card));
+
+ m_CaptureCard = card;
+ m_CaptureDevice = dev;
+ SoundFormat f = m_CaptureFormat;
+ if (m_hCapture)
+ openCaptureDevice(f, /* reopen = */ true);
+ if (m_hCaptureMixer)
+ openCaptureMixerDevice(/* reopen = */ true);
+
+ getCaptureMixerChannels(m_CaptureCard,
+ m_hCaptureMixer,
+ m_CaptureChannels, m_CaptureChannels2ID, m_CaptureChannelsSwitch, m_CaptureChannelsSwitch2ID);
+ notifyCaptureChannelsChanged(m_SoundStreamClientID, m_CaptureChannels);
+}
+
+
+TQString AlsaSoundDevice::getSoundStreamClientDescription() const
+{
+ return i18n("ALSA Sound Device %1").arg(PluginBase::name());
+}
+
+
+bool AlsaSoundDevice::mute (SoundStreamID id, bool mute)
+{
+ if (id.isValid() && (m_PlaybackStreamID == id || m_PassivePlaybackStreams.contains(id))) {
+ SoundStreamConfig &cfg = m_PlaybackStreams[id];
+ if (mute != cfg.m_Muted) {
+ if (writePlaybackMixerVolume(cfg.m_Channel, cfg.m_Volume, cfg.m_Muted = mute)) {
+ notifyMuted(id, cfg.m_Muted);
+ }
+ }
+ return true;
+ }
+ return false;
+}
+
+bool AlsaSoundDevice::unmute (SoundStreamID id, bool unmute)
+{
+ if (id.isValid() && (m_PlaybackStreamID == id || m_PassivePlaybackStreams.contains(id))) {
+ SoundStreamConfig &cfg = m_PlaybackStreams[id];
+ bool mute = !unmute;
+ if (mute != cfg.m_Muted) {
+ if (writePlaybackMixerVolume(cfg.m_Channel, cfg.m_Volume, cfg.m_Muted = mute)) {
+ notifyMuted(id, cfg.m_Muted);
+ }
+ }
+ return true;
+ }
+ return false;
+}
+
+bool AlsaSoundDevice::isMuted(SoundStreamID id, bool &m) const
+{
+ if (id.isValid() && (m_PlaybackStreamID == id || m_PassivePlaybackStreams.contains(id))) {
+ const SoundStreamConfig &cfg = m_PlaybackStreams[id];
+ m = cfg.m_Muted;
+ return true;
+ }
+ return false;
+}
+
+
+void AlsaSoundDevice::setCaptureMixerSettings(const TQMap<TQString, AlsaConfigMixerSetting> &map)
+{
+ m_CaptureMixerSettings = map;
+}
+
+
+
+// bool AlsaSoundDevice::event(TQEvent *_e)
+// {
+// bool retval = false;
+//
+// switch (_e->type()) {
+//
+// case CaptureTerminated :
+// retval = true;
+// break;
+//
+// case CaptureStep :
+//
+// slotPollCapture();
+//
+// retval = true;
+// break;
+//
+// case CaptureError :
+// case CaptureWarning :
+// case CaptureInfo :
+// case CaptureDebug :
+// if (m_captureThread) {
+// AlsaCaptureEvent *e = static_cast<AlsaCaptureEvent*>(_e);
+// TQString msg = i18n("ALSA Plugin, device plughw:%1,%2: %3")
+// .arg(m_CaptureCard)
+// .arg(m_CaptureDevice)
+// .arg(e->message());
+// switch (_e->type()) {
+// case CaptureError :
+// logError(msg);
+// m_captureThread->resetError();
+// break;
+// case CaptureWarning :
+// logWarning(msg);
+// break;
+// case CaptureInfo :
+// logInfo(msg);
+// break;
+// case CaptureDebug :
+// logDebug(msg);
+// break;
+// default:
+// break;
+// }
+// }
+// retval = true;
+// break;
+//
+// default:
+// retval = TQObject::event(_e);
+// break;
+// }
+//
+// return retval;
+// }
+
+
+
+
+
+
+
+
+#include "alsa-sound.moc"
diff --git a/plugins/alsa-sound/alsa-sound.h b/plugins/alsa-sound/alsa-sound.h
new file mode 100644
index 0000000..4a79832
--- /dev/null
+++ b/plugins/alsa-sound/alsa-sound.h
@@ -0,0 +1,297 @@
+/***************************************************************************
+ alsa-sound.h - description
+ -------------------
+ begin : Thu May 26 2005
+ copyright : (C) 2005 by Martin Witte
+ email : witte@kawo1.rwth-aachen.de
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef _KRADIO_ALSA_SOUND_H
+#define _KRADIO_ALSA_SOUND_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "../../src/include/ringbuffer.h"
+#include "../../src/include/plugins.h"
+#include "../../src/include/soundstreamclient_interfaces.h"
+
+#include "alsa-config-mixer-setting.h"
+
+#include <tqobject.h>
+#include <tqtimer.h>
+#include <alsa/asoundlib.h>
+
+enum DUPLEX_MODE { DUPLEX_UNKNOWN, DUPLEX_FULL, DUPLEX_HALF };
+
+
+struct SoundStreamConfig
+{
+ SoundStreamConfig()
+ : m_ActiveMode(false),
+ m_Channel(TQString()),
+ m_Volume(-1),
+ m_Muted(false)
+ {}
+
+ SoundStreamConfig(const TQString &_channel, bool active_mode = true)
+ : m_ActiveMode(active_mode),
+ m_Channel(_channel),
+ m_Volume(-1),
+ m_Muted(false)
+ {}
+
+ SoundStreamConfig(const SoundStreamConfig &c)
+ : m_ActiveMode(c.m_ActiveMode),
+ m_Channel(c.m_Channel),
+ m_Volume(c.m_Volume),
+ m_Muted(c.m_Muted)
+ {}
+
+ bool m_ActiveMode;
+ TQString m_Channel;
+ float m_Volume;
+ bool m_Muted;
+};
+
+
+class AlsaCaptureThread;
+
+class AlsaMixerElement
+{
+public:
+ AlsaMixerElement() { snd_mixer_selem_id_malloc(&m_ID); }
+ AlsaMixerElement(snd_mixer_selem_id_t *id) { snd_mixer_selem_id_malloc(&m_ID); snd_mixer_selem_id_copy(m_ID, id) ; }
+ AlsaMixerElement(const AlsaMixerElement &x) { snd_mixer_selem_id_malloc(&m_ID); snd_mixer_selem_id_copy(m_ID, x.m_ID); }
+ ~AlsaMixerElement() { snd_mixer_selem_id_free (m_ID); }
+
+ operator snd_mixer_selem_id_t *&() { return m_ID; }
+
+ AlsaMixerElement &operator = (const AlsaMixerElement &x) { snd_mixer_selem_id_copy(m_ID, x.m_ID); return *this; }
+
+protected:
+ snd_mixer_selem_id_t *m_ID;
+};
+
+
+class AlsaSoundDevice : public TQObject,
+ public PluginBase,
+ public ISoundStreamClient
+{
+Q_OBJECT
+
+
+public:
+ AlsaSoundDevice (const TQString &name);
+ virtual ~AlsaSoundDevice ();
+
+ virtual bool connectI(Interface *i);
+ virtual bool disconnectI(Interface *i);
+
+ // PluginBase
+
+public:
+ virtual void saveState (TDEConfig *) const;
+ virtual void restoreState (TDEConfig *);
+
+ virtual TQString pluginClassName() const { return "AlsaSoundDevice"; }
+
+ virtual const TQString &name() const { return PluginBase::name(); }
+ virtual TQString &name() { return PluginBase::name(); }
+
+ virtual ConfigPageInfo createConfigurationPage();
+ virtual AboutPageInfo createAboutPage();
+
+ // ISoundStreamClient: direct device access
+
+RECEIVERS:
+ void noticeConnectedI (ISoundStreamServer *s, bool pointer_valid);
+ bool preparePlayback(SoundStreamID id, const TQString &channel, bool active_mode, bool start_immediately);
+ bool prepareCapture(SoundStreamID id, const TQString &channel);
+ bool releasePlayback(SoundStreamID id);
+ bool releaseCapture(SoundStreamID id);
+
+ANSWERS:
+ bool supportsPlayback() const;
+ bool supportsCapture() const;
+
+ TQString getSoundStreamClientDescription() const;
+
+ // ISoundStreamClient: mixer access
+
+public:
+ static
+ void getPlaybackMixerChannels(int card, snd_mixer_t *mixer_handle,
+ TQStringList &retval, TQMap<TQString, AlsaMixerElement> &int2id);
+ static
+ void getCaptureMixerChannels (int card, snd_mixer_t *mixer_handle,
+ TQStringList &vol_list, TQMap<TQString, AlsaMixerElement> &vol_ch2id,
+ TQStringList &sw_list, TQMap<TQString, AlsaMixerElement> &sw_ch2id,
+ TQStringList *all_list = NULL);
+
+ANSWERS:
+ const TQStringList &getPlaybackChannels() const;
+ const TQStringList &getCaptureChannels() const;
+
+RECEIVERS:
+ bool setPlaybackVolume(SoundStreamID id, float volume);
+ bool setCaptureVolume(SoundStreamID id, float volume);
+ bool getPlaybackVolume(SoundStreamID id, float &volume) const;
+ bool getCaptureVolume(SoundStreamID id, float &volume) const;
+
+ bool mute (SoundStreamID id, bool mute);
+ bool unmute (SoundStreamID id, bool unmute);
+ bool isMuted(SoundStreamID id, bool &m) const;
+
+
+ // ISoundStreamClient: generic broadcasts
+
+RECEIVERS:
+ bool startPlayback(SoundStreamID id);
+ bool pausePlayback(SoundStreamID id);
+ bool stopPlayback(SoundStreamID id);
+ bool isPlaybackRunning(SoundStreamID id, bool &b) const;
+
+ bool startCaptureWithFormat(SoundStreamID id,
+ const SoundFormat &proposed_format,
+ SoundFormat &real_format,
+ bool force_format);
+ bool stopCapture(SoundStreamID id);
+ bool isCaptureRunning(SoundStreamID id, bool &b, SoundFormat &sf) const;
+
+ bool noticeSoundStreamClosed(SoundStreamID id);
+ bool noticeSoundStreamRedirected(SoundStreamID oldID, SoundStreamID newID);
+
+ bool noticeSoundStreamData(SoundStreamID id,
+ const SoundFormat &,
+ const char *data, size_t size, size_t &consumed_size,
+ const SoundMetaData &md
+ );
+
+
+ // Config Access
+
+ int getHWBufferSize() const { return m_HWBufferSize; }
+ int getBufferSize() const { return m_BufferSize; }
+ bool isPlaybackEnabled() const { return m_EnablePlayback; }
+ bool isCaptureEnabled() const { return m_EnableCapture; }
+ int getPlaybackCard() const { return m_PlaybackCard; }
+ int getPlaybackDevice() const { return m_PlaybackDevice; }
+ int getCaptureCard() const { return m_CaptureCard; }
+ int getCaptureDevice() const { return m_CaptureDevice; }
+ const TQMap<TQString, AlsaConfigMixerSetting> &
+ getCaptureMixerSettings() const { return m_CaptureMixerSettings; }
+
+ void setHWBufferSize(int s);
+ void setBufferSize(int s);
+ void enablePlayback(bool on);
+ void enableCapture(bool on);
+ void setPlaybackDevice(int card, int device);
+ void setCaptureDevice(int card, int device);
+ void setCaptureMixerSettings(const TQMap<TQString, AlsaConfigMixerSetting> &map);
+
+protected slots:
+
+ void slotPollPlayback();
+ void slotPollCapture();
+
+signals:
+
+ void sigUpdateConfig();
+
+protected:
+// bool event(TQEvent *_e);
+
+ bool openAlsaDevice(snd_pcm_t *&alsa_handle, SoundFormat &format, const char *pcm_name, snd_pcm_stream_t stream, int flags, unsigned &latency);
+
+ bool openPlaybackDevice (const SoundFormat &format, bool reopen = false);
+ bool openCaptureDevice (const SoundFormat &format, bool reopen = false);
+ bool closePlaybackDevice(bool force = false);
+ bool closeCaptureDevice (bool force = false);
+
+ bool openPlaybackMixerDevice (bool reopen = false);
+ bool openCaptureMixerDevice (bool reopen = false);
+ static bool openMixerDevice(snd_mixer_t *&mixer_handle, int card, bool reopen, TQTimer *timer, int timer_latency);
+ bool closeCaptureMixerDevice (bool force = false);
+ bool closePlaybackMixerDevice(bool force = false);
+ static bool closeMixerDevice(snd_mixer_t *&mixer_handle, int card, SoundStreamID id, snd_pcm_t *pcm_handle, bool force, TQTimer *timer);
+
+ void checkMixerVolume(SoundStreamID id);
+ float readPlaybackMixerVolume(const TQString &channel, bool &muted) const;
+ float readCaptureMixerVolume(const TQString &channel) const;
+ bool writePlaybackMixerVolume(const TQString &channel, float &vol, bool muted);
+ bool writeCaptureMixerVolume(const TQString &channel, float &vol);
+ bool writeCaptureMixerSwitch(const TQString &channel, bool capture);
+
+ void selectCaptureChannel (const TQString &channel);
+
+ /* ALSA HANDLES */
+ snd_pcm_t *m_hPlayback;
+ snd_pcm_t *m_hCapture;
+ snd_mixer_t *m_hPlaybackMixer;
+ snd_mixer_t *m_hCaptureMixer;
+
+ SoundFormat m_PlaybackFormat;
+ SoundFormat m_CaptureFormat;
+ int m_PlaybackCard;
+ int m_PlaybackDevice;
+ int m_CaptureCard;
+ int m_CaptureDevice;
+
+ unsigned m_PlaybackLatency;
+ unsigned m_CaptureLatency;
+
+ TQStringList m_PlaybackChannels,
+ m_CaptureChannels,
+ m_CaptureChannelsSwitch;
+
+ TQMap<TQString, AlsaMixerElement> m_PlaybackChannels2ID,
+ m_CaptureChannels2ID,
+ m_CaptureChannelsSwitch2ID;
+
+ TQMap<SoundStreamID, SoundStreamConfig>
+ m_PlaybackStreams,
+ m_CaptureStreams;
+
+ TQValueList<SoundStreamID>
+ m_PassivePlaybackStreams;
+ SoundStreamID m_PlaybackStreamID,
+ m_CaptureStreamID;
+
+ size_t m_HWBufferSize;
+ size_t m_BufferSize;
+ RingBuffer m_PlaybackBuffer,
+ m_CaptureBuffer;
+
+ unsigned m_CaptureRequestCounter;
+ TQ_UINT64 m_CapturePos;
+ time_t m_CaptureStartTime;
+
+ size_t //m_PlaybackSkipCount,
+ m_CaptureSkipCount;
+
+ bool m_EnablePlayback,
+ m_EnableCapture;
+
+ TQTimer m_PlaybackPollingTimer;
+ TQTimer m_CapturePollingTimer;
+
+// AlsaCaptureThread *m_captureThread;
+
+ TQMap<TQString, AlsaConfigMixerSetting> m_CaptureMixerSettings;
+
+};
+
+
+
+#endif
diff --git a/plugins/alsa-sound/icons/Makefile.am b/plugins/alsa-sound/icons/Makefile.am
new file mode 100644
index 0000000..c9577fb
--- /dev/null
+++ b/plugins/alsa-sound/icons/Makefile.am
@@ -0,0 +1,7 @@
+# icons_ICON = tderadio_alsa*
+# iconsdir = $(datadir)/icons
+
+KDE_ICON = alsa alsa2
+
+icons_ICON = tderadio_alsa tderadio_alsa2
+iconsdir = $(datadir)/icons
diff --git a/plugins/alsa-sound/icons/alsa.png b/plugins/alsa-sound/icons/alsa.png
new file mode 100644
index 0000000..151f9b1
--- /dev/null
+++ b/plugins/alsa-sound/icons/alsa.png
Binary files differ
diff --git a/plugins/alsa-sound/icons/alsa2.png b/plugins/alsa-sound/icons/alsa2.png
new file mode 100644
index 0000000..524f16f
--- /dev/null
+++ b/plugins/alsa-sound/icons/alsa2.png
Binary files differ
diff --git a/plugins/alsa-sound/icons/hi16-action-tderadio_alsa.png b/plugins/alsa-sound/icons/hi16-action-tderadio_alsa.png
new file mode 100644
index 0000000..5272859
--- /dev/null
+++ b/plugins/alsa-sound/icons/hi16-action-tderadio_alsa.png
Binary files differ
diff --git a/plugins/alsa-sound/icons/hi16-action-tderadio_alsa2.png b/plugins/alsa-sound/icons/hi16-action-tderadio_alsa2.png
new file mode 100644
index 0000000..e521ea0
--- /dev/null
+++ b/plugins/alsa-sound/icons/hi16-action-tderadio_alsa2.png
Binary files differ
diff --git a/plugins/alsa-sound/icons/hi22-action-tderadio_alsa.png b/plugins/alsa-sound/icons/hi22-action-tderadio_alsa.png
new file mode 100644
index 0000000..f0c3906
--- /dev/null
+++ b/plugins/alsa-sound/icons/hi22-action-tderadio_alsa.png
Binary files differ
diff --git a/plugins/alsa-sound/icons/hi22-action-tderadio_alsa2.png b/plugins/alsa-sound/icons/hi22-action-tderadio_alsa2.png
new file mode 100644
index 0000000..0e7adfa
--- /dev/null
+++ b/plugins/alsa-sound/icons/hi22-action-tderadio_alsa2.png
Binary files differ
diff --git a/plugins/alsa-sound/icons/hi32-action-tderadio_alsa.png b/plugins/alsa-sound/icons/hi32-action-tderadio_alsa.png
new file mode 100644
index 0000000..2eebb0d
--- /dev/null
+++ b/plugins/alsa-sound/icons/hi32-action-tderadio_alsa.png
Binary files differ
diff --git a/plugins/alsa-sound/icons/hi32-action-tderadio_alsa2.png b/plugins/alsa-sound/icons/hi32-action-tderadio_alsa2.png
new file mode 100644
index 0000000..47ff4b0
--- /dev/null
+++ b/plugins/alsa-sound/icons/hi32-action-tderadio_alsa2.png
Binary files differ
diff --git a/plugins/alsa-sound/icons/hi48-action-tderadio_alsa.png b/plugins/alsa-sound/icons/hi48-action-tderadio_alsa.png
new file mode 100644
index 0000000..afaa77a
--- /dev/null
+++ b/plugins/alsa-sound/icons/hi48-action-tderadio_alsa.png
Binary files differ
diff --git a/plugins/alsa-sound/icons/hi48-action-tderadio_alsa2.png b/plugins/alsa-sound/icons/hi48-action-tderadio_alsa2.png
new file mode 100644
index 0000000..c638081
--- /dev/null
+++ b/plugins/alsa-sound/icons/hi48-action-tderadio_alsa2.png
Binary files differ
diff --git a/plugins/alsa-sound/icons/hi64-action-tderadio_alsa.png b/plugins/alsa-sound/icons/hi64-action-tderadio_alsa.png
new file mode 100644
index 0000000..971528b
--- /dev/null
+++ b/plugins/alsa-sound/icons/hi64-action-tderadio_alsa.png
Binary files differ
diff --git a/plugins/alsa-sound/icons/hi64-action-tderadio_alsa2.png b/plugins/alsa-sound/icons/hi64-action-tderadio_alsa2.png
new file mode 100644
index 0000000..60467b3
--- /dev/null
+++ b/plugins/alsa-sound/icons/hi64-action-tderadio_alsa2.png
Binary files differ
diff --git a/plugins/alsa-sound/po/Makefile.am b/plugins/alsa-sound/po/Makefile.am
new file mode 100644
index 0000000..ca0f4d9
--- /dev/null
+++ b/plugins/alsa-sound/po/Makefile.am
@@ -0,0 +1,3 @@
+
+PACKAGE = tderadio-alsa-sound
+POFILES = AUTO
diff --git a/plugins/alsa-sound/po/de.po b/plugins/alsa-sound/po/de.po
new file mode 100644
index 0000000..03af16f
--- /dev/null
+++ b/plugins/alsa-sound/po/de.po
@@ -0,0 +1,285 @@
+# translation of de.po to
+# translation of tderadio-alsa-sound.po to
+# This file is put in the public domain.
+#
+# Ernst Martin Witte <emw@nocabal.de>, 2006.
+msgid ""
+msgstr ""
+"Project-Id-Version: de\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2021-07-07 18:28+0000\n"
+"PO-Revision-Date: 2019-11-27 16:56+0000\n"
+"Last-Translator: Chris <xchrisx@uber.space>\n"
+"Language-Team: German <https://mirror.git.trinitydesktop.org/weblate/"
+"projects/applications/tderadio-alsa-sound/de/>\n"
+"Language: de\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=n != 1;\n"
+"X-Generator: Weblate 3.9.1\n"
+
+#. Instead of a literal translation, add your name to the end of the list (separated by a comma).
+msgid ""
+"_: NAME OF TRANSLATORS\n"
+"Your names"
+msgstr "Ernst Martin Witte"
+
+#. Instead of a literal translation, add your email to the end of the list (separated by a comma).
+msgid ""
+"_: EMAIL OF TRANSLATORS\n"
+"Your emails"
+msgstr "emw@nocabal.de"
+
+#: alsa-sound-configuration.cpp:258
+msgid ""
+"_: context-card-plus-device-number\n"
+"%1 device %2"
+msgstr "%1 Gerät %2"
+
+#: alsa-sound.cpp:40
+msgid "Advanced Linux Sound Architecture (ALSA) Support"
+msgstr "Unterstützung für die \"Advanced Linux Sound Architecture\" (ALSA)"
+
+#: alsa-sound.cpp:48
+msgid "TDERadio ALSA Sound Plugin"
+msgstr "TDERadio ALSA Sound Modul"
+
+#: alsa-sound.cpp:196
+msgid "ALSA Sound"
+msgstr "ALSA Sound"
+
+#: alsa-sound.cpp:197
+msgid "ALSA Sound Device Options"
+msgstr "Optionen für die ALSA-Sound-Geräte"
+
+#: alsa-sound.cpp:553
+msgid "ALSA Plugin: cannot write data for device plughw:%1,%2"
+msgstr "ALSA Plugin: Das schreiben auf das Gerät plughw:%1,%2 schlug fehl"
+
+#: alsa-sound.cpp:558
+msgid "ALSA Plugin: buffer underrun for device plughw:%1,%2"
+msgstr "ALSA Plugin: Pufferunterlauf im Gerät plughw:%1,%2"
+
+#: alsa-sound.cpp:611
+msgid "ALSA Plugin: cannot read data from device plughw:%1,%2"
+msgstr "ALSA Plugin: Das Lesen vom Gerät plughw:%1,%2 schlug fehl"
+
+#: alsa-sound.cpp:616
+msgid ""
+"ALSA Plugin: buffer overrun for device plughw:%1,%2 (buffersize=%3, buffer="
+"%4)"
+msgstr ""
+"ALSA Plugin: Pufferüberlauf im Gerät plughw:%1,%2 (Puffergröße=%3, buffer=%4)"
+
+#: alsa-sound.cpp:626
+msgid "internal stream, not stored (%1)"
+msgstr "interner, nicht aufgezeichneter Datenstrom (%1)"
+
+#: alsa-sound.cpp:736
+#, c-format
+msgid "ALSA Plugin: Error opening PCM device %1"
+msgstr "ALSA Plugin: Fehler beim Öffnen des Gerätes %1"
+
+#: alsa-sound.cpp:741
+#, c-format
+msgid "ALSA Plugin: Can not configure PCM device %1"
+msgstr "ALSA Plugin: Die Einrichtung des Gerätes %1 schlug fehl"
+
+#: alsa-sound.cpp:748
+#, c-format
+msgid "ALSA Plugin: Error setting access for %1"
+msgstr "ALSA Plugin: Fehler beim einrichten des Zugriffsmodus auf Gerät %1"
+
+#: alsa-sound.cpp:758
+#, c-format
+msgid "ALSA Plugin: Error setting sample format for %1"
+msgstr "ALSA Plugin: Fehler beim Einstellen des Abtastformats für Gerät %1"
+
+#: alsa-sound.cpp:764
+#, c-format
+msgid "ALSA Plugin: Error setting channels for %1"
+msgstr "ALSA Plugin: Fehler beim Einstellen der Kanäle für Gerät %1"
+
+#: alsa-sound.cpp:771
+#, c-format
+msgid "ALSA Plugin: Error setting rate for %1"
+msgstr "ALSA Plugin: Fehler beim Einstellen der Abtastrate für Gerät %1"
+
+#: alsa-sound.cpp:775
+msgid ""
+"ALSA Plugin: The rate %1 Hz is not supported by your hardware %2. Using %3 "
+"Hz instead"
+msgstr ""
+"ALSA Plugin: Die Abtastrate von %1 Hz wird von Ihrer Soundkarte %2 nicht "
+"unterstützt. Es werden stattdessen %3 Hz verwendet"
+
+#: alsa-sound.cpp:781
+#, c-format
+msgid "ALSA Plugin: Error setting period size for %1"
+msgstr ""
+"ALSA Plugin: Fehler beim Einstellen der Puffer-Periodengröße für Gerät %1"
+
+#: alsa-sound.cpp:817
+msgid "ALSA Plugin: Error setting HW params"
+msgstr "ALSA Plugin: Fehler beim Einstellen der Hardwareparameter"
+
+#: alsa-sound.cpp:822
+#, c-format
+msgid "ALSA Plugin: Error getting period size for %1"
+msgstr "ALSA Plugin: Fehler beim Lesen der Puffer-Periodengröße von Gerät %1"
+
+#: alsa-sound.cpp:920
+msgid "ALSA Plugin: Error opening mixer"
+msgstr "ALSA Plugin: Fehler beim Öffnen des Mixers"
+
+#: alsa-sound.cpp:927
+#, c-format
+msgid "ALSA Plugin: ERROR: snd_mixer_attach for card %1"
+msgstr "ALSA Plugin: Fehler in Funktion snd_mixer_attach bei Soundkarte %1"
+
+#: alsa-sound.cpp:934
+#, c-format
+msgid "ALSA Plugin: Error: snd_mixer_selem_register for card %1"
+msgstr ""
+"ALSA Plugin: Fehler in Funktion snd_mixer_selem_register bei Soundkarte %1"
+
+#: alsa-sound.cpp:938
+#, c-format
+msgid "ALSA Plugin: Error: snd_mixer_load for card %1"
+msgstr "ALSA Plugin: Fehler in Funktion snd_mixer_load bei Soundkarte %1"
+
+#: alsa-sound.cpp:1006
+msgid ""
+"_: context-mixername-number\n"
+"%1 %2"
+msgstr "%1 %2"
+
+#: alsa-sound.cpp:1053
+msgid ""
+"_: context-mixerelement-name-number\n"
+"%1 %2"
+msgstr "%1 %2"
+
+#: alsa-sound.cpp:1206 alsa-sound.cpp:1236
+msgid "error while reading volume from hwplug:%1,%2"
+msgstr "Fehler beim Lesen der Lautstärke von Gerät hwplug:%1,%2"
+
+#: alsa-sound.cpp:1269 alsa-sound.cpp:1304
+msgid "error while writing volume %1 to hwplug:%2,%3"
+msgstr "Fehler beim Setzen der Lautstärke von Gerät hwplug:%1,%2"
+
+#: alsa-sound.cpp:1327
+msgid "error while setting capture switch %1 for hwplug:%2,%3"
+msgstr ""
+"Fehler beim Einstellen des Aufnahmeauswahlschalters %1 für Gerät hwplug:%2,%3"
+
+#: alsa-sound.cpp:1448
+#, c-format
+msgid "ALSA Sound Device %1"
+msgstr "ALSA Soundkarte %1"
+
+#: alsa-mixer-element-ui.ui:16
+#, no-c-format
+msgid "Form1"
+msgstr "Form1"
+
+#: alsa-mixer-element-ui.ui:210
+#, no-c-format
+msgid "O&n"
+msgstr "A&n"
+
+#: alsa-mixer-element-ui.ui:213
+#, no-c-format
+msgid "Alt+N"
+msgstr "Alt+N"
+
+#: alsa-mixer-element-ui.ui:221
+#, no-c-format
+msgid "&Use"
+msgstr "&Verwenden"
+
+#: alsa-mixer-element-ui.ui:224
+#, no-c-format
+msgid "Alt+U"
+msgstr "Alt+U"
+
+#: alsa-mixer-element-ui.ui:256
+#, no-c-format
+msgid "MixerName"
+msgstr "MixerName"
+
+#: alsa-sound-configuration-ui.ui:16
+#, no-c-format
+msgid "AlsaSoundConfigurationUI"
+msgstr "AlsaSoundConfigurationUI"
+
+#: alsa-sound-configuration-ui.ui:34
+#, no-c-format
+msgid "Devices"
+msgstr "Geräte"
+
+#: alsa-sound-configuration-ui.ui:73
+#, no-c-format
+msgid "PCM Capture Card"
+msgstr "Soundkarte für die Aufnahme"
+
+#: alsa-sound-configuration-ui.ui:94
+#, no-c-format
+msgid "Hardware Buffer Size"
+msgstr "Hardware-Puffergröße"
+
+#: alsa-sound-configuration-ui.ui:123 alsa-sound-configuration-ui.ui:145
+#, no-c-format
+msgid " kB"
+msgstr " kB"
+
+#: alsa-sound-configuration-ui.ui:172
+#, no-c-format
+msgid "Buffer Size"
+msgstr "Puffergröße"
+
+#: alsa-sound-configuration-ui.ui:193
+#, no-c-format
+msgid "PCM Playback Device"
+msgstr "Gerät für die Wiedergabe"
+
+#: alsa-sound-configuration-ui.ui:201
+#, no-c-format
+msgid "PCM Capture Device"
+msgstr "Gerät für die Aufnahme"
+
+#: alsa-sound-configuration-ui.ui:209
+#, no-c-format
+msgid "PCM Playback Card"
+msgstr "Soundkarte für die Wiedergabe"
+
+#: alsa-sound-configuration-ui.ui:221
+#, no-c-format
+msgid "E&xtended Options"
+msgstr "Erweiterte Optionen"
+
+#: alsa-sound-configuration-ui.ui:235
+#, no-c-format
+msgid "Disable Pla&yback"
+msgstr "Wiedergabe abschalten"
+
+#: alsa-sound-configuration-ui.ui:238
+#, no-c-format
+msgid "Alt+Y"
+msgstr "Alt+Y"
+
+#: alsa-sound-configuration-ui.ui:246
+#, no-c-format
+msgid "Disa&ble Capture"
+msgstr "Aufnahme abschalten"
+
+#: alsa-sound-configuration-ui.ui:249
+#, no-c-format
+msgid "Alt+B"
+msgstr "Alt+B"
+
+#: alsa-sound-configuration-ui.ui:276
+#, no-c-format
+msgid "Capture Mixer Settings"
+msgstr "Mixereinstellungen für die Aufnahme"
diff --git a/plugins/alsa-sound/po/ru.po b/plugins/alsa-sound/po/ru.po
new file mode 100644
index 0000000..d226310
--- /dev/null
+++ b/plugins/alsa-sound/po/ru.po
@@ -0,0 +1,284 @@
+# translation of ru.po to
+# translation of tderadio-alsa-sound.po to
+# This file is put in the public domain.
+# Алексей Кузнецов <Alexey.Kouznetsov@GMail.com>, 2006.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: ru\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2021-07-07 18:28+0000\n"
+"PO-Revision-Date: 2006-11-08 12:15+0300\n"
+"Last-Translator: Алексей Кузнецов <Alexey.Kouznetsov@GMail.com>\n"
+"Language-Team: <ru@li.org>\n"
+"Language: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: KBabel 1.10\n"
+
+#. Instead of a literal translation, add your name to the end of the list (separated by a comma).
+msgid ""
+"_: NAME OF TRANSLATORS\n"
+"Your names"
+msgstr "Алексей Кузнецов"
+
+#. Instead of a literal translation, add your email to the end of the list (separated by a comma).
+msgid ""
+"_: EMAIL OF TRANSLATORS\n"
+"Your emails"
+msgstr "Alexey.Kouznetsov@GMail.com"
+
+#: alsa-sound-configuration.cpp:258
+msgid ""
+"_: context-card-plus-device-number\n"
+"%1 device %2"
+msgstr ""
+
+#: alsa-sound.cpp:40
+msgid "Advanced Linux Sound Architecture (ALSA) Support"
+msgstr "Поддержка Расширенной звуковой архитектуры Linux (ALSA)"
+
+#: alsa-sound.cpp:48
+msgid "TDERadio ALSA Sound Plugin"
+msgstr "Модуль ALSA для TDERadio"
+
+#: alsa-sound.cpp:196
+msgid "ALSA Sound"
+msgstr "ALSA"
+
+#: alsa-sound.cpp:197
+msgid "ALSA Sound Device Options"
+msgstr "Параметры звука для драйвера ALSA"
+
+#: alsa-sound.cpp:553
+msgid "ALSA Plugin: cannot write data for device plughw:%1,%2"
+msgstr "Модуль ALSA: не могу записать данные в устройство plughw:%1,%2"
+
+#: alsa-sound.cpp:558
+msgid "ALSA Plugin: buffer underrun for device plughw:%1,%2"
+msgstr "Модуль ALSA: нехватка данных в буфере устройства plughw:%1,%2"
+
+#: alsa-sound.cpp:611
+msgid "ALSA Plugin: cannot read data from device plughw:%1,%2"
+msgstr "Модуль ALSA: не могу прочесть данные с устройства plughw:%1,%2"
+
+#: alsa-sound.cpp:616
+msgid ""
+"ALSA Plugin: buffer overrun for device plughw:%1,%2 (buffersize=%3, buffer="
+"%4)"
+msgstr ""
+"Модуль ALSA: переполнение буфера устройства plughw:%1,%2 (размер буфера=%3, "
+"буфер=%4)"
+
+#: alsa-sound.cpp:626
+msgid "internal stream, not stored (%1)"
+msgstr ""
+
+#: alsa-sound.cpp:736
+#, c-format
+msgid "ALSA Plugin: Error opening PCM device %1"
+msgstr "Модуль ALSA: Ошибка при открытии устройства PCM: %1"
+
+#: alsa-sound.cpp:741
+#, c-format
+msgid "ALSA Plugin: Can not configure PCM device %1"
+msgstr "Модуль ALSA: не могу настроить устройство PCM %1"
+
+#: alsa-sound.cpp:748
+#, c-format
+msgid "ALSA Plugin: Error setting access for %1"
+msgstr ""
+
+#: alsa-sound.cpp:758
+#, c-format
+msgid "ALSA Plugin: Error setting sample format for %1"
+msgstr "Модуль ALSA: ошибка при установке формата данных для %1"
+
+#: alsa-sound.cpp:764
+#, c-format
+msgid "ALSA Plugin: Error setting channels for %1"
+msgstr "Модуль ALSA: ошибка при установке числа каналов для %1"
+
+#: alsa-sound.cpp:771
+#, c-format
+msgid "ALSA Plugin: Error setting rate for %1"
+msgstr "Модуль ALSA: ошибка при установке частоты дискретизации для %1"
+
+#: alsa-sound.cpp:775
+msgid ""
+"ALSA Plugin: The rate %1 Hz is not supported by your hardware %2. Using %3 "
+"Hz instead"
+msgstr ""
+"Модуль ALSA: частота дискретизации %1 Гц не поддерживается Вашим "
+"оборудованием %2. Вместо неё использую %3 Гц."
+
+#: alsa-sound.cpp:781
+#, c-format
+msgid "ALSA Plugin: Error setting period size for %1"
+msgstr ""
+
+#: alsa-sound.cpp:817
+msgid "ALSA Plugin: Error setting HW params"
+msgstr "Модуль ALSA: ошибка при установке параметров оборудоания"
+
+#: alsa-sound.cpp:822
+#, c-format
+msgid "ALSA Plugin: Error getting period size for %1"
+msgstr ""
+
+#: alsa-sound.cpp:920
+msgid "ALSA Plugin: Error opening mixer"
+msgstr "Модуль ALSA: ошибка при открытии микшера"
+
+#: alsa-sound.cpp:927
+#, c-format
+msgid "ALSA Plugin: ERROR: snd_mixer_attach for card %1"
+msgstr "Модуль ALSA: ошибка при вызове функции snd_mixer_attach для платы %1"
+
+#: alsa-sound.cpp:934
+#, c-format
+msgid "ALSA Plugin: Error: snd_mixer_selem_register for card %1"
+msgstr ""
+"Модуль ALSA: ошибка при вызове функции snd_mixer_selem_register для платы %1"
+
+#: alsa-sound.cpp:938
+#, c-format
+msgid "ALSA Plugin: Error: snd_mixer_load for card %1"
+msgstr "Модуль ALSA: ошибка при вызове функции snd_mixer_load для платы %1"
+
+#: alsa-sound.cpp:1006
+#, fuzzy
+msgid ""
+"_: context-mixername-number\n"
+"%1 %2"
+msgstr "context-mixername-number"
+
+#: alsa-sound.cpp:1053
+#, fuzzy
+msgid ""
+"_: context-mixerelement-name-number\n"
+"%1 %2"
+msgstr "context-mixerelement-name-number"
+
+#: alsa-sound.cpp:1206 alsa-sound.cpp:1236
+msgid "error while reading volume from hwplug:%1,%2"
+msgstr "Ошибка считывания громкости устройства hwplug:%1,%2"
+
+#: alsa-sound.cpp:1269 alsa-sound.cpp:1304
+msgid "error while writing volume %1 to hwplug:%2,%3"
+msgstr "Ошибка при записи громкости %1 в устройство hwplug:%2,%3"
+
+#: alsa-sound.cpp:1327
+msgid "error while setting capture switch %1 for hwplug:%2,%3"
+msgstr "Ошибка при установке флажка записи %1 для устройства hwplug:%2,%3"
+
+#: alsa-sound.cpp:1448
+#, c-format
+msgid "ALSA Sound Device %1"
+msgstr "Устройство ALSA: %1"
+
+#: alsa-mixer-element-ui.ui:16
+#, no-c-format
+msgid "Form1"
+msgstr "Form1"
+
+#: alsa-mixer-element-ui.ui:210
+#, no-c-format
+msgid "O&n"
+msgstr "&Вкл."
+
+#: alsa-mixer-element-ui.ui:213
+#, no-c-format
+msgid "Alt+N"
+msgstr "Alt+N"
+
+#: alsa-mixer-element-ui.ui:221
+#, no-c-format
+msgid "&Use"
+msgstr "&Исп."
+
+#: alsa-mixer-element-ui.ui:224
+#, no-c-format
+msgid "Alt+U"
+msgstr "Alt+U"
+
+#: alsa-mixer-element-ui.ui:256
+#, no-c-format
+msgid "MixerName"
+msgstr ""
+
+#: alsa-sound-configuration-ui.ui:16
+#, no-c-format
+msgid "AlsaSoundConfigurationUI"
+msgstr "AlsaSoundConfigurationUI"
+
+#: alsa-sound-configuration-ui.ui:34
+#, no-c-format
+msgid "Devices"
+msgstr "Устройства"
+
+#: alsa-sound-configuration-ui.ui:73
+#, no-c-format
+msgid "PCM Capture Card"
+msgstr "Плата для захвата"
+
+#: alsa-sound-configuration-ui.ui:94
+#, no-c-format
+msgid "Hardware Buffer Size"
+msgstr "Аппаратный размер буфера"
+
+#: alsa-sound-configuration-ui.ui:123 alsa-sound-configuration-ui.ui:145
+#, no-c-format
+msgid " kB"
+msgstr " кБ"
+
+#: alsa-sound-configuration-ui.ui:172
+#, no-c-format
+msgid "Buffer Size"
+msgstr "Размер буфера"
+
+#: alsa-sound-configuration-ui.ui:193
+#, no-c-format
+msgid "PCM Playback Device"
+msgstr "Устройство воспроизведения"
+
+#: alsa-sound-configuration-ui.ui:201
+#, no-c-format
+msgid "PCM Capture Device"
+msgstr "Устройство записи"
+
+#: alsa-sound-configuration-ui.ui:209
+#, no-c-format
+msgid "PCM Playback Card"
+msgstr "Плата для проигрывания"
+
+#: alsa-sound-configuration-ui.ui:221
+#, no-c-format
+msgid "E&xtended Options"
+msgstr "&Дополнительные параметры"
+
+#: alsa-sound-configuration-ui.ui:235
+#, no-c-format
+msgid "Disable Pla&yback"
+msgstr "Запретить &воспроизведение"
+
+#: alsa-sound-configuration-ui.ui:238
+#, no-c-format
+msgid "Alt+Y"
+msgstr "Alt+Y"
+
+#: alsa-sound-configuration-ui.ui:246
+#, no-c-format
+msgid "Disa&ble Capture"
+msgstr "Запретить &запись"
+
+#: alsa-sound-configuration-ui.ui:249
+#, no-c-format
+msgid "Alt+B"
+msgstr "Alt+B"
+
+#: alsa-sound-configuration-ui.ui:276
+#, no-c-format
+msgid "Capture Mixer Settings"
+msgstr "&Параметры микшера для записи"
diff --git a/plugins/alsa-sound/po/tderadio-alsa-sound.pot b/plugins/alsa-sound/po/tderadio-alsa-sound.pot
new file mode 100644
index 0000000..6554981
--- /dev/null
+++ b/plugins/alsa-sound/po/tderadio-alsa-sound.pot
@@ -0,0 +1,275 @@
+# SOME DESCRIPTIVE TITLE.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"POT-Creation-Date: 2021-07-07 18:28+0000\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#. Instead of a literal translation, add your name to the end of the list (separated by a comma).
+#, ignore-inconsistent
+msgid ""
+"_: NAME OF TRANSLATORS\n"
+"Your names"
+msgstr ""
+
+#. Instead of a literal translation, add your email to the end of the list (separated by a comma).
+#, ignore-inconsistent
+msgid ""
+"_: EMAIL OF TRANSLATORS\n"
+"Your emails"
+msgstr ""
+
+#: alsa-sound-configuration.cpp:258
+msgid ""
+"_: context-card-plus-device-number\n"
+"%1 device %2"
+msgstr ""
+
+#: alsa-sound.cpp:40
+msgid "Advanced Linux Sound Architecture (ALSA) Support"
+msgstr ""
+
+#: alsa-sound.cpp:48
+msgid "TDERadio ALSA Sound Plugin"
+msgstr ""
+
+#: alsa-sound.cpp:196
+msgid "ALSA Sound"
+msgstr ""
+
+#: alsa-sound.cpp:197
+msgid "ALSA Sound Device Options"
+msgstr ""
+
+#: alsa-sound.cpp:553
+msgid "ALSA Plugin: cannot write data for device plughw:%1,%2"
+msgstr ""
+
+#: alsa-sound.cpp:558
+msgid "ALSA Plugin: buffer underrun for device plughw:%1,%2"
+msgstr ""
+
+#: alsa-sound.cpp:611
+msgid "ALSA Plugin: cannot read data from device plughw:%1,%2"
+msgstr ""
+
+#: alsa-sound.cpp:616
+msgid ""
+"ALSA Plugin: buffer overrun for device plughw:%1,%2 (buffersize=%3, buffer="
+"%4)"
+msgstr ""
+
+#: alsa-sound.cpp:626
+msgid "internal stream, not stored (%1)"
+msgstr ""
+
+#: alsa-sound.cpp:736
+#, c-format
+msgid "ALSA Plugin: Error opening PCM device %1"
+msgstr ""
+
+#: alsa-sound.cpp:741
+#, c-format
+msgid "ALSA Plugin: Can not configure PCM device %1"
+msgstr ""
+
+#: alsa-sound.cpp:748
+#, c-format
+msgid "ALSA Plugin: Error setting access for %1"
+msgstr ""
+
+#: alsa-sound.cpp:758
+#, c-format
+msgid "ALSA Plugin: Error setting sample format for %1"
+msgstr ""
+
+#: alsa-sound.cpp:764
+#, c-format
+msgid "ALSA Plugin: Error setting channels for %1"
+msgstr ""
+
+#: alsa-sound.cpp:771
+#, c-format
+msgid "ALSA Plugin: Error setting rate for %1"
+msgstr ""
+
+#: alsa-sound.cpp:775
+msgid ""
+"ALSA Plugin: The rate %1 Hz is not supported by your hardware %2. Using %3 "
+"Hz instead"
+msgstr ""
+
+#: alsa-sound.cpp:781
+#, c-format
+msgid "ALSA Plugin: Error setting period size for %1"
+msgstr ""
+
+#: alsa-sound.cpp:817
+msgid "ALSA Plugin: Error setting HW params"
+msgstr ""
+
+#: alsa-sound.cpp:822
+#, c-format
+msgid "ALSA Plugin: Error getting period size for %1"
+msgstr ""
+
+#: alsa-sound.cpp:920
+msgid "ALSA Plugin: Error opening mixer"
+msgstr ""
+
+#: alsa-sound.cpp:927
+#, c-format
+msgid "ALSA Plugin: ERROR: snd_mixer_attach for card %1"
+msgstr ""
+
+#: alsa-sound.cpp:934
+#, c-format
+msgid "ALSA Plugin: Error: snd_mixer_selem_register for card %1"
+msgstr ""
+
+#: alsa-sound.cpp:938
+#, c-format
+msgid "ALSA Plugin: Error: snd_mixer_load for card %1"
+msgstr ""
+
+#: alsa-sound.cpp:1006
+msgid ""
+"_: context-mixername-number\n"
+"%1 %2"
+msgstr ""
+
+#: alsa-sound.cpp:1053
+msgid ""
+"_: context-mixerelement-name-number\n"
+"%1 %2"
+msgstr ""
+
+#: alsa-sound.cpp:1206 alsa-sound.cpp:1236
+msgid "error while reading volume from hwplug:%1,%2"
+msgstr ""
+
+#: alsa-sound.cpp:1269 alsa-sound.cpp:1304
+msgid "error while writing volume %1 to hwplug:%2,%3"
+msgstr ""
+
+#: alsa-sound.cpp:1327
+msgid "error while setting capture switch %1 for hwplug:%2,%3"
+msgstr ""
+
+#: alsa-sound.cpp:1448
+#, c-format
+msgid "ALSA Sound Device %1"
+msgstr ""
+
+#: alsa-mixer-element-ui.ui:16
+#, no-c-format
+msgid "Form1"
+msgstr ""
+
+#: alsa-mixer-element-ui.ui:210
+#, no-c-format
+msgid "O&n"
+msgstr ""
+
+#: alsa-mixer-element-ui.ui:213
+#, no-c-format
+msgid "Alt+N"
+msgstr ""
+
+#: alsa-mixer-element-ui.ui:221
+#, no-c-format
+msgid "&Use"
+msgstr ""
+
+#: alsa-mixer-element-ui.ui:224
+#, no-c-format
+msgid "Alt+U"
+msgstr ""
+
+#: alsa-mixer-element-ui.ui:256
+#, no-c-format
+msgid "MixerName"
+msgstr ""
+
+#: alsa-sound-configuration-ui.ui:16
+#, no-c-format
+msgid "AlsaSoundConfigurationUI"
+msgstr ""
+
+#: alsa-sound-configuration-ui.ui:34
+#, no-c-format
+msgid "Devices"
+msgstr ""
+
+#: alsa-sound-configuration-ui.ui:73
+#, no-c-format
+msgid "PCM Capture Card"
+msgstr ""
+
+#: alsa-sound-configuration-ui.ui:94
+#, no-c-format
+msgid "Hardware Buffer Size"
+msgstr ""
+
+#: alsa-sound-configuration-ui.ui:123 alsa-sound-configuration-ui.ui:145
+#, no-c-format
+msgid " kB"
+msgstr ""
+
+#: alsa-sound-configuration-ui.ui:172
+#, no-c-format
+msgid "Buffer Size"
+msgstr ""
+
+#: alsa-sound-configuration-ui.ui:193
+#, no-c-format
+msgid "PCM Playback Device"
+msgstr ""
+
+#: alsa-sound-configuration-ui.ui:201
+#, no-c-format
+msgid "PCM Capture Device"
+msgstr ""
+
+#: alsa-sound-configuration-ui.ui:209
+#, no-c-format
+msgid "PCM Playback Card"
+msgstr ""
+
+#: alsa-sound-configuration-ui.ui:221
+#, no-c-format
+msgid "E&xtended Options"
+msgstr ""
+
+#: alsa-sound-configuration-ui.ui:235
+#, no-c-format
+msgid "Disable Pla&yback"
+msgstr ""
+
+#: alsa-sound-configuration-ui.ui:238
+#, no-c-format
+msgid "Alt+Y"
+msgstr ""
+
+#: alsa-sound-configuration-ui.ui:246
+#, no-c-format
+msgid "Disa&ble Capture"
+msgstr ""
+
+#: alsa-sound-configuration-ui.ui:249
+#, no-c-format
+msgid "Alt+B"
+msgstr ""
+
+#: alsa-sound-configuration-ui.ui:276
+#, no-c-format
+msgid "Capture Mixer Settings"
+msgstr ""