diff options
author | tpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2010-02-22 18:23:26 +0000 |
---|---|---|
committer | tpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2010-02-22 18:23:26 +0000 |
commit | ae364d9bed0589bf1a22cd5f530c563462379e3e (patch) | |
tree | e32727e2664e7ce68d0d30270afa040320ae35a1 /kradio3/plugins | |
download | tderadio-ae364d9bed0589bf1a22cd5f530c563462379e3e.tar.gz tderadio-ae364d9bed0589bf1a22cd5f530c563462379e3e.zip |
Added old KDE3 version of kradio
git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/applications/kradio@1094417 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'kradio3/plugins')
219 files changed, 33838 insertions, 0 deletions
diff --git a/kradio3/plugins/Makefile.am b/kradio3/plugins/Makefile.am new file mode 100644 index 0000000..3e9e46f --- /dev/null +++ b/kradio3/plugins/Makefile.am @@ -0,0 +1,4 @@ +INCLUDES = +METASOURCES = AUTO +SUBDIRS = gui-docking-menu gui-error-log gui-quickbar gui-standard-display $(PLUGIN_LIRC) \ + radio timecontrol v4lradio $(PLUGIN_OSS) soundserver recording timeshifter $(PLUGIN_ALSA) streaming diff --git a/kradio3/plugins/alsa-sound/Makefile.am b/kradio3/plugins/alsa-sound/Makefile.am new file mode 100644 index 0000000..a00e32c --- /dev/null +++ b/kradio3/plugins/alsa-sound/Makefile.am @@ -0,0 +1,20 @@ +SUBDIRS = po icons . + +INCLUDES = $(all_includes) +METASOURCES = AUTO + +libkradio_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/kradio-alsa-sound.pot + +messages: rc.cpp + $(EXTRACTRC) *.rc *.ui >> rc.cpp + $(XGETTEXT) rc.cpp *.h *.cpp -o po/kradio-alsa-sound.pot diff --git a/kradio3/plugins/alsa-sound/alsa-config-mixer-setting.cpp b/kradio3/plugins/alsa-sound/alsa-config-mixer-setting.cpp new file mode 100644 index 0000000..873b29e --- /dev/null +++ b/kradio3/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 <kconfig.h> + +AlsaConfigMixerSetting::AlsaConfigMixerSetting() + : m_card(-1), + m_name(QString::null), + m_use(false), + m_active(false), + m_volume(-1) +{ +} + +AlsaConfigMixerSetting::AlsaConfigMixerSetting(KConfig *c, const QString &prefix) +{ + m_card = c->readNumEntry (prefix+"card", -1); + m_name = c->readEntry (prefix+"name", QString::null); + 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 QString &name, bool use, bool active, float volume) + : m_card(card), + m_name(name), + m_use(use), + m_active(active), + m_volume(volume) +{ +} + +AlsaConfigMixerSetting::~AlsaConfigMixerSetting() +{ +} + +QString AlsaConfigMixerSetting::getIDString(int card, const QString &name) +{ + return QString::number(card) + "-" + name; +} + +void AlsaConfigMixerSetting::saveState(KConfig *c, const QString &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/kradio3/plugins/alsa-sound/alsa-config-mixer-setting.h b/kradio3/plugins/alsa-sound/alsa-config-mixer-setting.h new file mode 100644 index 0000000..a9f5d88 --- /dev/null +++ b/kradio3/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 <qstring.h> + +class KConfig; + +class AlsaConfigMixerSetting +{ +public: + AlsaConfigMixerSetting(); + AlsaConfigMixerSetting(KConfig *c, const QString &prefix); + AlsaConfigMixerSetting(int card, const QString &name, bool use, bool active, float volume); + ~AlsaConfigMixerSetting(); + + QString getIDString() const { return getIDString(m_card, m_name); } + static QString getIDString(int card, const QString &m_name); + + void saveState(KConfig *c, const QString &prefix) const; + + int m_card; + QString m_name; + bool m_use; + bool m_active; + float m_volume; +}; + +#endif diff --git a/kradio3/plugins/alsa-sound/alsa-mixer-element-ui.ui b/kradio3/plugins/alsa-sound/alsa-mixer-element-ui.ui new file mode 100644 index 0000000..e2c170d --- /dev/null +++ b/kradio3/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="QWidget"> + <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="QLayoutWidget"> + <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="QSlider"> + <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="QLayoutWidget"> + <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="QLayoutWidget"> + <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="QLayoutWidget"> + <property name="name"> + <cstring>layout4</cstring> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QCheckBox"> + <property name="name"> + <cstring>m_checkboxActive</cstring> + </property> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="text"> + <string>O&n</string> + </property> + <property name="accel"> + <string>Alt+N</string> + </property> + </widget> + <widget class="QCheckBox"> + <property name="name"> + <cstring>m_checkboxOverride</cstring> + </property> + <property name="text"> + <string>&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="QLabel"> + <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"/> +<includehints> + <includehint>knuminput.h</includehint> +</includehints> +</UI> diff --git a/kradio3/plugins/alsa-sound/alsa-mixer-element.cpp b/kradio3/plugins/alsa-sound/alsa-mixer-element.cpp new file mode 100644 index 0000000..1fbc75a --- /dev/null +++ b/kradio3/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 <qslider.h> +#include <qlabel.h> +#include <qcheckbox.h> + +#include <math.h> + +QAlsaMixerElement::QAlsaMixerElement(QWidget *parent, const QString &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); + + QObject::connect(m_spinboxVolume, SIGNAL(valueChanged(int)), + this, SLOT (slotSpinboxValueChanged(int))); + QObject::connect(m_sliderVolume, SIGNAL(valueChanged(int)), + this, SLOT (slotSliderValueChanged(int))); + + if (m_HasVolume) { + QObject::connect(m_checkboxOverride, SIGNAL(toggled(bool)), + m_spinboxVolume, SLOT (setEnabled(bool))); + QObject::connect(m_checkboxOverride, SIGNAL(toggled(bool)), + m_sliderVolume, SLOT (setEnabled(bool))); + } else { + m_spinboxVolume->hide(); + m_sliderVolume->hide(); + } + if (m_HasSwitch) { + QObject::connect(m_checkboxOverride, SIGNAL(toggled(bool)), + m_checkboxActive, SLOT (setEnabled(bool))); + } else { + //m_checkboxActive->hide(); + m_checkboxActive->setEnabled(false); + m_checkboxActive->setChecked(true); + } + + connect(m_checkboxOverride, SIGNAL(toggled(bool)), this, SLOT(slotSetDirty())); + connect(m_checkboxActive, SIGNAL(toggled(bool)), this, SLOT(slotSetDirty())); + connect(m_spinboxVolume, SIGNAL(valueChanged(int)), this, SLOT(slotSetDirty())); + connect(m_sliderVolume, SIGNAL(valueChanged(int)), this, 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 QString &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/kradio3/plugins/alsa-sound/alsa-mixer-element.h b/kradio3/plugins/alsa-sound/alsa-mixer-element.h new file mode 100644 index 0000000..149e0b9 --- /dev/null +++ b/kradio3/plugins/alsa-sound/alsa-mixer-element.h @@ -0,0 +1,62 @@ +/*************************************************************************** + 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(QWidget *parent, const QString &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 QString &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/kradio3/plugins/alsa-sound/alsa-sound-configuration-ui.ui b/kradio3/plugins/alsa-sound/alsa-sound-configuration-ui.ui new file mode 100644 index 0000000..d1d2105 --- /dev/null +++ b/kradio3/plugins/alsa-sound/alsa-sound-configuration-ui.ui @@ -0,0 +1,323 @@ +<!DOCTYPE UI><UI version="3.3" stdsetdef="1"> +<class>AlsaSoundConfigurationUI</class> +<widget class="QWidget"> + <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="QTabWidget" row="0" column="0"> + <property name="name"> + <cstring>kTabWidget8</cstring> + </property> + <widget class="QWidget"> + <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="QLayoutWidget" row="0" column="0"> + <property name="name"> + <cstring>layout58</cstring> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel" 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="QLabel" 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="QLabel" 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="QLabel" row="1" column="0"> + <property name="name"> + <cstring>textLabel2_3</cstring> + </property> + <property name="text"> + <string>PCM Playback Device</string> + </property> + </widget> + <widget class="QLabel" row="3" column="0"> + <property name="name"> + <cstring>textLabel2_4</cstring> + </property> + <property name="text"> + <string>PCM Capture Device</string> + </property> + </widget> + <widget class="QLabel" 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="QWidget"> + <property name="name"> + <cstring>TabPage</cstring> + </property> + <attribute name="title"> + <string>E&xtended Options</string> + </attribute> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>11</number> + </property> + <widget class="QCheckBox" row="0" column="0"> + <property name="name"> + <cstring>chkDisablePlayback</cstring> + </property> + <property name="text"> + <string>Disable Pla&yback</string> + </property> + <property name="accel"> + <string>Alt+Y</string> + </property> + </widget> + <widget class="QCheckBox" row="1" column="0"> + <property name="name"> + <cstring>chkDisableCapture</cstring> + </property> + <property name="text"> + <string>Disa&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="QWidget"> + <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="QGroupBox" 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"/> +<includehints> + <includehint>kcombobox.h</includehint> + <includehint>kcombobox.h</includehint> + <includehint>knuminput.h</includehint> + <includehint>knuminput.h</includehint> + <includehint>kcombobox.h</includehint> + <includehint>kcombobox.h</includehint> +</includehints> +</UI> diff --git a/kradio3/plugins/alsa-sound/alsa-sound-configuration.cpp b/kradio3/plugins/alsa-sound/alsa-sound-configuration.cpp new file mode 100644 index 0000000..f4914f2 --- /dev/null +++ b/kradio3/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 <qcheckbox.h> +#include <qgroupbox.h> +#include <qlayout.h> +#include <qscrollview.h> + +#include <kurlrequester.h> +#include <knuminput.h> +#include <klineedit.h> +#include <kcombobox.h> +#include <ktabwidget.h> +#include <klocale.h> + +#include "alsa-mixer-element.h" +#include "alsa-sound-configuration.h" +#include "alsa-sound.h" + + +AlsaSoundConfiguration::AlsaSoundConfiguration (QWidget *parent, AlsaSoundDevice *dev) + : AlsaSoundConfigurationUI(parent), + m_SoundDevice (dev), + m_groupMixerLayout(NULL), + m_groupMixerScrollView(NULL), + m_groupMixerSubFrame(NULL), + m_dirty(true), + m_ignore_updates(false) +{ + QObject::connect(m_comboPlaybackCard, SIGNAL(activated(int)), this, SLOT(slotSetDirty())); + QObject::connect(m_comboCaptureCard, SIGNAL(activated(int)), this, SLOT(slotSetDirty())); + QObject::connect(m_comboPlaybackDevice, SIGNAL(activated(int)), this, SLOT(slotSetDirty())); + QObject::connect(m_comboCaptureDevice, SIGNAL(activated(int)), this, SLOT(slotSetDirty())); + QObject::connect(editHWBufferSize, SIGNAL(valueChanged(int)), this, SLOT(slotSetDirty())); + QObject::connect(editBufferSize, SIGNAL(valueChanged(int)), this, SLOT(slotSetDirty())); + QObject::connect(chkDisablePlayback, SIGNAL(toggled(bool)), this, SLOT(slotSetDirty())); + QObject::connect(chkDisableCapture, SIGNAL(toggled(bool)), this, SLOT(slotSetDirty())); + + QObject::connect(m_comboPlaybackCard, SIGNAL(activated(const QString &)), + this, SLOT(slotPlaybackCardSelected(const QString &))); + QObject::connect(m_comboCaptureCard, SIGNAL(activated(const QString &)), + this, SLOT(slotCaptureCardSelected(const QString &))); + + m_groupMixer->setColumnLayout(0, Qt::Horizontal ); + + QHBoxLayout *tmp_layout = new QHBoxLayout( m_groupMixer->layout() ); + + m_groupMixerScrollView = new QScrollView (m_groupMixer); + m_groupMixerScrollView->setFrameShape(QFrame::NoFrame); + m_groupMixerScrollView->setFrameShadow(QFrame::Plain); + m_groupMixerScrollView->enableClipper(true); + m_groupMixerScrollView->setResizePolicy(QScrollView::AutoOneFit); + //m_groupMixerScrollView->setHScrollBarMode(QScrollView::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 QString &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 QString &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]; + + QStringList vol_list, sw_list, all_list; + QMap<QString, AlsaMixerElement> vol_ch2id, sw_ch2id; + AlsaSoundDevice::getCaptureMixerChannels(m_name2card[cardname], NULL, vol_list, vol_ch2id, sw_list, sw_ch2id, &all_list); + + for (QMapIterator<QString, QAlsaMixerElement*> it = m_MixerElements.begin(); it != m_MixerElements.end(); ++it) { + delete *it; + } + m_MixerElements.clear(); + + if (m_groupMixerSubFrame) + delete m_groupMixerSubFrame; + + m_groupMixerSubFrame = new QFrame(m_groupMixerScrollView->viewport()); + m_groupMixerSubFrame->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Maximum); + m_groupMixerScrollView->addChild(m_groupMixerSubFrame); + + int rows = 1; + int cols = (all_list.count()+rows-1)/rows; + m_groupMixerLayout = new QGridLayout( m_groupMixerSubFrame, rows, cols, 0, 0 ); + m_groupMixerLayout->setAlignment( Qt::AlignBottom ); + + int idx = 0; + for (QValueListConstIterator<QString> 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)); + QObject::connect(e, SIGNAL(sigDirty()), this, 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 (QMapIterator<QString, QAlsaMixerElement*> it = m_MixerElements.begin(); it != m_MixerElements.end(); ++it) { + const QString &name = it.key(); + int card = m_currentCaptureCard; + QString 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 (QMapIterator<QString, QAlsaMixerElement*> it = m_MixerElements.begin(); it != m_MixerElements.end(); ++it) { + const QString &name = it.key(); + int card = m_currentCaptureCard; + QString 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, QMap<QString, int> *devname2dev, QMap<int, QString> *dev2devname, QMap<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); + + QString ctlname = "hw:"+QString::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(QString("control digital audio info (%1): %2").arg(card).arg(snd_strerror(err))); + } + continue; + } + const char *dev_name = snd_pcm_info_get_name(pcminfo); + QString 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(QString("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(QString("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/kradio3/plugins/alsa-sound/alsa-sound-configuration.h b/kradio3/plugins/alsa-sound/alsa-sound-configuration.h new file mode 100644 index 0000000..0dd361a --- /dev/null +++ b/kradio3/plugins/alsa-sound/alsa-sound-configuration.h @@ -0,0 +1,83 @@ +/*************************************************************************** + 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 QHBoxLayout; +class QGridLayout; +class QAlsaMixerElement; +class QScrollView; +class QFrame; + +class AlsaSoundConfiguration : public AlsaSoundConfigurationUI +{ +Q_OBJECT +public : + AlsaSoundConfiguration (QWidget *parent, AlsaSoundDevice *); + ~AlsaSoundConfiguration (); + +protected slots: + + void slotOK(); + void slotCancel(); + + void slotSetDirty(); + + void slotUpdateConfig(); + + void slotPlaybackCardSelected(const QString &cardname); + void slotCaptureCardSelected(const QString &cardname); + +protected: + int listSoundDevices(KComboBox *combobox, QMap<QString, int> *devname2dev, QMap<int, QString> *dev2devname, QMap<int, int> *dev2idx, int card, snd_pcm_stream_t stream); + void saveCaptureMixerSettings(); + void restoreCaptureMixerSettings(); + + AlsaSoundDevice *m_SoundDevice; + int m_currentCaptureCard; + QMap<QString, int> m_name2card, + m_name2capturedevice, + m_playbackDeviceName2dev, + m_captureDeviceName2dev; + QMap<int, QString> m_card2name, + m_dev2playbackDeviceName, + m_dev2captureDeviceName; + QMap<int, int> m_captureCard2idx, + m_captureDevice2idx, + m_playbackCard2idx, + m_playbackDevice2idx; + QGridLayout *m_groupMixerLayout; + QScrollView *m_groupMixerScrollView; + QFrame *m_groupMixerSubFrame; + QMap<QString, QAlsaMixerElement*> m_MixerElements; + + QMap<QString, AlsaConfigMixerSetting> m_MixerSettings; + + bool m_dirty; + bool m_ignore_updates; +}; + +#endif diff --git a/kradio3/plugins/alsa-sound/alsa-sound.cpp b/kradio3/plugins/alsa-sound/alsa-sound.cpp new file mode 100644 index 0000000..d67d5c8 --- /dev/null +++ b/kradio3/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 <klocale.h> +#include <kaboutdata.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, "kradio-alsa-sound", i18n("Advanced Linux Sound Architecture (ALSA) Support")); + +///////////////////////////////////////////////////////////////////////////// + +struct _lrvol { unsigned char l, r; short dummy; }; + +AlsaSoundDevice::AlsaSoundDevice(const QString &name) + : QObject(NULL, NULL), + PluginBase(name, i18n("KRadio 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) +{ + QObject::connect(&m_PlaybackPollingTimer, SIGNAL(timeout()), this, SLOT(slotPollPlayback())); + QObject::connect(&m_CapturePollingTimer, SIGNAL(timeout()), this, 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 (KConfig *c) const +{ + c->setGroup(QString("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 (QMapConstIterator<QString, AlsaConfigMixerSetting> it = m_CaptureMixerSettings.begin(); it != m_CaptureMixerSettings.end(); ++it, ++i) { + + QString prefix = QString("mixer-setting-%1-").arg(i); + (*it).saveState(c, prefix); + } + +} + + +void AlsaSoundDevice::restoreState (KConfig *c) +{ + c->setGroup(QString("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) { + QString prefix = QString("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); + QObject::connect(this, SIGNAL(sigUpdateConfig()), conf, SLOT(slotUpdateConfig())); + return ConfigPageInfo (conf, + i18n("ALSA Sound"), + i18n("ALSA Sound Device Options"), + "kradio_alsa2"); +} + + +AboutPageInfo AlsaSoundDevice::createAboutPage() +{ +/* KAboutData aboutData("kradio", + NULL, + NULL, + I18N_NOOP("ALSA Sound Plugin for KRadio"), + KAboutData::License_GPL, + "(c) 2005 Martin Witte", + 0, + "http://sourceforge.net/projects/kradio", + 0); + aboutData.addAuthor("Martin Witte", "", "witte@kawo1.rwth-aachen.de"); + + return AboutPageInfo( + new KRadioAboutWidget(aboutData, KRadioAboutWidget::AbtTabbed), + i18n("ALSA Sound"), + i18n("ALSA Sound"), + "kradio_alsa_sound" + ); +*/ + return AboutPageInfo(); +} + + + +bool AlsaSoundDevice::preparePlayback(SoundStreamID id, const QString &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 QString &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(QString::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); + } + + QValueListConstIterator<SoundStreamID> end = m_PassivePlaybackStreams.end(); + for (QValueListConstIterator<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()) { +// QString dev = QString("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)); + } + + QString dev = QString("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; + + QString dev = QString("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; + + QString dev = QString("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(QString::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 == " + QString::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, QTimer *timer, int timer_latency) +{ + if (reopen) { + if (mixer_handle >= 0) + 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; + } + QString cardid = "hw:" + QString::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, QTimer *timer) +{ + if (!id.isValid() || force) { + + if (!pcm_handle && timer) + timer->stop(); + + if (mixer_handle) { + QString cardid = "hw:" + QString::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, + QStringList &retval, QMap<QString, 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); + QString 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, + QStringList &vol_list, QMap<QString, AlsaMixerElement> &vol_ch2id, + QStringList &sw_list, QMap<QString, AlsaMixerElement> &sw_ch2id, + QStringList *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 == " + QString::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); + QString 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 QStringList &AlsaSoundDevice::getPlaybackChannels() const +{ + return m_PlaybackChannels; +} + + +const QStringList &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 QString &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 QString &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 QString &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 QString &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 QString &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 QString &channel) +{ + writeCaptureMixerSwitch(channel, true); + + const QString 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 QString 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 QString WAVE = "Wave"; + if (m_CaptureChannels2ID.contains(WAVE)) { + float x = 0; + writeCaptureMixerVolume(WAVE, x); + } + const QString Capture = "Capture"; + if (m_CaptureChannelsSwitch2ID.contains(Capture)) { + writeCaptureMixerSwitch(Capture, true); + } + + for (QMapConstIterator<QString, 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 == " + QString::number(m_CaptureCard) + ", card == " + QString::number(card)); + if (m_CaptureCard == card && m_CaptureDevice == dev) + return; +// logDebug("AlsaSoundDevice::setCaptureDevice-2: m_CaptureCard == " + QString::number(m_CaptureCard) + ", card == " + QString::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); +} + + +QString 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 QMap<QString, AlsaConfigMixerSetting> &map) +{ + m_CaptureMixerSettings = map; +} + + + +// bool AlsaSoundDevice::event(QEvent *_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); +// QString 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 = QObject::event(_e); +// break; +// } +// +// return retval; +// } + + + + + + + + +#include "alsa-sound.moc" diff --git a/kradio3/plugins/alsa-sound/alsa-sound.h b/kradio3/plugins/alsa-sound/alsa-sound.h new file mode 100644 index 0000000..93a9fc8 --- /dev/null +++ b/kradio3/plugins/alsa-sound/alsa-sound.h @@ -0,0 +1,296 @@ +/*************************************************************************** + 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 <qobject.h> +#include <qtimer.h> +#include <alsa/asoundlib.h> + +enum DUPLEX_MODE { DUPLEX_UNKNOWN, DUPLEX_FULL, DUPLEX_HALF }; + + +struct SoundStreamConfig +{ + SoundStreamConfig() + : m_ActiveMode(false), + m_Channel(QString::null), + m_Volume(-1), + m_Muted(false) + {} + + SoundStreamConfig(const QString &_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; + QString 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 QObject, + public PluginBase, + public ISoundStreamClient +{ +Q_OBJECT + +public: + AlsaSoundDevice (const QString &name); + virtual ~AlsaSoundDevice (); + + virtual bool connectI(Interface *i); + virtual bool disconnectI(Interface *i); + + // PluginBase + +public: + virtual void saveState (KConfig *) const; + virtual void restoreState (KConfig *); + + virtual QString pluginClassName() const { return "AlsaSoundDevice"; } + + virtual const QString &name() const { return PluginBase::name(); } + virtual QString &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 QString &channel, bool active_mode, bool start_immediately); + bool prepareCapture(SoundStreamID id, const QString &channel); + bool releasePlayback(SoundStreamID id); + bool releaseCapture(SoundStreamID id); + +ANSWERS: + bool supportsPlayback() const; + bool supportsCapture() const; + + QString getSoundStreamClientDescription() const; + + // ISoundStreamClient: mixer access + +public: + static + void getPlaybackMixerChannels(int card, snd_mixer_t *mixer_handle, + QStringList &retval, QMap<QString, AlsaMixerElement> &int2id); + static + void getCaptureMixerChannels (int card, snd_mixer_t *mixer_handle, + QStringList &vol_list, QMap<QString, AlsaMixerElement> &vol_ch2id, + QStringList &sw_list, QMap<QString, AlsaMixerElement> &sw_ch2id, + QStringList *all_list = NULL); + +ANSWERS: + const QStringList &getPlaybackChannels() const; + const QStringList &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 QMap<QString, 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 QMap<QString, AlsaConfigMixerSetting> &map); + +protected slots: + + void slotPollPlayback(); + void slotPollCapture(); + +signals: + + void sigUpdateConfig(); + +protected: +// bool event(QEvent *_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, QTimer *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, QTimer *timer); + + void checkMixerVolume(SoundStreamID id); + float readPlaybackMixerVolume(const QString &channel, bool &muted) const; + float readCaptureMixerVolume(const QString &channel) const; + bool writePlaybackMixerVolume(const QString &channel, float &vol, bool muted); + bool writeCaptureMixerVolume(const QString &channel, float &vol); + bool writeCaptureMixerSwitch(const QString &channel, bool capture); + + void selectCaptureChannel (const QString &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; + + QStringList m_PlaybackChannels, + m_CaptureChannels, + m_CaptureChannelsSwitch; + + QMap<QString, AlsaMixerElement> m_PlaybackChannels2ID, + m_CaptureChannels2ID, + m_CaptureChannelsSwitch2ID; + + QMap<SoundStreamID, SoundStreamConfig> + m_PlaybackStreams, + m_CaptureStreams; + + QValueList<SoundStreamID> + m_PassivePlaybackStreams; + SoundStreamID m_PlaybackStreamID, + m_CaptureStreamID; + + size_t m_HWBufferSize; + size_t m_BufferSize; + RingBuffer m_PlaybackBuffer, + m_CaptureBuffer; + + unsigned m_CaptureRequestCounter; + Q_UINT64 m_CapturePos; + time_t m_CaptureStartTime; + + size_t //m_PlaybackSkipCount, + m_CaptureSkipCount; + + bool m_EnablePlayback, + m_EnableCapture; + + QTimer m_PlaybackPollingTimer; + QTimer m_CapturePollingTimer; + +// AlsaCaptureThread *m_captureThread; + + QMap<QString, AlsaConfigMixerSetting> m_CaptureMixerSettings; + +}; + + + +#endif diff --git a/kradio3/plugins/alsa-sound/icons/Makefile.am b/kradio3/plugins/alsa-sound/icons/Makefile.am new file mode 100644 index 0000000..b3f2583 --- /dev/null +++ b/kradio3/plugins/alsa-sound/icons/Makefile.am @@ -0,0 +1,2 @@ +icons_ICON = AUTO +iconsdir = $(kde_datadir)/kradio/icons diff --git a/kradio3/plugins/alsa-sound/icons/hi16-action-kradio_alsa.png b/kradio3/plugins/alsa-sound/icons/hi16-action-kradio_alsa.png Binary files differnew file mode 100644 index 0000000..a25cfd2 --- /dev/null +++ b/kradio3/plugins/alsa-sound/icons/hi16-action-kradio_alsa.png diff --git a/kradio3/plugins/alsa-sound/icons/hi16-action-kradio_alsa2.png b/kradio3/plugins/alsa-sound/icons/hi16-action-kradio_alsa2.png Binary files differnew file mode 100644 index 0000000..479a6cc --- /dev/null +++ b/kradio3/plugins/alsa-sound/icons/hi16-action-kradio_alsa2.png diff --git a/kradio3/plugins/alsa-sound/icons/hi22-action-kradio_alsa.png b/kradio3/plugins/alsa-sound/icons/hi22-action-kradio_alsa.png Binary files differnew file mode 100644 index 0000000..796b052 --- /dev/null +++ b/kradio3/plugins/alsa-sound/icons/hi22-action-kradio_alsa.png diff --git a/kradio3/plugins/alsa-sound/icons/hi22-action-kradio_alsa2.png b/kradio3/plugins/alsa-sound/icons/hi22-action-kradio_alsa2.png Binary files differnew file mode 100644 index 0000000..5e6cc22 --- /dev/null +++ b/kradio3/plugins/alsa-sound/icons/hi22-action-kradio_alsa2.png diff --git a/kradio3/plugins/alsa-sound/icons/hi32-action-kradio_alsa.png b/kradio3/plugins/alsa-sound/icons/hi32-action-kradio_alsa.png Binary files differnew file mode 100644 index 0000000..d1deb5d --- /dev/null +++ b/kradio3/plugins/alsa-sound/icons/hi32-action-kradio_alsa.png diff --git a/kradio3/plugins/alsa-sound/icons/hi32-action-kradio_alsa2.png b/kradio3/plugins/alsa-sound/icons/hi32-action-kradio_alsa2.png Binary files differnew file mode 100644 index 0000000..a849948 --- /dev/null +++ b/kradio3/plugins/alsa-sound/icons/hi32-action-kradio_alsa2.png diff --git a/kradio3/plugins/alsa-sound/icons/hi48-action-kradio_alsa.png b/kradio3/plugins/alsa-sound/icons/hi48-action-kradio_alsa.png Binary files differnew file mode 100644 index 0000000..aa89348 --- /dev/null +++ b/kradio3/plugins/alsa-sound/icons/hi48-action-kradio_alsa.png diff --git a/kradio3/plugins/alsa-sound/icons/hi48-action-kradio_alsa2.png b/kradio3/plugins/alsa-sound/icons/hi48-action-kradio_alsa2.png Binary files differnew file mode 100644 index 0000000..802f64f --- /dev/null +++ b/kradio3/plugins/alsa-sound/icons/hi48-action-kradio_alsa2.png diff --git a/kradio3/plugins/alsa-sound/icons/hi64-action-kradio_alsa.png b/kradio3/plugins/alsa-sound/icons/hi64-action-kradio_alsa.png Binary files differnew file mode 100644 index 0000000..fef1ba3 --- /dev/null +++ b/kradio3/plugins/alsa-sound/icons/hi64-action-kradio_alsa.png diff --git a/kradio3/plugins/alsa-sound/icons/hi64-action-kradio_alsa2.png b/kradio3/plugins/alsa-sound/icons/hi64-action-kradio_alsa2.png Binary files differnew file mode 100644 index 0000000..1489f65 --- /dev/null +++ b/kradio3/plugins/alsa-sound/icons/hi64-action-kradio_alsa2.png diff --git a/kradio3/plugins/alsa-sound/icons/kradio_alsa.png b/kradio3/plugins/alsa-sound/icons/kradio_alsa.png Binary files differnew file mode 100644 index 0000000..11b3ce4 --- /dev/null +++ b/kradio3/plugins/alsa-sound/icons/kradio_alsa.png diff --git a/kradio3/plugins/alsa-sound/icons/kradio_alsa2.png b/kradio3/plugins/alsa-sound/icons/kradio_alsa2.png Binary files differnew file mode 100644 index 0000000..82d97c0 --- /dev/null +++ b/kradio3/plugins/alsa-sound/icons/kradio_alsa2.png diff --git a/kradio3/plugins/alsa-sound/po/Makefile.am b/kradio3/plugins/alsa-sound/po/Makefile.am new file mode 100644 index 0000000..9de3420 --- /dev/null +++ b/kradio3/plugins/alsa-sound/po/Makefile.am @@ -0,0 +1,3 @@ + +PACKAGE = kradio-alsa-sound +POFILES = AUTO diff --git a/kradio3/plugins/alsa-sound/po/de.po b/kradio3/plugins/alsa-sound/po/de.po new file mode 100644 index 0000000..9c47ebc --- /dev/null +++ b/kradio3/plugins/alsa-sound/po/de.po @@ -0,0 +1,289 @@ +# translation of de.po to +# translation of kradio-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: 2006-11-12 18:41+0100\n" +"PO-Revision-Date: 2006-11-12 18:23+0100\n" +"Last-Translator: Ernst Martin Witte <emw@nocabal.de>\n" +"Language-Team: <de@li.org>\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: KBabel 1.11.4\n" + +#. i18n: file alsa-mixer-element-ui.ui line 16 +#: rc.cpp:3 rc.cpp:70 alsa-mixer-element-ui.cpp:104 +#, no-c-format +msgid "Form1" +msgstr "Form1" + +#. i18n: file alsa-mixer-element-ui.ui line 210 +#: rc.cpp:6 rc.cpp:73 alsa-mixer-element-ui.cpp:105 +#, no-c-format +msgid "O&n" +msgstr "A&n" + +#. i18n: file alsa-mixer-element-ui.ui line 213 +#: rc.cpp:9 rc.cpp:76 alsa-mixer-element-ui.cpp:106 +#, no-c-format +msgid "Alt+N" +msgstr "Alt+N" + +#. i18n: file alsa-mixer-element-ui.ui line 221 +#: rc.cpp:12 rc.cpp:79 alsa-mixer-element-ui.cpp:107 +#, no-c-format +msgid "&Use" +msgstr "&Verwenden" + +#. i18n: file alsa-mixer-element-ui.ui line 224 +#: rc.cpp:15 rc.cpp:82 alsa-mixer-element-ui.cpp:108 +#, no-c-format +msgid "Alt+U" +msgstr "Alt+U" + +#. i18n: file alsa-mixer-element-ui.ui line 256 +#: rc.cpp:18 rc.cpp:85 alsa-mixer-element-ui.cpp:109 +#, no-c-format +msgid "MixerName" +msgstr "MixerName" + +#. i18n: file alsa-sound-configuration-ui.ui line 16 +#: rc.cpp:21 rc.cpp:88 alsa-sound-configuration-ui.cpp:152 +#, no-c-format +msgid "AlsaSoundConfigurationUI" +msgstr "AlsaSoundConfigurationUI" + +#. i18n: file alsa-sound-configuration-ui.ui line 34 +#: rc.cpp:24 rc.cpp:91 alsa-sound-configuration-ui.cpp:161 +#, no-c-format +msgid "Devices" +msgstr "Geräte" + +#. i18n: file alsa-sound-configuration-ui.ui line 73 +#: rc.cpp:27 rc.cpp:94 alsa-sound-configuration-ui.cpp:153 +#, no-c-format +msgid "PCM Capture Card" +msgstr "Soundkarte für die Aufnahme" + +#. i18n: file alsa-sound-configuration-ui.ui line 94 +#: rc.cpp:30 rc.cpp:97 alsa-sound-configuration-ui.cpp:154 +#, no-c-format +msgid "Hardware Buffer Size" +msgstr "Hardware-Puffergröße" + +#. i18n: file alsa-sound-configuration-ui.ui line 123 +#. i18n: file alsa-sound-configuration-ui.ui line 145 +#. i18n: file alsa-sound-configuration-ui.ui line 123 +#. i18n: file alsa-sound-configuration-ui.ui line 145 +#: rc.cpp:33 rc.cpp:36 rc.cpp:100 rc.cpp:103 +#: alsa-sound-configuration-ui.cpp:155 alsa-sound-configuration-ui.cpp:156 +#, no-c-format +msgid " kB" +msgstr " kB" + +#. i18n: file alsa-sound-configuration-ui.ui line 172 +#: rc.cpp:39 rc.cpp:106 alsa-sound-configuration-ui.cpp:157 +#, no-c-format +msgid "Buffer Size" +msgstr "Puffergröße" + +#. i18n: file alsa-sound-configuration-ui.ui line 193 +#: rc.cpp:42 rc.cpp:109 alsa-sound-configuration-ui.cpp:158 +#, no-c-format +msgid "PCM Playback Device" +msgstr "Gerät für die Wiedergabe" + +#. i18n: file alsa-sound-configuration-ui.ui line 201 +#: rc.cpp:45 rc.cpp:112 alsa-sound-configuration-ui.cpp:159 +#, no-c-format +msgid "PCM Capture Device" +msgstr "Gerät für die Aufnahme" + +#. i18n: file alsa-sound-configuration-ui.ui line 209 +#: rc.cpp:48 rc.cpp:115 alsa-sound-configuration-ui.cpp:160 +#, no-c-format +msgid "PCM Playback Card" +msgstr "Soundkarte für die Wiedergabe" + +#. i18n: file alsa-sound-configuration-ui.ui line 221 +#: rc.cpp:51 rc.cpp:118 alsa-sound-configuration-ui.cpp:166 +#, no-c-format +msgid "E&xtended Options" +msgstr "Erweiterte Optionen" + +#. i18n: file alsa-sound-configuration-ui.ui line 235 +#: rc.cpp:54 rc.cpp:121 alsa-sound-configuration-ui.cpp:162 +#, no-c-format +msgid "Disable Pla&yback" +msgstr "Wiedergabe abschalten" + +#. i18n: file alsa-sound-configuration-ui.ui line 238 +#: rc.cpp:57 rc.cpp:124 alsa-sound-configuration-ui.cpp:163 +#, no-c-format +msgid "Alt+Y" +msgstr "Alt+Y" + +#. i18n: file alsa-sound-configuration-ui.ui line 246 +#: rc.cpp:60 rc.cpp:127 alsa-sound-configuration-ui.cpp:164 +#, no-c-format +msgid "Disa&ble Capture" +msgstr "Aufnahme abschalten" + +#. i18n: file alsa-sound-configuration-ui.ui line 249 +#: rc.cpp:63 rc.cpp:130 alsa-sound-configuration-ui.cpp:165 +#, no-c-format +msgid "Alt+B" +msgstr "Alt+B" + +#. i18n: file alsa-sound-configuration-ui.ui line 276 +#: rc.cpp:66 rc.cpp:133 alsa-sound-configuration-ui.cpp:168 +#, no-c-format +msgid "Capture Mixer Settings" +msgstr "Mixereinstellungen für die Aufnahme" + +#: _translatorinfo.cpp:1 +msgid "" +"_: NAME OF TRANSLATORS\n" +"Your names" +msgstr "Ernst Martin Witte" + +#: _translatorinfo.cpp:3 +msgid "" +"_: EMAIL OF TRANSLATORS\n" +"Your emails" +msgstr "emw@nocabal.de" + +#: alsa-sound-configuration.cpp:258 +msgid "context-card-plus-device-number" +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 "KRadio ALSA Sound Plugin" +msgstr "KRadio ALSA Sound Plugin" + +#: 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 +msgid "ALSA Plugin: Error opening PCM device %1" +msgstr "ALSA Plugin: Fehler beim Öffnen des Gerätes %1" + +#: alsa-sound.cpp:741 +msgid "ALSA Plugin: Can not configure PCM device %1" +msgstr "ALSA Plugin: Das Konfigurieren des Gerätes %1 schlug fehl" + +#: alsa-sound.cpp:748 +msgid "ALSA Plugin: Error setting access for %1" +msgstr "ALSA Plugin: Fehler beim Konfigurieren des Zugriffsmodus auf Gerät %1" + +#: alsa-sound.cpp:758 +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 +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 +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 +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 +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 +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 +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 +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" +msgstr "%1 - %2" + +#: alsa-sound.cpp:1053 +msgid "context-mixerelement-name-number" +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 +msgid "ALSA Sound Device %1" +msgstr "ALSA Soundkarte %1" diff --git a/kradio3/plugins/alsa-sound/po/ru.po b/kradio3/plugins/alsa-sound/po/ru.po new file mode 100644 index 0000000..afdd1cc --- /dev/null +++ b/kradio3/plugins/alsa-sound/po/ru.po @@ -0,0 +1,288 @@ +# translation of ru.po to +# translation of kradio-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: 2006-11-12 18:20+0100\n" +"PO-Revision-Date: 2006-11-08 12:15+0300\n" +"Last-Translator: Алексей Кузнецов <Alexey.Kouznetsov@GMail.com>\n" +"Language-Team: <ru@li.org>\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" + +#. i18n: file alsa-mixer-element-ui.ui line 16 +#: rc.cpp:3 rc.cpp:70 alsa-mixer-element-ui.cpp:104 +#, no-c-format +msgid "Form1" +msgstr "Form1" + +#. i18n: file alsa-mixer-element-ui.ui line 210 +#: rc.cpp:6 rc.cpp:73 alsa-mixer-element-ui.cpp:105 +#, no-c-format +msgid "O&n" +msgstr "&Вкл." + +#. i18n: file alsa-mixer-element-ui.ui line 213 +#: rc.cpp:9 rc.cpp:76 alsa-mixer-element-ui.cpp:106 +#, no-c-format +msgid "Alt+N" +msgstr "Alt+N" + +#. i18n: file alsa-mixer-element-ui.ui line 221 +#: rc.cpp:12 rc.cpp:79 alsa-mixer-element-ui.cpp:107 +#, no-c-format +msgid "&Use" +msgstr "&Исп." + +#. i18n: file alsa-mixer-element-ui.ui line 224 +#: rc.cpp:15 rc.cpp:82 alsa-mixer-element-ui.cpp:108 +#, no-c-format +msgid "Alt+U" +msgstr "Alt+U" + +#. i18n: file alsa-mixer-element-ui.ui line 256 +#: rc.cpp:18 rc.cpp:85 alsa-mixer-element-ui.cpp:109 +#, no-c-format +msgid "MixerName" +msgstr "" + +#. i18n: file alsa-sound-configuration-ui.ui line 16 +#: rc.cpp:21 rc.cpp:88 alsa-sound-configuration-ui.cpp:152 +#, no-c-format +msgid "AlsaSoundConfigurationUI" +msgstr "AlsaSoundConfigurationUI" + +#. i18n: file alsa-sound-configuration-ui.ui line 34 +#: rc.cpp:24 rc.cpp:91 alsa-sound-configuration-ui.cpp:161 +#, no-c-format +msgid "Devices" +msgstr "Устройства" + +#. i18n: file alsa-sound-configuration-ui.ui line 73 +#: rc.cpp:27 rc.cpp:94 alsa-sound-configuration-ui.cpp:153 +#, no-c-format +msgid "PCM Capture Card" +msgstr "Плата для захвата" + +#. i18n: file alsa-sound-configuration-ui.ui line 94 +#: rc.cpp:30 rc.cpp:97 alsa-sound-configuration-ui.cpp:154 +#, no-c-format +msgid "Hardware Buffer Size" +msgstr "Аппаратный размер буфера" + +#. i18n: file alsa-sound-configuration-ui.ui line 123 +#. i18n: file alsa-sound-configuration-ui.ui line 145 +#. i18n: file alsa-sound-configuration-ui.ui line 123 +#. i18n: file alsa-sound-configuration-ui.ui line 145 +#: rc.cpp:33 rc.cpp:36 rc.cpp:100 rc.cpp:103 +#: alsa-sound-configuration-ui.cpp:155 alsa-sound-configuration-ui.cpp:156 +#, no-c-format +msgid " kB" +msgstr " кБ" + +#. i18n: file alsa-sound-configuration-ui.ui line 172 +#: rc.cpp:39 rc.cpp:106 alsa-sound-configuration-ui.cpp:157 +#, no-c-format +msgid "Buffer Size" +msgstr "Размер буфера" + +#. i18n: file alsa-sound-configuration-ui.ui line 193 +#: rc.cpp:42 rc.cpp:109 alsa-sound-configuration-ui.cpp:158 +#, no-c-format +msgid "PCM Playback Device" +msgstr "Устройство воспроизведения" + +#. i18n: file alsa-sound-configuration-ui.ui line 201 +#: rc.cpp:45 rc.cpp:112 alsa-sound-configuration-ui.cpp:159 +#, no-c-format +msgid "PCM Capture Device" +msgstr "Устройство записи" + +#. i18n: file alsa-sound-configuration-ui.ui line 209 +#: rc.cpp:48 rc.cpp:115 alsa-sound-configuration-ui.cpp:160 +#, no-c-format +msgid "PCM Playback Card" +msgstr "Плата для проигрывания" + +#. i18n: file alsa-sound-configuration-ui.ui line 221 +#: rc.cpp:51 rc.cpp:118 alsa-sound-configuration-ui.cpp:166 +#, no-c-format +msgid "E&xtended Options" +msgstr "&Дополнительные параметры" + +#. i18n: file alsa-sound-configuration-ui.ui line 235 +#: rc.cpp:54 rc.cpp:121 alsa-sound-configuration-ui.cpp:162 +#, no-c-format +msgid "Disable Pla&yback" +msgstr "Запретить &воспроизведение" + +#. i18n: file alsa-sound-configuration-ui.ui line 238 +#: rc.cpp:57 rc.cpp:124 alsa-sound-configuration-ui.cpp:163 +#, no-c-format +msgid "Alt+Y" +msgstr "Alt+Y" + +#. i18n: file alsa-sound-configuration-ui.ui line 246 +#: rc.cpp:60 rc.cpp:127 alsa-sound-configuration-ui.cpp:164 +#, no-c-format +msgid "Disa&ble Capture" +msgstr "Запретить &запись" + +#. i18n: file alsa-sound-configuration-ui.ui line 249 +#: rc.cpp:63 rc.cpp:130 alsa-sound-configuration-ui.cpp:165 +#, no-c-format +msgid "Alt+B" +msgstr "Alt+B" + +#. i18n: file alsa-sound-configuration-ui.ui line 276 +#: rc.cpp:66 rc.cpp:133 alsa-sound-configuration-ui.cpp:168 +#, no-c-format +msgid "Capture Mixer Settings" +msgstr "&Параметры микшера для записи" + +#: _translatorinfo.cpp:1 +msgid "" +"_: NAME OF TRANSLATORS\n" +"Your names" +msgstr "Алексей Кузнецов" + +#: _translatorinfo.cpp:3 +msgid "" +"_: EMAIL OF TRANSLATORS\n" +"Your emails" +msgstr "Alexey.Kouznetsov@GMail.com" + +#: alsa-sound-configuration.cpp:258 +msgid "context-card-plus-device-number" +msgstr "" + +#: alsa-sound.cpp:40 +msgid "Advanced Linux Sound Architecture (ALSA) Support" +msgstr "Поддержка Расширенной звуковой архитектуры Linux (ALSA)" + +#: alsa-sound.cpp:48 +msgid "KRadio ALSA Sound Plugin" +msgstr "Модуль ALSA для KRadio" + +#: 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 +msgid "ALSA Plugin: Error opening PCM device %1" +msgstr "Модуль ALSA: Ошибка при открытии устройства PCM: %1" + +#: alsa-sound.cpp:741 +msgid "ALSA Plugin: Can not configure PCM device %1" +msgstr "Модуль ALSA: не могу настроить устройство PCM %1" + +#: alsa-sound.cpp:748 +msgid "ALSA Plugin: Error setting access for %1" +msgstr "" + +#: alsa-sound.cpp:758 +msgid "ALSA Plugin: Error setting sample format for %1" +msgstr "Модуль ALSA: ошибка при установке формата данных для %1" + +#: alsa-sound.cpp:764 +msgid "ALSA Plugin: Error setting channels for %1" +msgstr "Модуль ALSA: ошибка при установке числа каналов для %1" + +#: alsa-sound.cpp:771 +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 +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 +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 +msgid "ALSA Plugin: ERROR: snd_mixer_attach for card %1" +msgstr "Модуль ALSA: ошибка при вызове функции snd_mixer_attach для платы %1" + +#: alsa-sound.cpp:934 +msgid "ALSA Plugin: Error: snd_mixer_selem_register for card %1" +msgstr "" +"Модуль ALSA: ошибка при вызове функции snd_mixer_selem_register для платы %1" + +#: alsa-sound.cpp:938 +msgid "ALSA Plugin: Error: snd_mixer_load for card %1" +msgstr "Модуль ALSA: ошибка при вызове функции snd_mixer_load для платы %1" + +#: alsa-sound.cpp:1006 +msgid "context-mixername-number" +msgstr "context-mixername-number" + +#: alsa-sound.cpp:1053 +msgid "context-mixerelement-name-number" +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 +msgid "ALSA Sound Device %1" +msgstr "Устройство ALSA: %1" diff --git a/kradio3/plugins/gui-docking-menu/Makefile.am b/kradio3/plugins/gui-docking-menu/Makefile.am new file mode 100644 index 0000000..be50ef5 --- /dev/null +++ b/kradio3/plugins/gui-docking-menu/Makefile.am @@ -0,0 +1,18 @@ +SUBDIRS = po . + +INCLUDES = -I$(top_builddir)/kradio3/src $(all_includes) +METASOURCES = AUTO + +libkradio_LTLIBRARIES = libdocking-menu.la +libdocking_menu_la_SOURCES = docking-configuration.cpp docking.cpp +libdocking_menu_la_LDFLAGS = -module -avoid-version $(KDE_RPATH) $(all_libraries) + +noinst_HEADERS = docking-configuration.h docking.h + + +#messages: rc.cpp +# $(XGETTEXT) *.cpp *.h -o po/kradio-gui-docking-menu.pot + +messages: rc.cpp + $(EXTRACTRC) *.rc *.ui >> rc.cpp + $(XGETTEXT) rc.cpp *.h *.cpp -o po/kradio-gui-docking-menu.pot diff --git a/kradio3/plugins/gui-docking-menu/docking-configuration.cpp b/kradio3/plugins/gui-docking-menu/docking-configuration.cpp new file mode 100644 index 0000000..3e32c64 --- /dev/null +++ b/kradio3/plugins/gui-docking-menu/docking-configuration.cpp @@ -0,0 +1,114 @@ +/*************************************************************************** + docking-configuration.cpp - description + ------------------- + begin : Son Aug 3 2003 + copyright : (C) 2003 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 "docking-configuration.h" + +#include <qcombobox.h> +#include <qlabel.h> +#include <qlayout.h> +#include <qframe.h> + +#include <klocale.h> + +using namespace std; + +DockingConfiguration::DockingConfiguration (RadioDocking *docking, QWidget *parent) + : StationSelector(parent), + m_docking(docking), + m_disableGUIUpdates(false) +{ + QHBoxLayout *layout = new QHBoxLayout(); + QHBoxLayout *layout2 = new QHBoxLayout(); + + m_labelClickMode = new QLabel(this); + layout->addWidget(m_labelClickMode); + + m_comboClickMode = new QComboBox(this); + layout->addWidget(m_comboClickMode); + + QSpacerItem *spacer = new QSpacerItem( 20, 2, QSizePolicy::Expanding, QSizePolicy::Minimum); + layout->addItem(spacer); + + QFrame *line = new QFrame(this); + line->setFrameShape ( QFrame::HLine ); + line->setFrameShadow( QFrame::Sunken ); + layout2->addWidget(line); + + StationSelectorUILayout->expand(2,0); + StationSelectorUILayout->addMultiCellLayout(layout2, 2, 2, 0, 2); + StationSelectorUILayout->addMultiCellLayout(layout, 3, 3, 0, 2); + + connect(m_comboClickMode, SIGNAL(activated( int )), this, SLOT(slotSetDirty())); + + languageChange(); + slotCancel(); +} + + +DockingConfiguration::~DockingConfiguration () +{ +} + + +void DockingConfiguration::languageChange() +{ + StationSelector::languageChange(); + m_labelClickMode->setText( i18n( "Left Mouse Click on Tray" ) ); + + m_comboClickMode->clear(); + m_comboClickMode->insertItem(i18n("Show/Hide all GUI Elements")); + m_comboClickMode->insertItem(i18n("Power On/Off")); +} + +void DockingConfiguration::slotOK() +{ + if (m_dirty) { + StationSelector::slotOK(); + bool old = m_disableGUIUpdates; + m_disableGUIUpdates = true; + if (m_docking) + m_docking->setLeftClickAction((LeftClickAction)m_comboClickMode->currentItem()); + m_disableGUIUpdates = old; + m_dirty = false; + } +} + +void DockingConfiguration::slotCancel() +{ + if (m_dirty) { + StationSelector::slotCancel(); + if (m_docking) + m_comboClickMode->setCurrentItem(m_docking->getLeftClickAction()); + m_dirty = false; + } +} + +void DockingConfiguration::slotLeftClickActionChanged(LeftClickAction action) +{ + if (!m_disableGUIUpdates) { + if (m_docking) + m_comboClickMode->setCurrentItem(action); + } +} + +void DockingConfiguration::slotSetDirty() +{ + m_dirty = true; +} + + +#include "docking-configuration.moc" diff --git a/kradio3/plugins/gui-docking-menu/docking-configuration.h b/kradio3/plugins/gui-docking-menu/docking-configuration.h new file mode 100644 index 0000000..77b17cf --- /dev/null +++ b/kradio3/plugins/gui-docking-menu/docking-configuration.h @@ -0,0 +1,54 @@ +/*************************************************************************** + docking-configuration.h - description + ------------------- + begin : Son Aug 3 2003 + copyright : (C) 2003 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_DOCKING_CONFIGURATION_H +#define KRADIO_DOCKING_CONFIGURATION_H + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "../../src/include/stationselector.h" +#include "docking.h" + +class QComboBox; +class QLabel; + +class DockingConfiguration : public StationSelector +{ +Q_OBJECT +public : + DockingConfiguration (RadioDocking *docking, QWidget *parent); + ~DockingConfiguration (); + +protected slots: + + void slotOK(); + void slotCancel(); + void slotSetDirty(); + + void slotLeftClickActionChanged(LeftClickAction action); + void languageChange(); + +protected: + RadioDocking *m_docking; + QComboBox *m_comboClickMode; + QLabel *m_labelClickMode; + bool m_disableGUIUpdates; +}; + +#endif diff --git a/kradio3/plugins/gui-docking-menu/docking.cpp b/kradio3/plugins/gui-docking-menu/docking.cpp new file mode 100644 index 0000000..e39ae32 --- /dev/null +++ b/kradio3/plugins/gui-docking-menu/docking.cpp @@ -0,0 +1,674 @@ +/*************************************************************************** + docking.cpp - description + ------------------- + begin : Don Mr 8 21:57:17 CET 2001 + copyright : (C) 2002 by Ernst 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 <kiconloader.h> +#include <qtooltip.h> +#include <kpopupmenu.h> +#include <kapplication.h> +#include <kaction.h> +#include <kdialogbase.h> +#include <kaboutdata.h> +#include <kconfig.h> +#include <kwin.h> + +#include "../../src/include/radiodevice_interfaces.h" +#include "../../src/include/stationlist.h" +#include "../../src/include/pluginmanager.h" +#include "../../src/include/widgetplugins.h" +#include "../../src/include/radiostation.h" +#include "../../src/include/aboutwidget.h" +#include "../../src/include/station-drag-object.h" + +#include "docking.h" +#include "docking-configuration.h" + +#define POPUP_ID_START_RECORDING_DEFAULT 0 +#define POPUP_ID_STOP_RECORDING_BASE 100 + +/////////////////////////////////////////////////////////////////////// + +PLUGIN_LIBRARY_FUNCTIONS(RadioDocking, "kradio-gui-docking-menu", i18n("Tray Menu for KRadio")); + +///////////////////////////////////////////////////////////////////////////// + +RadioDocking::RadioDocking(const QString &name) + : KSystemTray (NULL, name.ascii()), + PluginBase(name, i18n("Docking Plugin")), + m_pluginMenu(NULL), + m_recordingMenu(NULL), + m_NextRecordingMenuID(POPUP_ID_STOP_RECORDING_BASE), + m_leftClickAction(lcaShowHide) +{ + setPixmap(BarIcon("kradio")); + + m_menu = contextMenu(); + QObject::connect(m_menu, SIGNAL(activated(int)), + this, SLOT(slotMenuItemActivated(int))); + + buildContextMenu (); + show(); + setAcceptDrops(true); +} + +RadioDocking::~RadioDocking() +{ +} + + +bool RadioDocking::connectI (Interface *i) +{ + bool a = IRadioClient::connectI(i); + bool b = ITimeControlClient::connectI(i); + bool c = IRadioDevicePoolClient::connectI(i); + bool d = IStationSelection::connectI(i); + bool e = ISoundStreamClient::connectI(i); + bool f = PluginBase::connectI(i); + return a || b || c || d || e || f; +} + + +bool RadioDocking::disconnectI (Interface *i) +{ + bool a = IRadioClient::disconnectI(i); + bool b = ITimeControlClient::disconnectI(i); + bool c = IRadioDevicePoolClient::disconnectI(i); + bool d = IStationSelection::disconnectI(i); + bool e = ISoundStreamClient::disconnectI(i); + bool f = PluginBase::disconnectI(i); + return a || b || c || d || e || f; +} + + +void RadioDocking::noticeConnectedI (ISoundStreamServer *s, bool pointer_valid) +{ + ISoundStreamClient::noticeConnectedI(s, pointer_valid); + if (s && pointer_valid) { + s->register4_sendStartRecordingWithFormat(this); + s->register4_sendStopRecording (this); + s->register4_notifySoundStreamChanged (this); + } +} + + + +bool RadioDocking::setStationSelection(const QStringList &sl) +{ + if (m_stationIDs != sl) { + m_stationIDs = sl; + buildContextMenu(); + notifyStationSelectionChanged(m_stationIDs); + } + return true; +} + + +// PluginBase + +void RadioDocking::restoreState (KConfig *config) +{ + config->setGroup(QString("radiodocking-") + name()); + + m_stationIDs.clear(); + int nStations = config->readNumEntry("nStations", 0); + for (int i = 1; i <= nStations; ++i) { + QString s = config->readEntry(QString("stationID-") + QString().setNum(i), QString::null); + if (s.length()) + m_stationIDs += s; + } + + m_leftClickAction = (LeftClickAction)config->readNumEntry("left_click_action", lcaShowHide); + + buildContextMenu(); + notifyStationSelectionChanged(m_stationIDs); + + int n = config->readNumEntry("show_hide_cache_entries", 0); + for (int i = 1; i <= n; ++i) { + QString s = config->readEntry(QString("show_hide_cache_id_%1").arg(i), QString::null); + bool b = config->readBoolEntry(QString("show_hide_cache_value_%1").arg(i), false); + if (!s.isNull()) { + m_widgetsShownCache.insert(s,b); + } + } +} + + +void RadioDocking::saveState (KConfig *config) const +{ + config->setGroup(QString("radiodocking-") + name()); + + config->writeEntry("nStations", m_stationIDs.size()); + int i = 1; + QStringList::const_iterator end = m_stationIDs.end(); + for (QStringList::const_iterator it = m_stationIDs.begin(); it != end; ++it, ++i) { + config->writeEntry(QString("stationID-") + QString().setNum(i), *it); + } + config->writeEntry("left_click_action", (int)m_leftClickAction); + + config->writeEntry("show_hide_cache_entries", m_widgetsShownCache.count()); + i = 1; + for (QMapConstIterator<QString, bool> it = m_widgetsShownCache.begin(); it != m_widgetsShownCache.end(); ++it, ++i) { + config->writeEntry(QString("show_hide_cache_id_%1").arg(i), it.key()); + config->writeEntry(QString("show_hide_cache_value_%1").arg(i), *it); + } +} + + +ConfigPageInfo RadioDocking::createConfigurationPage() +{ + DockingConfiguration *conf = new DockingConfiguration(this, NULL); + connectI (conf); + + QObject::connect(this, SIGNAL(sigLeftClickActionChanged(LeftClickAction)), + conf, SLOT(slotLeftClickActionChanged(LeftClickAction))); + + return ConfigPageInfo( + conf, + i18n("Docking Menu"), + i18n("Docking Menu Configuration"), + "kmenuedit" + ); +} + +AboutPageInfo RadioDocking::createAboutPage() +{ +/* KAboutData aboutData("kradio", + NULL, + NULL, + I18N_NOOP("Docking Menu for KRadio"), + KAboutData::License_GPL, + "(c) 2002-2005 Martin Witte, Klas Kalass", + 0, + "http://sourceforge.net/projects/kradio", + 0); + aboutData.addAuthor("Martin Witte", "", "witte@kawo1.rwth-aachen.de"); + aboutData.addAuthor("Klas Kalass", "", "klas.kalass@gmx.de"); + + return AboutPageInfo( + new KRadioAboutWidget(aboutData, KRadioAboutWidget::AbtTabbed), + i18n("Docking Menu"), + i18n("Docking Menu Plugin"), + "kmenuedit" + );*/ + return AboutPageInfo(); +} + + + +void RadioDocking::buildContextMenu() +{ + m_menu->clear(); + m_pluginMenu = NULL; + m_recordingMenu = NULL; + + m_titleID = m_menu->insertTitle ("title-dummy"); + + buildStationList(); + + m_alarmID = m_menu->insertTitle ("alarm-dummy"); + noticeNextAlarmChanged(queryNextAlarm()); + + m_sleepID = m_menu->insertItem(SmallIcon("kradio_zzz"), "sleep-dummy", + this, SLOT(slotSleepCountdown())); + noticeCountdownStarted(queryCountdownEnd()); + + m_seekfwID = m_menu->insertItem(SmallIcon("forward"), i18n("Search Next Station"), + this, SLOT(slotSeekFwd())); + m_seekbwID = m_menu->insertItem(SmallIcon("back"), i18n("Search Previous Station"), + this, SLOT(slotSeekBkwd())); + + // recording menu + buildRecordingMenu(); + m_menu->insertItem(i18n("Recording"), m_recordingMenu); + + + m_powerID = m_menu->insertItem(SmallIcon("kradio_muteoff"), "power-dummy", + this, SLOT(slotPower())); + m_pauseID = m_menu->insertItem(SmallIcon("kradio_pause"), i18n("Pause Radio"), + this, SLOT(slotPause())); + noticePowerChanged(queryIsPowerOn()); + + m_menu->insertSeparator(); + + m_menu->insertItem(SmallIcon("kradio"), i18n("&About"), this, SLOT(slotShowAbout())); + + // build list of widgets for hide/show items + m_pluginMenu = new KPopupMenu(m_menu); + if (m_manager) { + m_manager->addWidgetPluginMenuItems(m_pluginMenu, m_widgetPluginIDs); + m_menu->insertItem(SmallIcon("kradio_plugins"), i18n("Show/Hide Plugins"), m_pluginMenu); + } + + m_menu->insertSeparator(); + m_menu->insertItem( SmallIcon("exit"), i18n("&Quit" ), kapp, SLOT(quit()) ); + + + noticeStationChanged(queryCurrentStation(), -1); + +} + + +void RadioDocking::buildStationList() +{ + m_stationMenuIDs.clear(); + + const RawStationList &sl = queryStations().all(); + const RadioStation &crs = queryCurrentStation(); + + int k = 0; + QStringList::iterator end = m_stationIDs.end(); + for (QStringList::iterator it = m_stationIDs.begin(); it != end; ++it) { + const RadioStation &rs = sl.stationWithID(*it); + + if (rs.isValid()) { + + ++k; + QString shortcut = k < 10 ? "&"+QString().setNum(k) : k == 10 ? "1&0" : QString().setNum(k); + QString name = rs.longName().replace("&", "&&"); + QString item = shortcut + " " + name; + int id = m_menu->insertItem(item); + + m_stationMenuIDs.push_back(id); + m_menu->setItemChecked (id, rs.compare(crs) == 0); + + } else { + m_stationMenuIDs.push_back(-1); + } + } +} + + +void RadioDocking::slotSeekFwd() +{ + ISeekRadio *seeker = dynamic_cast<ISeekRadio*>(queryActiveDevice()); + if (seeker) + seeker->startSeekUp(); +} + + +void RadioDocking::slotSeekBkwd() +{ + ISeekRadio *seeker = dynamic_cast<ISeekRadio*>(queryActiveDevice()); + if (seeker) + seeker->startSeekUp(); +} + + + +void RadioDocking::slotShowAbout() +{ + if (m_manager) { + KDialogBase *d = m_manager->getAboutDialog(); + if (d) d->show(); + } +} + + +void RadioDocking::slotPower() +{ + if (queryIsPowerOn()) { + sendPowerOff(); + } else { + sendPowerOn(); + } +} + + +void RadioDocking::slotPause() +{ + if (queryIsPowerOn()) { + sendPausePlayback(queryCurrentSoundStreamID()); + } +} + + +void RadioDocking::slotSleepCountdown() +{ + if (queryCountdownEnd().isValid()) { + sendStopCountdown(); + } else { + sendStartCountdown(); + } +} + + +bool RadioDocking::noticeNextAlarmChanged(const Alarm *a) +{ + QDateTime d; + if (a) d = a->nextAlarm(); + + if (d.isValid()) + m_menu->changeTitle (m_alarmID, i18n("next alarm: %1").arg(d.toString())); + else + m_menu->changeTitle (m_alarmID, i18n("<no alarm pending>")); + return true; +} + + +bool RadioDocking::noticeCountdownStarted(const QDateTime &end) +{ + if (end.isValid()) + m_menu->changeItem (m_sleepID, SmallIcon("kradio_zzz"), i18n("Stop Sleep Countdown (running until %1)").arg(end.toString())); + else + m_menu->changeItem (m_sleepID, SmallIcon("kradio_zzz"), i18n("Start Sleep Countdown")); + return true; +} + + +bool RadioDocking::noticeCountdownStopped() +{ + m_menu->changeItem (m_sleepID, SmallIcon("kradio_zzz"), i18n("Start Sleep Countdown")); + return true; +} + + +bool RadioDocking::noticeCountdownZero() +{ + m_menu->changeItem (m_sleepID, SmallIcon("kradio_zzz"), i18n("Start Sleep Countdown")); + return true; +} + + +bool RadioDocking::noticePowerChanged(bool on) +{ + m_menu->changeItem(m_powerID, SmallIcon(on ? "kradio_muteon" : "kradio_muteoff"), + on ? i18n("Power Off") : i18n("Power On")); + m_menu->setItemEnabled(m_pauseID, on); + return true; +} + +bool RadioDocking::noticeCountdownSecondsChanged(int /*n*/) +{ + return false; +} + + + +bool RadioDocking::noticeStationChanged (const RadioStation &rs, int /*idx*/) +{ + QString s = i18n("invalid station"); + if (rs.isValid()) + s = rs.longName(); + + QToolTip::add(this, s); + m_menu->changeTitle (m_titleID, i18n("KRadio: %1").arg(s)); + // FIXME: title does not change in opened popupmenu + + QValueList<int>::iterator iit = m_stationMenuIDs.begin(); + QValueList<int>::iterator end = m_stationMenuIDs.end(); + QStringList::iterator sit = m_stationIDs.begin(); + for (; iit != end; ++iit, ++sit) { + if (*iit != -1) { + bool on = rs.stationID() == *sit; + m_menu->setItemChecked (*iit, on); + } + } + + bool r = false; + SoundFormat sf; + queryIsRecordingRunning(queryCurrentSoundStreamID(), r, sf); + m_recordingMenu->setItemEnabled(m_recordingID, !r); + return true; +} + + +bool RadioDocking::noticeStationsChanged(const StationList &/*sl*/) +{ + buildContextMenu(); + return true; +} + + +void RadioDocking::mousePressEvent( QMouseEvent *e ) +{ + KSystemTray::mousePressEvent(e); + + switch ( e->button() ) { + case LeftButton: + switch (m_leftClickAction) { + case lcaShowHide : + ShowHideWidgetPlugins(); + // FIXME: [mcamen] According the KDE usability guidelines a left + // click on the systray icon should show/hide the + // application window + // TODO: [mcamen] Use KSystemtray::toggleActive and friends once we + // depend on KDE 3.3 + break; + case lcaPowerOnOff : + if (queryIsPowerOn()) + sendPowerOff(); + else + sendPowerOn(); + break; + default: + break; + } + break; + default: + // nothing + break; + } +} + +void RadioDocking::ShowHideWidgetPlugins() +{ + // nothing in cache => hide everything + if (!m_widgetsShownCache.count()) { + for (QMapIterator<WidgetPluginBase*, int> it = m_widgetPluginIDs.begin(); it != m_widgetPluginIDs.end(); ++it) { + WidgetPluginBase *p = it.key(); + if (p) { + bool visible = p->isAnywhereVisible(); + QString name = p->name(); + logDebug(QString("visibility of %1: %2").arg(name).arg(visible)); + m_widgetsShownCache.insert(name, visible); + p->getWidget()->hide(); + } + } + } + else { + QMap<QString, bool> tmpCache = m_widgetsShownCache; + int d = KWin::currentDesktop(); + for (QMapIterator<WidgetPluginBase*, int> it = m_widgetPluginIDs.begin(); it != m_widgetPluginIDs.end(); ++it) { + WidgetPluginBase *p = it.key(); + QString name = p ? p->name() : QString::null; + if (p && tmpCache.contains(name) && tmpCache[name]) { + p->showOnOrgDesktop(); + } + } + m_widgetsShownCache.clear(); + KWin::setCurrentDesktop(d); + } +} + +void RadioDocking::slotMenuItemActivated(int id) +{ + const StationList &sl = queryStations(); + QValueList<int>::iterator iit = m_stationMenuIDs.begin(); + QValueList<int>::iterator end = m_stationMenuIDs.end(); + QStringList::iterator sit = m_stationIDs.begin(); + for (; iit != end; ++iit, ++sit) { + if (*iit == id) { + const RadioStation &rs = sl.stationWithID(*sit); + if (rs.isValid()) + sendActivateStation(rs); + } + } +} + + +void RadioDocking::noticeWidgetPluginShown(WidgetPluginBase *b, bool shown) +{ + if (!m_manager || !b || !m_widgetPluginIDs.contains(b)) + return; + m_manager->updateWidgetPluginMenuItem(b, m_pluginMenu, m_widgetPluginIDs, shown); + + if (shown) + m_widgetsShownCache.clear(); +} + + +void RadioDocking::noticePluginsChanged(const PluginList &/*l*/) +{ + buildContextMenu(); +} + + +// ISoundStreamClient + +bool RadioDocking::startRecordingWithFormat( + SoundStreamID id, + const SoundFormat &/*proposed_format*/, + SoundFormat &/*real_format*/) +{ + if (!id.isValid() || id != queryCurrentSoundStreamID() || m_StreamID2MenuID.contains(id)) + return false; + + QString descr; + querySoundStreamDescription(id, descr); + int menu_id = m_NextRecordingMenuID++; + m_recordingMenu->insertItem(SmallIcon("kradio_record"), + i18n("Stop Recording of %1").arg(descr), + menu_id); + m_MenuID2StreamID.insert(menu_id, id); + m_StreamID2MenuID.insert(id, menu_id); + + if (id == queryCurrentSoundStreamID()) + m_recordingMenu->setItemEnabled(m_recordingID, false); + + setPixmap(BarIcon("kradio_plus_rec")); + return false; // this is only a "hook" that does not initiate the recording so don't say that we handled the event +} + + +bool RadioDocking::stopRecording (SoundStreamID id) +{ + if (!id.isValid() || !m_StreamID2MenuID.contains(id)) + return false; + + int menu_id = m_StreamID2MenuID[id]; + m_recordingMenu->removeItem(menu_id); + m_MenuID2StreamID.remove(menu_id); + m_StreamID2MenuID.remove(id); + + if (id == queryCurrentSoundStreamID()) + m_recordingMenu->setItemEnabled(m_recordingID, true); + + setPixmap(BarIcon("kradio")); + + return false; +} + + +void RadioDocking::slotRecordingMenu(int i) +{ + if (i == POPUP_ID_START_RECORDING_DEFAULT) { + SoundStreamID id = queryCurrentSoundStreamID(); + bool r = false; + SoundFormat sf; + queryIsRecordingRunning(id, r, sf); + if (!r) { + if (!queryIsPowerOn()) + sendPowerOn(); + sendStartRecording(id); + } + } else if (m_MenuID2StreamID.contains(i)) { + sendStopRecording(m_MenuID2StreamID[i]); + } +} + +void RadioDocking::buildRecordingMenu() +{ + QMap<QString, SoundStreamID> streams; + queryEnumerateSoundStreams(streams); + + KPopupMenu *m = new KPopupMenu(m_menu); + + m_recordingID = m->insertItem(SmallIcon("kradio_record"), i18n("Start Recording"), + POPUP_ID_START_RECORDING_DEFAULT); + QObject::connect(m, SIGNAL(activated(int)), + this, SLOT(slotRecordingMenu(int))); + SoundStreamID currentID = queryCurrentSoundStreamID(); + + QMapIterator<QString, SoundStreamID> end = streams.end(); + for (QMapIterator<QString, SoundStreamID> it = streams.begin(); it != end; ++it) { + + SoundStreamID id = *it; + QString descr = it.key(); + bool r = false; + SoundFormat sf; + queryIsRecordingRunning(id, r, sf); + if (r) { + int menu_id = m_NextRecordingMenuID++; + m->insertItem(SmallIcon("kradio_record"), + i18n("Stop Recording of %1").arg(descr), + menu_id); + m_MenuID2StreamID.insert(menu_id, id); + m_StreamID2MenuID.insert(id, menu_id); + + if (id == currentID) + m_recordingMenu->setItemEnabled(m_recordingID, false); + } + } + m_recordingMenu = m; +} + + +bool RadioDocking::noticeSoundStreamChanged(SoundStreamID id) +{ + if (m_StreamID2MenuID.contains(id)) { + QString descr; + querySoundStreamDescription(id, descr); + m_recordingMenu->changeItem(m_StreamID2MenuID[id], + SmallIcon("kradio_record"), + i18n("Stop Recording of %1").arg(descr)); + return true; + } + return false; +} + + +void RadioDocking::setLeftClickAction(LeftClickAction action) +{ + if (m_leftClickAction != action) { + m_leftClickAction = action; + emit sigLeftClickActionChanged(m_leftClickAction); + } +} + +void RadioDocking::dragEnterEvent(QDragEnterEvent* event) +{ + bool a = StationDragObject::canDecode(event); + if (a) + IErrorLogClient::staticLogDebug("contentsDragEnterEvent accepted"); + else + IErrorLogClient::staticLogDebug("contentsDragEnterEvent rejected"); + event->accept(a); +} + +void RadioDocking::dropEvent(QDropEvent* event) +{ + QStringList list; + + if ( StationDragObject::decode(event, list) ) { + QStringList l = getStationSelection(); + for (QValueListConstIterator<QString> it = list.begin(); it != list.end(); ++it) + if (!l.contains(*it)) + l.append(*it); + setStationSelection(l); + } +} + +#include "docking.moc" diff --git a/kradio3/plugins/gui-docking-menu/docking.h b/kradio3/plugins/gui-docking-menu/docking.h new file mode 100644 index 0000000..d9fbfde --- /dev/null +++ b/kradio3/plugins/gui-docking-menu/docking.h @@ -0,0 +1,189 @@ +/*************************************************************************** + docking.h - description + ------------------- + begin : Mon Jan 14 2002 + copyright : (C) 2001, 2002 by Frank Schwanz, Ernst Martin Witte + email : schwanz@fh-brandenburg.de, 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_DOCKING_H +#define KRADIO_DOCKING_H + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <ksystemtray.h> +#include <qpixmap.h> +#include <qptrdict.h> + +#include "../../src/include/timecontrol_interfaces.h" +#include "../../src/include/radio_interfaces.h" +#include "../../src/include/radiodevicepool_interfaces.h" +#include "../../src/include/stationselection_interfaces.h" +#include "../../src/include/plugins.h" +#include "../../src/include/soundstreamclient_interfaces.h" + +enum LeftClickAction { lcaShowHide = 0, lcaPowerOnOff = 1 }; + +class RadioDocking : public KSystemTray, + public PluginBase, + public IRadioClient, + public ITimeControlClient, + public IRadioDevicePoolClient, + public IStationSelection, + public ISoundStreamClient +{ +Q_OBJECT +public: + RadioDocking (const QString &name); + virtual ~RadioDocking(); + + virtual bool connectI (Interface *); + virtual bool disconnectI (Interface *); + + virtual QString pluginClassName() const { return "RadioDocking"; } + + virtual const QString &name() const { return PluginBase::name(); } + virtual QString &name() { return PluginBase::name(); } + + + // PluginBase + +public: + virtual void saveState (KConfig *) const; + virtual void restoreState (KConfig *); + + virtual ConfigPageInfo createConfigurationPage(); + virtual AboutPageInfo createAboutPage(); + + + // IStationSelection + +RECEIVERS: + bool setStationSelection(const QStringList &sl); + +ANSWERS: + const QStringList & getStationSelection () const { return m_stationIDs; } + + + // IRadioDevicePoolClient + +RECEIVERS: + bool noticeActiveDeviceChanged(IRadioDevice *) { return false; } + bool noticeDevicesChanged(const QPtrList<IRadioDevice> &) { return false; } + bool noticeDeviceDescriptionChanged(const QString &) { return false; } + + // ITimeControlClient + +RECEIVERS: + bool noticeAlarmsChanged(const AlarmVector &) { return false; } + bool noticeAlarm(const Alarm &) { return false; } + bool noticeNextAlarmChanged(const Alarm *); + bool noticeCountdownStarted(const QDateTime &/*end*/); + bool noticeCountdownStopped(); + bool noticeCountdownZero(); + bool noticeCountdownSecondsChanged(int n); + + + // IRadioClient + +RECEIVERS: + bool noticePowerChanged(bool on); + bool noticeStationChanged (const RadioStation &, int idx); + bool noticeStationsChanged(const StationList &sl); + bool noticePresetFileChanged(const QString &/*f*/) { return false; } + + bool noticeCurrentSoundStreamIDChanged(SoundStreamID /*id*/) { return false; } + + // ISoundStreamClient + +RECEIVERS: + void noticeConnectedI (ISoundStreamServer *s, bool pointer_valid); + + bool startRecordingWithFormat(SoundStreamID /*id*/, + const SoundFormat &/*proposed_format*/, + SoundFormat &/*real_format*/); + bool stopRecording(SoundStreamID /*id*/); + + bool noticeSoundStreamChanged(SoundStreamID id); + + +protected slots: + + void slotSeekFwd(); + void slotSeekBkwd(); + + void slotPower(); + void slotPause(); + void slotSleepCountdown(); + void slotShowAbout(); + + void slotMenuItemActivated(int id); + void slotRecordingMenu(int i); + +protected: + void mousePressEvent( QMouseEvent *e ); + + void buildContextMenu(); + void buildRecordingMenu(); + void buildStationList(); + + void noticeWidgetPluginShown(WidgetPluginBase *, bool shown); + void noticePluginsChanged(const PluginList &); + + void showEvent(QShowEvent *) {} // do nothing, original implementation adds "Quit" menu item + + void ShowHideWidgetPlugins(); + + void dragEnterEvent(QDragEnterEvent* event); + void dropEvent(QDropEvent* event); + +public: + + LeftClickAction getLeftClickAction() const { return m_leftClickAction; } + void setLeftClickAction(LeftClickAction action); + +signals: + void sigLeftClickActionChanged(LeftClickAction action); + +protected: + + KPopupMenu *m_menu; + KPopupMenu *m_pluginMenu; + KPopupMenu *m_recordingMenu; + QStringList m_stationIDs; + + // menu Item IDs + int m_titleID; + int m_alarmID; + int m_recordingID; + int m_powerID; + int m_pauseID; + int m_sleepID; + int m_seekfwID; + int m_seekbwID; + QValueList<int> m_stationMenuIDs; + + QMap<WidgetPluginBase *, int> m_widgetPluginIDs; + + int m_NextRecordingMenuID; + QMap<int, SoundStreamID> m_MenuID2StreamID; + QMap<SoundStreamID, int> m_StreamID2MenuID; + + LeftClickAction m_leftClickAction; + + QMap<QString, bool> m_widgetsShownCache; +}; + + +#endif diff --git a/kradio3/plugins/gui-docking-menu/po/Makefile.am b/kradio3/plugins/gui-docking-menu/po/Makefile.am new file mode 100644 index 0000000..e02511d --- /dev/null +++ b/kradio3/plugins/gui-docking-menu/po/Makefile.am @@ -0,0 +1,2 @@ +PACKAGE = kradio-gui-docking-menu +POFILES = AUTO diff --git a/kradio3/plugins/gui-docking-menu/po/de.po b/kradio3/plugins/gui-docking-menu/po/de.po new file mode 100644 index 0000000..3256a25 --- /dev/null +++ b/kradio3/plugins/gui-docking-menu/po/de.po @@ -0,0 +1,117 @@ +# translation of de.po to +# translation of kradio-gui-docking-menu.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: 2006-11-10 23:20+0100\n" +"PO-Revision-Date: 2006-11-06 00:36+0100\n" +"Last-Translator: Ernst Martin Witte <emw@nocabal.de>\n" +"Language-Team: <de@li.org>\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: KBabel 1.11.4\n" + +#: _translatorinfo.cpp:1 +msgid "" +"_: NAME OF TRANSLATORS\n" +"Your names" +msgstr "Ernst Martin Witte" + +#: _translatorinfo.cpp:3 +msgid "" +"_: EMAIL OF TRANSLATORS\n" +"Your emails" +msgstr "emw@nocabal.de" + +#: docking-configuration.cpp:70 +msgid "Left Mouse Click on Tray" +msgstr "Linker Mausklick auf Kontrolleistensymbol" + +#: docking-configuration.cpp:73 +msgid "Show/Hide all GUI Elements" +msgstr "Alle Fenster anzeigen/verstecken" + +#: docking-configuration.cpp:74 +msgid "Power On/Off" +msgstr "Ein/Ausschalten" + +#: docking.cpp:44 +msgid "Tray Menu for KRadio" +msgstr "Kontrollleistenmenü für KRadio" + +#: docking.cpp:50 +msgid "Docking Plugin" +msgstr "Plugin für die Kontrolleiste" + +#: docking.cpp:180 +msgid "Docking Menu" +msgstr "Kontrolleisten-Menü" + +#: docking.cpp:181 +msgid "Docking Menu Configuration" +msgstr "Konfiguration des Kontrollleisten-Menüs" + +#: docking.cpp:228 +msgid "Search Next Station" +msgstr "Suche nächsten Sender" + +#: docking.cpp:230 +msgid "Search Previous Station" +msgstr "Suche vorherigen Sender" + +#: docking.cpp:235 +msgid "Recording" +msgstr "Aufnahme" + +#: docking.cpp:240 +msgid "Pause Radio" +msgstr "Radiowiedergabe pausieren" + +#: docking.cpp:252 +msgid "Show/Hide Plugins" +msgstr "Plugins anzeigen/verstecken" + +#: docking.cpp:354 +msgid "next alarm: %1" +msgstr "Nächstes Wecken: %1" + +#: docking.cpp:356 +msgid "<no alarm pending>" +msgstr "<Wecker nicht aktiv>" + +#: docking.cpp:364 +msgid "Stop Sleep Countdown (running until %1)" +msgstr "Schlummermodus abbrechen (liefe bis %1)" + +#: docking.cpp:366 docking.cpp:373 docking.cpp:380 +msgid "Start Sleep Countdown" +msgstr "Schlummermodus einschalten" + +#: docking.cpp:388 +msgid "Power Off" +msgstr "Ausschalten" + +#: docking.cpp:388 +msgid "Power On" +msgstr "Einschalten" + +#: docking.cpp:402 +msgid "invalid station" +msgstr "ungültiger Sender" + +#: docking.cpp:407 +msgid "KRadio: %1" +msgstr "KRadio: %1" + +#: docking.cpp:543 docking.cpp:616 docking.cpp:636 +msgid "Stop Recording of %1" +msgstr "Aufnahme %1 abbrechen" + +#: docking.cpp:599 +msgid "Start Recording" +msgstr "Aufnahme starten" diff --git a/kradio3/plugins/gui-docking-menu/po/ru.po b/kradio3/plugins/gui-docking-menu/po/ru.po new file mode 100644 index 0000000..183c31d --- /dev/null +++ b/kradio3/plugins/gui-docking-menu/po/ru.po @@ -0,0 +1,117 @@ +# translation of ru.po to +# translation of kradio-gui-docking-menu.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: 2006-11-11 02:11+0100\n" +"PO-Revision-Date: 2006-11-08 12:16+0300\n" +"Last-Translator: Алексей Кузнецов <Alexey.Kouznetsov@GMail.com>\n" +"Language-Team: <ru@li.org>\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" + +#: _translatorinfo.cpp:1 +msgid "" +"_: NAME OF TRANSLATORS\n" +"Your names" +msgstr "Алексей Кузнецов" + +#: _translatorinfo.cpp:3 +msgid "" +"_: EMAIL OF TRANSLATORS\n" +"Your emails" +msgstr "Alexey.Kouznetsov@GMail.com" + +#: docking-configuration.cpp:70 +msgid "Left Mouse Click on Tray" +msgstr "По щелчку левой кнопкой мыши" + +#: docking-configuration.cpp:73 +msgid "Show/Hide all GUI Elements" +msgstr "Показать/скрыть все окна" + +#: docking-configuration.cpp:74 +msgid "Power On/Off" +msgstr "Включить/выключить" + +#: docking.cpp:44 +msgid "Tray Menu for KRadio" +msgstr "Меню лотка для KRadio" + +#: docking.cpp:50 +msgid "Docking Plugin" +msgstr "Модуль системного лотка" + +#: docking.cpp:180 +msgid "Docking Menu" +msgstr "Меню лотка" + +#: docking.cpp:181 +msgid "Docking Menu Configuration" +msgstr "Конфигурация меню лотка" + +#: docking.cpp:228 +msgid "Search Next Station" +msgstr "Искать следующую станцию" + +#: docking.cpp:230 +msgid "Search Previous Station" +msgstr "Искать предыдущую станцию" + +#: docking.cpp:235 +msgid "Recording" +msgstr "Запись" + +#: docking.cpp:240 +msgid "Pause Radio" +msgstr "Приостановить" + +#: docking.cpp:252 +msgid "Show/Hide Plugins" +msgstr "Показать/скрыть" + +#: docking.cpp:354 +msgid "next alarm: %1" +msgstr "След. действие: %1" + +#: docking.cpp:356 +msgid "<no alarm pending>" +msgstr "<Расписание пусто>" + +#: docking.cpp:364 +msgid "Stop Sleep Countdown (running until %1)" +msgstr "Остановить таймер отключения (установлено на %1)" + +#: docking.cpp:366 docking.cpp:373 docking.cpp:380 +msgid "Start Sleep Countdown" +msgstr "Запустить таймер отключения" + +#: docking.cpp:388 +msgid "Power Off" +msgstr "Выключить" + +#: docking.cpp:388 +msgid "Power On" +msgstr "Включить" + +#: docking.cpp:402 +msgid "invalid station" +msgstr "Неверная станция" + +#: docking.cpp:407 +msgid "KRadio: %1" +msgstr "Радиоприёмник KDE" + +#: docking.cpp:543 docking.cpp:616 docking.cpp:636 +msgid "Stop Recording of %1" +msgstr "Остановить запись %1" + +#: docking.cpp:599 +msgid "Start Recording" +msgstr "Начать запись" diff --git a/kradio3/plugins/gui-error-log/Makefile.am b/kradio3/plugins/gui-error-log/Makefile.am new file mode 100644 index 0000000..1ac0e60 --- /dev/null +++ b/kradio3/plugins/gui-error-log/Makefile.am @@ -0,0 +1,17 @@ +SUBDIRS = po . + +INCLUDES = $(all_includes) +METASOURCES = AUTO + +libkradio_LTLIBRARIES = liberror-log.la +liberror_log_la_SOURCES = errorlog.cpp +liberror_log_la_LDFLAGS = -module -avoid-version $(KDE_RPATH) $(all_libraries) + +noinst_HEADERS = errorlog.h + +#messages: rc.cpp +# $(XGETTEXT) *.cpp *.h -o po/kradio-gui-error-log.pot + +messages: rc.cpp + $(EXTRACTRC) *.rc *.ui >> rc.cpp + $(XGETTEXT) rc.cpp *.h *.cpp -o po/kradio-gui-error-log.pot diff --git a/kradio3/plugins/gui-error-log/errorlog.cpp b/kradio3/plugins/gui-error-log/errorlog.cpp new file mode 100644 index 0000000..2eb58ad --- /dev/null +++ b/kradio3/plugins/gui-error-log/errorlog.cpp @@ -0,0 +1,263 @@ +/*************************************************************************** + errorlog.cpp - description + ------------------- + begin : Sa Sep 13 2003 + copyright : (C) 2003 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 "errorlog.h" + +#include <qframe.h> +#include <qdatetime.h> +#include <qlayout.h> + +#include <klocale.h> +#include <kiconloader.h> +#include <qtextedit.h> +#include <kfiledialog.h> +#include <kurl.h> +#include <ktempfile.h> +#include <kio/netaccess.h> + +#define PAGE_ID_INFO 0 +#define PAGE_ID_WARN 1 +#define PAGE_ID_ERROR 2 +#define PAGE_ID_DEBUG 3 + +/////////////////////////////////////////////////////////////////////// + +PLUGIN_LIBRARY_FUNCTIONS(ErrorLog, "kradio-gui-error-log", i18n("Error Logging Window for KRadio")); + +///////////////////////////////////////////////////////////////////////////// + +ErrorLog::ErrorLog(const QString &name) + : KDialogBase(KDialogBase::IconList, + "", + KDialogBase::Close|KDialogBase::User1, + KDialogBase::Close, + NULL, + name.ascii(), + false, + false, + KGuiItem(i18n("Save &as"), "filesaveas") + ), + WidgetPluginBase(name, i18n("Error Logger")), + init_done(false) +{ + QWidget::setCaption(i18n("KRadio Logger")); + QFrame *info = addPage(i18n("Information"), i18n("Information"), + KGlobal::instance()->iconLoader()->loadIcon( + "messagebox_info", KIcon::NoGroup, KIcon::SizeMedium + ) + ); + + QGridLayout *linfo = new QGridLayout(info); + linfo->setSpacing( 5 ); + linfo->setMargin ( 0 ); + m_teInfos = new QTextEdit(info); + linfo->addWidget(m_teInfos, 0, 0); + m_teInfos->setReadOnly(true); + logInfo(i18n("logging started")); + + + QFrame *warn = addPage(i18n("Warnings"), i18n("Warnings"), + KGlobal::instance()->iconLoader()->loadIcon( + "messagebox_warning", KIcon::NoGroup, KIcon::SizeMedium + ) + ); + QGridLayout *lwarn = new QGridLayout(warn); + lwarn->setSpacing( 5 ); + lwarn->setMargin ( 0 ); + m_teWarnings = new QTextEdit(warn); + lwarn->addWidget(m_teWarnings, 0, 0); + m_teWarnings->setReadOnly(true); + logWarning(i18n("logging started")); + + + + QFrame *err = addPage(i18n("Errors"), i18n("Errors"), + KGlobal::instance()->iconLoader()->loadIcon( + "messagebox_critical", KIcon::NoGroup, KIcon::SizeMedium + ) + ); + QGridLayout *lerr = new QGridLayout(err); + lerr->setSpacing( 5 ); + lerr->setMargin ( 0 ); + m_teErrors = new QTextEdit(err); + lerr->addWidget(m_teErrors, 0, 0); + m_teErrors->setReadOnly(true); + logError(i18n("logging started")); + + QFrame *debug = addPage(i18n("Debugging"), i18n("Debugging"), + KGlobal::instance()->iconLoader()->loadIcon( + "find", KIcon::NoGroup, KIcon::SizeMedium + ) + ); + + QGridLayout *ldebug = new QGridLayout(debug); + ldebug->setSpacing( 5 ); + ldebug->setMargin ( 0 ); + m_teDebug = new QTextEdit(debug); + ldebug->addWidget(m_teDebug, 0, 0); + m_teDebug->setReadOnly(true); + logDebug(i18n("logging started")); + + init_done = true; +} + + +ErrorLog::~ErrorLog() +{ +} + +bool ErrorLog::connectI (Interface *i) +{ + bool a = IErrorLog::connectI(i); + bool b = PluginBase::connectI(i); + return a || b; +} + +bool ErrorLog::disconnectI (Interface *i) +{ + bool a = IErrorLog::disconnectI(i); + bool b = PluginBase::disconnectI(i); + return a || b; +} + +void ErrorLog::restoreState (KConfig *config) +{ + config->setGroup(QString("errorlog-") + WidgetPluginBase::name()); + WidgetPluginBase::restoreState(config, false); +} + + +void ErrorLog::saveState (KConfig *config) const +{ + config->setGroup(QString("errorlog-") + WidgetPluginBase::name()); + WidgetPluginBase::saveState(config); +} + + +void ErrorLog::show() +{ + WidgetPluginBase::pShow(); + KDialogBase::show(); +} + +void ErrorLog::showOnOrgDesktop() +{ + WidgetPluginBase::pShowOnOrgDesktop(); + //KDialogBase::show(); +} + +void ErrorLog::hide() +{ + logDebug(QString("%1, ErrorLog::hide: all: %2, desktop: %3, visible:%4, anywherevisible:%5, cachevalid: %6").arg(name()).arg(m_saveSticky).arg(m_saveDesktop).arg(isReallyVisible()).arg(isAnywhereVisible()).arg(m_geoCacheValid)); + WidgetPluginBase::pHide(); + KDialogBase::hide(); +} + +void ErrorLog::showEvent(QShowEvent *e) +{ + KDialogBase::showEvent(e); + WidgetPluginBase::pShowEvent(e); +} + +void ErrorLog::hideEvent(QHideEvent *e) +{ + KDialogBase::hideEvent(e); + WidgetPluginBase::pHideEvent(e); +} + +// IErrorLog + +bool ErrorLog::logError (const QString &s) +{ + m_teErrors->append("<i>" + QDateTime::currentDateTime().toString(Qt::ISODate) + "</i> " + s + "\n"); + if (init_done) { + showPage(PAGE_ID_ERROR); + show(); + } + return true; +} + +bool ErrorLog::logWarning(const QString &s) +{ + m_teWarnings->append("<i>" + QDateTime::currentDateTime().toString(Qt::ISODate) + "</i> " + s + "\n"); + return true; +} + +bool ErrorLog::logInfo (const QString &s) +{ + m_teInfos->append("<i>" + QDateTime::currentDateTime().toString(Qt::ISODate) + "</i> " + s + "\n"); + return true; +} + +bool ErrorLog::logDebug (const QString &s) +{ + m_teDebug->append("<i>" + QDateTime::currentDateTime().toString(Qt::ISODate) + "</i> " + s + "\n"); + return true; +} + +// KDialogBase + + +// store Log Data +void ErrorLog::slotUser1() +{ + KFileDialog fd("", + ("*.log|" + i18n("Log Files") + "( *.log )").ascii(), + this, + i18n("Select Log File").ascii(), + true); + fd.setMode(KFile::File); + fd.setOperationMode(KFileDialog::Saving); + fd.setCaption (i18n("Save KRadio Logging Data as ...")); + + if (fd.exec() == QDialog::Accepted) { + KURL url = fd.selectedURL(); + + KTempFile tmpFile; + tmpFile.setAutoDelete(true); + QFile *outf = tmpFile.file(); + + QTextStream outs(outf); + outs.setEncoding(QTextStream::UnicodeUTF8); + + switch (activePageIndex()) { + case PAGE_ID_INFO: outs << m_teInfos->text(); break; + case PAGE_ID_WARN: outs << m_teWarnings->text(); break; + case PAGE_ID_ERROR: outs << m_teErrors->text(); break; + case PAGE_ID_DEBUG: outs << m_teDebug->text(); break; + default: break; + } + + if (outf->status() != IO_Ok) { + logError("ErrorLogger: " + + i18n("error writing to tempfile %1").arg(tmpFile.name())); + return; + } + + // close hopefully flushes buffers ;) + outf->close(); + + if (!KIO::NetAccess::upload(tmpFile.name(), url, this)) { + logError("ErrorLogger: " + + i18n("error uploading preset file %1").arg(url.url())); + } + } + setIconListAllVisible(true); +} + + +#include "errorlog.moc" diff --git a/kradio3/plugins/gui-error-log/errorlog.h b/kradio3/plugins/gui-error-log/errorlog.h new file mode 100644 index 0000000..d558037 --- /dev/null +++ b/kradio3/plugins/gui-error-log/errorlog.h @@ -0,0 +1,89 @@ +/*************************************************************************** + errorlog.h - description + ------------------- + begin : Sa Sep 13 2003 + copyright : (C) 2003 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_ERRORLOG_H +#define KRADIO_ERRORLOG_H + +#include <kdialogbase.h> + +#include "../../src/include/errorlog-interfaces.h" +#include "../../src/include/widgetplugins.h" + + +class QTextEdit; +class ErrorLog : public KDialogBase, + public WidgetPluginBase, + public IErrorLog +{ +Q_OBJECT +public: + ErrorLog(const QString &name = QString::null); + ~ErrorLog(); + + virtual QString pluginClassName() const { return "ErrorLog"; } + virtual const QString &name() const { return PluginBase::name(); } + virtual QString &name() { return PluginBase::name(); } + + virtual bool connectI (Interface *); + virtual bool disconnectI (Interface *); + +// WidgetPluginBase + + virtual void saveState (KConfig *) const; + virtual void restoreState (KConfig *); + +public slots: + virtual void showOnOrgDesktop(); + virtual void show(); + virtual void hide(); + virtual void toggleShown () { WidgetPluginBase::pToggleShown(); } + +protected: + QWidget *getWidget() { return this; } + const QWidget *getWidget() const { return this; } + + virtual void showEvent(QShowEvent *); + virtual void hideEvent(QHideEvent *); + + virtual ConfigPageInfo createConfigurationPage () { return ConfigPageInfo(); } + virtual AboutPageInfo createAboutPage () { return AboutPageInfo(); } + +// IErrorLog + +RECEIVERS: + bool logError (const QString &); + bool logWarning(const QString &); + bool logInfo (const QString &); + bool logDebug (const QString &); + +// KDialogBase + +protected slots: + + void slotUser1(); + +protected: + + QTextEdit *m_teDebug, + *m_teInfos, + *m_teWarnings, + *m_teErrors; + + bool init_done; +}; + +#endif diff --git a/kradio3/plugins/gui-error-log/po/Makefile.am b/kradio3/plugins/gui-error-log/po/Makefile.am new file mode 100644 index 0000000..c3b26b7 --- /dev/null +++ b/kradio3/plugins/gui-error-log/po/Makefile.am @@ -0,0 +1,2 @@ +PACKAGE = kradio-gui-error-log +POFILES = AUTO diff --git a/kradio3/plugins/gui-error-log/po/de.po b/kradio3/plugins/gui-error-log/po/de.po new file mode 100644 index 0000000..0f357c7 --- /dev/null +++ b/kradio3/plugins/gui-error-log/po/de.po @@ -0,0 +1,69 @@ +# translation of de.po to +# translation of kradio-gui-error-log.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: 2006-11-10 23:20+0100\n" +"PO-Revision-Date: 2006-11-06 01:15+0100\n" +"Last-Translator: Ernst Martin Witte <emw@nocabal.de>\n" +"Language-Team: <de@li.org>\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: KBabel 1.11.4\n" + +#: errorlog.cpp:39 +msgid "Error Logging Window for KRadio" +msgstr "Fehlerprotokollierungsfenster für KRadio" + +#: errorlog.cpp:52 +msgid "Save &as" +msgstr "Sichern &unter" + +#: errorlog.cpp:54 +msgid "Error Logger" +msgstr "Fehlerprotokoll" + +#: errorlog.cpp:57 +msgid "KRadio Logger" +msgstr "KRadio Fehlerprotokoll" + +#: errorlog.cpp:70 errorlog.cpp:84 errorlog.cpp:99 errorlog.cpp:113 +msgid "logging started" +msgstr "Beginn des Protokollierung" + +#: errorlog.cpp:73 +msgid "Warnings" +msgstr "Warnungen" + +#: errorlog.cpp:88 +msgid "Errors" +msgstr "Fehler" + +#: errorlog.cpp:101 +msgid "Debugging" +msgstr "Debugging" + +#: errorlog.cpp:219 +msgid "Log Files" +msgstr "Protokoll-Dateien" + +#: errorlog.cpp:221 +msgid "Select Log File" +msgstr "Auswahl der Protokolldatei" + +#: errorlog.cpp:225 +msgid "Save KRadio Logging Data as ..." +msgstr "KRadio-Fehlerprotokoll sichern untern ..." + +#: errorlog.cpp:247 +msgid "error writing to tempfile %1" +msgstr "Fehler beim schreiben in die temporäre Datei %1" + +#: errorlog.cpp:256 +msgid "error uploading preset file %1" +msgstr "Fehler beim Upload der Senderdatei %1" diff --git a/kradio3/plugins/gui-error-log/po/ru.po b/kradio3/plugins/gui-error-log/po/ru.po new file mode 100644 index 0000000..0bac8e7 --- /dev/null +++ b/kradio3/plugins/gui-error-log/po/ru.po @@ -0,0 +1,71 @@ +# translation of ru.po to +# translation of kradio-gui-error-log.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: 2006-11-11 02:11+0100\n" +"PO-Revision-Date: 2006-11-08 12:56+0300\n" +"Last-Translator: Алексей Кузнецов <Alexey.Kouznetsov@GMail.com>\n" +"Language-Team: <ru@li.org>\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" + +#: errorlog.cpp:39 +msgid "Error Logging Window for KRadio" +msgstr "Окно ведения журнала ошибок KRadio" + +#: errorlog.cpp:52 +msgid "Save &as" +msgstr "Сохранить &как" + +#: errorlog.cpp:54 +msgid "Error Logger" +msgstr "Журнал ошибок" + +#: errorlog.cpp:57 +msgid "KRadio Logger" +msgstr "Журнал KRadio" + +#: errorlog.cpp:70 errorlog.cpp:84 errorlog.cpp:99 errorlog.cpp:113 +msgid "logging started" +msgstr "Журналирование включено" + +#: errorlog.cpp:73 +msgid "Warnings" +msgstr "Предупреждения" + +#: errorlog.cpp:88 +msgid "Errors" +msgstr "Ошибки" + +#: errorlog.cpp:101 +msgid "Debugging" +msgstr "" +"Отладочные\n" +"сообщения" + +#: errorlog.cpp:219 +msgid "Log Files" +msgstr "Файлы журнала" + +#: errorlog.cpp:221 +msgid "Select Log File" +msgstr "Выберите файлы журнала" + +#: errorlog.cpp:225 +msgid "Save KRadio Logging Data as ..." +msgstr "Сохранить данные журнала KRadio как..." + +#: errorlog.cpp:247 +msgid "error writing to tempfile %1" +msgstr "Ошибка записи во временный файл %1" + +#: errorlog.cpp:256 +msgid "error uploading preset file %1" +msgstr "Ошибка выгрузки файла настроек %1" diff --git a/kradio3/plugins/gui-quickbar/Makefile.am b/kradio3/plugins/gui-quickbar/Makefile.am new file mode 100644 index 0000000..09c58ee --- /dev/null +++ b/kradio3/plugins/gui-quickbar/Makefile.am @@ -0,0 +1,18 @@ +SUBDIRS = po . + +INCLUDES = -I$(top_builddir)/kradio3/src $(all_includes) +METASOURCES = AUTO + +libkradio_LTLIBRARIES = libquickbar.la +libquickbar_la_SOURCES = buttonflowlayout.cpp quickbar.cpp \ + quickbar-configuration.cpp +libquickbar_la_LDFLAGS = -module -avoid-version $(KDE_RPATH) $(all_libraries) + +noinst_HEADERS = buttonflowlayout.h quickbar-configuration.h quickbar.h + +#messages: rc.cpp +# $(XGETTEXT) *.cpp *.h -o po/kradio-gui-quickbar.pot + +messages: rc.cpp + $(EXTRACTRC) *.rc *.ui >> rc.cpp + $(XGETTEXT) rc.cpp *.h *.cpp -o po/kradio-gui-quickbar.pot diff --git a/kradio3/plugins/gui-quickbar/buttonflowlayout.cpp b/kradio3/plugins/gui-quickbar/buttonflowlayout.cpp new file mode 100644 index 0000000..40d7da4 --- /dev/null +++ b/kradio3/plugins/gui-quickbar/buttonflowlayout.cpp @@ -0,0 +1,232 @@ +/**************************************************************************** +** $Id: buttonflowlayout.cpp 272 2005-05-18 08:12:51Z emw $ +** +** Implementing your own layout: flow example +** +** Copyright (C) 1996 by Trolltech AS. All rights reserved. +** +** This file is part of an example program for Qt. This example +** program may be used, distributed and modified without limitation. +** +*****************************************************************************/ +/** + Modified 2002 by Klas Kalass (klas.kalass@gmx.de) for kradio + */ + +#include <kdebug.h> + +#include "buttonflowlayout.h" + +/*********************************************/ +/* Iterator */ +class ButtonFlowLayoutIterator :public QGLayoutIterator +{ +public: + ButtonFlowLayoutIterator( QPtrList<QLayoutItem> *l ) :idx(0), list(l) {} + uint count() const; + QLayoutItem *current(); + QLayoutItem *next(); + QLayoutItem *takeCurrent(); + +private: + int idx; + QPtrList<QLayoutItem> *list; + +}; + +uint ButtonFlowLayoutIterator::count() const +{ + return list->count(); +} + +QLayoutItem *ButtonFlowLayoutIterator::current() +{ + return idx < int(count()) ? list->at(idx) : 0; +} + +QLayoutItem *ButtonFlowLayoutIterator::next() +{ + idx++; return current(); +} + +QLayoutItem *ButtonFlowLayoutIterator::takeCurrent() +{ + return idx < int(count()) ? list->take( idx ) : 0; +} + +/**************************************************************/ + +ButtonFlowLayout::ButtonFlowLayout( QWidget *parent, int margin, int spacing, + const char *name ) + : QLayout( parent, margin, spacing, name ), + cached_width(0) +{ +} + +ButtonFlowLayout::ButtonFlowLayout( QLayout* parentLayout, int spacing, const char *name ) + : QLayout( parentLayout, spacing, name ), + cached_width(0) +{ +} + +ButtonFlowLayout::ButtonFlowLayout( int spacing, const char *name ) + : QLayout( spacing, name ), + cached_width(0) +{ +} + +ButtonFlowLayout::~ButtonFlowLayout() +{ + deleteAllItems(); +} + + +int ButtonFlowLayout::heightForWidth( int w ) const +{ + if ( cached_width != w ) { + //Not all C++ compilers support "mutable" yet: + ButtonFlowLayout * mthis = (ButtonFlowLayout*)this; + int h = mthis->doLayout( QRect(0,0,w,0), TRUE ); + mthis->cached_hfw = h; + mthis->cached_width = w; + return h; + } + return cached_hfw; +} + +void ButtonFlowLayout::addItem( QLayoutItem *item) +{ + list.append( item ); +} + +bool ButtonFlowLayout::hasHeightForWidth() const +{ + return TRUE; +} + +QSize ButtonFlowLayout::sizeHint() const +{ + return minimumSize(); +} + +QSizePolicy::ExpandData ButtonFlowLayout::expanding() const +{ + return QSizePolicy::NoDirection; +} + +QLayoutIterator ButtonFlowLayout::iterator() +{ + return QLayoutIterator( new ButtonFlowLayoutIterator( &list ) ); +} + +void ButtonFlowLayout::setGeometry( const QRect &r ) +{ + QLayout::setGeometry( r ); + doLayout( r ); +} + +int ButtonFlowLayout::doLayout( const QRect &r, bool testonly ) +{ +/* kdDebug() << "buttonflowlayout::doLayout (" + << r.x() << "," << r.y() << "," + << r.width() << "," << r.height() << ", " << testonly << ")\n"; +*/ + float x = r.x(); + float y = r.y(); + int h = 0; //height of this line so far. + float buttonWidth = 0; + int buttonHeight = 0; + int linecount = 0; + int totalWidth = r.width(); + int totalHeight = r.height(); + + QPtrListIterator<QLayoutItem> it(list); + QLayoutItem *o; + + // get the width of the biggest Button + + it.toFirst(); + while ( (o=it.current()) != 0 ) { + ++it; + buttonWidth = QMAX( buttonWidth, o->sizeHint().width() ); + buttonHeight = QMAX( buttonHeight, o->sizeHint().height() ); + } + + // calculate the optimal width + unsigned int columns = (totalWidth + spacing()) / + ((int)buttonWidth + spacing()); + if (columns > it.count() ) columns = it.count(); + if (columns == 0) columns = 1; // avoid division by zero + + + int rows = (it.count() - 1) / columns + 1; + float deltaH = (float)(totalHeight - rows * buttonHeight - (rows - 1) * spacing()) + / (float)(rows + 1) ; + if (deltaH < 0) deltaH = 0; + + y += deltaH; + + buttonWidth = (float)(totalWidth - spacing()*(columns-1)) / (float)columns; + +/* fprintf (stderr, "cols = %i col-width = %f\n" + "rows = %i row-height = %i\n" + "w = %i h = %i\n", + columns, buttonWidth, + rows, buttonHeight, + totalWidth, totalHeight + ); +*/ + // calculate the positions and sizes + it.toFirst(); + while ( (o = it.current()) != 0 ) { + +// fprintf (stderr, "x = %i y = %i\n", x, (int)y); + ++it; + int btnRight = (int)rint(x + buttonWidth) - 1, + btnLeft = (int)rint(x); + + if ( btnRight > r.right() && h > 0 ) { + x = r.x(); + btnRight = (int)rint(x + buttonWidth) - 1; + btnLeft = (int)rint(x); + + y += h + spacing() + deltaH; + h = 0; + linecount++; + } + if (!testonly) + o->setGeometry( QRect( QPoint( btnLeft, (int)rint(y) ), + QSize( btnRight - btnLeft + 1, + buttonHeight) ) + ); + + x += buttonWidth + spacing(); + h = QMAX( h, buttonHeight ); + } + + int ret = (int)rint(y + h + deltaH) - r.y(); + +// kdDebug() << "ButtonFlowLayout::doLayout() = " << ret << endl; + return ret; +} + + +QSize ButtonFlowLayout::minimumSize() const +{ + return minimumSize(geometry().size()); +} + + +QSize ButtonFlowLayout::minimumSize(const QSize &r) const +{ + QSize s(0, 0); + + for (QPtrListIterator<QLayoutItem> it(list); it.current(); ++it) { + QLayoutItem *o = it.current(); + s = s.expandedTo( o->sizeHint()); //minimumSize() ); + } + + s.setHeight(heightForWidth(r.width())); + + return s; +} diff --git a/kradio3/plugins/gui-quickbar/buttonflowlayout.h b/kradio3/plugins/gui-quickbar/buttonflowlayout.h new file mode 100644 index 0000000..337a850 --- /dev/null +++ b/kradio3/plugins/gui-quickbar/buttonflowlayout.h @@ -0,0 +1,60 @@ +/**************************************************************************** +** $Id: buttonflowlayout.h 471 2006-11-11 17:04:51Z emw $ +** +** Definition of simple flow layout for custom layout example +** +** Created : 979899 +** +** Copyright (C) 1997 by Trolltech AS. All rights reserved. +** +** This file is part of an example program for Qt. This example +** program may be used, distributed and modified without limitation. +** +*****************************************************************************/ +/** + Modified 2002 by Klas Kalass (klas.kalass@gmx.de) for kradio + */ +#ifndef BUTTONFLOWLAYOUT_H +#define BUTTONFLOWLAYOUT_H + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "../../src/include/utils.h" + +#include <qlayout.h> +#include <qptrlist.h> + +class ButtonFlowLayout : public QLayout +{ +public: + ButtonFlowLayout( QWidget *parent, int margin = 0, int spacing=-1, + const char *name=0 ); + + ButtonFlowLayout( QLayout* parentLayout, int spacing=-1, const char *name=0 ); + + ButtonFlowLayout( int spacing=-1, const char *name=0 ); + + ~ButtonFlowLayout(); + + void addItem( QLayoutItem *item); + bool hasHeightForWidth() const; + int heightForWidth( int ) const; + QSize sizeHint() const; + QSize minimumSize() const; + QSize minimumSize(const QSize &r) const; // minimumSize is dependent from width + QLayoutIterator iterator(); + QSizePolicy::ExpandData expanding() const; + +protected: + void setGeometry( const QRect& ); + +private: + int doLayout( const QRect&, bool testonly = FALSE ); + QPtrList<QLayoutItem> list; + int cached_width; + int cached_hfw; +}; + +#endif diff --git a/kradio3/plugins/gui-quickbar/po/Makefile.am b/kradio3/plugins/gui-quickbar/po/Makefile.am new file mode 100644 index 0000000..fbee5b4 --- /dev/null +++ b/kradio3/plugins/gui-quickbar/po/Makefile.am @@ -0,0 +1,2 @@ +PACKAGE = kradio-gui-quickbar +POFILES = AUTO diff --git a/kradio3/plugins/gui-quickbar/po/de.po b/kradio3/plugins/gui-quickbar/po/de.po new file mode 100644 index 0000000..9ac8533 --- /dev/null +++ b/kradio3/plugins/gui-quickbar/po/de.po @@ -0,0 +1,53 @@ +# translation of de.po to +# translation of kradio-gui-quickbar.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: 2006-11-10 23:20+0100\n" +"PO-Revision-Date: 2006-11-06 00:32+0100\n" +"Last-Translator: Ernst Martin Witte <emw@nocabal.de>\n" +"Language-Team: <de@li.org>\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: KBabel 1.11.4\n" + +#: _translatorinfo.cpp:1 +msgid "" +"_: NAME OF TRANSLATORS\n" +"Your names" +msgstr "Ernst Martin Witte " + +#: _translatorinfo.cpp:3 +msgid "" +"_: EMAIL OF TRANSLATORS\n" +"Your emails" +msgstr "emw@nocabal.de" + +#: quickbar.cpp:42 +msgid "Radio Station Quick Selection Toolbar" +msgstr "Senderkurzwahlfenster" + +#: quickbar.cpp:48 +msgid "Quickbar Plugin" +msgstr "Schnellauswahlfenster" + +#: quickbar.cpp:139 +msgid "Quickbar" +msgstr "Kurzwahlfenster" + +#: quickbar.cpp:140 +msgid "Quickbar Configuration" +msgstr "Konfiguration des Kurzwahlfensters" + +#: quickbar.cpp:404 +msgid "contentsDragEnterEvent accepted" +msgstr "contentsDragEnterEvent angenommen" + +#: quickbar.cpp:406 +msgid "contentsDragEnterEvent rejected" +msgstr "contentsDragEnterEvent abgelehnt" diff --git a/kradio3/plugins/gui-quickbar/po/ru.po b/kradio3/plugins/gui-quickbar/po/ru.po new file mode 100644 index 0000000..7742fde --- /dev/null +++ b/kradio3/plugins/gui-quickbar/po/ru.po @@ -0,0 +1,55 @@ +# translation of ru.po to +# translation of kradio-gui-quickbar.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: 2006-11-11 02:11+0100\n" +"PO-Revision-Date: 2006-11-08 12:00+0300\n" +"Last-Translator: Алексей Кузнецов <Alexey.Kouznetsov@GMail.com>\n" +"Language-Team: <ru@li.org>\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" + +#: _translatorinfo.cpp:1 +msgid "" +"_: NAME OF TRANSLATORS\n" +"Your names" +msgstr "Алексей Кузнецов" + +#: _translatorinfo.cpp:3 +msgid "" +"_: EMAIL OF TRANSLATORS\n" +"Your emails" +msgstr "Alexey.Kouznetsov@GMail.com" + +#: quickbar.cpp:42 +msgid "Radio Station Quick Selection Toolbar" +msgstr "Панель быстрого выбора радиостанций" + +#: quickbar.cpp:48 +msgid "Quickbar Plugin" +msgstr "Панель быстрого доступа" + +#: quickbar.cpp:139 +msgid "Quickbar" +msgstr "" +"Панель\n" +" радиостанций" + +#: quickbar.cpp:140 +msgid "Quickbar Configuration" +msgstr "Настройка панели быстрого доступа" + +#: quickbar.cpp:404 +msgid "contentsDragEnterEvent accepted" +msgstr "contentsDragEnterEvent accepted" + +#: quickbar.cpp:406 +msgid "contentsDragEnterEvent rejected" +msgstr "contentsDragEnterEvent rejected" diff --git a/kradio3/plugins/gui-quickbar/quickbar-configuration.cpp b/kradio3/plugins/gui-quickbar/quickbar-configuration.cpp new file mode 100644 index 0000000..bb8b0f6 --- /dev/null +++ b/kradio3/plugins/gui-quickbar/quickbar-configuration.cpp @@ -0,0 +1,35 @@ +/*************************************************************************** + quickbar-configuration.cpp - description + ------------------- + begin : Son Aug 3 2003 + copyright : (C) 2003 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 "quickbar-configuration.h" + +using namespace std; + +QuickbarConfiguration::QuickbarConfiguration (QWidget *parent) + : StationSelector(parent) +{ +} + + +QuickbarConfiguration::~QuickbarConfiguration () +{ +} + + + + +#include "quickbar-configuration.moc" diff --git a/kradio3/plugins/gui-quickbar/quickbar-configuration.h b/kradio3/plugins/gui-quickbar/quickbar-configuration.h new file mode 100644 index 0000000..e2e1c08 --- /dev/null +++ b/kradio3/plugins/gui-quickbar/quickbar-configuration.h @@ -0,0 +1,36 @@ +/*************************************************************************** + quickbar-configuration.h - description + ------------------- + begin : Son Aug 3 2003 + copyright : (C) 2003 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_QUICKBAR_CONFIGURATION_H +#define KRADIO_QUICKBAR_CONFIGURATION_H + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "../../src/include/stationselector.h" + +class QuickbarConfiguration : public StationSelector +{ +Q_OBJECT +public : + QuickbarConfiguration (QWidget *parent); + ~QuickbarConfiguration (); + +}; + +#endif diff --git a/kradio3/plugins/gui-quickbar/quickbar.cpp b/kradio3/plugins/gui-quickbar/quickbar.cpp new file mode 100644 index 0000000..628a1bf --- /dev/null +++ b/kradio3/plugins/gui-quickbar/quickbar.cpp @@ -0,0 +1,424 @@ +/*************************************************************************** + quickbar.cpp - description + ------------------- + begin : Mon Feb 11 2002 + copyright : (C) 2002 by Martin Witte / Frank Schwanz + email : witte@kawo1.rwth-aachen.de / schwanz@fh-brandenburg.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 <qtooltip.h> +#include <qnamespace.h> +#include <qhbuttongroup.h> +#include <qvbuttongroup.h> + +#include <ktoolbarbutton.h> +#include <kwin.h> +#include <klocale.h> +#include <kglobal.h> +#include <kconfig.h> +#include <kaboutdata.h> + +#include "../../src/include/aboutwidget.h" +#include "../../src/include/station-drag-object.h" +#include "../../src/include/stationlist.h" +#include "../../src/include/radiostation.h" + +#include "buttonflowlayout.h" +#include "quickbar-configuration.h" +#include "quickbar.h" + +/////////////////////////////////////////////////////////////////////// +//// plugin library functions + +PLUGIN_LIBRARY_FUNCTIONS(QuickBar, "kradio-gui-quickbar", i18n("Radio Station Quick Selection Toolbar")); + +///////////////////////////////////////////////////////////////////////////// + +QuickBar::QuickBar(const QString &name) + : QWidget(NULL, name.ascii()), + WidgetPluginBase(name, i18n("Quickbar Plugin")), + m_layout(NULL), + m_buttonGroup(NULL), + m_showShortName(true), + m_ignoreNoticeActivation(false) +{ + autoSetCaption(); + setAcceptDrops(true); +} + + +QuickBar::~QuickBar() +{ +} + + +bool QuickBar::connectI(Interface *i) +{ + bool a = IRadioClient::connectI(i); + bool b = IStationSelection::connectI(i); + bool c = PluginBase::connectI(i); + + return a || b || c; +} + + +bool QuickBar::disconnectI(Interface *i) +{ + bool a = IRadioClient::disconnectI(i); + bool b = IStationSelection::disconnectI(i); + bool c = PluginBase::disconnectI(i); + + return a || b || c; +} + + +// IStationSelection + +bool QuickBar::setStationSelection(const QStringList &sl) +{ + if (m_stationIDs != sl) { + m_stationIDs = sl; + rebuildGUI(); + notifyStationSelectionChanged(m_stationIDs); + } + return true; +} + +// PluginBase methods + + +void QuickBar::restoreState (KConfig *config) +{ + config->setGroup(QString("quickBar-") + name()); + + WidgetPluginBase::restoreState(config, false); + + int nStations = config->readNumEntry("nStations", 0); + m_stationIDs.clear(); + for (int i = 1; i <= nStations; ++i) { + QString s = config->readEntry(QString("stationID-") + QString().setNum(i), QString::null); + if (s.length()) + m_stationIDs += s; + } + + rebuildGUI(); + notifyStationSelectionChanged(m_stationIDs); +} + + +void QuickBar::saveState (KConfig *config) const +{ + config->setGroup(QString("quickBar-") + name()); + + WidgetPluginBase::saveState(config); + + config->writeEntry("nStations", m_stationIDs.size()); + int i = 1; + QStringList::const_iterator end = m_stationIDs.end(); + for (QStringList::const_iterator it = m_stationIDs.begin(); it != end; ++it, ++i) { + config->writeEntry(QString("stationID-") + QString().setNum(i), *it); + } +} + + +ConfigPageInfo QuickBar::createConfigurationPage() +{ + QuickbarConfiguration *conf = new QuickbarConfiguration(NULL); + connectI (conf); + return ConfigPageInfo( + conf, + i18n("Quickbar"), + i18n("Quickbar Configuration"), + "view_icon" + ); +} + + +AboutPageInfo QuickBar::createAboutPage() +{ +/* KAboutData aboutData("kradio", + NULL, + NULL, + I18N_NOOP("Quickback for KRadio"), + KAboutData::License_GPL, + "(c) 2002-2005 Martin Witte, Klas Kalass", + 0, + "http://sourceforge.net/projects/kradio", + 0); + aboutData.addAuthor("Martin Witte", "", "witte@kawo1.rwth-aachen.de"); + aboutData.addAuthor("Klas Kalass", "", "klas.kalass@gmx.de"); + + return AboutPageInfo( + new KRadioAboutWidget(aboutData, KRadioAboutWidget::AbtTabbed), + i18n("Quickbar"), + i18n("Quickbar Plugin"), + "view_icon" + );*/ + return AboutPageInfo(); +} + + +// IRadio methods + +bool QuickBar::noticePowerChanged(bool /*on*/) +{ + activateCurrentButton(); + autoSetCaption(); + return true; +} + + +bool QuickBar::noticeStationChanged (const RadioStation &rs, int /*idx*/) +{ + if (!m_ignoreNoticeActivation) + activateButton(rs); + autoSetCaption(); + return true; +} + + +bool QuickBar::noticeStationsChanged(const StationList &/*sl*/) +{ + // FIXME + // we can remove no longer existent stationIDs, + // but it doesn't matter if we don't care. + rebuildGUI(); + return true; +} + + +// button management methods + +void QuickBar::buttonClicked(int id) +{ + // ouch, but we are still using QStringList :( + if (queryIsPowerOn() && id == getButtonID(queryCurrentStation())) { + sendPowerOff(); + } else { + + int k = 0; + QStringList::iterator end = m_stationIDs.end(); + for (QStringList::iterator it = m_stationIDs.begin(); it != end; ++it, ++k) { + if (k == id) { + const RawStationList &sl = queryStations().all(); + const RadioStation &rs = sl.stationWithID(*it); + bool old = m_ignoreNoticeActivation; + m_ignoreNoticeActivation = true; + sendActivateStation(rs); + m_ignoreNoticeActivation = old; + sendPowerOn(); + } + } + } + // Problem: if we click a button twice, there will be no + // "station changed"-notification. Thus it would be possible to + // enable a button even if power is off or the radio does not + // accept the radiostation + //activateCurrentButton(); +} + + +int QuickBar::getButtonID(const RadioStation &rs) const +{ + QString stationID = rs.stationID(); + int k = 0; + QStringList::const_iterator end = m_stationIDs.end(); + for (QStringList::const_iterator it = m_stationIDs.begin(); it != end; ++it, ++k) { + if (*it == stationID) + return k; + } + return -1; +} + + +void QuickBar::activateCurrentButton() +{ + activateButton(queryCurrentStation()); +} + + +void QuickBar::activateButton(const RadioStation &rs) +{ + int buttonID = getButtonID(rs); + bool pwr = queryIsPowerOn(); + + if (pwr && buttonID >= 0) { + m_buttonGroup->setButton(buttonID); + } else { + for (QToolButton *b = m_buttons.first(); b; b = m_buttons.next()) { + b->setOn(false); + } + } + autoSetCaption(); +} + + + +// KDE/Qt gui + + +void QuickBar::rebuildGUI() +{ + if (m_layout) delete m_layout; + if (m_buttonGroup) delete m_buttonGroup; + + for (QPtrListIterator<QToolButton> it(m_buttons); it.current(); ++it) + delete it.current(); + m_buttons.clear(); + + m_layout = new ButtonFlowLayout(this); + m_layout->setMargin(1); + m_layout->setSpacing(2); + + m_buttonGroup = new QButtonGroup(this); + QObject::connect (m_buttonGroup, SIGNAL(clicked(int)), this, SLOT(buttonClicked(int))); + // we use buttonGroup to enable automatic toggle/untoggle + m_buttonGroup->setExclusive(true); + m_buttonGroup->setFrameStyle(QFrame::NoFrame); + m_buttonGroup->show(); + + int buttonID = 0; + const RawStationList &stations = queryStations().all(); + + QStringList::iterator end = m_stationIDs.end(); + for (QStringList::iterator it = m_stationIDs.begin(); it != end; ++it, ++buttonID) { + + const RadioStation &rs = stations.stationWithID(*it); + if (! rs.isValid()) continue; + + QToolButton *b = new QToolButton(this); + m_buttons.append(b); + b->setToggleButton(true); + if (rs.iconName().length()) + b->setIconSet(QPixmap(rs.iconName())); + else + b->setText(m_showShortName ? rs.shortName() : rs.name()); + + b->setSizePolicy(QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred)); + + QToolTip::add(b, rs.longName()); + if (isVisible()) b->show(); + + + m_buttonGroup->insert(b, buttonID); + m_layout->add(b); + } + + // activate correct button + activateCurrentButton(); + + // calculate geometry + if (m_layout) { + QRect r = geometry(); + int h = m_layout->heightForWidth( r.width()); + + if (h > r.height()) + setGeometry(r.x(), r.y(), r.width(), h); + } +} + + + + +void QuickBar::show() +{ +// KWin::setType(winId(), NET::Toolbar); + WidgetPluginBase::pShow(); + QWidget::show(); +} + + +void QuickBar::showOnOrgDesktop() +{ + WidgetPluginBase::pShowOnOrgDesktop(); + //QWidget::show(); +} + + +void QuickBar::hide() +{ + WidgetPluginBase::pHide(); + QWidget::hide(); +} + +void QuickBar::showEvent(QShowEvent *e) +{ + QWidget::showEvent(e); + WidgetPluginBase::pShowEvent(e); +} + +void QuickBar::hideEvent(QHideEvent *e) +{ + QWidget::hideEvent(e); + WidgetPluginBase::pHideEvent(e); +} + + +void QuickBar::setGeometry (int x, int y, int w, int h) +{ + if (m_layout) { + QSize marginSize(m_layout->margin()*2, m_layout->margin()*2); + setMinimumSize(m_layout->minimumSize(QSize(w, h) - marginSize) + marginSize); + } + QWidget::setGeometry (x, y, w, h); +} + + +void QuickBar::setGeometry (const QRect &r) +{ + setGeometry (r.x(), r.y(), r.width(), r.height()); +} + + +void QuickBar::resizeEvent (QResizeEvent *e) +{ + // minimumSize might change because of the flow layout + if (m_layout) { + QSize marginSize(m_layout->margin()*2, m_layout->margin()*2); + setMinimumSize(m_layout->minimumSize(e->size() - marginSize) + marginSize); + } + + QWidget::resizeEvent (e); +} + + +void QuickBar::autoSetCaption() +{ + const RadioStation &rs = queryCurrentStation(); + setCaption((queryIsPowerOn() && rs.isValid()) ? rs.longName() : QString("KRadio")); +} + +void QuickBar::dragEnterEvent(QDragEnterEvent* event) +{ + bool a = StationDragObject::canDecode(event); + if (a) + IErrorLogClient::staticLogDebug(i18n("contentsDragEnterEvent accepted")); + else + IErrorLogClient::staticLogDebug(i18n("contentsDragEnterEvent rejected")); + event->accept(a); +} + +void QuickBar::dropEvent(QDropEvent* event) +{ + QStringList list; + + if ( StationDragObject::decode(event, list) ) { + QStringList l = getStationSelection(); + for (QValueListConstIterator<QString> it = list.begin(); it != list.end(); ++it) + if (!l.contains(*it)) + l.append(*it); + setStationSelection(l); + } +} + + +#include "quickbar.moc" diff --git a/kradio3/plugins/gui-quickbar/quickbar.h b/kradio3/plugins/gui-quickbar/quickbar.h new file mode 100644 index 0000000..7bf5193 --- /dev/null +++ b/kradio3/plugins/gui-quickbar/quickbar.h @@ -0,0 +1,138 @@ +/*************************************************************************** + quickbar.h - description + ------------------- + begin : Mon Feb 11 2002 + copyright : (C) 2002 by Martin Witte / Klas Kalass + 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_QUICKBAR_H +#define KRADIO_QUICKBAR_H + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <qwidget.h> + +#include "../../src/include/radio_interfaces.h" +#include "../../src/include/widgetplugins.h" +#include "../../src/include/stationselection_interfaces.h" + +class ButtonFlowLayout; +class QButtonGroup; +class KConfig; +class QToolButton; + +/** + *@author Martin Witte / Klas Kalass + */ + +class QuickBar : public QWidget, + public WidgetPluginBase, + public IRadioClient, + public IStationSelection +{ +Q_OBJECT +public: + QuickBar(const QString &name = QString::null); + ~QuickBar(); + + virtual QString pluginClassName() const { return "QuickBar"; } + + const QString &name() const { return PluginBase::name(); } + QString &name() { return PluginBase::name(); } + + virtual bool connectI(Interface *i); + virtual bool disconnectI(Interface *i); + + // IStationSelection + +RECEIVERS: + bool setStationSelection(const QStringList &sl); + +ANSWERS: + const QStringList & getStationSelection () const { return m_stationIDs; } + + + // PluginBase + +public: + virtual void saveState (KConfig *) const; + virtual void restoreState (KConfig *); + + virtual ConfigPageInfo createConfigurationPage(); + virtual AboutPageInfo createAboutPage(); + + // IRadioClient + +RECEIVERS: + bool noticePowerChanged(bool on); + bool noticeStationChanged (const RadioStation &, int idx); + bool noticeStationsChanged(const StationList &sl); + bool noticePresetFileChanged(const QString &/*f*/) { return false; } + + bool noticeCurrentSoundStreamIDChanged(SoundStreamID /*id*/) { return false; } + + // button/station Management + + +protected slots: + + void buttonClicked(int id); + +protected: + + int getButtonID(const RadioStation &rs) const; + void activateCurrentButton(); + void activateButton(const RadioStation &); + + void autoSetCaption(); + + + void dragEnterEvent(QDragEnterEvent* event); + void dropEvent(QDropEvent* event); + + // KDE/QT + +public slots: + + void toggleShown() { WidgetPluginBase::pToggleShown(); } + void show(); + void hide(); + void showOnOrgDesktop(); + void setGeometry (const QRect &r); + void setGeometry (int x, int y, int w, int h); + +protected: + void rebuildGUI(); + void showEvent(QShowEvent *); + void hideEvent(QHideEvent *); + void resizeEvent(QResizeEvent *); + + const QWidget *getWidget() const { return this; } + QWidget *getWidget() { return this; } + +protected : + + ButtonFlowLayout *m_layout; + QButtonGroup *m_buttonGroup; + + QPtrList<QToolButton> m_buttons; + + // config + bool m_showShortName; + QStringList m_stationIDs; + + bool m_ignoreNoticeActivation; +}; +#endif diff --git a/kradio3/plugins/gui-standard-display/Makefile.am b/kradio3/plugins/gui-standard-display/Makefile.am new file mode 100644 index 0000000..a7e7544 --- /dev/null +++ b/kradio3/plugins/gui-standard-display/Makefile.am @@ -0,0 +1,22 @@ +SUBDIRS = po . + +INCLUDES = $(all_includes) +METASOURCES = AUTO + +libkradio_LTLIBRARIES = libstandard-display.la +libstandard_display_la_SOURCES = displaycfg.cpp displaycfg_interfaces.cpp \ + radioview-configuration.cpp radioview.cpp \ + radioview_element.cpp \ + radioview_frequencyradio.cpp \ + radioview_frequencyseeker.cpp \ + radioview_volume.cpp +libstandard_display_la_LDFLAGS = -module -avoid-version $(KDE_RPATH) $(all_libraries) + +noinst_HEADERS = displaycfg.h displaycfg_interfaces.h radioview-configuration.h radioview_element.h radioview_frequencyradio.h radioview_frequencyseeker.h radioview.h radioview_volume.h + +#messages: rc.cpp +# $(XGETTEXT) *.cpp *.h -o po/kradio-gui-standard-display.pot + +messages: rc.cpp + $(EXTRACTRC) *.rc *.ui >> rc.cpp + $(XGETTEXT) rc.cpp *.h *.cpp -o po/kradio-gui-standard-display.pot diff --git a/kradio3/plugins/gui-standard-display/displaycfg.cpp b/kradio3/plugins/gui-standard-display/displaycfg.cpp new file mode 100644 index 0000000..8e26e72 --- /dev/null +++ b/kradio3/plugins/gui-standard-display/displaycfg.cpp @@ -0,0 +1,145 @@ +/*************************************************************************** + displaycfg.cpp - description + ------------------- + begin : Fr Aug 15 2003 + copyright : (C) 2003 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 "displaycfg.h" +#include <kcolorbutton.h> +#include <kcolordialog.h> +#include <kfontdialog.h> + +#include <qlayout.h> +#include <klocale.h> +#include <qlabel.h> +#include <qbuttongroup.h> + +DisplayConfiguration::DisplayConfiguration(QWidget *parent) + : QWidget (parent), + m_dirty(true), + m_ignore_gui_updates(false) +{ + QGroupBox *bg = new QGroupBox(i18n("Display Colors"), this); + bg->setColumnLayout(0, Qt::Vertical ); + bg->layout()->setSpacing( 8 ); + bg->layout()->setMargin( 12 ); + QGridLayout *gl = new QGridLayout (bg->layout()); + + m_btnActive = new KColorButton(queryDisplayActiveColor(), bg); + m_btnInactive = new KColorButton(queryDisplayInactiveColor(), bg); + m_btnBkgnd = new KColorButton(queryDisplayBkgndColor(), bg); + + connect(m_btnActive, SIGNAL(changed(const QColor &)), this, SLOT(slotSetDirty())); + connect(m_btnInactive, SIGNAL(changed(const QColor &)), this, SLOT(slotSetDirty())); + connect(m_btnBkgnd, SIGNAL(changed(const QColor &)), this, SLOT(slotSetDirty())); + + QLabel *l1 = new QLabel(i18n("Active Text"), bg); + QLabel *l2 = new QLabel(i18n("Inactive Text"), bg); + QLabel *l3 = new QLabel(i18n("Background Color"), bg); + + l1->setAlignment(QLabel::AlignCenter); + l2->setAlignment(QLabel::AlignCenter); + l3->setAlignment(QLabel::AlignCenter); + + l1->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed)); + l2->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed)); + l3->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed)); + m_btnActive ->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding)); + m_btnInactive->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding)); + m_btnBkgnd ->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding)); + + m_btnActive ->setMinimumSize(QSize(40, 40)); + m_btnInactive->setMinimumSize(QSize(40, 40)); + m_btnBkgnd ->setMinimumSize(QSize(40, 40)); + + gl->addWidget (l1, 0, 0, Qt::AlignCenter); + gl->addWidget (l2, 0, 1, Qt::AlignCenter); + gl->addWidget (l3, 0, 2, Qt::AlignCenter); + gl->addWidget (m_btnActive, 1, 0); + gl->addWidget (m_btnInactive, 1, 1); + gl->addWidget (m_btnBkgnd, 1, 2); + + m_fontChooser = new KFontChooser(this, NULL, false, QStringList(), true, 4); + m_fontChooser->setFont(queryDisplayFont()); + m_fontChooser->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding)); + + QVBoxLayout *l = new QVBoxLayout(this, 10); + l->addWidget(bg); + l->addWidget(m_fontChooser); + + connect(m_btnActive, SIGNAL(changed(const QColor &)), this, SLOT(slotSetDirty())); + connect(m_btnInactive, SIGNAL(changed(const QColor &)), this, SLOT(slotSetDirty())); + connect(m_btnBkgnd, SIGNAL(changed(const QColor &)), this, SLOT(slotSetDirty())); + connect(m_fontChooser, SIGNAL(fontSelected(const QFont &)), this, SLOT(slotSetDirty())); + +} + + +DisplayConfiguration::~DisplayConfiguration() +{ +} + + +bool DisplayConfiguration::noticeDisplayColorsChanged(const QColor &activeColor, const QColor &inactiveColor, const QColor &bkgnd) +{ + m_ignore_gui_updates = true; + m_btnActive->setColor(activeColor); + m_btnInactive->setColor(inactiveColor); + m_btnBkgnd->setColor(bkgnd); + m_ignore_gui_updates = false; + return true; +} + + +bool DisplayConfiguration::noticeDisplayFontChanged(const QFont &f) +{ + m_ignore_gui_updates = true; + m_fontChooser->setFont(f); + m_ignore_gui_updates = false; + return true; +} + + +void DisplayConfiguration::slotOK() +{ + if (m_dirty) { + sendDisplayColors(m_btnActive->color(), m_btnInactive->color(), m_btnBkgnd->color()); + sendDisplayFont(m_fontChooser->font()); + m_dirty = false; + } +} + +void DisplayConfiguration::slotCancel() +{ + if (m_dirty) { + m_ignore_gui_updates = true; + m_btnActive ->setColor(queryDisplayActiveColor()); + m_btnInactive->setColor(queryDisplayInactiveColor()); + m_btnBkgnd ->setColor(queryDisplayBkgndColor()); + m_fontChooser->setFont(queryDisplayFont()); + m_dirty = false; + m_ignore_gui_updates = false; + } +} + +void DisplayConfiguration::slotSetDirty() +{ + if (!m_dirty && !m_ignore_gui_updates) { + m_dirty = true; + emit sigDirty(); + } +} + + +#include "displaycfg.moc" diff --git a/kradio3/plugins/gui-standard-display/displaycfg.h b/kradio3/plugins/gui-standard-display/displaycfg.h new file mode 100644 index 0000000..fcd6079 --- /dev/null +++ b/kradio3/plugins/gui-standard-display/displaycfg.h @@ -0,0 +1,72 @@ +/*************************************************************************** + displaycfg.h - description + ------------------- + begin : Fr Aug 15 2003 + copyright : (C) 2003 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_DISPLAYCFG_H +#define KRADIO_DISPLAYCFG_H + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "displaycfg_interfaces.h" +#include <qwidget.h> + +class KColorButton; +class KFontChooser; + +class DisplayConfiguration : public QWidget, + public IDisplayCfgClient +{ +Q_OBJECT +public: + DisplayConfiguration(QWidget *parent); + ~DisplayConfiguration(); + +// Interface + + bool connectI (Interface *i) { return IDisplayCfgClient::connectI(i); } + bool disconnectI (Interface *i) { return IDisplayCfgClient::disconnectI(i); } + +// IDisplayCfgClient + +RECEIVERS: + bool noticeDisplayColorsChanged(const QColor &activeColor, const QColor &inactiveColor, const QColor &bkgnd); + bool noticeDisplayFontChanged(const QFont &f); + + +public slots: + + void slotOK(); + void slotCancel(); + void slotSetDirty(); + +signals: + + void sigDirty(); + +protected: + KColorButton *m_btnActive; + KColorButton *m_btnInactive; + KColorButton *m_btnBkgnd; + KFontChooser *m_fontChooser; + + bool m_dirty; + bool m_ignore_gui_updates; +}; + + +#endif diff --git a/kradio3/plugins/gui-standard-display/displaycfg_interfaces.cpp b/kradio3/plugins/gui-standard-display/displaycfg_interfaces.cpp new file mode 100644 index 0000000..a7bbf01 --- /dev/null +++ b/kradio3/plugins/gui-standard-display/displaycfg_interfaces.cpp @@ -0,0 +1,69 @@ +/*************************************************************************** + displaycfg_interfaces.cpp - description + ------------------- + begin : Fr Aug 15 2003 + copyright : (C) 2003 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 "displaycfg_interfaces.h" + +// IDisplayCfg + +IF_IMPL_SENDER ( IDisplayCfg::notifyDisplayColorsChanged(const QColor &a, const QColor &b, const QColor &c), + noticeDisplayColorsChanged(a,b, c) ) + +IF_IMPL_SENDER ( IDisplayCfg::notifyDisplayFontChanged(const QFont &f), + noticeDisplayFontChanged(f) ) + +// IDisplayCfgClient + +IF_IMPL_SENDER ( IDisplayCfgClient::sendDisplayColors(const QColor &a, const QColor &b, const QColor &c), + setDisplayColors(a,b, c) ) + +IF_IMPL_SENDER ( IDisplayCfgClient::sendDisplayFont(const QFont &f), + setDisplayFont(f) ) + +const QColor default_display_active_color = QColor(20, 244, 20); +IF_IMPL_QUERY ( const QColor &IDisplayCfgClient::queryDisplayActiveColor(), + getDisplayActiveColor(), + default_display_active_color ) + +const QColor default_display_inactive_color = QColor(10, 117, 10).light(75); +IF_IMPL_QUERY ( const QColor &IDisplayCfgClient::queryDisplayInactiveColor(), + getDisplayInactiveColor(), + default_display_inactive_color ) + +const QColor default_display_bkgnd_color = QColor(10, 117, 10); +IF_IMPL_QUERY ( const QColor &IDisplayCfgClient::queryDisplayBkgndColor(), + getDisplayBkgndColor(), + default_display_bkgnd_color ) + +const QFont default_display_font = QFont("Helvetica"); +IF_IMPL_QUERY ( const QFont &IDisplayCfgClient::queryDisplayFont(), + getDisplayFont(), + default_display_font ) + + +void IDisplayCfgClient::noticeConnectedI (cmplInterface *, bool /*pointer_valid*/) +{ + noticeDisplayColorsChanged(queryDisplayActiveColor(), queryDisplayInactiveColor(), queryDisplayBkgndColor()); + noticeDisplayFontChanged(queryDisplayFont()); +} + + +void IDisplayCfgClient::noticeDisconnectedI (cmplInterface *, bool /*pointer_valid*/) +{ + noticeDisplayColorsChanged(queryDisplayActiveColor(), queryDisplayInactiveColor(), queryDisplayBkgndColor()); + noticeDisplayFontChanged(queryDisplayFont()); +} + diff --git a/kradio3/plugins/gui-standard-display/displaycfg_interfaces.h b/kradio3/plugins/gui-standard-display/displaycfg_interfaces.h new file mode 100644 index 0000000..ac2ef5d --- /dev/null +++ b/kradio3/plugins/gui-standard-display/displaycfg_interfaces.h @@ -0,0 +1,82 @@ +/*************************************************************************** + displaycfg_interfaces.h - description + ------------------- + begin : Fr Aug 15 2003 + copyright : (C) 2003 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_DISPLAYCFG_INTERFACES_H +#define KRADIO_DISPLAYCFG_INTERFACES_H + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "../../src/include/interfaces.h" + +#include <qfont.h> +#include <qcolor.h> + +/////////////////////////////////////////////////////////////////////// + + +INTERFACE(IDisplayCfg, IDisplayCfgClient) +{ +public : + IF_CON_DESTRUCTOR(IDisplayCfg, -1) + +RECEIVERS: + IF_RECEIVER( setDisplayColors(const QColor &activeColor, const QColor &inactiveColor, const QColor &bkgnd) ) + IF_RECEIVER( setDisplayFont (const QFont &f) ) + +SENDERS: + IF_SENDER ( notifyDisplayColorsChanged(const QColor &activeColor, const QColor &inactiveColor, const QColor &bkgnd) ) + IF_SENDER ( notifyDisplayFontChanged(const QFont &f) ) + +ANSWERS: + IF_ANSWER ( const QColor &getDisplayActiveColor() const ) + IF_ANSWER ( const QColor &getDisplayInactiveColor() const ) + IF_ANSWER ( const QColor &getDisplayBkgndColor() const ) + IF_ANSWER ( const QFont &getDisplayFont() const ) + +}; + + +INTERFACE(IDisplayCfgClient, IDisplayCfg) +{ +friend class IDisplayCfg; + +public : + IF_CON_DESTRUCTOR(IDisplayCfgClient, 1) + +SENDERS: + IF_SENDER ( sendDisplayColors(const QColor &activeColor, const QColor &inactiveColor, const QColor &bkgnd) ) + IF_SENDER ( sendDisplayFont (const QFont &f) ) + +RECEIVERS: + IF_RECEIVER( noticeDisplayColorsChanged(const QColor &activeColor, const QColor &inactiveColor, const QColor &bkgnd) ) + IF_RECEIVER( noticeDisplayFontChanged(const QFont &f) ) + +QUERIES: + IF_QUERY ( const QColor &queryDisplayActiveColor() ) + IF_QUERY ( const QColor &queryDisplayInactiveColor() ) + IF_QUERY ( const QColor &queryDisplayBkgndColor() ) + IF_QUERY ( const QFont &queryDisplayFont() ) + +RECEIVERS: + virtual void noticeConnectedI (cmplInterface *, bool pointer_valid); + virtual void noticeDisconnectedI (cmplInterface *, bool pointer_valid); +}; + + +#endif diff --git a/kradio3/plugins/gui-standard-display/po/Makefile.am b/kradio3/plugins/gui-standard-display/po/Makefile.am new file mode 100644 index 0000000..956ae72 --- /dev/null +++ b/kradio3/plugins/gui-standard-display/po/Makefile.am @@ -0,0 +1,2 @@ +PACKAGE = kradio-gui-standard-display +POFILES = AUTO diff --git a/kradio3/plugins/gui-standard-display/po/de.po b/kradio3/plugins/gui-standard-display/po/de.po new file mode 100644 index 0000000..5013f29 --- /dev/null +++ b/kradio3/plugins/gui-standard-display/po/de.po @@ -0,0 +1,212 @@ +# translation of kradio-gui-standard-display.po to +# This file is put in the public domain. +# +# Ernst Martin Witte <emw@nocabal.de>, 2006. +msgid "" +msgstr "" +"Project-Id-Version: kradio-gui-standard-display\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2006-11-06 01:24+0100\n" +"PO-Revision-Date: 2006-11-06 01:23+0100\n" +"Last-Translator: Ernst Martin Witte <emw@nocabal.de>\n" +"Language-Team: <de@li.org>\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: KBabel 1.11.4\n" + +#. i18n: file radioview_seekinterface.ui line 17 +#: rc.cpp:3 rc.cpp:25 +#, no-c-format +msgid "RadioView_SeekInterface" +msgstr "RadioView_SeekInterface" + +#. i18n: file radioview_seekinterface.ui line 45 +#: rc.cpp:7 rc.cpp:29 +#, no-c-format +msgid "search previous station" +msgstr "Suche vorherigen Sender" + +#. i18n: file radioview_seekinterface.ui line 73 +#: rc.cpp:11 rc.cpp:33 +#, no-c-format +msgid "decrease freq. by 0.05 MHz" +msgstr "Frequenz um 0.05 MHz verringern" + +#. i18n: file radioview_seekinterface.ui line 108 +#: rc.cpp:14 rc.cpp:36 +#, no-c-format +msgid "Frequency control" +msgstr "Frequenz verändern" + +#. i18n: file radioview_seekinterface.ui line 129 +#: rc.cpp:18 rc.cpp:40 +#, no-c-format +msgid "increase freq. by 0.05 MHz" +msgstr "Frequenz um 0.05 MHz erhöhen" + +#. i18n: file radioview_seekinterface.ui line 146 +#: rc.cpp:22 rc.cpp:44 +#, no-c-format +msgid "search next station" +msgstr "Suche nächsten Sender" + +#: _translatorinfo.cpp:1 +msgid "" +"_: NAME OF TRANSLATORS\n" +"Your names" +msgstr "Ernst Martin Witte" + +#: _translatorinfo.cpp:3 +msgid "" +"_: EMAIL OF TRANSLATORS\n" +"Your emails" +msgstr "emw@nocabal.de" + +#: displaycfg.cpp:33 +msgid "Display Colors" +msgstr "Farben für die Radioanzeige" + +#: displaycfg.cpp:47 +msgid "Active Text" +msgstr "Aktiver Text" + +#: displaycfg.cpp:48 +msgid "Inactive Text" +msgstr "Inaktiver Text" + +#: displaycfg.cpp:49 +msgid "Background Color" +msgstr "Hintergrundfarbe" + +#: radioview.cpp:55 +msgid "Standard Display for KRadio" +msgstr "Standardanzeige für KRadio" + +#: radioview.cpp:72 +msgid "Radio Display" +msgstr "Radio-Anzeige" + +#: radioview.cpp:127 +msgid "Pause KRadio" +msgstr "KRadio pausieren" + +#: radioview.cpp:133 +msgid "Start Recording" +msgstr "Aufnahme starten" + +#: radioview.cpp:141 +msgid "5 min" +msgstr "5 min" + +#: radioview.cpp:142 +msgid "10 min" +msgstr "10 min" + +#: radioview.cpp:143 +msgid "15 min" +msgstr "15 min" + +#: radioview.cpp:144 +msgid "30 min" +msgstr "30 min" + +#: radioview.cpp:145 +msgid "60 min" +msgstr "60 min" + +#: radioview.cpp:189 +msgid "Configure KRadio" +msgstr "KRadio Einrichten" + +#: radioview.cpp:190 +msgid "Power On/Off" +msgstr "Ein/Ausschalten" + +#: radioview.cpp:191 +msgid "Quit KRadio Application" +msgstr "KRadio beenden" + +#: radioview.cpp:192 +msgid "Start/Stop Recording" +msgstr "Aufnahme starten/beenden" + +#: radioview.cpp:193 +msgid "Start/Stop Sleep Countdown" +msgstr "Schlummermodus ein/ausschalten" + +#: radioview.cpp:194 +msgid "Show/Hide Plugins" +msgstr "Plugins anzeigen/verstecken" + +#: radioview.cpp:195 +msgid "Select a Radio Station" +msgstr "Sender auswählen" + +#: radioview.cpp:332 +msgid "no preset defined" +msgstr "kein voreingestellter Sender gefunden" + +#: radioview.cpp:442 radioview.cpp:480 +msgid "Stop Recording of %1" +msgstr "Aufnahme von %1 beenden" + +#: radioview.cpp:553 +msgid "Display" +msgstr "Anzeige" + +#: radioview.cpp:554 +msgid "Display Configuration" +msgstr "Konfiguration der Radio-Anzeige" + +#: radioview.cpp:590 +msgid "set Toolbar-Flag for Display" +msgstr "Werkzeugleisten-Flag für das Displayfenster" + +#: radioview.cpp:593 +msgid "Common" +msgstr "Allgemein" + +#: radioview_frequencyradio.cpp:99 radioview_frequencyradio.cpp:100 +msgid "Frequency Display" +msgstr "Frequenzanzeige" + +#: radioview_frequencyradio.cpp:388 radioview_frequencyradio.cpp:389 +msgid "AM" +msgstr "MW" + +#: radioview_frequencyradio.cpp:394 radioview_frequencyradio.cpp:395 +msgid "FM" +msgstr "UKW" + +#: radioview_frequencyradio.cpp:406 +msgid "%1 kHz" +msgstr "%1 kHz" + +#: radioview_frequencyradio.cpp:408 +msgid "%1 MHz" +msgstr "%1 MHz" + +#: radioview_frequencyseeker.cpp:76 +msgid "Search for previous Radio Station" +msgstr "Suche nach vorherigem Sender" + +#: radioview_frequencyseeker.cpp:77 +msgid "Search for next Radio Station" +msgstr "Suche nach nächstem Sender" + +#: radioview_frequencyseeker.cpp:78 +msgid "Decrement Frequency" +msgstr "Frequenz erniedrigen" + +#: radioview_frequencyseeker.cpp:79 +msgid "Increment Frequency" +msgstr "Frequenz erhöhen" + +#: radioview_frequencyseeker.cpp:80 +msgid "Change Frequency" +msgstr "Frequenz verändern" + +#: radioview_volume.cpp:56 +msgid "Change Volume" +msgstr "Läutstärke verändern" diff --git a/kradio3/plugins/gui-standard-display/po/ru.po b/kradio3/plugins/gui-standard-display/po/ru.po new file mode 100644 index 0000000..722b790 --- /dev/null +++ b/kradio3/plugins/gui-standard-display/po/ru.po @@ -0,0 +1,213 @@ +# translation of ru.po to +# translation of kradio-gui-standard-display.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: 2006-11-11 02:11+0100\n" +"PO-Revision-Date: 2006-11-08 13:06+0300\n" +"Last-Translator: Алексей Кузнецов <Alexey.Kouznetsov@GMail.com>\n" +"Language-Team: <ru@li.org>\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" + +#. i18n: file radioview_seekinterface.ui line 17 +#: rc.cpp:3 rc.cpp:25 +#, no-c-format +msgid "RadioView_SeekInterface" +msgstr "RadioView_SeekInterface" + +#. i18n: file radioview_seekinterface.ui line 45 +#: rc.cpp:7 rc.cpp:29 +#, no-c-format +msgid "search previous station" +msgstr "Поиск предыдущей станции" + +#. i18n: file radioview_seekinterface.ui line 73 +#: rc.cpp:11 rc.cpp:33 +#, no-c-format +msgid "decrease freq. by 0.05 MHz" +msgstr "Уменьшать частоту по 0,05 МГц" + +#. i18n: file radioview_seekinterface.ui line 108 +#: rc.cpp:14 rc.cpp:36 +#, no-c-format +msgid "Frequency control" +msgstr "Управление частотой" + +#. i18n: file radioview_seekinterface.ui line 129 +#: rc.cpp:18 rc.cpp:40 +#, no-c-format +msgid "increase freq. by 0.05 MHz" +msgstr "Увеличивать частоту по 0,05 МГц" + +#. i18n: file radioview_seekinterface.ui line 146 +#: rc.cpp:22 rc.cpp:44 +#, no-c-format +msgid "search next station" +msgstr "Поиск следующей станции" + +#: _translatorinfo.cpp:1 +msgid "" +"_: NAME OF TRANSLATORS\n" +"Your names" +msgstr "Алексей Кузнецов" + +#: _translatorinfo.cpp:3 +msgid "" +"_: EMAIL OF TRANSLATORS\n" +"Your emails" +msgstr "Alexey.Kouznetsov@GMail.com" + +#: displaycfg.cpp:33 +msgid "Display Colors" +msgstr "Цвета" + +#: displaycfg.cpp:47 +msgid "Active Text" +msgstr "Цвет активного текста" + +#: displaycfg.cpp:48 +msgid "Inactive Text" +msgstr "Цвет инертного текста" + +#: displaycfg.cpp:49 +msgid "Background Color" +msgstr "Цвет фона" + +#: radioview.cpp:55 +msgid "Standard Display for KRadio" +msgstr "Главное окно KRadio" + +#: radioview.cpp:72 +msgid "Radio Display" +msgstr "Главное окно" + +#: radioview.cpp:127 +msgid "Pause KRadio" +msgstr "Приостановить" + +#: radioview.cpp:133 +msgid "Start Recording" +msgstr "Начать запись" + +#: radioview.cpp:141 +msgid "5 min" +msgstr "5 минут" + +#: radioview.cpp:142 +msgid "10 min" +msgstr "10 минут" + +#: radioview.cpp:143 +msgid "15 min" +msgstr "четверть часа" + +#: radioview.cpp:144 +msgid "30 min" +msgstr "полчаса" + +#: radioview.cpp:145 +msgid "60 min" +msgstr "час" + +#: radioview.cpp:189 +msgid "Configure KRadio" +msgstr "Настроить KRadio" + +#: radioview.cpp:190 +msgid "Power On/Off" +msgstr "Включить/выключить" + +#: radioview.cpp:191 +msgid "Quit KRadio Application" +msgstr "Закрыть KRadio" + +#: radioview.cpp:192 +msgid "Start/Stop Recording" +msgstr "Начать/завершить запись" + +#: radioview.cpp:193 +msgid "Start/Stop Sleep Countdown" +msgstr "Включить/выключить таймер отключения" + +#: radioview.cpp:194 +msgid "Show/Hide Plugins" +msgstr "Показать/скрыть" + +#: radioview.cpp:195 +msgid "Select a Radio Station" +msgstr "Выбор радиостанции из списка" + +#: radioview.cpp:332 +msgid "no preset defined" +msgstr "Станция не определена" + +#: radioview.cpp:442 radioview.cpp:480 +msgid "Stop Recording of %1" +msgstr "Остановить запись %1" + +#: radioview.cpp:553 +msgid "Display" +msgstr "Вид" + +#: radioview.cpp:554 +msgid "Display Configuration" +msgstr "Настройка внешнего вида" + +#: radioview.cpp:590 +msgid "set Toolbar-Flag for Display" +msgstr "" + +#: radioview.cpp:593 +msgid "Common" +msgstr "Общие" + +#: radioview_frequencyradio.cpp:99 radioview_frequencyradio.cpp:100 +msgid "Frequency Display" +msgstr "Отображение частоты" + +#: radioview_frequencyradio.cpp:388 radioview_frequencyradio.cpp:389 +msgid "AM" +msgstr "ДВ/СВ/КВ" + +#: radioview_frequencyradio.cpp:394 radioview_frequencyradio.cpp:395 +msgid "FM" +msgstr "УКВ" + +#: radioview_frequencyradio.cpp:406 +msgid "%1 kHz" +msgstr "%1 кГц" + +#: radioview_frequencyradio.cpp:408 +msgid "%1 MHz" +msgstr "%1 МГц" + +#: radioview_frequencyseeker.cpp:76 +msgid "Search for previous Radio Station" +msgstr "Искать станцию вниз" + +#: radioview_frequencyseeker.cpp:77 +msgid "Search for next Radio Station" +msgstr "Искать станцию вверх" + +#: radioview_frequencyseeker.cpp:78 +msgid "Decrement Frequency" +msgstr "Уменьшить частоту" + +#: radioview_frequencyseeker.cpp:79 +msgid "Increment Frequency" +msgstr "Увеличить частоту" + +#: radioview_frequencyseeker.cpp:80 +msgid "Change Frequency" +msgstr "Изменить частоту" + +#: radioview_volume.cpp:56 +msgid "Change Volume" +msgstr "Изменить громкость" diff --git a/kradio3/plugins/gui-standard-display/radioview-configuration.cpp b/kradio3/plugins/gui-standard-display/radioview-configuration.cpp new file mode 100644 index 0000000..9a22313 --- /dev/null +++ b/kradio3/plugins/gui-standard-display/radioview-configuration.cpp @@ -0,0 +1,116 @@ +/*************************************************************************** + radioview-configuration.cpp - description + ------------------- + begin : Fr Aug 15 2003 + copyright : (C) 2003 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 "radioview-configuration.h" + +RadioViewConfiguration::RadioViewConfiguration(QWidget *parent) + : QTabWidget (parent), + m_dirty(true) +{ +} + +RadioViewConfiguration::~RadioViewConfiguration() +{ +} + + +void RadioViewConfiguration::addTab (QWidget *child, const QString &label) +{ + QTabWidget::addTab(child, label); + QObject::connect(this, SIGNAL(sigOK()), child, SLOT(slotOK())); + QObject::connect(this, SIGNAL(sigCancel()), child, SLOT(slotCancel())); + QObject::connect(child, SIGNAL(sigDirty()), this, SLOT(slotSetDirty())); +} + + +void RadioViewConfiguration::addTab (QWidget *child, const QIconSet &iconset, const QString &label) +{ + QTabWidget::addTab(child, iconset, label); + QObject::connect(this, SIGNAL(sigOK()), child, SLOT(slotOK())); + QObject::connect(this, SIGNAL(sigCancel()), child, SLOT(slotCancel())); + QObject::connect(child, SIGNAL(sigDirty()), this, SLOT(slotSetDirty())); +} + + +void RadioViewConfiguration::addTab (QWidget *child, QTab *tab) +{ + QTabWidget::addTab(child, tab); + QObject::connect(this, SIGNAL(sigOK()), child, SLOT(slotOK())); + QObject::connect(this, SIGNAL(sigCancel()), child, SLOT(slotCancel())); + QObject::connect(child, SIGNAL(sigDirty()), this, SLOT(slotSetDirty())); +} + + +void RadioViewConfiguration::insertTab (QWidget *child, const QString &label, int index) +{ + QTabWidget::insertTab(child, label, index); + QObject::connect(this, SIGNAL(sigOK()), child, SLOT(slotOK())); + QObject::connect(this, SIGNAL(sigCancel()), child, SLOT(slotCancel())); + QObject::connect(child, SIGNAL(sigDirty()), this, SLOT(slotSetDirty())); +} + + +void RadioViewConfiguration::insertTab (QWidget *child, const QIconSet &iconset, const QString &label, int index) +{ + QTabWidget::insertTab(child, iconset, label, index); + QObject::connect(this, SIGNAL(sigOK()), child, SLOT(slotOK())); + QObject::connect(this, SIGNAL(sigCancel()), child, SLOT(slotCancel())); + QObject::connect(child, SIGNAL(sigDirty()), this, SLOT(slotSetDirty())); +} + + +void RadioViewConfiguration::insertTab (QWidget *child, QTab *tab, int index) +{ + QTabWidget::insertTab(child, tab, index); + QObject::connect(this, SIGNAL(sigOK()), child, SLOT(slotOK())); + QObject::connect(this, SIGNAL(sigCancel()), child, SLOT(slotCancel())); + QObject::connect(child, SIGNAL(sigDirty()), this, SLOT(slotSetDirty())); +} + + +void RadioViewConfiguration::removePage(QWidget *w) +{ + QObject::disconnect(this, SIGNAL(sigOK()), w, SLOT(slotOK())); + QObject::disconnect(this, SIGNAL(sigCancel()), w, SLOT(slotCancel())); + QObject::disconnect(w, SIGNAL(sigDirty()), this, SLOT(slotSetDirty())); + QTabWidget::removePage(w); +} + + +void RadioViewConfiguration::slotOK() +{ + if (m_dirty) { + emit sigOK(); + m_dirty = false; + } +} + +void RadioViewConfiguration::slotCancel() +{ + if (m_dirty) { + emit sigCancel(); + m_dirty = false; + } +} + +void RadioViewConfiguration::slotSetDirty() +{ + m_dirty = true; +} + + +#include "radioview-configuration.moc" diff --git a/kradio3/plugins/gui-standard-display/radioview-configuration.h b/kradio3/plugins/gui-standard-display/radioview-configuration.h new file mode 100644 index 0000000..a85d4d9 --- /dev/null +++ b/kradio3/plugins/gui-standard-display/radioview-configuration.h @@ -0,0 +1,61 @@ +/*************************************************************************** + radioview-configuration.h - description + ------------------- + begin : Fr Aug 15 2003 + copyright : (C) 2003 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_RADIOVIEW_CONFIGURATION_H +#define KRADIO_RADIOVIEW_CONFIGURATION_H + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + + + +#include <qtabwidget.h> + +class RadioViewConfiguration : public QTabWidget +{ +Q_OBJECT +public : + RadioViewConfiguration(QWidget *parent = NULL); + ~RadioViewConfiguration(); + + void addTab (QWidget *child, const QString &label); + void addTab (QWidget *child, const QIconSet &iconset, const QString &label); + void addTab (QWidget *child, QTab *tab); + void insertTab (QWidget *child, const QString &label, int index = -1); + void insertTab (QWidget *child, const QIconSet &iconset, const QString &label, int index = -1); + void insertTab (QWidget *child, QTab *tab, int index = -1); + void removePage(QWidget *w); + +public slots: + + void slotOK(); + void slotCancel(); + void slotSetDirty(); + +signals: + + void sigOK(); + void sigCancel(); + +protected: + bool m_dirty; +}; + + + +#endif diff --git a/kradio3/plugins/gui-standard-display/radioview.cpp b/kradio3/plugins/gui-standard-display/radioview.cpp new file mode 100644 index 0000000..e1fd8e4 --- /dev/null +++ b/kradio3/plugins/gui-standard-display/radioview.cpp @@ -0,0 +1,807 @@ +/*************************************************************************** + radioview.cpp - description + ------------------- + begin : Mit Mai 28 2003 + copyright : (C) 2003 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 <qwidgetstack.h> +#include <qlayout.h> +#include <qtoolbutton.h> +#include <qslider.h> +#include <qfile.h> +#include <qtooltip.h> +#include <qcheckbox.h> +#include <qimage.h> + +#include <kcombobox.h> +#include <kiconloader.h> +#include <klocale.h> +#include <kapplication.h> +#include <kwin.h> +#include <kconfig.h> +#include <kpopupmenu.h> + +#include "../../src/include/radiodevice_interfaces.h" +#include "../../src/include/radiostation.h" +#include "../../src/include/stationlist.h" +#include "../../src/include/pluginmanager.h" +#include "../../src/include/plugin_configuration_dialog.h" +#include "../../src/include/aboutwidget.h" + +#include "radioview.h" +#include "radioview_frequencyradio.h" +#include "radioview_volume.h" +#include "radioview_frequencyseeker.h" +#include "radioview-configuration.h" + +#include <kaboutdata.h> + +#define POPUP_ID_START_RECORDING_DEFAULT 0 +#define POPUP_ID_STOP_RECORDING_BASE 100 + +/////////////////////////////////////////////////////////////////////// + +PLUGIN_LIBRARY_FUNCTIONS(RadioView, "kradio-gui-standard-display", i18n("Standard Display for KRadio")); + +/////////////////////////////////////////////////////////////////////// + +bool RadioView::ElementCfg::operator == (const ElementCfg &x) const +{ + if (!x.element || !element) + return x.cfg == cfg; + if (!x.cfg || !cfg) + return x.element == element; + return element == x.element && cfg == x.cfg; +} + +/////////////////////////////////////////////////////////////////////// + +RadioView::RadioView(const QString &name) + : QWidget(NULL, name.ascii()), + WidgetPluginBase(name, i18n("Radio Display")), + enableToolbarFlag(false), + btnPower(NULL), + btnConfigure(NULL), + btnQuit(NULL), + btnRecording(NULL), + btnSnooze(NULL), + btnPlugins(NULL), + comboStations(NULL), + currentDevice(NULL), + m_RecordingMenu(NULL), + m_NextRecordingMenuID(POPUP_ID_STOP_RECORDING_BASE), + m_PluginMenu(NULL) +{ + for (int i = 0; i < clsClassMAX; ++i) + maxUsability[i] = 0; + + QBoxLayout *l01 = new QBoxLayout(this, QBoxLayout::LeftToRight, /*spacing=*/3); + l01->setMargin(1); + l01->setSpacing(2); + widgetStacks[clsRadioSound] = new QWidgetStack (this); + l01->addWidget(widgetStacks[clsRadioSound]); + + QBoxLayout *l02 = new QBoxLayout(l01, QBoxLayout::Down); + QBoxLayout *l03 = new QBoxLayout(l02, QBoxLayout::LeftToRight); + comboStations = new KComboBox (this); + l02->addWidget (comboStations); + + QBoxLayout *l05 = new QBoxLayout(l03, QBoxLayout::Down); + widgetStacks[clsRadioDisplay] = new QWidgetStack (this); + l05->addWidget(widgetStacks[clsRadioDisplay]); + widgetStacks[clsRadioSeek] = new QWidgetStack (this); + l05->addWidget(widgetStacks[clsRadioSeek]); + + QGridLayout *l04 = new QGridLayout (l03, /*rows=*/ 3, /*cols=*/ 2); + btnPower = new QToolButton(this); + btnPower->setToggleButton(true); + btnRecording = new QToolButton(this); + btnRecording->setToggleButton(true); + btnConfigure = new QToolButton(this); + btnConfigure->setToggleButton(true); + btnQuit = new QToolButton(this); + btnSnooze = new QToolButton(this); + btnSnooze->setToggleButton(true); + btnPlugins = new QToolButton(this); + btnPlugins->setPopupDelay(1); + l04->addWidget (btnPower, 0, 0); + l04->addWidget (btnRecording, 0, 1); + l04->addWidget (btnConfigure, 1, 0); + l04->addWidget (btnQuit, 1, 1); + l04->addWidget (btnSnooze, 2, 0); + l04->addWidget (btnPlugins, 2, 1); + + m_pauseMenu = new KPopupMenu(btnPower); + m_pauseMenu->insertItem(SmallIcon("kradio_pause"), + i18n("Pause KRadio"), + this, SLOT(slotPause())); + btnPower->setPopupDelay(200); + + m_RecordingMenu = new KPopupMenu(btnRecording); + m_RecordingMenu->insertItem(SmallIcon("kradio_record"), + i18n("Start Recording"), + POPUP_ID_START_RECORDING_DEFAULT); + QObject::connect(m_RecordingMenu, SIGNAL(activated(int)), + this, SLOT(slotRecordingMenu(int))); + btnRecording->setPopup(m_RecordingMenu); + + + m_SnoozeMenu = new KPopupMenu(btnSnooze); + m_SnoozeMenu->insertItem(i18n("5 min"), this, SLOT(slotSnooze(int)), 0, 5); + m_SnoozeMenu->insertItem(i18n("10 min"), this, SLOT(slotSnooze(int)), 0, 10); + m_SnoozeMenu->insertItem(i18n("15 min"), this, SLOT(slotSnooze(int)), 0, 15); + m_SnoozeMenu->insertItem(i18n("30 min"), this, SLOT(slotSnooze(int)), 0, 30); + m_SnoozeMenu->insertItem(i18n("60 min"), this, SLOT(slotSnooze(int)), 0, 60); + btnSnooze->setPopup(m_SnoozeMenu); + btnSnooze->setPopupDelay(200); + + // Plugin-Button/Menu + + m_PluginMenu = new KPopupMenu(btnPlugins); + if (m_manager) + m_manager->addWidgetPluginMenuItems(m_PluginMenu, m_Plugins2MenuID); + btnPlugins->setPopup(m_PluginMenu); + + // ICONS + + btnPower->setIconSet(SmallIconSet("kradio_muteon")); + btnRecording->setIconSet(SmallIconSet("kradio_record")); + btnConfigure->setIconSet(SmallIconSet("configure")); + btnQuit->setIconSet(SmallIconSet("exit")); + btnSnooze->setIconSet(SmallIconSet("kradio_zzz")); + btnPlugins->setIconSet(SmallIconSet("kradio_plugins")); + + widgetStacks[clsRadioSound] ->setSizePolicy(QSizePolicy(QSizePolicy::Minimum, QSizePolicy::Preferred)); + widgetStacks[clsRadioDisplay]->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred)); + widgetStacks[clsRadioSeek] ->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed)); + comboStations ->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed)); + comboStations->setMinimumHeight(28); + + + QObject::connect(btnPower, SIGNAL(toggled(bool)), + this, SLOT(slotPower(bool))); + QObject::connect(btnQuit, SIGNAL(clicked()), + kapp, SLOT(quit())); + QObject::connect(btnConfigure, SIGNAL(toggled(bool)), + this, SLOT(slotConfigure(bool))); + QObject::connect(btnRecording, SIGNAL(clicked()), + this, SLOT(slotRecord())); + QObject::connect(btnSnooze, SIGNAL(toggled(bool)), + this, SLOT(slotSnooze(bool))); + QObject::connect(comboStations, SIGNAL(activated(int)), + this, SLOT(slotComboStationSelected(int))); + QObject::connect(btnPlugins, SIGNAL(clicked()), + this, SLOT(slotBtnPluginsClicked())); + + // tooltips + + QToolTip::add(btnConfigure, i18n("Configure KRadio")); + QToolTip::add(btnPower, i18n("Power On/Off")); + QToolTip::add(btnQuit, i18n("Quit KRadio Application")); + QToolTip::add(btnRecording, i18n("Start/Stop Recording")); + QToolTip::add(btnSnooze, i18n("Start/Stop Sleep Countdown")); + QToolTip::add(btnPlugins, i18n("Show/Hide Plugins")); + QToolTip::add(comboStations, i18n("Select a Radio Station")); + + // testing + addElement (new RadioViewFrequencyRadio (this, QString::null)); + addElement (new RadioViewVolume(this, QString::null)); + addElement (new RadioViewFrequencySeeker(this, QString::null)); + + autoSetCaption(); +} + + +RadioView::~RadioView () +{ + QPtrListIterator<QObject> it(configPages); + while (configPages.first()) { + delete configPages.first(); + } + configPages.clear(); +} + + +bool RadioView::addElement (RadioViewElement *e) +{ + if (!e) return false; + + RadioViewClass cls = e->getClass(); + + if (cls < 0 || cls >= clsClassMAX) + return false; + + + e->reparent(this, QPoint(0, 0), true); + QObject::connect(e, SIGNAL(destroyed(QObject*)), + this, SLOT(removeElement(QObject*))); + elements.append(e); + widgetStacks[cls]->addWidget(e); + + // connect Element with device, disconnect doesn't matter (comp. removeElement) + // other devices follow if currentDevice changes + if (currentDevice) + e->connectI(currentDevice); + + e->connectI(getSoundStreamServer()); + + QPtrListIterator<QObject> it(configPages); + for (; it.current(); ++it) { + addConfigurationTabFor(e, (QTabWidget *)it.current()); + } + + selectTopWidgets(); + + return true; +} + + +bool RadioView::removeElement (QObject *_e) +{ + RadioViewElement *e = dynamic_cast<RadioViewElement*>(_e); + if (!e) + return false; + + ElementCfgListIterator it; + while ((it = elementConfigPages.find(e)) != elementConfigPages.end()) { + delete (*it).cfg; + // it must not used behind, the element will be deleted automatically + // by slotElementConfigPageDeleted + } + + e->disconnectI(getSoundStreamServer()); + + if (currentDevice) + e->disconnectI(currentDevice); + + RadioViewClass cls = e->getClass(); + QObject::disconnect(e, SIGNAL(destroyed(QObject*)), + this, SLOT(removeElement(QObject*))); + widgetStacks[cls]->removeWidget(e); + elements.remove(e); + + selectTopWidgets(); + + return true; +} + + +void RadioView::selectTopWidgets() +{ + for (int i = 0; i < clsClassMAX; ++i) + maxUsability[i] = 0; + + for (ElementListIterator i(elements); i.current(); ++i) { + RadioViewElement *e = i.current(); + RadioViewClass cls = e->getClass(); + float u = e->getUsability(currentDevice); + if (u > maxUsability[cls]) { + maxUsability[cls] = u; + widgetStacks[cls]->raiseWidget(e); + } + } + // adjustLayout!? +} + + +// IRadioClient + +bool RadioView::noticePowerChanged(bool on) +{ + btnPower->setIconSet(SmallIconSet( on ? "kradio_muteoff" : "kradio_muteon")); + btnPower->setOn(on); + if (on) { + btnPower->setPopup(m_pauseMenu); + } else { + btnPower->setPopup(NULL); + } + autoSetCaption(); + return true; +} + + +bool RadioView::noticeStationChanged (const RadioStation &, int idx) +{ + // add 1 for "no preset defined" entry + comboStations->setCurrentItem(idx + 1); + autoSetCaption(); + bool r = false; + SoundFormat sf; + queryIsRecordingRunning(queryCurrentSoundStreamID(), r, sf); + m_RecordingMenu->setItemEnabled(POPUP_ID_START_RECORDING_DEFAULT, !r); + return true; +} + + +bool RadioView::noticeStationsChanged(const StationList &sl) +{ + const RawStationList &list = sl.all(); + + comboStations->clear(); + comboStations->insertItem("<" + i18n("no preset defined") + ">"); + + for (RawStationList::Iterator i(list); i.current(); ++i) { + RadioStation *stn = i.current(); + QString icon = stn->iconName(); + if (icon.length() && QFile(icon).exists()) { + QImage img(icon); + int h = img.height(); + float f = (float)(comboStations->height() - 4) / (h ? (float)h : 1.0); + comboStations->insertItem(img.smoothScale((int)(img.width()*f), (int)(h * f)), stn->name()); + } else { + comboStations->insertItem(stn->name()); + } + } + + noticeStationChanged(queryCurrentStation(), queryCurrentStationIdx()); + return true; +} + + +bool RadioView::noticeCurrentSoundStreamIDChanged(SoundStreamID /*id*/) +{ + // FIXME: perhaps do something + return false; +} + +// IRadioDevicePoolClient + +bool RadioView::noticeActiveDeviceChanged(IRadioDevice *newDevice) +{ + IRadioDevice *oldDevice = currentDevice; + currentDevice = newDevice; + + for (ElementListIterator i(elements); i.current(); ++i) { + RadioViewElement *e = i.current(); + if (oldDevice) + e->disconnectI(oldDevice); + if (newDevice) + e->connectI(currentDevice); + } + + selectTopWidgets(); + return true; +} + + +// Interface + +bool RadioView::connectI(Interface *i) +{ + bool a = IRadioClient::connectI(i); + bool b = IRadioDevicePoolClient::connectI(i); + bool c = PluginBase::connectI(i); + bool d = ITimeControlClient::connectI(i); + + // Callbacks for ISoundStreamClient + + bool e = ISoundStreamClient::connectI(i); + + return a || b || c || d || e; +} + + +bool RadioView::disconnectI(Interface *i) +{ + bool a = IRadioClient::disconnectI(i); + bool b = IRadioDevicePoolClient::disconnectI(i); + bool c = PluginBase::disconnectI(i); + bool d = ITimeControlClient::disconnectI(i); + bool e = ISoundStreamClient::disconnectI(i); + if (e) { + // special task for soundstreamclient, different from radio device pool + for (ElementListIterator it(elements); it.current(); ++it) { + RadioViewElement *e = it.current(); + e->disconnectI(i); + } + } + return a || b || c || d || e; +} + +void RadioView::noticeConnectedI (ISoundStreamServer *s, bool pointer_valid) +{ + ISoundStreamClient::noticeConnectedI(s, pointer_valid); + if (s && pointer_valid) { + s->register4_sendStartRecordingWithFormat(this); + s->register4_sendStopRecording (this); + s->register4_notifySoundStreamChanged (this); + + // special task for soundstreamclient, different from radio device pool + for (ElementListIterator it(elements); it.current(); ++it) { + RadioViewElement *e = it.current(); + e->connectI(s); + } + } +} + +// ISoundStreamClient + +bool RadioView::startRecordingWithFormat( + SoundStreamID id, + const SoundFormat &/*proposed_format*/, + SoundFormat &/*real_format*/) +{ + if (!id.isValid() || id != queryCurrentSoundStreamID() || m_StreamID2MenuID.contains(id)) + return false; + + QString descr; + querySoundStreamDescription(id, descr); + int menu_id = m_NextRecordingMenuID++; + m_RecordingMenu->insertItem(SmallIcon("kradio_record"), + i18n("Stop Recording of %1").arg(descr), + menu_id); + m_MenuID2StreamID.insert(menu_id, id); + m_StreamID2MenuID.insert(id, menu_id); + btnRecording->setOn(true); + + if (id == queryCurrentSoundStreamID()) + m_RecordingMenu->setItemEnabled(POPUP_ID_START_RECORDING_DEFAULT, false); + + return false; // this is only a "hook" that does not initiate the recording so don't say that we handled the event +} + + +bool RadioView::stopRecording (SoundStreamID id) +{ + if (!id.isValid() || !m_StreamID2MenuID.contains(id)) + return false; + + int menu_id = m_StreamID2MenuID[id]; + m_RecordingMenu->removeItem(menu_id); + m_MenuID2StreamID.remove(menu_id); + m_StreamID2MenuID.remove(id); + btnRecording->setOn(m_StreamID2MenuID.count() > 0); + + if (id == queryCurrentSoundStreamID()) + m_RecordingMenu->setItemEnabled(POPUP_ID_START_RECORDING_DEFAULT, true); + + return false; +} + + +bool RadioView::noticeSoundStreamChanged(SoundStreamID id) +{ + if (m_StreamID2MenuID.contains(id)) { + QString descr; + querySoundStreamDescription(id, descr); + m_RecordingMenu->changeItem(m_StreamID2MenuID[id], + SmallIcon("kradio_record"), + i18n("Stop Recording of %1").arg(descr)); + return true; + } + return false; +} + + +// ITimeControl + +bool RadioView::noticeCountdownStarted(const QDateTime &) +{ + btnSnooze->setOn(true); + return true; +} + +bool RadioView::noticeCountdownStopped() +{ + btnSnooze->setOn(false); + return true; +} + +bool RadioView::noticeCountdownZero() +{ + btnSnooze->setOn(false); + return true; +} + +// WidgetPluginBase + +void RadioView::saveState (KConfig *config) const +{ + config->setGroup(QString("radioview-") + name()); + + config->writeEntry("enableToobarFlag", enableToolbarFlag); + WidgetPluginBase::saveState(config); + + for (ElementListIterator i(elements); i.current(); ++i) { + RadioViewElement *e = i.current(); + e->saveState(config); + } +} + + +void RadioView::restoreState (KConfig *config) +{ + config->setGroup(QString("radioview-") + name()); + + enableToolbarFlag = config->readBoolEntry("enableToolbarFlag", false); + WidgetPluginBase::restoreState(config); + + for (ElementListIterator i(elements); i.current(); ++i) { + RadioViewElement *e = i.current(); + e->restoreState(config); + } +} + + +ConfigPageInfo RadioView::createConfigurationPage() +{ + RadioViewConfiguration *c = new RadioViewConfiguration(); + + //addCommonConfigurationTab(c); + + for (ElementListIterator i(elements); i.current(); ++i) { + addConfigurationTabFor(i.current(), c); + } + + configPages.append(c); + QObject::connect(c, SIGNAL(destroyed(QObject *)), + this, SLOT(slotConfigPageDeleted(QObject *))); + + return ConfigPageInfo( + c, + i18n("Display"), + i18n("Display Configuration"), + "openterm" + ); +} + + +void RadioView::addConfigurationTabFor(RadioViewElement *e, QTabWidget *c) +{ + if (!e || !c) + return; + + ConfigPageInfo inf = e->createConfigurationPage(); + + if (inf.page) { + + if (inf.iconName.length()) { + c->addTab(inf.page, QIconSet(SmallIconSet(inf.iconName)), inf.itemName); + } else { + c->addTab(inf.page, inf.itemName); + } + + elementConfigPages.push_back(ElementCfg(e, inf.page)); + QObject::connect(inf.page, SIGNAL(destroyed(QObject *)), + this, SLOT(slotElementConfigPageDeleted(QObject *))); + } +} + + +void RadioView::addCommonConfigurationTab(QTabWidget *c) +{ + if (!c) + return; + + QFrame *f = new QFrame(c); + QVBoxLayout *l = new QVBoxLayout(f, 10); + + l->addWidget(new QCheckBox(i18n("set Toolbar-Flag for Display"), f)); + l->addItem(new QSpacerItem(1, 3, QSizePolicy::Fixed, QSizePolicy::Expanding)); + + c->addTab(f, i18n("Common")); + + elementConfigPages.push_back(ElementCfg(f)); + QObject::connect(f, SIGNAL(destroyed(QObject *)), + this, SLOT(slotElementConfigPageDeleted(QObject *))); +} + + +AboutPageInfo RadioView::createAboutPage() +{ +/* KAboutData aboutData("kradio", + NULL, + NULL, + I18N_NOOP("Standard Radio Display for KRadio"), + KAboutData::License_GPL, + "(c) 2002-2005 Martin Witte, Klas Kalass", + 0, + "http://sourceforge.net/projects/kradio", + 0); + aboutData.addAuthor("Martin Witte", "", "witte@kawo1.rwth-aachen.de"); + aboutData.addAuthor("Klas Kalass", "", "klas.kalass@gmx.de"); + + return AboutPageInfo( + new KRadioAboutWidget(aboutData, KRadioAboutWidget::AbtTabbed), + i18n("Display"), + i18n("Standard Radio Display for KRadio"), + "openterm" + );*/ + return AboutPageInfo(); +} + + +void RadioView::noticeWidgetPluginShown(WidgetPluginBase *p, bool shown) +{ + if (!m_manager || !p) + return; + if ((WidgetPluginBase*)m_manager->getConfigDialog() == p) { + btnConfigure->blockSignals(true); + btnConfigure->setOn(shown); + btnConfigure->blockSignals(false); + } + + if (m_Plugins2MenuID.contains(p)) { + m_manager->updateWidgetPluginMenuItem(p, m_PluginMenu, m_Plugins2MenuID, shown); + } +} + + +// own Stuff + +void RadioView::noticePluginsChanged(const PluginList &/*l*/) +{ + m_Plugins2MenuID.clear(); + m_PluginMenu->clear(); + if (m_manager) + m_manager->addWidgetPluginMenuItems(m_PluginMenu, m_Plugins2MenuID); +} + + +void RadioView::slotPower(bool on) +{ + on ? sendPowerOn() : sendPowerOff(); + btnPower->setOn(queryIsPowerOn()); +} + + +void RadioView::slotPause() +{ + if (queryIsPowerOn()) { + sendPausePlayback(queryCurrentSoundStreamID()); + } +} + + +void RadioView::slotConfigure(bool b) +{ + QWidget *w = m_manager ? m_manager->getConfigDialog() : NULL; + if (w) b ? w->show() : w->hide(); + if (!w) + btnConfigure->setOn(false); +} + + +void RadioView::slotRecord() +{ + SoundStreamID id = queryCurrentSoundStreamID(); + bool b = btnRecording->isOn(); + + bool r = false; + SoundFormat sf; + queryIsRecordingRunning(id, r, sf); + + if (!r && b /*!m_StreamID2MenuID.contains(id)*/) { + if (!queryIsPowerOn()) + sendPowerOn(); + sendStartRecording(id); + } else if (r && !b) { + sendStopRecording(id); + } +} + + +void RadioView::slotRecordingMenu(int i) +{ + if (i == POPUP_ID_START_RECORDING_DEFAULT) { + SoundStreamID id = queryCurrentSoundStreamID(); + bool r = false; + SoundFormat sf; + queryIsRecordingRunning(id, r, sf); + if (!r) { + if (!queryIsPowerOn()) + sendPowerOn(); + sendStartRecording(id); + } + } else if (m_MenuID2StreamID.contains(i)) { + sendStopRecording(m_MenuID2StreamID[i]); + } +} + + +void RadioView::slotSnooze(bool on) +{ + if (on) + sendStartCountdown(); + else + sendStopCountdown(); +} + + +void RadioView::slotSnooze(int n) +{ + sendCountdownSeconds(n*60); + sendStartCountdown(); +} + + +void RadioView::slotComboStationSelected(int idx) +{ + if (idx > 0) { + sendActivateStation(idx - 1); + } else { + comboStations->setCurrentItem(queryCurrentStationIdx() + 1); + } +} + +void RadioView::slotBtnPluginsClicked() +{ + btnPlugins->openPopup(); +} + +void RadioView::slotConfigPageDeleted(QObject *o) +{ + configPages.remove(o); +} + + +void RadioView::slotElementConfigPageDeleted(QObject *o) +{ + ElementCfgListIterator it; + while ((it = elementConfigPages.find(o)) != elementConfigPages.end()) { + elementConfigPages.remove(it); + } +} + + +void RadioView::show() +{ + if (enableToolbarFlag) + KWin::setType(winId(), NET::Toolbar); + else + KWin::setType(winId(), NET::Normal); + WidgetPluginBase::pShow(); + QWidget::show(); +} + + +void RadioView::showOnOrgDesktop() +{ + WidgetPluginBase::pShowOnOrgDesktop(); + //QWidget::show(); +} + + + +void RadioView::hide() +{ + WidgetPluginBase::pHide(); + QWidget::hide(); +} + + +void RadioView::showEvent(QShowEvent *e) +{ + QWidget::showEvent(e); + WidgetPluginBase::pShowEvent(e); +} + + +void RadioView::hideEvent(QHideEvent *e) +{ + QWidget::hideEvent(e); + WidgetPluginBase::pHideEvent(e); +} + + +void RadioView::autoSetCaption() +{ + const RadioStation &rs = queryCurrentStation(); + setCaption((queryIsPowerOn() && rs.isValid()) ? rs.longName() : QString("KRadio")); +} + + + + +#include "radioview.moc" diff --git a/kradio3/plugins/gui-standard-display/radioview.h b/kradio3/plugins/gui-standard-display/radioview.h new file mode 100644 index 0000000..6cddc26 --- /dev/null +++ b/kradio3/plugins/gui-standard-display/radioview.h @@ -0,0 +1,207 @@ +/*************************************************************************** + radioview.h - description + ------------------- + begin : Mit Mai 28 2003 + copyright : (C) 2003 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_RADIOVIEW_H +#define KRADIO_RADIOVIEW_H + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <qobjectlist.h> + +#include "../../src/include/radio_interfaces.h" +#include "../../src/include/radiodevicepool_interfaces.h" +#include "../../src/include/soundstreamclient_interfaces.h" +#include "../../src/include/timecontrol_interfaces.h" +#include "../../src/include/widgetplugins.h" +#include "radioview_element.h" + +class QWidgetStack; +class QToolButton; +class KComboBox; +class QTabWidget; +class KPopupMenu; + + + +class RadioView : public QWidget, + public WidgetPluginBase, + public IRadioClient, + public IRadioDevicePoolClient, + public ISoundStreamClient, + public ITimeControlClient +{ +Q_OBJECT +public: + + RadioView(const QString &name); + virtual ~RadioView(); + + virtual QString pluginClassName() const { return "RadioView"; } + + const QString &name() const { return PluginBase::name(); } + QString &name() { return PluginBase::name(); } + + // WidgetPluginBase + +public: + virtual void saveState (KConfig *) const; + virtual void restoreState (KConfig *); + + virtual bool connectI(Interface *i); + virtual bool disconnectI(Interface *i); + + virtual void noticeWidgetPluginShown(WidgetPluginBase *p, bool shown); + virtual void noticePluginsChanged(const PluginList &); + + virtual ConfigPageInfo createConfigurationPage(); + virtual AboutPageInfo createAboutPage(); + +public slots: + // connects destroy-msg with remove-function + bool addElement (RadioViewElement *); + bool removeElement (QObject *); + +protected: + void selectTopWidgets(); + + + // IRadioClient + +RECEIVERS: + bool noticePowerChanged(bool on); + bool noticeStationChanged (const RadioStation &, int idx); + bool noticeStationsChanged(const StationList &sl); + bool noticePresetFileChanged(const QString &/*f*/) { return false; } + + bool noticeCurrentSoundStreamIDChanged(SoundStreamID id); + + // IRadioDevicePoolClient + +RECEIVERS: + bool noticeActiveDeviceChanged(IRadioDevice *rd); + bool noticeDevicesChanged(const QPtrList<IRadioDevice> &) { return false; } + bool noticeDeviceDescriptionChanged(const QString &) { return false; } + + // ISoundStreamClient + +RECEIVERS: + void noticeConnectedI (ISoundStreamServer *s, bool pointer_valid); + + bool startRecordingWithFormat(SoundStreamID /*id*/, + const SoundFormat &/*proposed_format*/, + SoundFormat &/*real_format*/); + bool stopRecording(SoundStreamID /*id*/); + + bool noticeSoundStreamChanged(SoundStreamID id); + + // ITimeControlClient + +RECEIVERS: + bool noticeAlarmsChanged(const AlarmVector &) { return false; } + bool noticeAlarm(const Alarm &) { return false; } + bool noticeNextAlarmChanged(const Alarm *) { return false; } + bool noticeCountdownStarted(const QDateTime &end); + bool noticeCountdownStopped(); + bool noticeCountdownZero(); + bool noticeCountdownSecondsChanged(int) { return false; } + +protected slots: + + void slotPower (bool on); + void slotPause(); + void slotConfigure (bool show); + void slotRecord (); + void slotSnooze (bool start); + void slotSnooze (int time); + void slotRecordingMenu(int i); + void slotBtnPluginsClicked(); + void slotComboStationSelected(int); + + void slotConfigPageDeleted(QObject*); + void slotElementConfigPageDeleted(QObject*); + +public slots: + + void toggleShown() { WidgetPluginBase::pToggleShown(); } + void showOnOrgDesktop(); + void show(); + void hide(); + +protected: + virtual void showEvent(QShowEvent *); + virtual void hideEvent(QHideEvent *); + + virtual void autoSetCaption(); + + const QWidget *getWidget() const { return this; } + QWidget *getWidget() { return this; } + + void addConfigurationTabFor(RadioViewElement *, QTabWidget *); + void addCommonConfigurationTab(QTabWidget *); + +protected: + bool enableToolbarFlag; + + QToolButton *btnPower; + QToolButton *btnConfigure; + QToolButton *btnQuit; + QToolButton *btnRecording; + QToolButton *btnSnooze; + QToolButton *btnPlugins; + KComboBox *comboStations; + + struct ElementCfg + { + RadioViewElement *element; + QObject *cfg; + ElementCfg() : element(NULL), cfg(NULL) {} + ElementCfg(RadioViewElement *e, QObject *w) : element(e), cfg(w) {} + ElementCfg(RadioViewElement *e) : element(e), cfg(NULL) {} + ElementCfg(QObject *w) : element(NULL), cfg(w) {} + bool operator == (const ElementCfg &x) const; + }; + + typedef QPtrList<RadioViewElement> ElementList; + typedef QPtrListIterator<RadioViewElement> ElementListIterator; + typedef QValueList<ElementCfg> ElementCfgList; + typedef QValueListIterator<ElementCfg> ElementCfgListIterator; + + ElementList elements; + ElementCfgList elementConfigPages; + QObjectList configPages; + QWidgetStack * widgetStacks[clsClassMAX]; + float maxUsability[clsClassMAX]; + + IRadioDevice *currentDevice; + + KPopupMenu *m_RecordingMenu; + KPopupMenu *m_pauseMenu; + KPopupMenu *m_SnoozeMenu; + int m_NextRecordingMenuID; + QMap<int, SoundStreamID> m_MenuID2StreamID; + QMap<SoundStreamID, int> m_StreamID2MenuID; + + KPopupMenu *m_PluginMenu; + QMap<WidgetPluginBase *, int> m_Plugins2MenuID; +}; + + + + +#endif diff --git a/kradio3/plugins/gui-standard-display/radioview_element.cpp b/kradio3/plugins/gui-standard-display/radioview_element.cpp new file mode 100644 index 0000000..9c3396f --- /dev/null +++ b/kradio3/plugins/gui-standard-display/radioview_element.cpp @@ -0,0 +1,34 @@ +/*************************************************************************** + radioview_element.cpp - description + ------------------- + begin : Fre Jun 20 2003 + copyright : (C) 2003 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 "radioview_element.h" + +RadioViewElement::RadioViewElement (QWidget * /*parent*/, const QString & /*name*/, + RadioViewClass cls) + : myClass(cls) +{ +} + + +RadioViewElement::~RadioViewElement() +{ +} + + + + +#include "radioview_element.moc" diff --git a/kradio3/plugins/gui-standard-display/radioview_element.h b/kradio3/plugins/gui-standard-display/radioview_element.h new file mode 100644 index 0000000..11c77ac --- /dev/null +++ b/kradio3/plugins/gui-standard-display/radioview_element.h @@ -0,0 +1,66 @@ +/*************************************************************************** + radioview_element.h - description + ------------------- + begin : Fre Jun 20 2003 + copyright : (C) 2003 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_RADIOVIEW_ELEMENT_H +#define KRADIO_RADIOVIEW_ELEMENT_H + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <qframe.h> +#include "../../src/include/interfaces.h" +#include "../../src/include/plugins.h" + +enum RadioViewClass { clsRadioSound = 0, + clsRadioSeek, + clsRadioDisplay, + clsClassMAX + }; + + +// Defaults to an empty element +class RadioViewElement : public QFrame, + public virtual Interface +{ +Q_OBJECT +public: + RadioViewElement (QWidget *parent, const QString &name, RadioViewClass myClass); + virtual ~RadioViewElement(); + + bool connectI (Interface *) { return false; } // default behaviour, please overwrite in derived class + bool disconnectI(Interface *) { return false; } // default behaviour, please overwrite in derived class + + float getUsability (Interface *) const { return 0.01; } // 0 <= Usability <= 1, used to decide wich Element to use + // should be overwritten ;) + + RadioViewClass getClass() const { return myClass; } + + // Configuration ?? + virtual ConfigPageInfo createConfigurationPage() { return ConfigPageInfo(); } + + virtual void saveState (KConfig *) const {} + virtual void restoreState (KConfig *) {} + + +protected : + + RadioViewClass myClass; +}; + + +#endif diff --git a/kradio3/plugins/gui-standard-display/radioview_frequencyradio.cpp b/kradio3/plugins/gui-standard-display/radioview_frequencyradio.cpp new file mode 100644 index 0000000..8c6d15d --- /dev/null +++ b/kradio3/plugins/gui-standard-display/radioview_frequencyradio.cpp @@ -0,0 +1,443 @@ +/*************************************************************************** + kradiodisplay.cpp - description + ------------------- + begin : Mit Jan 29 2003 + copyright : (C) 2003 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 "../../src/include/utils.h" + +#include <qpainter.h> +#include <qimage.h> +#include <qpixmap.h> +#include <kimageeffect.h> // fading, blending, ... +#include <kpixmapio.h> // fast conversion between QPixmap/QImage +#include "radioview_frequencyradio.h" +#include "displaycfg.h" + +RadioViewFrequencyRadio::RadioViewFrequencyRadio(QWidget *parent, const QString &name ) + : RadioViewElement(parent, name, clsRadioDisplay), + m_power(false), + m_valid(false), + m_frequency(0), + m_quality(0.0), + m_stereo(false) +{ + setFrameStyle(Box | Sunken); + setLineWidth(1); + setMidLineWidth(1); + + + // set some sensless default colors + // real values are read in restoreState + setDisplayColors(QColor(20, 244, 20), + QColor(10, 117, 10).light(75), + QColor(10, 117, 10)); + setDisplayFont(QFont("Helvetica")); + +} + + +RadioViewFrequencyRadio::~RadioViewFrequencyRadio(){ +} + + +float RadioViewFrequencyRadio::getUsability (Interface *i) const +{ + if (dynamic_cast<IFrequencyRadio*>(i)) + return 1.0; + else + return 0.0; +} + + +void RadioViewFrequencyRadio::saveState (KConfig *config) const +{ + config->writeEntry("frequency-view-colorActiveText", m_colorActiveText); + config->writeEntry("frequency-view-colorInactiveText", m_colorInactiveText); + config->writeEntry("frequency-view-colorButton", m_colorButton); + config->writeEntry("frequency-view-font", m_font); +} + + +void RadioViewFrequencyRadio::restoreState (KConfig *config) +{ + QColor defaultActive (20, 244, 20), + defaultInactive(QColor(10, 117, 10).light(75)), + defaultButton (10, 117, 10); + QFont defaultFont ("Helvetica"); + QColor a, b, c; + QFont f; + a = config->readColorEntry ("frequency-view-colorActiveText", + &defaultActive); + b = config->readColorEntry ("frequency-view-colorInactiveText", + &defaultInactive); + c = config->readColorEntry ("frequency-view-colorButton", + &defaultButton); + f = config->readFontEntry ("frequency-view-font", + &defaultFont); + setDisplayColors(a, b, c); + setDisplayFont(f); +} + + +ConfigPageInfo RadioViewFrequencyRadio::createConfigurationPage() +{ + DisplayConfiguration *a = new DisplayConfiguration(NULL); + connectI(a); + return ConfigPageInfo (a, + i18n("Frequency Display"), + i18n("Frequency Display"), + QString::null + ); +} + + +// Interface + +bool RadioViewFrequencyRadio::connectI(Interface *i) +{ + bool o = IDisplayCfg::connectI(i); + bool c = ISoundStreamClient::connectI(i); + if (dynamic_cast<IFrequencyRadio *>(i)) { + + bool a = IRadioDeviceClient::connectI(i); + bool b = IFrequencyRadioClient::connectI(i); + return o || a || b || c; + + } else { + return o || c; + } +} + + +bool RadioViewFrequencyRadio::disconnectI(Interface *i) +{ + // no check for IFrequencyRadio, it's just a disconnect + + bool a = IRadioDeviceClient::disconnectI(i); + bool b = IFrequencyRadioClient::disconnectI(i); + bool c = ISoundStreamClient::disconnectI(i); + bool o = IDisplayCfg::disconnectI(i); + + return a || b || c || o; +} + +void RadioViewFrequencyRadio::noticeConnectedI (ISoundStreamServer *s, bool pointer_valid) +{ + ISoundStreamClient::noticeConnectedI(s, pointer_valid); + if (s && pointer_valid) { + s->register4_notifySignalQualityChanged(this); + s->register4_notifyStereoChanged(this); + } +} + +// IDisplayCfg + +bool RadioViewFrequencyRadio::setDisplayColors(const QColor &activeText, + const QColor &inactiveText, + const QColor &button) +{ + bool change = (activeText != m_colorActiveText || inactiveText != m_colorInactiveText || button != m_colorButton); + + m_colorActiveText = activeText; + m_colorInactiveText = inactiveText; + m_colorButton = button; + + QPalette pl = palette(); + QColorGroup cg = pl.inactive(); + + QBrush fg = cg.brush(QColorGroup::Foreground), + btn = cg.brush(QColorGroup::Button), + lgt = cg.brush(QColorGroup::Light), + drk = cg.brush(QColorGroup::Dark), + mid = cg.brush(QColorGroup::Mid), + txt = cg.brush(QColorGroup::Text), + btx = cg.brush(QColorGroup::BrightText), + bas = cg.brush(QColorGroup::Base), + bg = cg.brush(QColorGroup::Background); + + fg.setColor (m_colorActiveText); + btn.setColor(m_colorButton); + lgt.setColor(m_colorButton.light(180)); + drk.setColor(m_colorButton.light( 50)); + mid.setColor(m_colorInactiveText); + txt.setColor(m_colorActiveText); + btx.setColor(m_colorActiveText); + bas.setColor(m_colorButton); + bg.setColor (m_colorButton); + + QColorGroup ncg(fg, btn, lgt, drk, mid, txt, btx, bas, bg); + pl.setInactive(ncg); + pl.setActive(ncg); + setPalette(pl); + + if (parentWidget() && parentWidget()->backgroundPixmap() ){ + KPixmapIO io; + QImage i = io.convertToImage(*parentWidget()->backgroundPixmap()); + KImageEffect::fade(i, 0.5, colorGroup().color(QColorGroup::Dark)); + setPaletteBackgroundPixmap(io.convertToPixmap(i)); + setBackgroundOrigin(WindowOrigin); + } else { + setBackgroundColor(colorGroup().color(QColorGroup::Button)); + } + + if (change) + notifyDisplayColorsChanged(m_colorActiveText, m_colorInactiveText, m_colorButton); + return true; +} + +bool RadioViewFrequencyRadio::setDisplayFont (const QFont &f) +{ + if (m_font != f) { + m_font = f; + notifyDisplayFontChanged(m_font); + RadioViewElement::setFont(f); + } + return true; +} + +// IRadioDeviceClient + + +bool RadioViewFrequencyRadio::noticePowerChanged (bool on, const IRadioDevice */*sender*/) +{ + m_power = on; + + SoundStreamID ssid = queryCurrentSoundStreamID(); + float q = 0.0; + bool s = false; + querySignalQuality(ssid, q); + noticeSignalQualityChanged(ssid, q); + queryIsStereo(ssid, s); + noticeStereoChanged(ssid, s); + + repaint(); + return true; +} + + +bool RadioViewFrequencyRadio::noticeStationChanged (const RadioStation &, const IRadioDevice */*sender*/) +{ + return false; // we don't care +} + + +bool RadioViewFrequencyRadio::noticeDescriptionChanged (const QString &, const IRadioDevice */*sender*/) +{ + return false; // we don't care +} + + +// IRadioSoundClient + +bool RadioViewFrequencyRadio::noticeSignalQualityChanged(SoundStreamID id, float q) +{ + if (queryCurrentSoundStreamID() != id) + return false; + m_quality = q; + repaint (); + return true; +} + + +bool RadioViewFrequencyRadio::noticeStereoChanged(SoundStreamID id, bool s) +{ + if (queryCurrentSoundStreamID() != id) + return false; + m_stereo = s; + repaint (); + return true; +} + + + + +// IFrequencyRadioClient + + +bool RadioViewFrequencyRadio::noticeFrequencyChanged(float f, const RadioStation *) +{ + m_frequency = f; + repaint (); + return true; +} + + +bool RadioViewFrequencyRadio::noticeMinMaxFrequencyChanged(float /*min*/, float /*max*/) +{ + return false; // we don't care +} + + +bool RadioViewFrequencyRadio::noticeDeviceMinMaxFrequencyChanged(float /*min*/, float /*max*/) +{ + return false; // we don't care +} + + +bool RadioViewFrequencyRadio::noticeScanStepChanged(float /*s*/) +{ + return false; // we don't care +} + + + +void RadioViewFrequencyRadio::drawContents(QPainter *paint) +{ + if (!paint) return; + + QRect r = contentsRect(); + + int margin = QMAX(4, QMIN(r.width() / 50, r.height() / 50)), + tmp = QMIN(r.height(), (r.width() - 2*margin) / 4), + xd_st = QMIN((r.height() - margin * 2) / 3, tmp/3), + xw = QMIN(tmp / 2, xd_st * 3 / 2), + penw = QMAX(1, xw / 25), + xh_st = xd_st, + xx_st = r.x() + margin + xw + 2 * margin + penw/2, + xy_st = r.y() + margin + penw/2, + + xx_am = xx_st, + xy_am = xy_st + xh_st + margin / 2, + xh_am = (r.bottom() - margin - xy_am + 1 - margin/2) / 2, + + xx_fm = xx_am, + xy_fm = xy_am + xh_am + margin/2, + xh_fm = xh_am, + + xh_sg = r.height() - margin * 2, + xx_sg = r.x() + margin, + xy_sg = r.y() + margin; + + QPen activePen (colorGroup().color(QColorGroup::Text), penw); + QPen inactivePen (colorGroup().color(QColorGroup::Mid), penw); + QBrush activeBrush = colorGroup().brush(QColorGroup::Text); + QBrush inactiveBrush = colorGroup().brush(QColorGroup::Mid); + + // draw stereo symbol + paint->setPen( (m_stereo && m_power) ? activePen : inactivePen); + paint->drawArc((int)xx_st, (int)xy_st, + (int)(xd_st - penw), (int)(xd_st - penw), + 0, 360*16); + paint->drawArc((int)(xx_st + xd_st/2), (int)xy_st, + (int)(xd_st - penw), (int)(xd_st - penw), + 0, 360*16); + + // draw signal quality symbol + float cx = xx_sg, + cy = xy_sg, + cw = xw, + ch = xw; + + float open_a = 30.0; + // outer circle + paint->setPen( (m_quality > 0.75 && m_power) ? activePen : inactivePen); + paint->drawArc((int)rint(cx), (int)rint(cy), + (int)rint(cw), (int)rint(ch), + (int)(-90+open_a)*16, (int)(360 - 2*open_a)*16 + ); + + // mid circle + paint->setPen( (m_quality > 0.50 && m_power) ? activePen : inactivePen); + cx += (float)xw/5.0; cy += (float)xw/5.0; + cw -= (float)xw/2.5; ch -= (float)xw/2.5; + paint->drawArc((int)rint(cx), (int)rint(cy), + (int)rint(cw), (int)rint(ch), + (int)(-90+open_a)*16, (int)(360 - 2*open_a)*16 + ); + + // inner circle + paint->setPen( (m_quality > 0.25 && m_power) ? activePen : inactivePen); + cx += (float)xw/5.0; cy += (float)xw/5.0; + cw -= (float)xw/2.5; ch -= (float)xw/2.5; + paint->drawArc((int)rint(cx), (int)rint(cy), + (int)rint(cw), (int)rint(ch), + (int)(-90+open_a)*16, (int)(360 - 2*open_a)*16 + ); + + // triangle + QPen tmppen = (m_quality > 0.1 && m_power) ? activePen : inactivePen; + tmppen.setWidth(1); + paint->setPen(tmppen); + paint->setBrush( (m_quality > 0.1 && m_power) ? activeBrush : inactiveBrush); + QPointArray pts(3); + pts.setPoint(0, (int)(xx_sg + xw / 4), (int)(xy_sg + xh_sg - penw/2)); + pts.setPoint(1, (int)(xx_sg + xw *3/4), (int)(xy_sg + xh_sg - penw/2)); + pts.setPoint(2, (int)(xx_sg + xw / 2), (int)(xy_sg + xw/2 + penw)); + paint->drawConvexPolygon(pts); + + + + // AM/FM display + + QFont f = m_font; + paint->setPen ( (m_frequency <= 10 && m_power) ? activePen : inactivePen); + f.setPixelSize(xh_am); + paint->setFont(f); + paint->drawText(xx_am, xy_am + xh_am - 1, i18n("AM")); + int xw_am = QFontMetrics(f).width(i18n("AM")); + + paint->setPen ( (m_frequency > 10 && m_power) ? activePen : inactivePen); + f.setPixelSize(xh_fm); + paint->setFont(f); + paint->drawText(xx_fm, xy_fm + xh_fm - 1, i18n("FM")); + int xw_fm = QFontMetrics(f).width(i18n("FM")); + + int xx_f = QMAX(xx_fm + xw_fm, QMAX(xw_am + xx_am, QMAX(xx_st + xw, xw + xx_sg))) + margin, + xy_f = r.y() + margin, + xw_f = r.right() - margin - xx_f + 1, + xh_f = r.bottom() - margin - xy_f + 1; + + // Frequency Display + + QString s; + if (m_frequency < 10) { + s = i18n("%1 kHz").arg(KGlobal::locale()->formatNumber((int)(m_frequency * 1000), 0)); + } else { + s = i18n("%1 MHz").arg(KGlobal::locale()->formatNumber(m_frequency, 2)); + } + + float pxs = xh_f; + paint->setPen ( m_power ? activePen : inactivePen); + f.setPixelSize((int)pxs); + int n = 30; + while (1) { + QFontMetrics fm(f); + int sw = fm.boundingRect(xx_f, xy_f, xw_f, xh_f, Qt::AlignRight | Qt::AlignVCenter, s).width(); + if (sw <= xw_f || --n <= 0) break; + + float fact = (float)xw_f / (float)sw; + pxs = QMIN(pxs - 1, pxs * fact); + f.setPixelSize(QMAX(1,(int)pxs)); + } + paint->setFont(f); + paint->drawText(xx_f, xy_f, xw_f, xh_f, Qt::AlignRight | Qt::AlignVCenter, s); +} + + + + + + +void RadioViewFrequencyRadio::reparent (QWidget *prnt, + WFlags f, + const QPoint &p, + bool showIt) +{ + RadioViewElement::reparent(prnt, f, p, showIt); + setDisplayColors(m_colorActiveText, m_colorInactiveText, m_colorButton); +} + + +#include "radioview_frequencyradio.moc" diff --git a/kradio3/plugins/gui-standard-display/radioview_frequencyradio.h b/kradio3/plugins/gui-standard-display/radioview_frequencyradio.h new file mode 100644 index 0000000..795eae1 --- /dev/null +++ b/kradio3/plugins/gui-standard-display/radioview_frequencyradio.h @@ -0,0 +1,108 @@ +/*************************************************************************** + kradiodisplay.h - description + ------------------- + begin : Mit Jan 29 2003 + copyright : (C) 2003 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_RADIOVIEW_FREQUENCYRADIO_H +#define KRADIO_RADIOVIEW_FREQUENCYRADIO_H + +#include "../../src/include/radiodevice_interfaces.h" +#include "../../src/include/soundstreamclient_interfaces.h" +#include "radioview_element.h" +#include "displaycfg_interfaces.h" + +/** + *@author Martin Witte + */ + +class RadioViewFrequencyRadio : public RadioViewElement, // is a QObject, must be first + public IRadioDeviceClient, + public IFrequencyRadioClient, + public ISoundStreamClient, + public IDisplayCfg +{ +Q_OBJECT +public: + RadioViewFrequencyRadio(QWidget *parent, const QString &name); + ~RadioViewFrequencyRadio(); + + float getUsability (Interface *) const; + + virtual void saveState (KConfig *) const; + virtual void restoreState (KConfig *); + + ConfigPageInfo createConfigurationPage(); + +// Interface + + bool connectI (Interface *); + bool disconnectI(Interface *); + +// IDisplayCfg + +RECEIVERS: + bool setDisplayColors(const QColor &activeColor, const QColor &inactiveColor, const QColor &bkgnd); + bool setDisplayFont (const QFont &f); + +ANSWERS: + const QColor &getDisplayActiveColor() const { return m_colorActiveText; } + const QColor &getDisplayInactiveColor() const { return m_colorInactiveText; } + const QColor &getDisplayBkgndColor() const { return m_colorButton; } + const QFont &getDisplayFont() const { return m_font; } + +// IRadioDeviceClient +RECEIVERS: + bool noticePowerChanged (bool on, const IRadioDevice *sender = NULL); + bool noticeStationChanged (const RadioStation &, const IRadioDevice *sender = NULL); + bool noticeDescriptionChanged (const QString &, const IRadioDevice *sender = NULL); + bool noticeCurrentSoundStreamIDChanged(SoundStreamID /*id*/, const IRadioDevice */*sender*/) { return false; } + +// ISoundStreamClient +RECEIVERS: + void noticeConnectedI (ISoundStreamServer *s, bool pointer_valid); + + bool noticeSignalQualityChanged(SoundStreamID id, float q); + bool noticeStereoChanged(SoundStreamID id, bool s); + +// IFrequencyRadioClient +RECEIVERS: + bool noticeFrequencyChanged(float f, const RadioStation *s); + bool noticeMinMaxFrequencyChanged(float min, float max); + bool noticeDeviceMinMaxFrequencyChanged(float min, float max); + bool noticeScanStepChanged(float s); + +// own stuff ;) + +public: + + void reparent (QWidget *parent, WFlags f, const QPoint &p, bool showIt = FALSE); + +protected: + + void drawContents(QPainter *p); + +protected: + + QColor m_colorActiveText, m_colorInactiveText, m_colorButton; + QFont m_font; + + bool m_power; + bool m_valid; + float m_frequency; + float m_quality; + bool m_stereo; +}; + +#endif diff --git a/kradio3/plugins/gui-standard-display/radioview_frequencyseeker.cpp b/kradio3/plugins/gui-standard-display/radioview_frequencyseeker.cpp new file mode 100644 index 0000000..938939a --- /dev/null +++ b/kradio3/plugins/gui-standard-display/radioview_frequencyseeker.cpp @@ -0,0 +1,250 @@ +/*************************************************************************** + radioview_frequencyseeker.cpp - description + ------------------- + begin : Fre Jun 20 2003 + copyright : (C) 2003 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 <math.h> +#include <qlayout.h> +#include <qslider.h> +#include <qtoolbutton.h> +#include <qaccel.h> +#include <qtooltip.h> + +#include <kiconloader.h> +#include <klocale.h> + +#include "radioview_frequencyseeker.h" + +RadioViewFrequencySeeker::RadioViewFrequencySeeker(QWidget *parent, const QString &name) + : RadioViewElement(parent, name, clsRadioSeek), + m_btnSearchLeft(NULL), + m_btnStepLeft(NULL), + m_btnStepRight(NULL), + m_btnSearchRight(NULL), + m_sldFrequency(NULL), + m_ignoreChanges(false) +{ + QBoxLayout *l = new QBoxLayout(this, QBoxLayout::LeftToRight, /*spacing=*/ 3); + l->setMargin(0); + + m_sldFrequency = new QSlider(Qt::Horizontal, this); + m_btnSearchLeft = new QToolButton(this); + m_btnSearchRight = new QToolButton(this); + m_btnStepLeft = new QToolButton(this); + m_btnStepRight = new QToolButton(this); + + m_btnSearchLeft ->setToggleButton(true); + m_btnSearchRight->setToggleButton(true); + m_sldFrequency->setPageStep(1); + + m_btnSearchLeft ->setIconSet(SmallIconSet("2leftarrow")); + m_btnSearchRight->setIconSet(SmallIconSet("2rightarrow")); + m_btnStepLeft ->setIconSet(SmallIconSet("1leftarrow")); + m_btnStepRight ->setIconSet(SmallIconSet("1rightarrow")); + + l->addWidget (m_btnSearchLeft); + l->addWidget (m_btnStepLeft); + l->addWidget (m_sldFrequency); + l->addWidget (m_btnStepRight); + l->addWidget (m_btnSearchRight); + + QObject::connect(m_sldFrequency, SIGNAL(valueChanged(int)), + this, SLOT(slotSliderChanged(int))); + QObject::connect(m_btnSearchLeft, SIGNAL(toggled(bool)), + this, SLOT(slotSearchLeft(bool))); + QObject::connect(m_btnSearchRight, SIGNAL(toggled(bool)), + this, SLOT(slotSearchRight(bool))); + QObject::connect(m_btnStepLeft, SIGNAL(clicked()), + m_sldFrequency, SLOT(subtractStep())); + QObject::connect(m_btnStepRight, SIGNAL(clicked()), + m_sldFrequency, SLOT(addStep())); + + // Tooltips + + QToolTip::add(m_btnSearchLeft, i18n("Search for previous Radio Station")); + QToolTip::add(m_btnSearchRight, i18n("Search for next Radio Station")); + QToolTip::add(m_btnStepLeft, i18n("Decrement Frequency")); + QToolTip::add(m_btnStepRight, i18n("Increment Frequency")); + QToolTip::add(m_sldFrequency, i18n("Change Frequency")); + + // Accelerators + + QAccel *Accel = new QAccel (this); + Accel->insertItem (Key_Left, 100); + Accel->insertItem (Key_Right, 101); + Accel->connectItem (100, m_sldFrequency, SLOT(subtractStep())); + Accel->connectItem (101, m_sldFrequency, SLOT(addStep())); +} + + +RadioViewFrequencySeeker::~RadioViewFrequencySeeker() +{ +} + + +float RadioViewFrequencySeeker::getUsability (Interface *i) const +{ + if (dynamic_cast<IFrequencyRadio*>(i)) + return 0.9; + else + return 0.0; +} + + +// Interface + +bool RadioViewFrequencySeeker::connectI (Interface *i) +{ + if (IFrequencyRadioClient::connectI(i)) { + ISeekRadioClient::connectI(i); + return true; + } else { + return false; + } +} + + +bool RadioViewFrequencySeeker::disconnectI(Interface *i) +{ + bool a = IFrequencyRadioClient::disconnectI(i); + bool b = ISeekRadioClient::disconnectI(i); + return a || b; +} + + + +// ISeekRadioClient + +bool RadioViewFrequencySeeker::noticeSeekStarted (bool up) +{ + m_ignoreChanges = true; + m_btnSearchLeft->setOn(!up); + m_btnSearchRight->setOn(up); + m_ignoreChanges = false; + return true; +} + + +bool RadioViewFrequencySeeker::noticeSeekStopped () +{ + m_ignoreChanges = true; + m_btnSearchLeft->setOn(false); + m_btnSearchRight->setOn(false); + m_ignoreChanges = false; + return true; +} + + +bool RadioViewFrequencySeeker::noticeSeekFinished (const RadioStation &/*s*/, bool /*goodQuality*/) +{ + m_ignoreChanges = true; + m_btnSearchLeft->setOn(false); + m_btnSearchRight->setOn(false); + m_ignoreChanges = false; + return true; +} + + + +// IFrequencyRadioClient + +bool RadioViewFrequencySeeker::noticeFrequencyChanged(float f, const RadioStation */*s*/) +{ + float step = queryScanStep(); + if (step == 0) step = 0.000001; + + m_ignoreChanges = true; + m_sldFrequency->setValue((int)rint(f / step)); + m_ignoreChanges = false; + return true; +} + + +bool RadioViewFrequencySeeker::noticeMinMaxFrequencyChanged(float min, float max) +{ + float step = queryScanStep(); + if (step == 0) step = 0.000001; + + m_ignoreChanges = true; + m_sldFrequency->setMinValue((int)rint(min / step)); + m_sldFrequency->setMaxValue((int)rint(max / step)); + m_sldFrequency->setValue ((int)rint(queryFrequency() / step)); + m_ignoreChanges = false; + return true; +} + + +bool RadioViewFrequencySeeker::noticeDeviceMinMaxFrequencyChanged(float /*min*/, float /*max*/) +{ + return false; // we don't care +} + + +bool RadioViewFrequencySeeker::noticeScanStepChanged(float s) +{ + if (s == 0) s = 0.000001; + m_ignoreChanges = true; + m_sldFrequency->setMinValue((int)rint(queryMinFrequency() / s)); + m_sldFrequency->setMaxValue((int)rint(queryMaxFrequency() / s)); + m_sldFrequency->setValue ((int)rint(queryFrequency() / s)); + m_ignoreChanges = false; + return true; +} + + +void RadioViewFrequencySeeker::slotSearchLeft(bool on) +{ + if (m_ignoreChanges) return; + if (on) { + if (queryIsSeekUpRunning()) + sendStopSeek(); + if (!queryIsSeekRunning()) + sendStartSeekDown(); + } else { + if (queryIsSeekDownRunning()) + sendStopSeek(); + } + if (!queryIsSeekDownRunning()) + m_btnSearchLeft->setOn(false); +} + + +void RadioViewFrequencySeeker::slotSearchRight(bool on) +{ + if (m_ignoreChanges) return; + if (on) { + if (queryIsSeekDownRunning()) + sendStopSeek(); + if (!queryIsSeekRunning()) + sendStartSeekUp(); + } else { + if (queryIsSeekUpRunning()) + sendStopSeek(); + } + if (!queryIsSeekUpRunning()) + m_btnSearchRight->setOn(false); +} + + +void RadioViewFrequencySeeker::slotSliderChanged(int val) +{ + if (m_ignoreChanges) return; + sendFrequency(val * queryScanStep()); +} + + + + +#include "radioview_frequencyseeker.moc" diff --git a/kradio3/plugins/gui-standard-display/radioview_frequencyseeker.h b/kradio3/plugins/gui-standard-display/radioview_frequencyseeker.h new file mode 100644 index 0000000..12ca7d4 --- /dev/null +++ b/kradio3/plugins/gui-standard-display/radioview_frequencyseeker.h @@ -0,0 +1,78 @@ +/*************************************************************************** + radioview_frequencyseeker.h - description + ------------------- + begin : Fre Jun 20 2003 + copyright : (C) 2003 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_RADIOVIEW_FREQUENCYSEEKER_H +#define KRADIO_RADIOVIEW_FREQUENCYSEEKER_H + +#include "../../src/include/radiodevice_interfaces.h" +#include "radioview_element.h" + +class QToolButton; +class QSlider; + +class RadioViewFrequencySeeker : public RadioViewElement, // is a QObject, must be first + public ISeekRadioClient, + public IFrequencyRadioClient +{ +Q_OBJECT +public: + RadioViewFrequencySeeker(QWidget *parent, const QString &name); + ~RadioViewFrequencySeeker(); + + float getUsability(Interface *) const; + +// Interface + + bool connectI (Interface *); + bool disconnectI(Interface *); + +// ISeekRadioClient +RECEIVERS: + bool noticeSeekStarted (bool up); + bool noticeSeekStopped (); + bool noticeSeekFinished (const RadioStation &s, bool goodQuality); + bool noticeProgress (float ) { return false; } + +// IFrequencyRadioClient +RECEIVERS: + bool noticeFrequencyChanged(float f, const RadioStation *s); + bool noticeMinMaxFrequencyChanged(float min, float max); + bool noticeDeviceMinMaxFrequencyChanged(float min, float max); + bool noticeScanStepChanged(float s); + +// own stuff ;) + +protected slots: + + void slotSearchLeft(bool on); + void slotSearchRight(bool on); + void slotSliderChanged(int val); + +protected: + + QToolButton *m_btnSearchLeft, + *m_btnStepLeft, + *m_btnStepRight, + *m_btnSearchRight; + QSlider *m_sldFrequency; + + bool m_ignoreChanges; +}; + + + +#endif diff --git a/kradio3/plugins/gui-standard-display/radioview_seekinterface.ui b/kradio3/plugins/gui-standard-display/radioview_seekinterface.ui new file mode 100644 index 0000000..f4fc98c --- /dev/null +++ b/kradio3/plugins/gui-standard-display/radioview_seekinterface.ui @@ -0,0 +1,167 @@ +<!DOCTYPE UI><UI version="3.0" stdsetdef="1"> +<class>RadioView_SeekerUI</class> +<author>Ernst Martin Witte</author> +<widget class="QWidget"> + <property name="name"> + <cstring>RadioView_SeekerUI</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>477</width> + <height>43</height> + </rect> + </property> + <property name="caption"> + <string>RadioView_SeekInterface</string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QToolButton" row="0" column="0"> + <property name="name"> + <cstring>btnSearchDown</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>1</hsizetype> + <vsizetype>1</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="focusPolicy"> + <enum>TabFocus</enum> + </property> + <property name="text"> + <string></string> + </property> + <property name="iconSet"> + <iconset>"2rightarrow"</iconset> + </property> + <property name="toolTip" stdset="0"> + <string>search previous station</string> + </property> + </widget> + <widget class="QToolButton" row="0" column="1"> + <property name="name"> + <cstring>btnStepDown</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>1</hsizetype> + <vsizetype>1</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="focusPolicy"> + <enum>TabFocus</enum> + </property> + <property name="text"> + <string></string> + </property> + <property name="autoRepeat"> + <bool>true</bool> + </property> + <property name="iconSet"> + <iconset>"2rightarrow"</iconset> + </property> + <property name="toolTip" stdset="0"> + <string>decrease freq. by 0.05 MHz</string> + </property> + </widget> + <widget class="QSlider" row="0" column="2"> + <property name="name"> + <cstring>sldRange</cstring> + </property> + <property name="minValue"> + <number>8700</number> + </property> + <property name="maxValue"> + <number>10900</number> + </property> + <property name="lineStep"> + <number>5</number> + </property> + <property name="pageStep"> + <number>5</number> + </property> + <property name="value"> + <number>8700</number> + </property> + <property name="tracking"> + <bool>true</bool> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="tickmarks"> + <enum>NoMarks</enum> + </property> + <property name="tickInterval"> + <number>100</number> + </property> + <property name="toolTip" stdset="0"> + <string>Frequency control</string> + <comment>Frequency</comment> + </property> + </widget> + <widget class="QToolButton" row="0" column="3"> + <property name="name"> + <cstring>btnStepUp</cstring> + </property> + <property name="focusPolicy"> + <enum>TabFocus</enum> + </property> + <property name="text"> + <string></string> + </property> + <property name="autoRepeat"> + <bool>true</bool> + </property> + <property name="iconSet"> + <iconset>"2rightarrow"</iconset> + </property> + <property name="toolTip" stdset="0"> + <string>increase freq. by 0.05 MHz</string> + </property> + </widget> + <widget class="QToolButton" row="0" column="4"> + <property name="name"> + <cstring>btnSearchUp</cstring> + </property> + <property name="focusPolicy"> + <enum>TabFocus</enum> + </property> + <property name="text"> + <string></string> + </property> + <property name="iconSet"> + <iconset>"2rightarrow"</iconset> + </property> + <property name="toolTip" stdset="0"> + <string>search next station</string> + </property> + </widget> + </grid> +</widget> +<tabstops> + <tabstop>btnSearchDown</tabstop> + <tabstop>btnStepDown</tabstop> + <tabstop>sldRange</tabstop> + <tabstop>btnStepUp</tabstop> + <tabstop>btnSearchUp</tabstop> +</tabstops> +<includes> + <include location="local" impldecl="in implementation">radioview_seekinterface.ui.h</include> +</includes> +<functions> + <function access="protected">init()</function> + <function>destroy()</function> +</functions> +<pixmapfunction>SmallIconSet</pixmapfunction> +<layoutdefaults spacing="6" margin="11"/> +</UI> diff --git a/kradio3/plugins/gui-standard-display/radioview_seekinterface.ui.h b/kradio3/plugins/gui-standard-display/radioview_seekinterface.ui.h new file mode 100644 index 0000000..1f75180 --- /dev/null +++ b/kradio3/plugins/gui-standard-display/radioview_seekinterface.ui.h @@ -0,0 +1,21 @@ +/**************************************************************************** +** ui.h extension file, included from the uic-generated form implementation. +** +** If you wish to add, delete or rename functions or slots use +** Qt Designer which will update this file, preserving your code. Create an +** init() function in place of a constructor, and a destroy() function in +** place of a destructor. +*****************************************************************************/ + +void RadioView_SeekerUI::init() +{ + Accel = new QAccel (this); + Accel->insertItem (Key_Left, 100); + Accel->insertItem (Key_Right, 101); + Accel->connectItem (100, sldRange, SLOT(subtractStep())); + Accel->connectItem (101, sldRange, SLOT(addStep())); +} + +void RadioView_SeekerUI::destroy() +{ +} diff --git a/kradio3/plugins/gui-standard-display/radioview_volume.cpp b/kradio3/plugins/gui-standard-display/radioview_volume.cpp new file mode 100644 index 0000000..d642aa4 --- /dev/null +++ b/kradio3/plugins/gui-standard-display/radioview_volume.cpp @@ -0,0 +1,141 @@ +/*************************************************************************** + radioview_volume.cpp - description + ------------------- + begin : Don Jun 19 2003 + copyright : (C) 2003 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 <math.h> +#include <qslider.h> +#include <qlayout.h> +#include <qaccel.h> +#include <qtooltip.h> + +#include <klocale.h> + +#include "radioview_volume.h" +#include "../../src/include/plugins.h" + +#define SLIDER_MINVAL 0 +#define SLIDER_MAXVAL 32768 +#define SLIDER_RANGE (SLIDER_MAXVAL - SLIDER_MINVAL) + +RadioViewVolume::RadioViewVolume(QWidget *parent, const QString &name) + : RadioViewElement (parent, name, clsRadioSound), + m_slider(NULL), + m_handlingSlot(false) +{ + float v = 0; + SoundStreamID ssid = queryCurrentSoundStreamID(); + sendLogDebug (QString ("RadioViewVolume: ssid=%1").arg(ssid.getID())); + queryPlaybackVolume(ssid, v); + m_slider = new QSlider(SLIDER_MINVAL, + SLIDER_MAXVAL, + SLIDER_RANGE/10, + getSlider4Volume(v), + Qt::Vertical, this); + + QObject::connect(m_slider, SIGNAL(valueChanged(int)), + this, SLOT(slotVolumeChanged(int))); + + QBoxLayout *l = new QBoxLayout(this, QBoxLayout::LeftToRight); + l->addWidget(m_slider); + + // Tooltips + + QToolTip::add(m_slider, i18n("Change Volume")); + + // Accelerators + QAccel *Accel = new QAccel (this); + Accel->insertItem (Key_Up, 100); + Accel->insertItem (Key_Down, 101); + Accel->connectItem (100, m_slider, SLOT(subtractStep())); + Accel->connectItem (101, m_slider, SLOT(addStep())); + +} + + +RadioViewVolume::~RadioViewVolume() +{ +} + + +float RadioViewVolume::getUsability (Interface */*i*/) const +{ + return 0.5; // there could be more features like mute control, capture settings, ... +} + + +bool RadioViewVolume::connectI (Interface *i) +{ + bool a = IRadioDeviceClient::connectI(i); + bool b = ISoundStreamClient::connectI(i); + return a || b; +} + + +bool RadioViewVolume::disconnectI(Interface *i) +{ + bool a = IRadioDeviceClient::disconnectI(i); + bool b = ISoundStreamClient::disconnectI(i); + return a || b; +} + +void RadioViewVolume::noticeConnectedI (ISoundStreamServer *s, bool pointer_valid) +{ + ISoundStreamClient::noticeConnectedI(s, pointer_valid); + if (s && pointer_valid) { + s->register4_notifyPlaybackVolumeChanged(this); + } +} + +// ISoundStreamClient + +bool RadioViewVolume::noticePlaybackVolumeChanged(SoundStreamID id, float v) +{ + if (queryCurrentSoundStreamID() != id) + return false; + m_slider->setValue(getSlider4Volume(v)); + return true; +} + + + +void RadioViewVolume::slotVolumeChanged(int val) +{ + if (m_handlingSlot) return; + m_handlingSlot = true; + SoundStreamID ssid = queryCurrentSoundStreamID(); + sendPlaybackVolume(ssid, getVolume4Slider(val)); + m_handlingSlot = false; +} + + +int RadioViewVolume::getSlider4Volume(float volume) +{ + if (volume >= 1) volume = 1; + if (volume < 0) volume = 0; + return SLIDER_MAXVAL - (int)rint(SLIDER_RANGE * volume); +} + + +float RadioViewVolume::getVolume4Slider(int sl) +{ + if (sl > SLIDER_MAXVAL) sl = SLIDER_MAXVAL; + if (sl < SLIDER_MINVAL) sl = SLIDER_MINVAL; + return (float)(SLIDER_MAXVAL - sl) / (float)SLIDER_RANGE; +} + + + +#include "radioview_volume.moc" diff --git a/kradio3/plugins/gui-standard-display/radioview_volume.h b/kradio3/plugins/gui-standard-display/radioview_volume.h new file mode 100644 index 0000000..a48c16d --- /dev/null +++ b/kradio3/plugins/gui-standard-display/radioview_volume.h @@ -0,0 +1,75 @@ +/*************************************************************************** + radioview_volume.h - description + ------------------- + begin : Don Jun 19 2003 + copyright : (C) 2003 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_RADIOVIEW_VOLUME_H +#define KRADIO_RADIOVIEW_VOLUME_H + +#include "../../src/include/radiodevice_interfaces.h" +#include "../../src/include/soundstreamclient_interfaces.h" +#include "radioview_element.h" + +/** + *@author Martin Witte + */ + +class QSlider; + +class RadioViewVolume : public RadioViewElement, // is a QObject, must be first + public IRadioDeviceClient, + public ISoundStreamClient, + public IErrorLogClient +{ +Q_OBJECT +public: + RadioViewVolume(QWidget *parent, const QString &name); + ~RadioViewVolume(); + + float getUsability(Interface *) const; + +// Interface + + bool connectI (Interface *); + bool disconnectI(Interface *); + +// IRadioDeviceClient +RECEIVERS: + bool noticePowerChanged (bool /*on*/, const IRadioDevice */*sender*/) { return false; } + bool noticeStationChanged (const RadioStation &, const IRadioDevice */*sender*/) { return false; } + bool noticeDescriptionChanged (const QString &, const IRadioDevice */*sender*/) { return false; } + bool noticeCurrentSoundStreamIDChanged(SoundStreamID /*id*/, const IRadioDevice */*sender*/) { return false; } + +// ISoundStreamClient +RECEIVERS: + void noticeConnectedI (ISoundStreamServer *s, bool pointer_valid); + bool noticePlaybackVolumeChanged(SoundStreamID id, float v); + +// own stuff +protected slots: + + void slotVolumeChanged(int val); + +protected: + + int getSlider4Volume(float volume); + float getVolume4Slider(int sl); + + QSlider *m_slider; + bool m_handlingSlot; + +}; + +#endif diff --git a/kradio3/plugins/lirc/Makefile.am b/kradio3/plugins/lirc/Makefile.am new file mode 100644 index 0000000..383fe28 --- /dev/null +++ b/kradio3/plugins/lirc/Makefile.am @@ -0,0 +1,28 @@ + +SUBDIRS = po . + +INCLUDES = $(all_includes) +METASOURCES = AUTO + +libkradio_LTLIBRARIES = liblirc.la +liblirc_la_SOURCES = lircsupport.cpp lirc-configuration-ui.ui \ + lirc-configuration.cpp listviewitem_lirc.cpp +liblirc_la_LDFLAGS = -module -avoid-version $(KDE_RPATH) $(all_libraries) +liblirc_la_LIBADD = $(LIB_LIRC) + +noinst_HEADERS = lircsupport.h lirc-configuration.h listviewitem_lirc.h + + +install-data-local: + $(mkinstalldirs) "$(DESTDIR)$(kde_datadir)/kradio/" + $(INSTALL_DATA) "$(srcdir)/default-dot-lircrc" "$(DESTDIR)$(kde_datadir)/kradio/default-dot-lircrc" + +uninstall-local: + -rm -f "$(DESTDIR)$(kde_datadir)/kradio/default-dot-lircrc" + +#messages: rc.cpp +# $(XGETTEXT) *.cpp *.h -o po/kradio-lirc.pot + +messages: rc.cpp + $(EXTRACTRC) *.rc *.ui >> rc.cpp + $(XGETTEXT) rc.cpp *.h *.cpp -o po/kradio-lirc.pot diff --git a/kradio3/plugins/lirc/default-dot-lircrc b/kradio3/plugins/lirc/default-dot-lircrc new file mode 100644 index 0000000..02ac704 --- /dev/null +++ b/kradio3/plugins/lirc/default-dot-lircrc @@ -0,0 +1,6 @@ + +begin + prog = kradio + config = eventmap + repeat = 1 +end diff --git a/kradio3/plugins/lirc/lirc-configuration-ui.ui b/kradio3/plugins/lirc/lirc-configuration-ui.ui new file mode 100644 index 0000000..8fadc85 --- /dev/null +++ b/kradio3/plugins/lirc/lirc-configuration-ui.ui @@ -0,0 +1,110 @@ +<!DOCTYPE UI><UI version="3.3" stdsetdef="1"> +<class>LIRCConfigurationUI</class> +<author>Ernst Martin Witte</author> +<widget class="QWidget"> + <property name="name"> + <cstring>LIRCConfigurationUI</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>600</width> + <height>585</height> + </rect> + </property> + <property name="caption"> + <string>LIRCConfigurationUI</string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="KListView" row="0" column="0"> + <column> + <property name="text"> + <string>Action</string> + </property> + <property name="clickable"> + <bool>true</bool> + </property> + <property name="resizable"> + <bool>true</bool> + </property> + </column> + <column> + <property name="text"> + <string>LIRC String</string> + </property> + <property name="clickable"> + <bool>true</bool> + </property> + <property name="resizable"> + <bool>true</bool> + </property> + </column> + <column> + <property name="text"> + <string>Alternative LIRC String</string> + </property> + <property name="clickable"> + <bool>true</bool> + </property> + <property name="resizable"> + <bool>true</bool> + </property> + </column> + <property name="name"> + <cstring>m_ActionList</cstring> + </property> + <property name="allColumnsShowFocus"> + <bool>true</bool> + </property> + <property name="itemMargin"> + <number>2</number> + </property> + <property name="rootIsDecorated"> + <bool>false</bool> + </property> + <property name="resizeMode"> + <enum>AllColumns</enum> + </property> + <property name="defaultRenameAction"> + <enum>Accept</enum> + </property> + <property name="fullWidth"> + <bool>true</bool> + </property> + </widget> + <widget class="Line" row="1" column="0"> + <property name="name"> + <cstring>line1</cstring> + </property> + <property name="frameShape"> + <enum>HLine</enum> + </property> + <property name="frameShadow"> + <enum>Sunken</enum> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + </widget> + <widget class="QLabel" row="2" column="0"> + <property name="name"> + <cstring>m_LabelHints</cstring> + </property> + <property name="text"> + <string>textLabel1</string> + </property> + </widget> + </grid> +</widget> +<customwidgets> +</customwidgets> +<pixmapfunction>SmallIconSet</pixmapfunction> +<layoutdefaults spacing="6" margin="0"/> +<includehints> + <includehint>klistview.h</includehint> +</includehints> +</UI> diff --git a/kradio3/plugins/lirc/lirc-configuration.cpp b/kradio3/plugins/lirc/lirc-configuration.cpp new file mode 100644 index 0000000..9b98a44 --- /dev/null +++ b/kradio3/plugins/lirc/lirc-configuration.cpp @@ -0,0 +1,193 @@ +/*************************************************************************** + lirc-configuration.cpp - description + ------------------- + begin : Sat May 21 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 <klistview.h> +#include <klocale.h> + +#include <qlistview.h> +#include <qlabel.h> + +#include "lirc-configuration.h" +#include "lircsupport.h" +#include "listviewitem_lirc.h" + +LIRCConfiguration::LIRCConfiguration (QWidget *parent, LircSupport *dev) + : LIRCConfigurationUI(parent), + m_LIRC (dev), + m_dirty(true), + m_ignore_gui_updates(false) +{ + m_descriptions[LIRC_DIGIT_0] = i18n("digit 0"); + m_descriptions[LIRC_DIGIT_1] = i18n("digit 1"); + m_descriptions[LIRC_DIGIT_2] = i18n("digit 2"); + m_descriptions[LIRC_DIGIT_3] = i18n("digit 3"); + m_descriptions[LIRC_DIGIT_4] = i18n("digit 4"); + m_descriptions[LIRC_DIGIT_5] = i18n("digit 5"); + m_descriptions[LIRC_DIGIT_6] = i18n("digit 6"); + m_descriptions[LIRC_DIGIT_7] = i18n("digit 7"); + m_descriptions[LIRC_DIGIT_8] = i18n("digit 8"); + m_descriptions[LIRC_DIGIT_9] = i18n("digit 9"); + m_descriptions[LIRC_POWER_ON] = i18n("Power On"); + m_descriptions[LIRC_POWER_OFF] = i18n("Power Off"); + m_descriptions[LIRC_PAUSE] = i18n("Pause"); + m_descriptions[LIRC_RECORD_START] = i18n("Start Recording"); + m_descriptions[LIRC_RECORD_STOP] = i18n("Stop Recording"); + m_descriptions[LIRC_VOLUME_INC] = i18n("Increase Volume"); + m_descriptions[LIRC_VOLUME_DEC] = i18n("Decrease Volume"); + m_descriptions[LIRC_CHANNEL_NEXT] = i18n("Next Channel"); + m_descriptions[LIRC_CHANNEL_PREV] = i18n("Previous Channel"); + m_descriptions[LIRC_SEARCH_NEXT] = i18n("Search Next Channel"); + m_descriptions[LIRC_SEARCH_PREV] = i18n("Search Previous Channel"); + m_descriptions[LIRC_SLEEP] = i18n("Enable Sleep Countdown"); + m_descriptions[LIRC_APPLICATION_QUIT] = i18n("Quit KRadio"); + + int k = 0; + m_order[k++] = LIRC_DIGIT_0; + m_order[k++] = LIRC_DIGIT_1; + m_order[k++] = LIRC_DIGIT_2; + m_order[k++] = LIRC_DIGIT_3; + m_order[k++] = LIRC_DIGIT_4; + m_order[k++] = LIRC_DIGIT_5; + m_order[k++] = LIRC_DIGIT_6; + m_order[k++] = LIRC_DIGIT_7; + m_order[k++] = LIRC_DIGIT_8; + m_order[k++] = LIRC_DIGIT_9; + m_order[k++] = LIRC_POWER_ON; + m_order[k++] = LIRC_POWER_OFF; + m_order[k++] = LIRC_PAUSE; + m_order[k++] = LIRC_RECORD_START; + m_order[k++] = LIRC_RECORD_STOP; + m_order[k++] = LIRC_VOLUME_INC; + m_order[k++] = LIRC_VOLUME_DEC; + m_order[k++] = LIRC_CHANNEL_NEXT; + m_order[k++] = LIRC_CHANNEL_PREV; + m_order[k++] = LIRC_SEARCH_NEXT; + m_order[k++] = LIRC_SEARCH_PREV; + m_order[k++] = LIRC_SLEEP; + m_order[k++] = LIRC_APPLICATION_QUIT; + + m_ActionList->setSorting(-1); + m_ActionList->setColumnWidthMode(0, QListView::Maximum); + m_ActionList->setColumnWidthMode(1, QListView::Maximum); + m_ActionList->setColumnWidthMode(2, QListView::Maximum); + + connect(m_ActionList, SIGNAL(itemRenamed(QListViewItem*, int)), this, SLOT(slotSetDirty())); + slotCancel(); +} + + +LIRCConfiguration::~LIRCConfiguration () +{ +} + + +void LIRCConfiguration::slotOK() +{ + if (m_dirty && m_LIRC) { + QListViewItem *item = m_ActionList->firstChild(); + + QMap<LIRC_Actions, QString> actions; + QMap<LIRC_Actions, QString> alt_actions; + + for (int i = 0; item; ++i, item = item->nextSibling()) { + LIRC_Actions action = m_order[i]; + actions[action] = item->text(1); + alt_actions[action] = item->text(2); + } + m_LIRC->setActions(actions, alt_actions); + } + m_dirty = false; +} + + +void LIRCConfiguration::slotCancel() +{ + if (m_dirty) { + m_ignore_gui_updates = true; + m_ActionList->clear(); + if (m_LIRC) { + const QMap<LIRC_Actions, QString> &actions = m_LIRC->getActions(); + const QMap<LIRC_Actions, QString> &alt_actions = m_LIRC->getAlternativeActions(); + + for (unsigned i = 0; m_order.contains(i) && i < m_order.count(); ++i) { + LIRC_Actions action = m_order[i]; + addKey(m_descriptions[action], actions[action], alt_actions[action]); + } + } + + slotRenamingStopped(NULL, -1); + m_ignore_gui_updates = false; + } + m_dirty = false; +} + + +void LIRCConfiguration::addKey(const QString &descr, const QString &key, const QString &alt_key) +{ + ListViewItemLirc *item = new ListViewItemLirc(m_ActionList, m_ActionList->lastChild()); + if (item) { + QObject::connect(item, SIGNAL(sigRenamingStarted (ListViewItemLirc *, int)), + this, SLOT (slotRenamingStarted(ListViewItemLirc *, int))); + QObject::connect(item, SIGNAL(sigRenamingStopped (ListViewItemLirc *, int)), + this, SLOT (slotRenamingStopped(ListViewItemLirc *, int))); + item->setText(0, descr); + item->setText(1, key); + item->setText(2, alt_key); + item->setRenameEnabled(1, true); + item->setRenameEnabled(2, true); + } +} + +void LIRCConfiguration::slotUpdateConfig() +{ + slotSetDirty(); + slotCancel(); +} + +void LIRCConfiguration::slotRawLIRCSignal(const QString &val, int /*repeat_counter*/, bool &consumed) +{ + QListViewItem *_it = m_ActionList->currentItem(); + ListViewItemLirc *it = static_cast<ListViewItemLirc*>(_it); + if (it->isRenamingInProcess()) { + int col = it->getRenamingColumn(); + it->cancelRename(col); + it->setText(col, val); + consumed = true; + m_dirty = true; + } +} + +void LIRCConfiguration::slotRenamingStarted(ListViewItemLirc */*sender*/, int /*col*/) +{ + m_LabelHints->setText(i18n("Enter the key string of your remote or just press the button on your remote control")); +} + + +void LIRCConfiguration::slotRenamingStopped(ListViewItemLirc */*sender*/, int /*col*/) +{ + m_LabelHints->setText(i18n("Double Click on the entries to change the assignments")); +} + + +void LIRCConfiguration::slotSetDirty() +{ + if (!m_ignore_gui_updates) { + m_dirty = true; + } +} + +#include "lirc-configuration.moc" diff --git a/kradio3/plugins/lirc/lirc-configuration.h b/kradio3/plugins/lirc/lirc-configuration.h new file mode 100644 index 0000000..13bcda4 --- /dev/null +++ b/kradio3/plugins/lirc/lirc-configuration.h @@ -0,0 +1,60 @@ +/*************************************************************************** + lirc-configuration.h - description + ------------------- + begin : Sat May 21 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_LIRC_CONFIGURATION_H +#define KRADIO_LIRC_CONFIGURATION_H + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "lirc-configuration-ui.h" +#include "lircsupport.h" +#include "listviewitem_lirc.h" + +class LIRCConfiguration : public LIRCConfigurationUI +{ +Q_OBJECT +public : + LIRCConfiguration (QWidget *parent, LircSupport *); + ~LIRCConfiguration (); + +protected slots: + + void slotOK(); + void slotCancel(); + void slotSetDirty(); + + void slotUpdateConfig(); + void slotRawLIRCSignal(const QString &val, int repeat_counter, bool &consumed); + + void slotRenamingStarted(ListViewItemLirc *, int); + void slotRenamingStopped(ListViewItemLirc *, int); + +protected: + void addKey(const QString &descr, const QString &key, const QString &alt_key); + + LircSupport *m_LIRC; + + QMap<int, LIRC_Actions> m_order; + QMap<LIRC_Actions, QString> m_descriptions; + + bool m_dirty; + bool m_ignore_gui_updates; +}; + +#endif diff --git a/kradio3/plugins/lirc/lircsupport.cpp b/kradio3/plugins/lirc/lircsupport.cpp new file mode 100644 index 0000000..3b64580 --- /dev/null +++ b/kradio3/plugins/lirc/lircsupport.cpp @@ -0,0 +1,553 @@ +/*************************************************************************** + lircsupport.cpp - description + ------------------- + begin : Mon Feb 4 2002 + copyright : (C) 2002 by Martin Witte / Frank Schwanz + email : witte@kawo1.rwth-aachen.de / schwanz@fh-brandenburg.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 "lircsupport.h" + +#ifdef HAVE_LIRC +#include <lirc/lirc_client.h> +#endif + +#include <qsocketnotifier.h> +#include <qtimer.h> +#include <qfile.h> + +#include <kapplication.h> +#include <kaboutdata.h> +#include <kstandarddirs.h> + +#include "../../src/include/errorlog-interfaces.h" +#include "../../src/include/radiodevice_interfaces.h" +#include "../../src/include/stationlist.h" +#include "../../src/include/aboutwidget.h" + +#include "lirc-configuration.h" + +#include <cstdlib> + +#define LIRCRC ".lircrc" + +/////////////////////////////////////////////////////////////////////// +//// plugin library functions + +//#ifdef HAVE_LIRC +PLUGIN_LIBRARY_FUNCTIONS(LircSupport, "kradio-lirc", i18n("Linux Infrared Control (LIRC) Support")); +//#endif + +///////////////////////////////////////////////////////////////////////////// + +LircSupport::LircSupport(const QString &name) + : PluginBase(name, i18n("LIRC Plugin")), + m_TakeRawLIRC(false) +{ + +#ifdef HAVE_LIRC + logDebug(i18n("initializing kradio lirc plugin")); + fprintf (stderr, "%s\n", (const char*)i18n("initializing kradio lirc plugin").utf8()); + char *prg = (char*)"kradio"; + + QString slircrc = getenv("HOME"); + slircrc += "/" LIRCRC; + + QFile lircrc(slircrc); + if (!lircrc.exists()) { + logWarning(i18n("%1 does not exist. File was created with KRadio's default .lircrc proposal").arg(LIRCRC)); + QFile default_lircrc(locate("data", "kradio/default-dot-lircrc")); + lircrc.open(IO_WriteOnly); + default_lircrc.open(IO_ReadOnly); + char *buf = new char [default_lircrc.size() + 1]; + default_lircrc.readBlock(buf, default_lircrc.size()); + lircrc.writeBlock(buf, default_lircrc.size()); + lircrc.close(); + default_lircrc.close(); + delete buf; + } + + m_fd_lirc = lirc_init(prg, 1); + m_lirc_notify = 0; + m_lircConfig = 0; + + if (m_fd_lirc != -1) { + if (lirc_readconfig (NULL, &m_lircConfig, NULL) == 0) { + m_lirc_notify = new QSocketNotifier(m_fd_lirc, QSocketNotifier::Read, this, "lirc_notifier"); + if (m_lirc_notify) + QObject::connect(m_lirc_notify, SIGNAL(activated(int)), this, SLOT(slotLIRC(int))); + + // check config + lirc_config_entry *found = NULL; + for (lirc_config_entry *e = m_lircConfig->first; e; e = e->next) { + if (QString(e->prog) == prg) + found = e; + } + if (!found) { + logWarning(i18n("There is no entry for kradio in any of your .lircrc files.")); + logWarning(i18n("Please setup your .lircrc files correctly.")); + m_TakeRawLIRC = true; + } + + } else { + lirc_deinit(); + m_fd_lirc = -1; + } + } + + if (m_fd_lirc == -1) { + logWarning(i18n("Initializing kradio lirc plugin failed")); + fprintf (stderr, "%s\n", (const char*)i18n("Initializing kradio lirc plugin failed").utf8()); + } else { + logDebug(i18n("Initializing kradio lirc plugin successful")); + fprintf (stderr, "%s\n", (const char*)i18n("Initializing kradio lirc plugin successful").utf8()); + } +#endif + + m_kbdTimer = new QTimer (this); + QObject::connect (m_kbdTimer, SIGNAL(timeout()), this, SLOT(slotKbdTimedOut())); + + m_addIndex = 0; +} + + +LircSupport::~LircSupport() +{ +#ifdef HAVE_LIRC + if (m_fd_lirc != -1) + lirc_deinit(); + if (m_lircConfig) + lirc_freeconfig(m_lircConfig); + m_fd_lirc = -1; + m_lircConfig = 0; +#endif +} + + +void LircSupport::slotLIRC(int /*socket*/ ) +{ +#ifdef HAVE_LIRC + if (!m_lircConfig || !m_lirc_notify || m_fd_lirc == -1) + return; + + char *code = 0, *c = 0; + if (lirc_nextcode(&code) == 0) { + while(m_TakeRawLIRC || (lirc_code2char (m_lircConfig, code, &c) == 0 && c != NULL)) { + + QString x = c; + int repeat_counter = 1; + if (m_TakeRawLIRC || (QString(c) == "eventmap")) { + QStringList l = QStringList::split(" ", code); + if (l.count() >=4) { + x = l[2]; + repeat_counter = l[1].toInt(NULL, 16); + } + } + + bool consumed = false; + logDebug(QString("LIRC: ") + x); + + emit sigRawLIRCSignal(x, repeat_counter, consumed); + + if (!consumed) { + if (!checkActions(x, repeat_counter, m_Actions)) + checkActions(x, repeat_counter, m_AlternativeActions); + } + } + } + else { + // some error has occurred on the socket => close lirc plugin + logWarning(i18n("Reading from LIRC socket failed. Disabling LIRC Functions till next start of kradio")); + delete m_lirc_notify; + m_lirc_notify = NULL; + } + + if (code) + free (code); +#endif +} + + +void LircSupport::slotKbdTimedOut() +{ + activateStation (m_addIndex); + m_addIndex = 0; +} + + +void LircSupport::activateStation (int i) +{ + if (! sendActivateStation(i - 1)) + sendActivateStation( (i + 9) % 10); +} + + +bool LircSupport::connectI (Interface *i) +{ + bool a = IRadioClient::connectI (i); + bool b = ITimeControlClient::connectI (i); + bool c = IRadioDevicePoolClient::connectI (i); + bool d = PluginBase::connectI(i); + bool e = ISoundStreamClient::connectI(i); + return a || b || c || d || e; +} + + +bool LircSupport::disconnectI (Interface *i) +{ + bool a = IRadioClient::disconnectI (i); + bool b = ITimeControlClient::disconnectI (i); + bool c = IRadioDevicePoolClient::disconnectI (i); + bool d = PluginBase::disconnectI(i); + bool e = ISoundStreamClient::disconnectI(i); + return a || b || c || d || e; +} + + + +void LircSupport::saveState (KConfig *c) const +{ + c->writeEntry("LIRC_DIGIT_0", m_Actions[LIRC_DIGIT_0]); + c->writeEntry("LIRC_DIGIT_1", m_Actions[LIRC_DIGIT_1]); + c->writeEntry("LIRC_DIGIT_2", m_Actions[LIRC_DIGIT_2]); + c->writeEntry("LIRC_DIGIT_3", m_Actions[LIRC_DIGIT_3]); + c->writeEntry("LIRC_DIGIT_4", m_Actions[LIRC_DIGIT_4]); + c->writeEntry("LIRC_DIGIT_5", m_Actions[LIRC_DIGIT_5]); + c->writeEntry("LIRC_DIGIT_6", m_Actions[LIRC_DIGIT_6]); + c->writeEntry("LIRC_DIGIT_7", m_Actions[LIRC_DIGIT_7]); + c->writeEntry("LIRC_DIGIT_8", m_Actions[LIRC_DIGIT_8]); + c->writeEntry("LIRC_DIGIT_9", m_Actions[LIRC_DIGIT_9]); + c->writeEntry("LIRC_POWER_ON", m_Actions[LIRC_POWER_ON]); + c->writeEntry("LIRC_POWER_OFF", m_Actions[LIRC_POWER_OFF]); + c->writeEntry("LIRC_PAUSE", m_Actions[LIRC_PAUSE]); + c->writeEntry("LIRC_RECORD_START", m_Actions[LIRC_RECORD_START]); + c->writeEntry("LIRC_RECORD_STOP", m_Actions[LIRC_RECORD_STOP]); + c->writeEntry("LIRC_VOLUME_INC", m_Actions[LIRC_VOLUME_INC]); + c->writeEntry("LIRC_VOLUME_DEC", m_Actions[LIRC_VOLUME_DEC]); + c->writeEntry("LIRC_CHANNEL_NEXT", m_Actions[LIRC_CHANNEL_NEXT]); + c->writeEntry("LIRC_CHANNEL_PREV", m_Actions[LIRC_CHANNEL_PREV]); + c->writeEntry("LIRC_SEARCH_NEXT", m_Actions[LIRC_SEARCH_NEXT]); + c->writeEntry("LIRC_SEARCH_PREV", m_Actions[LIRC_SEARCH_PREV]); + c->writeEntry("LIRC_SLEEP", m_Actions[LIRC_SLEEP]); + c->writeEntry("LIRC_APPLICATION_QUIT", m_Actions[LIRC_APPLICATION_QUIT]); + + + c->writeEntry("ALT_LIRC_DIGIT_0", m_AlternativeActions[LIRC_DIGIT_0]); + c->writeEntry("ALT_LIRC_DIGIT_1", m_AlternativeActions[LIRC_DIGIT_1]); + c->writeEntry("ALT_LIRC_DIGIT_2", m_AlternativeActions[LIRC_DIGIT_2]); + c->writeEntry("ALT_LIRC_DIGIT_3", m_AlternativeActions[LIRC_DIGIT_3]); + c->writeEntry("ALT_LIRC_DIGIT_4", m_AlternativeActions[LIRC_DIGIT_4]); + c->writeEntry("ALT_LIRC_DIGIT_5", m_AlternativeActions[LIRC_DIGIT_5]); + c->writeEntry("ALT_LIRC_DIGIT_6", m_AlternativeActions[LIRC_DIGIT_6]); + c->writeEntry("ALT_LIRC_DIGIT_7", m_AlternativeActions[LIRC_DIGIT_7]); + c->writeEntry("ALT_LIRC_DIGIT_8", m_AlternativeActions[LIRC_DIGIT_8]); + c->writeEntry("ALT_LIRC_DIGIT_9", m_AlternativeActions[LIRC_DIGIT_9]); + c->writeEntry("ALT_LIRC_POWER_ON", m_AlternativeActions[LIRC_POWER_ON]); + c->writeEntry("ALT_LIRC_POWER_OFF", m_AlternativeActions[LIRC_POWER_OFF]); + c->writeEntry("ALT_LIRC_PAUSE", m_AlternativeActions[LIRC_PAUSE]); + c->writeEntry("ALT_LIRC_RECORD_START", m_AlternativeActions[LIRC_RECORD_START]); + c->writeEntry("ALT_LIRC_RECORD_STOP", m_AlternativeActions[LIRC_RECORD_STOP]); + c->writeEntry("ALT_LIRC_VOLUME_INC", m_AlternativeActions[LIRC_VOLUME_INC]); + c->writeEntry("ALT_LIRC_VOLUME_DEC", m_AlternativeActions[LIRC_VOLUME_DEC]); + c->writeEntry("ALT_LIRC_CHANNEL_NEXT", m_AlternativeActions[LIRC_CHANNEL_NEXT]); + c->writeEntry("ALT_LIRC_CHANNEL_PREV", m_AlternativeActions[LIRC_CHANNEL_PREV]); + c->writeEntry("ALT_LIRC_SEARCH_NEXT", m_AlternativeActions[LIRC_SEARCH_NEXT]); + c->writeEntry("ALT_LIRC_SEARCH_PREV", m_AlternativeActions[LIRC_SEARCH_PREV]); + c->writeEntry("ALT_LIRC_SLEEP", m_AlternativeActions[LIRC_SLEEP]); + c->writeEntry("ALT_LIRC_APPLICATION_QUIT", m_AlternativeActions[LIRC_APPLICATION_QUIT]); +} + +void LircSupport::restoreState (KConfig *c) +{ + m_Actions[LIRC_DIGIT_0] = c->readEntry("LIRC_DIGIT_0", "0"); + m_Actions[LIRC_DIGIT_1] = c->readEntry("LIRC_DIGIT_1", "1"); + m_Actions[LIRC_DIGIT_2] = c->readEntry("LIRC_DIGIT_2", "2"); + m_Actions[LIRC_DIGIT_3] = c->readEntry("LIRC_DIGIT_3", "3"); + m_Actions[LIRC_DIGIT_4] = c->readEntry("LIRC_DIGIT_4", "4"); + m_Actions[LIRC_DIGIT_5] = c->readEntry("LIRC_DIGIT_5", "5"); + m_Actions[LIRC_DIGIT_6] = c->readEntry("LIRC_DIGIT_6", "6"); + m_Actions[LIRC_DIGIT_7] = c->readEntry("LIRC_DIGIT_7", "7"); + m_Actions[LIRC_DIGIT_8] = c->readEntry("LIRC_DIGIT_8", "8"); + m_Actions[LIRC_DIGIT_9] = c->readEntry("LIRC_DIGIT_9", "9"); + m_Actions[LIRC_POWER_ON] = c->readEntry("LIRC_POWER_ON", "RADIO"); + m_Actions[LIRC_POWER_OFF] = c->readEntry("LIRC_POWER_OFF", "RADIO"); + m_Actions[LIRC_PAUSE] = c->readEntry("LIRC_PAUSE", "FULL_SCREEN"); + m_Actions[LIRC_RECORD_START] = c->readEntry("LIRC_RECORD_START", ""); + m_Actions[LIRC_RECORD_STOP] = c->readEntry("LIRC_RECORD_STOP", ""); + m_Actions[LIRC_VOLUME_INC] = c->readEntry("LIRC_VOLUME_INC", "VOL+"); + m_Actions[LIRC_VOLUME_DEC] = c->readEntry("LIRC_VOLUME_DEC", "VOL-"); + m_Actions[LIRC_CHANNEL_NEXT] = c->readEntry("LIRC_CHANNEL_NEXT", "CH+"); + m_Actions[LIRC_CHANNEL_PREV] = c->readEntry("LIRC_CHANNEL_PREV", "CH-"); + m_Actions[LIRC_SEARCH_NEXT] = c->readEntry("LIRC_SEARCH_NEXT", "SOURCE"); + m_Actions[LIRC_SEARCH_PREV] = c->readEntry("LIRC_SEARCH_PREV", "MUTE"); + m_Actions[LIRC_SLEEP] = c->readEntry("LIRC_SLEEP", "MINIMIZE"); + m_Actions[LIRC_APPLICATION_QUIT] = c->readEntry("LIRC_APPLICATION_QUIT", ""); + + + m_AlternativeActions[LIRC_DIGIT_0] = c->readEntry("ALT_LIRC_DIGIT_0", ""); + m_AlternativeActions[LIRC_DIGIT_1] = c->readEntry("ALT_LIRC_DIGIT_1", ""); + m_AlternativeActions[LIRC_DIGIT_2] = c->readEntry("ALT_LIRC_DIGIT_2", ""); + m_AlternativeActions[LIRC_DIGIT_3] = c->readEntry("ALT_LIRC_DIGIT_3", ""); + m_AlternativeActions[LIRC_DIGIT_4] = c->readEntry("ALT_LIRC_DIGIT_4", ""); + m_AlternativeActions[LIRC_DIGIT_5] = c->readEntry("ALT_LIRC_DIGIT_5", ""); + m_AlternativeActions[LIRC_DIGIT_6] = c->readEntry("ALT_LIRC_DIGIT_6", ""); + m_AlternativeActions[LIRC_DIGIT_7] = c->readEntry("ALT_LIRC_DIGIT_7", ""); + m_AlternativeActions[LIRC_DIGIT_8] = c->readEntry("ALT_LIRC_DIGIT_8", ""); + m_AlternativeActions[LIRC_DIGIT_9] = c->readEntry("ALT_LIRC_DIGIT_9", ""); + m_AlternativeActions[LIRC_POWER_ON] = c->readEntry("ALT_LIRC_POWER_ON", ""); + m_AlternativeActions[LIRC_POWER_OFF] = c->readEntry("ALT_LIRC_POWER_OFF", "TV"); + m_AlternativeActions[LIRC_PAUSE] = c->readEntry("ALT_LIRC_PAUSE", ""); + m_AlternativeActions[LIRC_RECORD_START] = c->readEntry("ALT_LIRC_RECORD_START", ""); + m_AlternativeActions[LIRC_RECORD_STOP] = c->readEntry("ALT_LIRC_RECORD_STOP", ""); + m_AlternativeActions[LIRC_VOLUME_INC] = c->readEntry("ALT_LIRC_VOLUME_INC", ""); + m_AlternativeActions[LIRC_VOLUME_DEC] = c->readEntry("ALT_LIRC_VOLUME_DEC", ""); + m_AlternativeActions[LIRC_CHANNEL_NEXT] = c->readEntry("ALT_LIRC_CHANNEL_NEXT", ""); + m_AlternativeActions[LIRC_CHANNEL_PREV] = c->readEntry("ALT_LIRC_CHANNEL_PREV", ""); + m_AlternativeActions[LIRC_SEARCH_NEXT] = c->readEntry("ALT_LIRC_SEARCH_NEXT", ""); + m_AlternativeActions[LIRC_SEARCH_PREV] = c->readEntry("ALT_LIRC_SEARCH_PREV", ""); + m_AlternativeActions[LIRC_SLEEP] = c->readEntry("ALT_LIRC_SLEEP", ""); + m_AlternativeActions[LIRC_APPLICATION_QUIT] = c->readEntry("ALT_LIRC_APPLICATION_QUIT", ""); + + emit sigUpdateConfig(); +} + + +ConfigPageInfo LircSupport::createConfigurationPage() +{ + LIRCConfiguration *conf = new LIRCConfiguration(NULL, this); + QObject::connect(this, SIGNAL(sigUpdateConfig()), conf, SLOT(slotUpdateConfig())); + QObject::connect(this, SIGNAL(sigRawLIRCSignal(const QString &, int, bool &)), + conf, SLOT (slotRawLIRCSignal(const QString &, int, bool &))); + return ConfigPageInfo (conf, + i18n("LIRC Support"), + i18n("LIRC Plugin"), + "connect_creating"); +} + + +AboutPageInfo LircSupport::createAboutPage() +{ +/* KAboutData aboutData("kradio", + NULL, + NULL, + I18N_NOOP("Linux Infrared Remote Control Support for KRadio"), + KAboutData::License_GPL, + "(c) 2002-2005 Martin Witte", + 0, + "http://sourceforge.net/projects/kradio", + 0); + aboutData.addAuthor("Martin Witte", "", "witte@kawo1.rwth-aachen.de"); + + return AboutPageInfo( + new KRadioAboutWidget(aboutData, KRadioAboutWidget::AbtTabbed), + i18n("LIRC Support"), + i18n("LIRC Plugin"), + "connect_creating" + );*/ + return AboutPageInfo(); +} + + +bool LircSupport::checkActions(const QString &lirc_string, int repeat_counter, const QMap<LIRC_Actions, QString> &map) +{ + SoundStreamID streamID = queryCurrentSoundStreamID(); + + bool retval = false; + bool q = false; + SoundFormat sf; + ISeekRadio *seeker = NULL; + + QMapConstIterator<LIRC_Actions, QString> it = map.begin(); + QMapConstIterator<LIRC_Actions, QString> end = map.end(); + for (; !retval && it != end; ++it) { + if ((*it).length() && lirc_string == *it) { + LIRC_Actions action = it.key(); + int digit = -1; + switch (action) { + case LIRC_DIGIT_0 : + if (repeat_counter == 0) { + digit = 0; + retval = true; + } + break; + case LIRC_DIGIT_1 : + if (repeat_counter == 0) { + digit = 1; + retval = true; + } + break; + case LIRC_DIGIT_2 : + if (repeat_counter == 0) { + digit = 2; + retval = true; + } + break; + case LIRC_DIGIT_3 : + if (repeat_counter == 0) { + digit = 3; + retval = true; + } + break; + case LIRC_DIGIT_4 : + if (repeat_counter == 0) { + digit = 4; + retval = true; + } + break; + case LIRC_DIGIT_5 : + if (repeat_counter == 0) { + digit = 5; + retval = true; + } + break; + case LIRC_DIGIT_6 : + if (repeat_counter == 0) { + digit = 6; + retval = true; + } + break; + case LIRC_DIGIT_7 : + if (repeat_counter == 0) { + digit = 7; + retval = true; + } + break; + case LIRC_DIGIT_8 : + if (repeat_counter == 0) { + digit = 8; + retval = true; + } + break; + case LIRC_DIGIT_9 : + if (repeat_counter == 0) { + digit = 9; + retval = true; + } + break; + case LIRC_POWER_ON : + if (repeat_counter == 0 && !queryIsPowerOn()) { + retval = true; + sendPowerOn(); + } + break; + case LIRC_POWER_OFF : + if (repeat_counter == 0 && queryIsPowerOn()) { + retval = true; + sendPowerOff(); + } + break; + case LIRC_PAUSE : + if (repeat_counter == 0 && queryIsPowerOn()) { + retval = true; + sendPausePlayback(streamID); + } + break; + case LIRC_RECORD_START : + queryIsRecordingRunning(streamID, q = false, sf); + if (repeat_counter == 0 && !q) { + retval = true; + sendStartRecording(streamID); + } + break; + case LIRC_RECORD_STOP : + queryIsRecordingRunning(streamID, q = false, sf); + if (repeat_counter == 0 && q) { + retval = true; + sendStopRecording(streamID); + } + break; + case LIRC_VOLUME_INC : + if (queryIsPowerOn()) { + retval = true; + float oldVolume = 0; + queryPlaybackVolume(streamID, oldVolume); + sendPlaybackVolume (streamID, oldVolume + 1.0/32.0); + } + break; + case LIRC_VOLUME_DEC : + if (queryIsPowerOn()) { + retval = true; + float oldVolume = 0; + queryPlaybackVolume(streamID, oldVolume); + sendPlaybackVolume (streamID, oldVolume - 1.0/32.0); + } + break; + case LIRC_CHANNEL_NEXT : + if (repeat_counter == 0 && queryIsPowerOn()) { + retval = true; + int k = queryCurrentStationIdx() + 1; + if (k >= queryStations().count()) + k = 0; + sendActivateStation(k); + } + break; + case LIRC_CHANNEL_PREV : + if (repeat_counter == 0 && queryIsPowerOn()) { + retval = true; + int k = queryCurrentStationIdx() - 1; + if (k < 0) + k = queryStations().count() - 1; + sendActivateStation(k); + } + break; + case LIRC_SEARCH_NEXT : + if (repeat_counter == 0 && queryIsPowerOn()) { + retval = true; + seeker = dynamic_cast<ISeekRadio*> (queryActiveDevice()); + seeker->startSeekUp(); + } + break; + case LIRC_SEARCH_PREV : + if (repeat_counter == 0 && queryIsPowerOn()) { + retval = true; + seeker = dynamic_cast<ISeekRadio*> (queryActiveDevice()); + seeker->startSeekDown(); + } + break; + case LIRC_SLEEP : + if (repeat_counter == 0 && queryIsPowerOn()) { + retval = true; + sendStartCountdown(); + } + break; + case LIRC_APPLICATION_QUIT : + retval = true; + kapp->quit(); + break; + default: + break; + } + + if (digit >= 0) { + if (m_addIndex || digit == 0) { + activateStation(m_addIndex * 10 + digit); + m_kbdTimer->stop(); + m_addIndex = 0; + } else { + m_addIndex = digit; + m_kbdTimer->start(500, true); + } + } + } + } + return retval; +} + + +void LircSupport::setActions(const QMap<LIRC_Actions, QString> &actions, const QMap<LIRC_Actions, QString> &alt_actions) +{ + m_Actions = actions; + m_AlternativeActions = alt_actions; +} + + +#include "lircsupport.moc" diff --git a/kradio3/plugins/lirc/lircsupport.h b/kradio3/plugins/lirc/lircsupport.h new file mode 100644 index 0000000..47a113f --- /dev/null +++ b/kradio3/plugins/lirc/lircsupport.h @@ -0,0 +1,159 @@ +/*************************************************************************** + lircsupport.h - description + ------------------- + begin : Mon Feb 4 2002 + copyright : (C) 2002 by Martin Witte / Frank Schwanz + email : witte@kawo1.rwth-aachen.de / schwanz@fh-brandenburg.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 LIRCSUPPORT_H +#define LIRCSUPPORT_H + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <qobject.h> +#include "../../src/include/timecontrol_interfaces.h" +#include "../../src/include/radio_interfaces.h" +#include "../../src/include/radiodevicepool_interfaces.h" +#include "../../src/include/soundstreamclient_interfaces.h" +#include "../../src/include/plugins.h" + + +enum LIRC_Actions { + LIRC_DIGIT_0, + LIRC_DIGIT_1, + LIRC_DIGIT_2, + LIRC_DIGIT_3, + LIRC_DIGIT_4, + LIRC_DIGIT_5, + LIRC_DIGIT_6, + LIRC_DIGIT_7, + LIRC_DIGIT_8, + LIRC_DIGIT_9, + LIRC_POWER_ON, + LIRC_POWER_OFF, + LIRC_PAUSE, + LIRC_RECORD_START, + LIRC_RECORD_STOP, + LIRC_VOLUME_INC, + LIRC_VOLUME_DEC, + LIRC_CHANNEL_NEXT, + LIRC_CHANNEL_PREV, + LIRC_SEARCH_NEXT, + LIRC_SEARCH_PREV, + LIRC_SLEEP, + LIRC_APPLICATION_QUIT +}; + + +struct lirc_config; +class QSocketNotifier; +class QTimer; + +class LircSupport : public QObject, + public PluginBase, + public IRadioClient, + public ITimeControlClient, + public ISoundStreamClient, + public IRadioDevicePoolClient +{ +Q_OBJECT +public: + LircSupport(const QString &name); + ~LircSupport(); + + virtual bool connectI (Interface *); + virtual bool disconnectI (Interface *); + + virtual QString pluginClassName() const { return "LircSupport"; } + + virtual const QString &name() const { return PluginBase::name(); } + virtual QString &name() { return PluginBase::name(); } + + + virtual void setActions(const QMap<LIRC_Actions, QString> &actions, const QMap<LIRC_Actions, QString> &alt_actions); + virtual const QMap<LIRC_Actions, QString> &getActions() const { return m_Actions; } + virtual const QMap<LIRC_Actions, QString> &getAlternativeActions() const { return m_AlternativeActions; } + + // PluginBase + +public: + virtual void saveState (KConfig *) const; + virtual void restoreState (KConfig *); + + virtual ConfigPageInfo createConfigurationPage(); + virtual AboutPageInfo createAboutPage(); + + // IRadioClient methods + +RECEIVERS: + bool noticePowerChanged(bool /*on*/) { return false; } + bool noticeStationChanged (const RadioStation &, int /*idx*/) { return false; } + bool noticeStationsChanged(const StationList &/*sl*/) { return false; } + bool noticePresetFileChanged(const QString &/*f*/) { return false; } + + bool noticeCurrentSoundStreamIDChanged(SoundStreamID /*id*/) { return false; } + + // ITimeControlClient + +RECEIVERS: + bool noticeAlarmsChanged(const AlarmVector &) { return false; } + bool noticeAlarm(const Alarm &) { return false; } + bool noticeNextAlarmChanged(const Alarm *) { return false; } + bool noticeCountdownStarted(const QDateTime &/*end*/) { return false; } + bool noticeCountdownStopped() { return false; } + bool noticeCountdownZero() { return false; } + bool noticeCountdownSecondsChanged(int /*n*/) { return false; } + + // IRadioDevicePoolClient + +RECEIVERS: + bool noticeActiveDeviceChanged(IRadioDevice *) { return false; } + bool noticeDevicesChanged(const QPtrList<IRadioDevice> &) { return false; } + bool noticeDeviceDescriptionChanged(const QString &) { return false; } + + +protected: + void activateStation(int i); + bool checkActions(const QString &string, int repeat_counter, const QMap<LIRC_Actions, QString> &map); + +protected slots: + void slotLIRC(int socket); + void slotKbdTimedOut(); + +signals: + + void sigUpdateConfig(); + + void sigRawLIRCSignal(const QString &what, int repeat_counter, bool &consumed); + +protected: + +#ifdef HAVE_LIRC + QSocketNotifier *m_lirc_notify; + int m_fd_lirc; + struct lirc_config *m_lircConfig; +#endif + + QTimer *m_kbdTimer; + int m_addIndex; + bool m_TakeRawLIRC; + + QMap<LIRC_Actions, QString> m_Actions; + QMap<LIRC_Actions, QString> m_AlternativeActions; +}; + + + +#endif diff --git a/kradio3/plugins/lirc/listviewitem_lirc.cpp b/kradio3/plugins/lirc/listviewitem_lirc.cpp new file mode 100644 index 0000000..4f7d0ce --- /dev/null +++ b/kradio3/plugins/lirc/listviewitem_lirc.cpp @@ -0,0 +1,51 @@ +/*************************************************************************** + listviewitem_lirc.cpp - description + ------------------- + begin : Sun Aug 14 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 "listviewitem_lirc.h" + +ListViewItemLirc::ListViewItemLirc(QListView *parent, QListViewItem *after) + : KListViewItem(parent, after), + m_renamingInProcess(-1) +{ +} + +ListViewItemLirc::~ListViewItemLirc() +{ +} + +void ListViewItemLirc::startRename(int col) +{ + KListViewItem::startRename(col); + m_renamingInProcess = col; + emit sigRenamingStarted(this, col); +} + +void ListViewItemLirc::okRename(int col) +{ + KListViewItem::okRename(col); + m_renamingInProcess = -1; + emit sigRenamingStopped(this, col); +} + +void ListViewItemLirc::cancelRename(int col) +{ + KListViewItem::cancelRename(col); + m_renamingInProcess = -1; + emit sigRenamingStopped(this, col); +} + +#include "listviewitem_lirc.moc" diff --git a/kradio3/plugins/lirc/listviewitem_lirc.h b/kradio3/plugins/lirc/listviewitem_lirc.h new file mode 100644 index 0000000..051ff76 --- /dev/null +++ b/kradio3/plugins/lirc/listviewitem_lirc.h @@ -0,0 +1,51 @@ +/*************************************************************************** + listviewitem_lirc.cpp - description + ------------------- + begin : Sun Aug 14 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 LISTVIEWITEM_LIRC_H +#define LISTVIEWITEM_LIRC_H + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <klistview.h> + +class ListViewItemLirc : public QObject, public KListViewItem +{ +Q_OBJECT +public: + ListViewItemLirc(QListView *parent, QListViewItem *after); + ~ListViewItemLirc(); + + bool isRenamingInProcess() const { return m_renamingInProcess >= 0; } + int getRenamingColumn() const { return m_renamingInProcess; } + + virtual void startRename(int col); + virtual void okRename(int col); + virtual void cancelRename(int col); + +signals: + + void sigRenamingStarted(ListViewItemLirc *sender, int column); + void sigRenamingStopped(ListViewItemLirc *sender, int column); + +protected: + + int m_renamingInProcess; +}; + +#endif diff --git a/kradio3/plugins/lirc/po/Makefile.am b/kradio3/plugins/lirc/po/Makefile.am new file mode 100644 index 0000000..22fce99 --- /dev/null +++ b/kradio3/plugins/lirc/po/Makefile.am @@ -0,0 +1,2 @@ +PACKAGE = kradio-lirc +POFILES = AUTO diff --git a/kradio3/plugins/lirc/po/de.po b/kradio3/plugins/lirc/po/de.po new file mode 100644 index 0000000..1521094 --- /dev/null +++ b/kradio3/plugins/lirc/po/de.po @@ -0,0 +1,213 @@ +# translation of de.po to +# translation of kradio-lirc.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: 2006-11-12 18:20+0100\n" +"PO-Revision-Date: 2006-11-06 01:32+0100\n" +"Last-Translator: Ernst Martin Witte <emw@nocabal.de>\n" +"Language-Team: <de@li.org>\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: KBabel 1.11.4\n" + +#. i18n: file lirc-configuration-ui.ui line 17 +#: rc.cpp:3 rc.cpp:18 lirc-configuration-ui.cpp:75 +#, no-c-format +msgid "LIRCConfigurationUI" +msgstr "LIRCConfigurationUI" + +#. i18n: file lirc-configuration-ui.ui line 26 +#: rc.cpp:6 rc.cpp:21 lirc-configuration-ui.cpp:34 +#: lirc-configuration-ui.cpp:76 +#, no-c-format +msgid "Action" +msgstr "Aktion" + +#. i18n: file lirc-configuration-ui.ui line 37 +#: rc.cpp:9 rc.cpp:24 lirc-configuration-ui.cpp:35 +#: lirc-configuration-ui.cpp:77 +#, no-c-format +msgid "LIRC String" +msgstr "LIRC-Zeichenkette" + +#. i18n: file lirc-configuration-ui.ui line 48 +#: rc.cpp:12 rc.cpp:27 lirc-configuration-ui.cpp:36 +#: lirc-configuration-ui.cpp:78 +#, no-c-format +msgid "Alternative LIRC String" +msgstr "Alternative LIRC-Zeichenkette" + +#. i18n: file lirc-configuration-ui.ui line 98 +#: rc.cpp:15 rc.cpp:30 lirc-configuration-ui.cpp:79 +#, no-c-format +msgid "textLabel1" +msgstr "textLabel1" + +#: _translatorinfo.cpp:1 +msgid "" +"_: NAME OF TRANSLATORS\n" +"Your names" +msgstr "Ernst Martin Witte" + +#: _translatorinfo.cpp:3 +msgid "" +"_: EMAIL OF TRANSLATORS\n" +"Your emails" +msgstr "emw@nocabal.de" + +#: lirc-configuration.cpp:34 +msgid "digit 0" +msgstr "Ziffer 0" + +#: lirc-configuration.cpp:35 +msgid "digit 1" +msgstr "Ziffer 1" + +#: lirc-configuration.cpp:36 +msgid "digit 2" +msgstr "Ziffer 2" + +#: lirc-configuration.cpp:37 +msgid "digit 3" +msgstr "Ziffer 3" + +#: lirc-configuration.cpp:38 +msgid "digit 4" +msgstr "Ziffer 4" + +#: lirc-configuration.cpp:39 +msgid "digit 5" +msgstr "Ziffer 5" + +#: lirc-configuration.cpp:40 +msgid "digit 6" +msgstr "Ziffer 6" + +#: lirc-configuration.cpp:41 +msgid "digit 7" +msgstr "Ziffer 7" + +#: lirc-configuration.cpp:42 +msgid "digit 8" +msgstr "Ziffer 8" + +#: lirc-configuration.cpp:43 +msgid "digit 9" +msgstr "Ziffer 9" + +#: lirc-configuration.cpp:44 +msgid "Power On" +msgstr "Einschalten" + +#: lirc-configuration.cpp:45 +msgid "Power Off" +msgstr "Ausschalten" + +#: lirc-configuration.cpp:46 +msgid "Pause" +msgstr "Pause" + +#: lirc-configuration.cpp:47 +msgid "Start Recording" +msgstr "Aufnahme starten" + +#: lirc-configuration.cpp:48 +msgid "Stop Recording" +msgstr "Aufnahme beenden" + +#: lirc-configuration.cpp:49 +msgid "Increase Volume" +msgstr "Lautstärke erhöhen" + +#: lirc-configuration.cpp:50 +msgid "Decrease Volume" +msgstr "Lautstärke senken" + +#: lirc-configuration.cpp:51 +msgid "Next Channel" +msgstr "Nächster Sender" + +#: lirc-configuration.cpp:52 +msgid "Previous Channel" +msgstr "Vorheriger Sender" + +#: lirc-configuration.cpp:53 +msgid "Search Next Channel" +msgstr "Suche nächsten Sender" + +#: lirc-configuration.cpp:54 +msgid "Search Previous Channel" +msgstr "Suche vorherigen Sender" + +#: lirc-configuration.cpp:55 +msgid "Enable Sleep Countdown" +msgstr "Schlummer-Countdown aktivieren" + +#: lirc-configuration.cpp:56 +msgid "Quit KRadio" +msgstr "KRadio Beenden" + +#: lirc-configuration.cpp:176 +msgid "" +"Enter the key string of your remote or just press the button on your remote " +"control" +msgstr "" +"Geben Sie die Zeichenkette Ihrer Fernsteuerung ein oder drücken Sie die " +"Taste auf Ihrer Fernsteuerung" + +#: lirc-configuration.cpp:182 +msgid "Double Click on the entries to change the assignments" +msgstr "Doppelklicken Sie auf die Einträge um die Zuordnung zu ändern" + +#: lircsupport.cpp:45 +msgid "Linux Infrared Control (LIRC) Support" +msgstr "Unterstützung für die Fernsteuerung (LIRC)" + +#: lircsupport.cpp:51 lircsupport.cpp:330 +msgid "LIRC Plugin" +msgstr "Plugin für die Fernsteuerung (LIRC)" + +#: lircsupport.cpp:56 lircsupport.cpp:57 +msgid "initializing kradio lirc plugin" +msgstr "initialisiere das Plugin für die Fernsteuerung (LIRC)" + +#: lircsupport.cpp:65 +msgid "" +"%1 does not exist. File was created with KRadio's default .lircrc proposal" +msgstr "" +"Die Datei %1 existiert nicht. Die Datei wurde mit den Defaulteinstellungen " +"für KRadio erzeugt." + +#: lircsupport.cpp:94 +msgid "There is no entry for kradio in any of your .lircrc files." +msgstr "Es gibt keinen Eintrag für KRadio in jeglichen .lirc-Dateien" + +#: lircsupport.cpp:95 +msgid "Please setup your .lircrc files correctly." +msgstr "Bitte konfigurieren Sie Ihre .lirc-Dateien richtig." + +#: lircsupport.cpp:106 lircsupport.cpp:107 +msgid "Initializing kradio lirc plugin failed" +msgstr "Die Initialisierung des KRadio LIRC Plugins schlug fehl" + +#: lircsupport.cpp:109 lircsupport.cpp:110 +msgid "Initializing kradio lirc plugin successful" +msgstr "Die Initialisierung des LIRC Plugins war erfolgreich" + +#: lircsupport.cpp:167 +msgid "" +"Reading from LIRC socket failed. Disabling LIRC Functions till next start of " +"kradio" +msgstr "" +"Das Lesen vom LIRC-Socket ist fehlgeschlagen. Die LIRC-Funktion wird bis zum " +"nächsten Start von KRadio temporär abgeschaltet." + +#: lircsupport.cpp:329 +msgid "LIRC Support" +msgstr "Fernsteuerung" diff --git a/kradio3/plugins/lirc/po/ru.po b/kradio3/plugins/lirc/po/ru.po new file mode 100644 index 0000000..54edb74 --- /dev/null +++ b/kradio3/plugins/lirc/po/ru.po @@ -0,0 +1,209 @@ +# translation of ru.po to +# translation of kradio-lirc.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: 2006-11-12 18:20+0100\n" +"PO-Revision-Date: 2006-11-08 12:54+0300\n" +"Last-Translator: Алексей Кузнецов <Alexey.Kouznetsov@GMail.com>\n" +"Language-Team: <ru@li.org>\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" + +#. i18n: file lirc-configuration-ui.ui line 17 +#: rc.cpp:3 rc.cpp:18 lirc-configuration-ui.cpp:75 +#, no-c-format +msgid "LIRCConfigurationUI" +msgstr "LIRCConfigurationUI" + +#. i18n: file lirc-configuration-ui.ui line 26 +#: rc.cpp:6 rc.cpp:21 lirc-configuration-ui.cpp:34 +#: lirc-configuration-ui.cpp:76 +#, no-c-format +msgid "Action" +msgstr "Действие" + +#. i18n: file lirc-configuration-ui.ui line 37 +#: rc.cpp:9 rc.cpp:24 lirc-configuration-ui.cpp:35 +#: lirc-configuration-ui.cpp:77 +#, no-c-format +msgid "LIRC String" +msgstr "Строка LIRC" + +#. i18n: file lirc-configuration-ui.ui line 48 +#: rc.cpp:12 rc.cpp:27 lirc-configuration-ui.cpp:36 +#: lirc-configuration-ui.cpp:78 +#, no-c-format +msgid "Alternative LIRC String" +msgstr "Альтернативная строка LIRC" + +#. i18n: file lirc-configuration-ui.ui line 98 +#: rc.cpp:15 rc.cpp:30 lirc-configuration-ui.cpp:79 +#, no-c-format +msgid "textLabel1" +msgstr "textLabel1" + +#: _translatorinfo.cpp:1 +msgid "" +"_: NAME OF TRANSLATORS\n" +"Your names" +msgstr "Алексей Кузнецов" + +#: _translatorinfo.cpp:3 +msgid "" +"_: EMAIL OF TRANSLATORS\n" +"Your emails" +msgstr "Alexey.Kouznetsov@GMail.com" + +#: lirc-configuration.cpp:34 +msgid "digit 0" +msgstr "ноль" + +#: lirc-configuration.cpp:35 +msgid "digit 1" +msgstr "один" + +#: lirc-configuration.cpp:36 +msgid "digit 2" +msgstr "два" + +#: lirc-configuration.cpp:37 +msgid "digit 3" +msgstr "три" + +#: lirc-configuration.cpp:38 +msgid "digit 4" +msgstr "четыре" + +#: lirc-configuration.cpp:39 +msgid "digit 5" +msgstr "пять" + +#: lirc-configuration.cpp:40 +msgid "digit 6" +msgstr "шесть" + +#: lirc-configuration.cpp:41 +msgid "digit 7" +msgstr "семь" + +#: lirc-configuration.cpp:42 +msgid "digit 8" +msgstr "восемь" + +#: lirc-configuration.cpp:43 +msgid "digit 9" +msgstr "девять" + +#: lirc-configuration.cpp:44 +msgid "Power On" +msgstr "Включить" + +#: lirc-configuration.cpp:45 +msgid "Power Off" +msgstr "Выключить" + +#: lirc-configuration.cpp:46 +msgid "Pause" +msgstr "Приостановить" + +#: lirc-configuration.cpp:47 +msgid "Start Recording" +msgstr "Начать запись" + +#: lirc-configuration.cpp:48 +msgid "Stop Recording" +msgstr "Остановить запись" + +#: lirc-configuration.cpp:49 +msgid "Increase Volume" +msgstr "Увеличить громкость" + +#: lirc-configuration.cpp:50 +msgid "Decrease Volume" +msgstr "Уменьшить громкость" + +#: lirc-configuration.cpp:51 +msgid "Next Channel" +msgstr "Следующий канал" + +#: lirc-configuration.cpp:52 +msgid "Previous Channel" +msgstr "Предыдущий канал" + +#: lirc-configuration.cpp:53 +msgid "Search Next Channel" +msgstr "Поиск следующего канала" + +#: lirc-configuration.cpp:54 +msgid "Search Previous Channel" +msgstr "Поиск предыдущего канала" + +#: lirc-configuration.cpp:55 +msgid "Enable Sleep Countdown" +msgstr "Включить таймер отключения" + +#: lirc-configuration.cpp:56 +msgid "Quit KRadio" +msgstr "Закрыть KRadio" + +#: lirc-configuration.cpp:176 +msgid "" +"Enter the key string of your remote or just press the button on your remote " +"control" +msgstr "Введите ключевую строку вашего ПДУ либо просто нажмите кнопку на нём" + +#: lirc-configuration.cpp:182 +msgid "Double Click on the entries to change the assignments" +msgstr "Для изменения привязки дважды щёлкните по ней мышью" + +#: lircsupport.cpp:45 +msgid "Linux Infrared Control (LIRC) Support" +msgstr "Поддержка ПДУ в Linux (LIRC)" + +#: lircsupport.cpp:51 lircsupport.cpp:330 +msgid "LIRC Plugin" +msgstr "Модуль ДУ (LIRC)" + +#: lircsupport.cpp:56 lircsupport.cpp:57 +msgid "initializing kradio lirc plugin" +msgstr "Инициализация модуля LIRC" + +#: lircsupport.cpp:65 +msgid "" +"%1 does not exist. File was created with KRadio's default .lircrc proposal" +msgstr "%1 не существует. Был создан файл .lircrc для KRadio по умолчанию" + +#: lircsupport.cpp:94 +msgid "There is no entry for kradio in any of your .lircrc files." +msgstr "Ни в одном из ваших файлов .lircrc нет упоминания о KRadio." + +#: lircsupport.cpp:95 +msgid "Please setup your .lircrc files correctly." +msgstr "Настройте файлы .lircrc" + +#: lircsupport.cpp:106 lircsupport.cpp:107 +msgid "Initializing kradio lirc plugin failed" +msgstr "Инициализация модуля LIRC не удалась" + +#: lircsupport.cpp:109 lircsupport.cpp:110 +msgid "Initializing kradio lirc plugin successful" +msgstr "Модуль LIRC инициализирован" + +#: lircsupport.cpp:167 +msgid "" +"Reading from LIRC socket failed. Disabling LIRC Functions till next start of " +"kradio" +msgstr "" +"Чтение из сокета LIRC не удалось. Отключаю функции LIRC до следующего " +"запуска KRadio." + +#: lircsupport.cpp:329 +msgid "LIRC Support" +msgstr "Поддержка LIRC" diff --git a/kradio3/plugins/oss-sound/Makefile.am b/kradio3/plugins/oss-sound/Makefile.am new file mode 100644 index 0000000..ffdd5be --- /dev/null +++ b/kradio3/plugins/oss-sound/Makefile.am @@ -0,0 +1,18 @@ +SUBDIRS = po icons . + +INCLUDES = $(all_includes) +METASOURCES = AUTO + +libkradio_LTLIBRARIES = liboss-sound.la +liboss_sound_la_SOURCES = oss-sound.cpp oss-sound-configuration-ui.ui \ + oss-sound-configuration.cpp +liboss_sound_la_LDFLAGS = -module -avoid-version $(KDE_RPATH) $(all_libraries) + +noinst_HEADERS = oss-sound.h oss-sound-configuration.h + +#messages: rc.cpp +# $(XGETTEXT) *.cpp *.h -o po/kradio-oss-sound.pot + +messages: rc.cpp + $(EXTRACTRC) *.rc *.ui >> rc.cpp + $(XGETTEXT) rc.cpp *.h *.cpp -o po/kradio-oss-sound.pot diff --git a/kradio3/plugins/oss-sound/icons/Makefile.am b/kradio3/plugins/oss-sound/icons/Makefile.am new file mode 100644 index 0000000..b3f2583 --- /dev/null +++ b/kradio3/plugins/oss-sound/icons/Makefile.am @@ -0,0 +1,2 @@ +icons_ICON = AUTO +iconsdir = $(kde_datadir)/kradio/icons diff --git a/kradio3/plugins/oss-sound/icons/hi16-action-kradio_oss.png b/kradio3/plugins/oss-sound/icons/hi16-action-kradio_oss.png Binary files differnew file mode 100644 index 0000000..1241b1f --- /dev/null +++ b/kradio3/plugins/oss-sound/icons/hi16-action-kradio_oss.png diff --git a/kradio3/plugins/oss-sound/icons/hi32-action-kradio_oss.png b/kradio3/plugins/oss-sound/icons/hi32-action-kradio_oss.png Binary files differnew file mode 100644 index 0000000..85e5c63 --- /dev/null +++ b/kradio3/plugins/oss-sound/icons/hi32-action-kradio_oss.png diff --git a/kradio3/plugins/oss-sound/icons/hi48-action-kradio_oss.png b/kradio3/plugins/oss-sound/icons/hi48-action-kradio_oss.png Binary files differnew file mode 100644 index 0000000..2d2a08d --- /dev/null +++ b/kradio3/plugins/oss-sound/icons/hi48-action-kradio_oss.png diff --git a/kradio3/plugins/oss-sound/oss-sound-configuration-ui.ui b/kradio3/plugins/oss-sound/oss-sound-configuration-ui.ui new file mode 100644 index 0000000..7cf3483 --- /dev/null +++ b/kradio3/plugins/oss-sound/oss-sound-configuration-ui.ui @@ -0,0 +1,132 @@ +<!DOCTYPE UI><UI version="3.2" stdsetdef="1"> +<class>OSSSoundConfigurationUI</class> +<widget class="QWidget"> + <property name="name"> + <cstring>OSSSoundConfigurationUI</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>562</width> + <height>411</height> + </rect> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <widget class="QGroupBox" row="0" column="0"> + <property name="name"> + <cstring>groupBox20</cstring> + </property> + <property name="title"> + <string>Devices</string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>11</number> + </property> + <widget class="KURLRequester" row="1" column="1"> + <property name="name"> + <cstring>editMixerDevice</cstring> + </property> + </widget> + <widget class="KURLRequester" row="0" column="1"> + <property name="name"> + <cstring>editDSPDevice</cstring> + </property> + </widget> + <widget class="QLabel" row="0" column="0"> + <property name="name"> + <cstring>textLabel2</cstring> + </property> + <property name="text"> + <string>PCM Device</string> + </property> + </widget> + <widget class="QLabel" row="1" column="0"> + <property name="name"> + <cstring>textLabel2_2</cstring> + </property> + <property name="text"> + <string>Mixer Device</string> + </property> + </widget> + <widget class="QLabel" row="2" column="0"> + <property name="name"> + <cstring>textLabel2_2_2</cstring> + </property> + <property name="text"> + <string>Buffer Size</string> + </property> + </widget> + <widget class="KIntSpinBox" row="2" column="1"> + <property name="name"> + <cstring>editBufferSize</cstring> + </property> + <property name="suffix"> + <string> kB</string> + </property> + <property name="maxValue"> + <number>1024</number> + </property> + <property name="minValue"> + <number>4</number> + </property> + </widget> + </grid> + </widget> + <widget class="QGroupBox" row="1" column="0"> + <property name="name"> + <cstring>groupBox21</cstring> + </property> + <property name="title"> + <string>Extended Options</string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>11</number> + </property> + <widget class="QCheckBox" row="0" column="0"> + <property name="name"> + <cstring>chkDisablePlayback</cstring> + </property> + <property name="text"> + <string>Disable Playback</string> + </property> + </widget> + <widget class="QCheckBox" row="1" column="0"> + <property name="name"> + <cstring>chkDisableCapture</cstring> + </property> + <property name="text"> + <string>Disable Capture</string> + </property> + </widget> + </grid> + </widget> + </grid> +</widget> +<customwidgets> +</customwidgets> +<layoutdefaults spacing="6" margin="0"/> +<includehints> + <includehint>kurlrequester.h</includehint> + <includehint>klineedit.h</includehint> + <includehint>kpushbutton.h</includehint> + <includehint>kurlrequester.h</includehint> + <includehint>klineedit.h</includehint> + <includehint>kpushbutton.h</includehint> + <includehint>knuminput.h</includehint> +</includehints> +</UI> diff --git a/kradio3/plugins/oss-sound/oss-sound-configuration.cpp b/kradio3/plugins/oss-sound/oss-sound-configuration.cpp new file mode 100644 index 0000000..5665114 --- /dev/null +++ b/kradio3/plugins/oss-sound/oss-sound-configuration.cpp @@ -0,0 +1,86 @@ +/*************************************************************************** + oss-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 <qcheckbox.h> + +#include <kurlrequester.h> +#include <knuminput.h> + +#include "oss-sound-configuration.h" +#include "oss-sound.h" + +OSSSoundConfiguration::OSSSoundConfiguration (QWidget *parent, OSSSoundDevice *dev) + : OSSSoundConfigurationUI(parent), + m_SoundDevice (dev), + m_dirty(true), + m_ignore_gui_updates(false) +{ + connect(editDSPDevice, SIGNAL(textChanged(const QString &)), this, SLOT(slotSetDirty())); + connect(editMixerDevice, SIGNAL(textChanged(const QString &)), this, SLOT(slotSetDirty())); + connect(editBufferSize, SIGNAL(valueChanged(int)), this, SLOT(slotSetDirty())); + connect(chkDisablePlayback, SIGNAL(toggled(bool)), this, SLOT(slotSetDirty())); + connect(chkDisableCapture, SIGNAL(toggled(bool)), this, SLOT(slotSetDirty())); + slotCancel(); +} + + +OSSSoundConfiguration::~OSSSoundConfiguration () +{ +} + + +void OSSSoundConfiguration::slotOK() +{ + if (m_SoundDevice && m_dirty) { + m_SoundDevice->setBufferSize ( editBufferSize ->value() * 1024); + m_SoundDevice->enablePlayback (!chkDisablePlayback->isChecked()); + m_SoundDevice->enableCapture (!chkDisableCapture ->isChecked()); + m_SoundDevice->setDSPDeviceName ( editDSPDevice ->url()); + m_SoundDevice->setMixerDeviceName( editMixerDevice ->url()); + m_dirty = false; + } +} + + +void OSSSoundConfiguration::slotCancel() +{ + if (m_dirty) { + m_ignore_gui_updates = true; + editDSPDevice ->setURL (m_SoundDevice ? m_SoundDevice->getDSPDeviceName() : QString::null); + editMixerDevice ->setURL (m_SoundDevice ? m_SoundDevice->getMixerDeviceName() : QString::null); + 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); + m_ignore_gui_updates = false; + m_dirty = false; + } +} + +void OSSSoundConfiguration::slotUpdateConfig() +{ + slotSetDirty(); + slotCancel(); +} + +void OSSSoundConfiguration::slotSetDirty() +{ + if (!m_ignore_gui_updates) { + m_dirty = true; + } +} + +#include "oss-sound-configuration.moc" diff --git a/kradio3/plugins/oss-sound/oss-sound-configuration.h b/kradio3/plugins/oss-sound/oss-sound-configuration.h new file mode 100644 index 0000000..9106821 --- /dev/null +++ b/kradio3/plugins/oss-sound/oss-sound-configuration.h @@ -0,0 +1,51 @@ +/*************************************************************************** + oss-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_OSS_SOUND_CONFIGURATION_H +#define KRADIO_OSS_SOUND_CONFIGURATION_H + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "oss-sound-configuration-ui.h" +#include "oss-sound.h" + +class OSSSoundConfiguration : public OSSSoundConfigurationUI +{ +Q_OBJECT +public : + OSSSoundConfiguration (QWidget *parent, OSSSoundDevice *); + ~OSSSoundConfiguration (); + +protected slots: + + void slotOK(); + void slotCancel(); + void slotSetDirty(); + + void slotUpdateConfig(); + +protected: + + OSSSoundDevice *m_SoundDevice; + + bool m_dirty; + bool m_ignore_gui_updates; +}; + +#endif diff --git a/kradio3/plugins/oss-sound/oss-sound.cpp b/kradio3/plugins/oss-sound/oss-sound.cpp new file mode 100644 index 0000000..760399e --- /dev/null +++ b/kradio3/plugins/oss-sound/oss-sound.cpp @@ -0,0 +1,991 @@ +/*************************************************************************** + oss-sound.cpp - description + ------------------- + begin : Sun Mar 21 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 "oss-sound.h" + +#include "../../src/include/aboutwidget.h" +#include <klocale.h> +#include <kaboutdata.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/soundcard.h> +#include <sys/ioctl.h> +#include <fcntl.h> +#include <unistd.h> +#include <math.h> +#include <errno.h> + +#include "oss-sound-configuration.h" +#include "../../src/include/utils.h" + +/////////////////////////////////////////////////////////////////////// +//// plugin library functions + +PLUGIN_LIBRARY_FUNCTIONS(OSSSoundDevice, "kradio-oss-sound", i18n("Open Sound System (OSS) Support")); + +///////////////////////////////////////////////////////////////////////////// + +struct _lrvol { unsigned char l, r; short dummy; }; + +OSSSoundDevice::OSSSoundDevice(const QString &name) + : QObject(NULL, NULL), + PluginBase(name, i18n("KRadio OSS Sound Plugin")), + m_DSPDeviceName(""), + m_MixerDeviceName(""), + m_DSP_fd(-1), + m_Mixer_fd(-1), + m_DuplexMode(DUPLEX_UNKNOWN), + m_DSPFormat(), + m_PassivePlaybackStreams(), + m_PlaybackStreamID(), + m_CaptureStreamID(), + m_BufferSize(65536), + 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) +{ + QObject::connect(&m_PollingTimer, SIGNAL(timeout()), this, SLOT(slotPoll())); +} + + +OSSSoundDevice::~OSSSoundDevice() +{ + stopCapture(m_CaptureStreamID); + stopPlayback(m_PlaybackStreamID); + closeDSPDevice(); + closeMixerDevice(); +} + + +bool OSSSoundDevice::connectI(Interface *i) +{ + bool a = PluginBase::connectI(i); + bool b = ISoundStreamClient::connectI(i); + return a || b; +} + + +bool OSSSoundDevice::disconnectI(Interface *i) +{ + bool a = PluginBase::disconnectI(i); + bool b = ISoundStreamClient::disconnectI(i); + return a || b; +} + +void OSSSoundDevice::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_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 OSSSoundDevice::saveState (KConfig *c) const +{ + c->setGroup(QString("oss-sound-") + PluginBase::name()); + + c->writeEntry("dsp-device", m_DSPDeviceName); + c->writeEntry("mixer-device", m_MixerDeviceName); + c->writeEntry("enable-playback", m_EnablePlayback); + c->writeEntry("enable-capture", m_EnableCapture); + c->writeEntry("buffer-size", m_BufferSize); + c->writeEntry("soundstreamclient-id", m_SoundStreamClientID); +} + + +void OSSSoundDevice::restoreState (KConfig *c) +{ + c->setGroup(QString("oss-sound-") + PluginBase::name()); + + m_EnablePlayback = c->readBoolEntry("enable-playback", true); + m_EnableCapture = c->readBoolEntry("enable-capture", true); + m_BufferSize = c->readNumEntry ("buffer-size", 65536); + + setDSPDeviceName (c->readEntry ("dsp-device", "/dev/dsp")); + setMixerDeviceName (c->readEntry ("mixer-device", "/dev/mixer")); + + m_PlaybackBuffer.resize(m_BufferSize); + m_CaptureBuffer.resize(m_BufferSize); + + setSoundStreamClientID(c->readEntry("soundstreamclient-id", getSoundStreamClientID())); + + emit sigUpdateConfig(); +} + + +void OSSSoundDevice::setMixerDeviceName(const QString &dev_name) +{ + if (m_MixerDeviceName != dev_name) { + m_MixerDeviceName = dev_name; + if (m_Mixer_fd >= 0) + openMixerDevice(true); + getMixerChannels(SOUND_MIXER_DEVMASK, m_PlaybackChannels, m_revPlaybackChannels); + getMixerChannels(SOUND_MIXER_RECMASK, m_CaptureChannels, m_revCaptureChannels); + notifyPlaybackChannelsChanged(m_SoundStreamClientID, m_PlaybackChannels); + notifyCaptureChannelsChanged(m_SoundStreamClientID, m_CaptureChannels); + } +} + + +ConfigPageInfo OSSSoundDevice::createConfigurationPage() +{ + OSSSoundConfiguration *conf = new OSSSoundConfiguration(NULL, this); + QObject::connect(this, SIGNAL(sigUpdateConfig()), conf, SLOT(slotUpdateConfig())); + return ConfigPageInfo (conf, + i18n("OSS Sound"), + i18n("OSS Sound Device Options"), + "kradio_oss"); +} + + +AboutPageInfo OSSSoundDevice::createAboutPage() +{ +/* KAboutData aboutData("kradio", + NULL, + NULL, + I18N_NOOP("OSS Sound Plugin for KRadio"), + KAboutData::License_GPL, + "(c) 2004 Martin Witte", + 0, + "http://sourceforge.net/projects/kradio", + 0); + aboutData.addAuthor("Martin Witte", "", "witte@kawo1.rwth-aachen.de"); + + return AboutPageInfo( + new KRadioAboutWidget(aboutData, KRadioAboutWidget::AbtTabbed), + i18n("OSS Sound"), + i18n("OSS Sound"), + "kradio_oss_sound" + ); +*/ + return AboutPageInfo(); +} + + + +bool OSSSoundDevice::preparePlayback(SoundStreamID id, const QString &channel, bool active_mode, bool start_immediately) +{ + if (id.isValid() && m_revPlaybackChannels.contains(channel)) { + m_PlaybackStreams.insert(id, SoundStreamConfig(m_revPlaybackChannels[channel], active_mode)); + if (start_immediately) + startPlayback(id); + return true; + // FIXME: what to do if stream is already playing? + } + return false; +} + + +bool OSSSoundDevice::prepareCapture(SoundStreamID id, const QString &channel) +{ + if (id.isValid() && m_revCaptureChannels.contains(channel)) { + m_CaptureStreams.insert(id, SoundStreamConfig(m_revCaptureChannels[channel])); + return true; + // FIXME: what to do if stream is already playing? + } + return false; +} + +bool OSSSoundDevice::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 OSSSoundDevice::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 OSSSoundDevice::supportsPlayback() const +{ + return m_EnablePlayback; +} + + +bool OSSSoundDevice::supportsCapture() const +{ + return m_EnableCapture; +} + + +bool OSSSoundDevice::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) { + openMixerDevice(); + if (cfg.m_Volume >= 0) + writeMixerVolume(cfg.m_Channel, cfg.m_Volume); + } + + // error handling? + return true; + } else { + return false; + } +} + + +bool OSSSoundDevice::pausePlayback(SoundStreamID /*id*/) +{ + //return stopPlayback(id); + return false; +} + + +bool OSSSoundDevice::stopPlayback(SoundStreamID id) +{ + if (id.isValid() && m_PlaybackStreams.contains(id)) { + + SoundStreamConfig &cfg = m_PlaybackStreams[id]; + + if (!cfg.m_ActiveMode) { + if (m_PassivePlaybackStreams.contains(id)) { +// writeMixerVolume(cfg.m_Channel, 0); + m_PassivePlaybackStreams.remove(id); + } + } else if (m_PlaybackStreamID == id) { + m_PlaybackStreamID = SoundStreamID::InvalidID; + m_PlaybackBuffer.clear(); + closeDSPDevice(); + } + + closeMixerDevice(); + return true; + } else { + return false; + } +} + +bool OSSSoundDevice::isPlaybackRunning(SoundStreamID id, bool &b) const +{ + if (id.isValid() && m_PlaybackStreams.contains(id)) { + b = true; + return true; + } else { + return false; + } +} + +bool OSSSoundDevice::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) { + + m_CaptureStreamID = id; + SoundStreamConfig &cfg = m_CaptureStreams[id]; + + openMixerDevice(); + selectCaptureChannel(cfg.m_Channel); + if (cfg.m_Volume >= 0) + writeMixerVolume(cfg.m_Channel, cfg.m_Volume); + + openDSPDevice(proposed_format); + + // FIXME: error handling? + } + + real_format = m_DSPFormat; + m_CaptureRequestCounter++; + + return true; + } else { + return false; + } +} + + +bool OSSSoundDevice::stopCapture(SoundStreamID id) +{ + if (id.isValid() && m_CaptureStreamID == id) { + + if (--m_CaptureRequestCounter == 0) { + m_CaptureStreamID = SoundStreamID::InvalidID; + m_CaptureBuffer.clear(); + + closeMixerDevice(); + closeDSPDevice(); + } + return true; + } else { + return false; + } +} + + +bool OSSSoundDevice::isCaptureRunning(SoundStreamID id, bool &b, SoundFormat &sf) const +{ + if (id.isValid() && m_CaptureStreamID == id) { + b = true; + sf = m_DSPFormat; + return true; + } else { + return false; + } +} + + +bool OSSSoundDevice::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 OSSSoundDevice::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 OSSSoundDevice::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_DSP_fd < 0) { + openDSPDevice(format); + } else if (format != m_DSPFormat) { + if (m_CaptureStreamID.isValid()) + return false; + + // flush playback buffer + size_t buffersize = 0; + char *buffer = m_PlaybackBuffer.getData(buffersize); + write(m_DSP_fd, buffer, buffersize); + + // if not all could be written, it must be discarded + m_PlaybackBuffer.clear(); + + closeDSPDevice(); + openDSPDevice(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("%1: Playback buffer overflow. Skipped %1 bytes").arg(m_DSPDeviceName).arg(QString::number(m_PlaybackSkipCount))); +// m_PlaybackSkipCount = 0; +// } + + return true; //m_PlaybackSkipCount == 0; +} + + + +void OSSSoundDevice::slotPoll() +{ + int err = 0; + + if (m_CaptureStreamID.isValid() && m_DSP_fd >= 0) { + + size_t bufferSize = 0; + char *buffer = m_CaptureBuffer.getFreeSpace(bufferSize); + + int bytesRead = read(m_DSP_fd, buffer, bufferSize); + + if (bytesRead > 0) { + m_CaptureBuffer.removeFreeSpace(bytesRead); + } else if (bytesRead < 0 && errno == EAGAIN) { + bytesRead = 0; + } else if (bytesRead == 0) { + err = -1; + logError(i18n("OSS device %1: No data to record").arg(m_DSPDeviceName)); + } else { + err = errno; + } + + 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_DSPFormat, buffer, size, consumed_size, SoundMetaData(m_CapturePos, cur_time - m_CaptureStartTime, cur_time, i18n("internal stream, not stored (%1)").arg(m_DSPDeviceName))); + 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_PlaybackStreamID.isValid()/* && m_DSP_fd >= 0*/) { + + if (m_PlaybackBuffer.getFillSize() > 0 && m_DSP_fd >= 0) { + + size_t buffersize = 0; + char *buffer = m_PlaybackBuffer.getData(buffersize); + int bytesWritten = write(m_DSP_fd, buffer, buffersize); + + if (bytesWritten > 0) { + m_PlaybackBuffer.removeData(bytesWritten); + } else if (bytesWritten < 0 && errno == EAGAIN) { + bytesWritten = 0; + } else { + err = errno; + } + } + + if (m_PlaybackBuffer.getFreeSize() > 0) + notifyReadyForPlaybackData(m_PlaybackStreamID, m_PlaybackBuffer.getFreeSize()); + } + + if (err) { + logError(i18n("Error %1 while handling OSS device %2").arg(QString().setNum(err)).arg(m_DSPDeviceName)); + } + + if (m_PlaybackStreamID.isValid()) + checkMixerVolume(m_PlaybackStreamID); + if (m_CaptureStreamID.isValid()) + checkMixerVolume(m_CaptureStreamID); + + QValueListConstIterator<SoundStreamID> end = m_PassivePlaybackStreams.end(); + for (QValueListConstIterator<SoundStreamID> it = m_PassivePlaybackStreams.begin(); it != end; ++it) + checkMixerVolume(*it); + +} + + +bool OSSSoundDevice::openDSPDevice(const SoundFormat &format, bool reopen) +{ + if (m_DSP_fd >= 0) { + + if (reopen) { + + closeDSPDevice ( /* force = */ true); + + } else { + + if (format != m_DSPFormat) + return false; + + if (m_DuplexMode != DUPLEX_FULL && m_CaptureStreamID.isValid() && m_PlaybackStreamID.isValid()) + return false; + + return true; + } + } else { + if (reopen) + return true; + } + + m_DSPFormat = format; + + // first testopen for CAPS + m_DSP_fd = open(m_DSPDeviceName.ascii(), O_NONBLOCK | O_RDONLY); + bool err = m_DSP_fd < 0; + if (err) { + logError(i18n("Cannot open DSP device %1").arg(m_DSPDeviceName)); + return false; + } + int caps = 0; + err |= (ioctl (m_DSP_fd, SNDCTL_DSP_GETCAPS, &caps) != 0); + if (err) + logError(i18n("Cannot read DSP capabilities for %1").arg(m_DSPDeviceName)); + + m_DuplexMode = (caps & DSP_CAP_DUPLEX) ? DUPLEX_FULL : DUPLEX_HALF; + close (m_DSP_fd); + m_DSP_fd = -1; + + // opening and seeting up the device file + int mode = O_NONBLOCK; + if (m_DuplexMode == DUPLEX_FULL) { + mode |= O_RDWR; + } else if (m_CaptureStreamID.isValid()) { + mode |= O_RDONLY; + } else { + mode |= O_WRONLY; + } + + m_DSP_fd = open(m_DSPDeviceName.ascii(), mode); + + err = m_DSP_fd < 0; + if (err) { + logError(i18n("Cannot open DSP device %1").arg(m_DSPDeviceName)); + return false; + } + + int oss_format = getOSSFormat(m_DSPFormat); + err |= (ioctl(m_DSP_fd, SNDCTL_DSP_SETFMT, &oss_format) != 0); + if (err) + logError(i18n("Cannot set DSP sample format for %1").arg(m_DSPDeviceName)); + + int channels = m_DSPFormat.m_Channels; + err |= (ioctl(m_DSP_fd, SNDCTL_DSP_CHANNELS, &channels) != 0); + if (err) + logError(i18n("Cannot set number of channels for %1").arg(m_DSPDeviceName)); + + int rate = m_DSPFormat.m_SampleRate; + err |= (ioctl(m_DSP_fd, SNDCTL_DSP_SPEED, &rate) != 0); + if (err) + logError(i18n("Cannot set sampling rate for %1").arg(m_DSPDeviceName)); + if (rate != (int)m_DSPFormat.m_SampleRate) { + logWarning(i18n("Asking for %1 Hz but %2 uses %3 Hz"). + arg(QString::number(m_DSPFormat.m_SampleRate)). + arg(m_DSPDeviceName). + arg(QString::number(rate))); + m_DSPFormat.m_SampleRate = rate; + } + + int stereo = m_DSPFormat.m_Channels == 2; + err |= (ioctl(m_DSP_fd, SNDCTL_DSP_STEREO, &stereo) != 0); + if (err) + logError(i18n("Cannot set stereo mode for %1").arg(m_DSPDeviceName)); + + unsigned sampleSize = m_DSPFormat.m_SampleBits; + err |= (ioctl(m_DSP_fd, SNDCTL_DSP_SAMPLESIZE, &sampleSize) != 0); + if (err || sampleSize != m_DSPFormat.m_SampleBits) + logError(i18n("Cannot set sample size for %1").arg(m_DSPDeviceName)); + + // setup buffer, ask for 40ms latency + int tmp = (400 * m_DSPFormat.frameSize() * m_DSPFormat.m_SampleRate) / 1000; + int mask = -1; for (; tmp; tmp >>= 1) ++mask; + if (mask < 8) mask = 12; // default 4kB + mask |= 0x7FFF0000; + err |= ioctl (m_DSP_fd, SNDCTL_DSP_SETFRAGMENT, &mask); + if (err) + logError(i18n("Cannot set buffers for %1").arg(m_DSPDeviceName)); + + int bufferBlockSize = 0; + err |= ioctl (m_DSP_fd, SNDCTL_DSP_GETBLKSIZE, &bufferBlockSize); + if (err) { + logError(i18n("Cannot read buffer size for %1").arg(m_DSPDeviceName)); + } else { + logInfo(i18n("%1 uses buffer blocks of %2 bytes").arg(m_DSPDeviceName).arg(QString::number(bufferBlockSize))); + size_t tmp = (((m_BufferSize - 1) / bufferBlockSize) + 1) * bufferBlockSize; + setBufferSize(tmp); + logInfo(i18n("adjusted own buffer size to %1 bytes").arg(QString::number(tmp))); + } + + int trigger = ~PCM_ENABLE_INPUT & ~PCM_ENABLE_OUTPUT; + ioctl(m_DSP_fd, SNDCTL_DSP_SETTRIGGER, &trigger); + trigger = PCM_ENABLE_INPUT | PCM_ENABLE_OUTPUT; + ioctl(m_DSP_fd, SNDCTL_DSP_SETTRIGGER, &trigger); + + if (!err) { + m_PollingTimer.start(40); + } else { + closeDSPDevice(); + } + + m_CaptureSkipCount = 0; + //m_PlaybackSkipCount = 0; + + return !err; +} + + +bool OSSSoundDevice::closeDSPDevice(bool force) +{ + if ((!m_PlaybackStreamID.isValid() && !m_CaptureStreamID.isValid()) || force) { + + if (m_Mixer_fd < 0) + m_PollingTimer.stop(); + + if (m_DSP_fd >= 0) + close (m_DSP_fd); + m_DSP_fd = -1; + + m_PlaybackBuffer.clear(); + m_CaptureBuffer.clear(); + } + return true; +} + + +bool OSSSoundDevice::openMixerDevice(bool reopen) +{ + if (reopen) { + if (m_Mixer_fd >= 0) + closeMixerDevice(/* force = */ true); + else + return true; + } + + if (m_Mixer_fd < 0) + m_Mixer_fd = open(m_MixerDeviceName.ascii(), O_RDONLY); + + if (m_Mixer_fd < 0) { + logError(i18n("Cannot open mixer device %1").arg(m_MixerDeviceName)); + } else { + m_PollingTimer.start(40); + } + return m_Mixer_fd >= 0; +} + + +bool OSSSoundDevice::closeMixerDevice(bool force) +{ + if ((!m_PlaybackStreamID.isValid() && !m_CaptureStreamID.isValid()) || force) { + + if (m_DSP_fd < 0) + m_PollingTimer.stop(); + + if (m_Mixer_fd >= 0) + close (m_Mixer_fd); + m_Mixer_fd = -1; + } + return m_Mixer_fd < 0; +} + + +void OSSSoundDevice::getMixerChannels(int query, QStringList &retval, QMap<QString, int> &revmap) const +{ + retval.clear(); + revmap.clear(); + + int fd = m_Mixer_fd; + if (fd < 0) + fd = open(m_MixerDeviceName.ascii(), O_RDONLY); + + if (fd < 0) { + logError(i18n("OSSSoundDevice::getMixerChannels: Cannot open mixer device %1").arg(m_MixerDeviceName)); + } + + if (fd >= 0) { + int mask = 0; + if ( ioctl(fd, MIXER_READ(query), &mask) == 0 ) { + for (int i = 0; i < SOUND_MIXER_NRDEVICES; ++i) { + if (mask & (1 << i)) { + static const char *labels[] = SOUND_DEVICE_LABELS; + retval.append(i18n(labels[i])); + revmap.insert(i18n(labels[i]), i); + } + } + } else { + logError(i18n("OSSSoundDevice::getMixerChannels: Cannot read mixer device mask on device %1").arg(m_MixerDeviceName)); + } + } + if (fd != m_Mixer_fd) + close(fd); +} + + +const QStringList &OSSSoundDevice::getPlaybackChannels() const +{ + return m_PlaybackChannels; +} + + +const QStringList &OSSSoundDevice::getCaptureChannels() const +{ + return m_CaptureChannels; +} + + +bool OSSSoundDevice::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)) { + cfg.m_Volume = writeMixerVolume(cfg.m_Channel, volume); + notifyPlaybackVolumeChanged(id, cfg.m_Volume); + } + return true; + } + return false; +} + + +bool OSSSoundDevice::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)) { + cfg.m_Volume = writeMixerVolume(cfg.m_Channel, volume); + notifyCaptureVolumeChanged(id, cfg.m_Volume); + } + return true; + } + return false; +} + + +bool OSSSoundDevice::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 OSSSoundDevice::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 OSSSoundDevice::checkMixerVolume(SoundStreamID id) +{ + if (m_Mixer_fd >= 0 && id.isValid()) { + + if (m_PassivePlaybackStreams.contains(id) || m_PlaybackStreamID == id) { + SoundStreamConfig &cfg = m_PlaybackStreams[id]; + + float v = readMixerVolume(cfg.m_Channel); + if (rint(100*cfg.m_Volume) != rint(100*v)) { + cfg.m_Volume = v; + notifyPlaybackVolumeChanged(id, v); + } + } + + if (m_CaptureStreamID == id) { + SoundStreamConfig &cfg = m_CaptureStreams[id]; + + float v = readMixerVolume(cfg.m_Channel); + if (rint(100*cfg.m_Volume) != rint(100*v)) { + cfg.m_Volume = v; + notifyCaptureVolumeChanged(id, v); + } + } + } +} + + +float OSSSoundDevice::readMixerVolume(int channel) const +{ + _lrvol tmpvol; + int err = ioctl(m_Mixer_fd, MIXER_READ(channel), &tmpvol); + if (err) { + logError("OSSSound::readMixerVolume: " + + i18n("error %1 while reading volume from %2") + .arg(QString().setNum(err)) + .arg(m_MixerDeviceName)); + tmpvol.l = tmpvol.r = 0; + } + return float(tmpvol.l) / 100.0; +} + + +float OSSSoundDevice::writeMixerVolume (int channel, float vol) +{ + if (vol > 1.0) vol = 1.0; + if (vol < 0) vol = 0.0; + + const int divs = 100; + vol = rint(vol * divs) / float(divs); + + if (m_Mixer_fd >= 0) { + _lrvol tmpvol; + tmpvol.r = tmpvol.l = (unsigned int)(rint(vol * divs)); + int err = ioctl(m_Mixer_fd, MIXER_WRITE(channel), &tmpvol); + if (err != 0) { + logError("OSSSoundDevice::writeMixerVolume: " + + i18n("error %1 while setting volume to %2 on device %3") + .arg(QString().setNum(err)) + .arg(QString().setNum(vol)) + .arg(m_MixerDeviceName)); + return -1; + } + } + return vol; +} + + +void OSSSoundDevice::selectCaptureChannel (int channel) +{ + int x = 1 << channel; + int err = ioctl(m_Mixer_fd, SOUND_MIXER_WRITE_RECSRC, &x); + if (err) + logError(i18n("Selecting recording source on device %1 failed with error code %2") + .arg(m_MixerDeviceName) + .arg(QString::number(err))); + _lrvol tmpvol; + err = ioctl(m_Mixer_fd, MIXER_READ(SOUND_MIXER_IGAIN), &tmpvol); + if (err) + logError(i18n("Reading igain volume on device %1 failed with error code %2") + .arg(m_MixerDeviceName) + .arg(QString::number(err))); + if (tmpvol.r == 0 && tmpvol.l == 0) { + tmpvol.r = tmpvol.l = 1; + err = ioctl(m_Mixer_fd, MIXER_WRITE(SOUND_MIXER_IGAIN), &tmpvol); + if (err) + logError(i18n("Setting igain volume on device %1 failed with error code %2") + .arg(m_MixerDeviceName) + .arg(QString::number(err))); + } +} + + +int OSSSoundDevice::getOSSFormat(const SoundFormat &f) +{ + if (f.m_SampleBits == 16) { + switch (2 * f.m_IsSigned + (f.m_Endianess == LITTLE_ENDIAN)) { + case 0: return AFMT_U16_BE; + case 1: return AFMT_U16_LE; + case 2: return AFMT_S16_BE; + case 3: return AFMT_S16_LE; + } + } + if (f.m_SampleBits == 8) { + switch (f.m_IsSigned) { + case 0: return AFMT_U8; + case 1: return AFMT_S8; + } + } + return 0; +} + + +void OSSSoundDevice::setBufferSize(int s) +{ + m_BufferSize = s; + m_PlaybackBuffer.resize(m_BufferSize); + m_CaptureBuffer.resize(m_BufferSize); +} + + +void OSSSoundDevice::enablePlayback(bool on) +{ + m_EnablePlayback = on; +} + + +void OSSSoundDevice::enableCapture(bool on) +{ + m_EnableCapture = on; +} + + +void OSSSoundDevice::setDSPDeviceName(const QString &s) +{ + m_DSPDeviceName = s; + SoundFormat f = m_DSPFormat; + if (m_DSP_fd >= 0) + openDSPDevice(f, /* reopen = */ true); +} + + +QString OSSSoundDevice::getSoundStreamClientDescription() const +{ + return i18n("OSS Sound Device %1").arg(PluginBase::name()); +} + + + +#include "oss-sound.moc" diff --git a/kradio3/plugins/oss-sound/oss-sound.h b/kradio3/plugins/oss-sound/oss-sound.h new file mode 100644 index 0000000..139ee64 --- /dev/null +++ b/kradio3/plugins/oss-sound/oss-sound.h @@ -0,0 +1,224 @@ +/*************************************************************************** + oss-sound.h - description + ------------------- + begin : Sun Mar 21 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_OSS_SOUND_H +#define _KRADIO_OSS_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 <qobject.h> +#include <qtimer.h> + +enum DUPLEX_MODE { DUPLEX_UNKNOWN, DUPLEX_FULL, DUPLEX_HALF }; + + +struct SoundStreamConfig +{ + SoundStreamConfig() + : m_ActiveMode(false), + m_Channel(-1), + m_Volume(-1) + {} + + SoundStreamConfig(int _channel, bool active_mode = true) + : m_ActiveMode(active_mode), + m_Channel(_channel), + m_Volume(-1) + {} + + SoundStreamConfig(const SoundStreamConfig &c) + : m_ActiveMode(c.m_ActiveMode), + m_Channel(c.m_Channel), + m_Volume(c.m_Volume) + {} + + bool m_ActiveMode; + int m_Channel; + float m_Volume; +}; + + +class OSSSoundDevice : public QObject, + public PluginBase, + public ISoundStreamClient +{ +Q_OBJECT + +public: + OSSSoundDevice (const QString &name); + virtual ~OSSSoundDevice (); + + virtual bool connectI(Interface *i); + virtual bool disconnectI(Interface *i); + + // PluginBase + +public: + virtual void saveState (KConfig *) const; + virtual void restoreState (KConfig *); + + virtual QString pluginClassName() const { return "OSSSoundDevice"; } + + virtual const QString &name() const { return PluginBase::name(); } + virtual QString &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 QString &channel, bool active_mode, bool start_immediately); + bool prepareCapture(SoundStreamID id, const QString &channel); + bool releasePlayback(SoundStreamID id); + bool releaseCapture(SoundStreamID id); + +ANSWERS: + bool supportsPlayback() const; + bool supportsCapture() const; + + QString getSoundStreamClientDescription() const; + + // ISoundStreamClient: mixer access + +protected: + void getMixerChannels(int query_playback_or_rec_mask, QStringList &retval, QMap<QString, int> &revmap) const; + +ANSWERS: + const QStringList &getPlaybackChannels() const; + const QStringList &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; + + // 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 getBufferSize() const { return m_BufferSize; } + bool isPlaybackEnabled() const { return m_EnablePlayback; } + bool isCaptureEnabled() const { return m_EnableCapture; } + const QString &getDSPDeviceName() const { return m_DSPDeviceName; } + const QString &getMixerDeviceName() const { return m_MixerDeviceName; } + + void setBufferSize(int s); + void enablePlayback(bool on); + void enableCapture(bool on); + void setDSPDeviceName(const QString &s); + void setMixerDeviceName(const QString &dev_name); + + // own functions + + static int getOSSFormat(const SoundFormat &f); + +protected slots: + + void slotPoll(); + +signals: + + void sigUpdateConfig(); + +protected: + + bool openDSPDevice(const SoundFormat &format, bool reopen = false); + bool closeDSPDevice(bool force = false); + + bool openMixerDevice(bool reopen = false); + bool closeMixerDevice(bool force = false); + + void checkMixerVolume(SoundStreamID id); + float readMixerVolume(int channel) const; + float writeMixerVolume(int channel, float vol); + + void selectCaptureChannel (int channel); + + QString m_DSPDeviceName, + m_MixerDeviceName; + int m_DSP_fd, + m_Mixer_fd; + DUPLEX_MODE m_DuplexMode; + SoundFormat m_DSPFormat; + + QStringList m_PlaybackChannels, + m_CaptureChannels; + QMap<QString, int> m_revPlaybackChannels, + m_revCaptureChannels; + + QMap<SoundStreamID, SoundStreamConfig> + m_PlaybackStreams, + m_CaptureStreams; + + QValueList<SoundStreamID> + m_PassivePlaybackStreams; + SoundStreamID m_PlaybackStreamID, + m_CaptureStreamID; + + size_t m_BufferSize; + RingBuffer m_PlaybackBuffer, + m_CaptureBuffer; + + unsigned m_CaptureRequestCounter; + Q_UINT64 m_CapturePos; + time_t m_CaptureStartTime; + + + size_t //m_PlaybackSkipCount, + m_CaptureSkipCount; + + bool m_EnablePlayback, + m_EnableCapture; + + QTimer m_PollingTimer; +}; + + + +#endif diff --git a/kradio3/plugins/oss-sound/po/Makefile.am b/kradio3/plugins/oss-sound/po/Makefile.am new file mode 100644 index 0000000..d6cceda --- /dev/null +++ b/kradio3/plugins/oss-sound/po/Makefile.am @@ -0,0 +1,2 @@ +PACKAGE = kradio-oss-sound +POFILES = AUTO diff --git a/kradio3/plugins/oss-sound/po/de.po b/kradio3/plugins/oss-sound/po/de.po new file mode 100644 index 0000000..3ff8fdc --- /dev/null +++ b/kradio3/plugins/oss-sound/po/de.po @@ -0,0 +1,200 @@ +# translation of de.po to +# translation of kradio-oss-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: 2006-11-12 18:41+0100\n" +"PO-Revision-Date: 2006-11-12 18:24+0100\n" +"Last-Translator: Ernst Martin Witte <emw@nocabal.de>\n" +"Language-Team: <de@li.org>\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: KBabel 1.11.4\n" + +#. i18n: file oss-sound-configuration-ui.ui line 27 +#: rc.cpp:3 rc.cpp:27 oss-sound-configuration-ui.cpp:106 +#, no-c-format +msgid "Devices" +msgstr "Geräte" + +#. i18n: file oss-sound-configuration-ui.ui line 51 +#: rc.cpp:6 rc.cpp:30 oss-sound-configuration-ui.cpp:107 +#, no-c-format +msgid "PCM Device" +msgstr "Gerät" + +#. i18n: file oss-sound-configuration-ui.ui line 59 +#: rc.cpp:9 rc.cpp:33 oss-sound-configuration-ui.cpp:108 +#, no-c-format +msgid "Mixer Device" +msgstr "Mixer Gerätedatei" + +#. i18n: file oss-sound-configuration-ui.ui line 67 +#: rc.cpp:12 rc.cpp:36 oss-sound-configuration-ui.cpp:109 +#, no-c-format +msgid "Buffer Size" +msgstr "Puffergröße" + +#. i18n: file oss-sound-configuration-ui.ui line 75 +#: rc.cpp:15 rc.cpp:39 oss-sound-configuration-ui.cpp:110 +#, no-c-format +msgid " kB" +msgstr " kB" + +#. i18n: file oss-sound-configuration-ui.ui line 91 +#: rc.cpp:18 rc.cpp:42 oss-sound-configuration-ui.cpp:111 +#, no-c-format +msgid "Extended Options" +msgstr "Erweiterte Optionen" + +#. i18n: file oss-sound-configuration-ui.ui line 105 +#: rc.cpp:21 rc.cpp:45 oss-sound-configuration-ui.cpp:112 +#, no-c-format +msgid "Disable Playback" +msgstr "Wiedergabe abschalten" + +#. i18n: file oss-sound-configuration-ui.ui line 113 +#: rc.cpp:24 rc.cpp:48 oss-sound-configuration-ui.cpp:113 +#, no-c-format +msgid "Disable Capture" +msgstr "Aufnahme abschalten" + +#: _translatorinfo.cpp:1 +msgid "" +"_: NAME OF TRANSLATORS\n" +"Your names" +msgstr "Ernst Martin Witte" + +#: _translatorinfo.cpp:3 +msgid "" +"_: EMAIL OF TRANSLATORS\n" +"Your emails" +msgstr "emw@nocabal.de" + +#: oss-sound.cpp:38 +msgid "Open Sound System (OSS) Support" +msgstr "Unterstützung für das Open Sound System (OSS)" + +#: oss-sound.cpp:46 +msgid "KRadio OSS Sound Plugin" +msgstr "KRadio Plugin für das Open Sound System (OSS)" + +#: oss-sound.cpp:172 +msgid "OSS Sound" +msgstr "OSS Sound" + +#: oss-sound.cpp:173 +msgid "OSS Sound Device Options" +msgstr "Geräteoptionen für den OSS Sound" + +#: oss-sound.cpp:507 +msgid "OSS device %1: No data to record" +msgstr "OSS Gerät %1: Keine Daten zum Aufnehmen" + +#: oss-sound.cpp:517 +msgid "internal stream, not stored (%1)" +msgstr "interner, nicht aufgezeichneter Datenstrom (%1)" + +#: oss-sound.cpp:549 +msgid "Error %1 while handling OSS device %2" +msgstr "Fehler %1 beim Behandeln vom OSS-Gerät %2" + +#: oss-sound.cpp:593 oss-sound.cpp:619 +msgid "Cannot open DSP device %1" +msgstr "Die Audio-Gerätedatei %1 kann nicht geöffnet werden" + +#: oss-sound.cpp:599 +msgid "Cannot read DSP capabilities for %1" +msgstr "Kann die Fähigkeiten des Gerätes %1 nicht lesen." + +#: oss-sound.cpp:626 +msgid "Cannot set DSP sample format for %1" +msgstr "Kann das Abtastformat für %1 nicht schreiben" + +#: oss-sound.cpp:631 +msgid "Cannot set number of channels for %1" +msgstr "Kann die Anzahl der Kanäle für %1 nicht festlegen" + +#: oss-sound.cpp:636 +msgid "Cannot set sampling rate for %1" +msgstr "Kann die Abtastrate für %1 nicht setzen" + +#: oss-sound.cpp:638 +msgid "Asking for %1 Hz but %2 uses %3 Hz" +msgstr "" +"%1 Hz sollen als Abtastrate verwendet werden, kann aber nur %3 Hz für das " +"Gerät %2 verwendens" + +#: oss-sound.cpp:648 +msgid "Cannot set stereo mode for %1" +msgstr "Kann den Stereo-Modus für %1 nicht setzen" + +#: oss-sound.cpp:653 +msgid "Cannot set sample size for %1" +msgstr "Kann das Quantisierung-Format für %1 nicht setzen" + +#: oss-sound.cpp:662 +msgid "Cannot set buffers for %1" +msgstr "Kann die Puffer für %1 nicht einstellen" + +#: oss-sound.cpp:667 +msgid "Cannot read buffer size for %1" +msgstr "Kann die Puffergröße für %1 nicht lesen" + +#: oss-sound.cpp:669 +msgid "%1 uses buffer blocks of %2 bytes" +msgstr "Gerät %1 verwendet Pufferblöcke von %2 Bytes" + +#: oss-sound.cpp:672 +msgid "adjusted own buffer size to %1 bytes" +msgstr "Die interne Puffergröße wurde auf %1 bytes angepasst" + +#: oss-sound.cpp:724 +msgid "Cannot open mixer device %1" +msgstr "Die Mixergerätedatei %1 kann nicht geöffnet werden" + +#: oss-sound.cpp:757 +msgid "OSSSoundDevice::getMixerChannels: Cannot open mixer device %1" +msgstr "OSSSoundDevice::getMixerChannels: Kann den Mixer %1 nicht öffnen" + +#: oss-sound.cpp:771 +msgid "" +"OSSSoundDevice::getMixerChannels: Cannot read mixer device mask on device %1" +msgstr "" +"OSSSoundDevice::getMixerChannels: Kann die Gerätemaske des Mixers %1 nicht " +"lesen" + +#: oss-sound.cpp:876 +msgid "error %1 while reading volume from %2" +msgstr "Fehler %1 beim Lesen der Lautstärke von %2" + +#: oss-sound.cpp:899 +msgid "error %1 while setting volume to %2 on device %3" +msgstr "Fehler %1 beim setzen der Lautstärke %2 auf dem Gerät %3" + +#: oss-sound.cpp:915 +msgid "Selecting recording source on device %1 failed with error code %2" +msgstr "" +"Das Auswählen der Aufnahmequelle auf dem Gerät %1 schlug mit Fehlercode %2 " +"fehl" + +#: oss-sound.cpp:921 +msgid "Reading igain volume on device %1 failed with error code %2" +msgstr "" +"Das Lesen der Aufnahmeverstärkung vom Geräte %1 schlug fehl mit dem " +"Fehlercode %2" + +#: oss-sound.cpp:928 +msgid "Setting igain volume on device %1 failed with error code %2" +msgstr "" +"Das Schreiben der Aufnahmeverstärkung vom Geräte %1 schlug fehl mit dem " +"Fehlercode %2" + +#: oss-sound.cpp:986 +msgid "OSS Sound Device %1" +msgstr "OSS Sound Gerät %1" diff --git a/kradio3/plugins/oss-sound/po/ru.po b/kradio3/plugins/oss-sound/po/ru.po new file mode 100644 index 0000000..d8f18db --- /dev/null +++ b/kradio3/plugins/oss-sound/po/ru.po @@ -0,0 +1,193 @@ +# translation of ru.po to +# translation of kradio-oss-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: 2006-11-12 18:20+0100\n" +"PO-Revision-Date: 2006-11-08 12:45+0300\n" +"Last-Translator: Алексей Кузнецов <Alexey.Kouznetsov@GMail.com>\n" +"Language-Team: <ru@li.org>\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" + +#. i18n: file oss-sound-configuration-ui.ui line 27 +#: rc.cpp:3 rc.cpp:27 oss-sound-configuration-ui.cpp:106 +#, no-c-format +msgid "Devices" +msgstr "Устройства" + +#. i18n: file oss-sound-configuration-ui.ui line 51 +#: rc.cpp:6 rc.cpp:30 oss-sound-configuration-ui.cpp:107 +#, no-c-format +msgid "PCM Device" +msgstr "Устройство PCM" + +#. i18n: file oss-sound-configuration-ui.ui line 59 +#: rc.cpp:9 rc.cpp:33 oss-sound-configuration-ui.cpp:108 +#, no-c-format +msgid "Mixer Device" +msgstr "Устройство микшера" + +#. i18n: file oss-sound-configuration-ui.ui line 67 +#: rc.cpp:12 rc.cpp:36 oss-sound-configuration-ui.cpp:109 +#, no-c-format +msgid "Buffer Size" +msgstr "Размер буфера" + +#. i18n: file oss-sound-configuration-ui.ui line 75 +#: rc.cpp:15 rc.cpp:39 oss-sound-configuration-ui.cpp:110 +#, no-c-format +msgid " kB" +msgstr " кБ" + +#. i18n: file oss-sound-configuration-ui.ui line 91 +#: rc.cpp:18 rc.cpp:42 oss-sound-configuration-ui.cpp:111 +#, no-c-format +msgid "Extended Options" +msgstr "Дополнительные параметры" + +#. i18n: file oss-sound-configuration-ui.ui line 105 +#: rc.cpp:21 rc.cpp:45 oss-sound-configuration-ui.cpp:112 +#, no-c-format +msgid "Disable Playback" +msgstr "Запретить &воспроизведение" + +#. i18n: file oss-sound-configuration-ui.ui line 113 +#: rc.cpp:24 rc.cpp:48 oss-sound-configuration-ui.cpp:113 +#, no-c-format +msgid "Disable Capture" +msgstr "Запретить &запись" + +#: _translatorinfo.cpp:1 +msgid "" +"_: NAME OF TRANSLATORS\n" +"Your names" +msgstr "Алексей Кузнецов" + +#: _translatorinfo.cpp:3 +msgid "" +"_: EMAIL OF TRANSLATORS\n" +"Your emails" +msgstr "Alexey.Kouznetsov@GMail.com" + +#: oss-sound.cpp:38 +msgid "Open Sound System (OSS) Support" +msgstr "Поддержка Открытой звуковой системы (OSS)" + +#: oss-sound.cpp:46 +msgid "KRadio OSS Sound Plugin" +msgstr "Модуль OSS для KRadio" + +#: oss-sound.cpp:172 +msgid "OSS Sound" +msgstr "OSS" + +#: oss-sound.cpp:173 +msgid "OSS Sound Device Options" +msgstr "Параметры звука для драйвера OSS" + +#: oss-sound.cpp:507 +msgid "OSS device %1: No data to record" +msgstr "Устройство OSS %1: для записи нет данных" + +#: oss-sound.cpp:517 +msgid "internal stream, not stored (%1)" +msgstr "" + +#: oss-sound.cpp:549 +msgid "Error %1 while handling OSS device %2" +msgstr "Ошибка %1 при работе с устройством OSS %2." + +#: oss-sound.cpp:593 oss-sound.cpp:619 +msgid "Cannot open DSP device %1" +msgstr "Не могу открыть устройство звуковой платы %1" + +#: oss-sound.cpp:599 +msgid "Cannot read DSP capabilities for %1" +msgstr "Не могу узнать возможности звуковой платы %1" + +#: oss-sound.cpp:626 +msgid "Cannot set DSP sample format for %1" +msgstr "Не могу установить формат данных для звуковой платы %1" + +#: oss-sound.cpp:631 +msgid "Cannot set number of channels for %1" +msgstr "Не могу установить число каналов для звуковой платы %1" + +#: oss-sound.cpp:636 +msgid "Cannot set sampling rate for %1" +msgstr "Не могу установить частоту дискретизации для звуковой платы %1" + +#: oss-sound.cpp:638 +msgid "Asking for %1 Hz but %2 uses %3 Hz" +msgstr "Был дан запрос на %1 Гц, однако %2 использует %3 Гц." + +#: oss-sound.cpp:648 +msgid "Cannot set stereo mode for %1" +msgstr "Не могу установить стерео режим для звуковой платы %1" + +#: oss-sound.cpp:653 +msgid "Cannot set sample size for %1" +msgstr "Не могу установить размер элемента выборки для звуковой платы %1" + +#: oss-sound.cpp:662 +msgid "Cannot set buffers for %1" +msgstr "Не могу установить буферы для звуковой платы %1" + +#: oss-sound.cpp:667 +msgid "Cannot read buffer size for %1" +msgstr "Не могу узнать размер буфера звуковой платы %1" + +#: oss-sound.cpp:669 +msgid "%1 uses buffer blocks of %2 bytes" +msgstr "%1 использует блоки буфера по %2 байт" + +#: oss-sound.cpp:672 +msgid "adjusted own buffer size to %1 bytes" +msgstr "Размер собственного буфера установлен %1 байт." + +#: oss-sound.cpp:724 +msgid "Cannot open mixer device %1" +msgstr "Не могу открыть устройство микшера %1" + +#: oss-sound.cpp:757 +msgid "OSSSoundDevice::getMixerChannels: Cannot open mixer device %1" +msgstr "" +"OSSSoundDevice::getMixerChannels: Не могу открыть устройство микшера %1" + +#: oss-sound.cpp:771 +msgid "" +"OSSSoundDevice::getMixerChannels: Cannot read mixer device mask on device %1" +msgstr "" +"OSSSoundDevice::getMixerChannels: не могу прочесть маску устройства микшера " +"для устройства %1" + +#: oss-sound.cpp:876 +msgid "error %1 while reading volume from %2" +msgstr "Ошибка %1 при считывании громкости с %2." + +#: oss-sound.cpp:899 +msgid "error %1 while setting volume to %2 on device %3" +msgstr "Ошибка %1 при установке громкости %2 на устройстве %3." + +#: oss-sound.cpp:915 +msgid "Selecting recording source on device %1 failed with error code %2" +msgstr "Выбор источника записи на устройстве %1 не удался (код ошибки %2)" + +#: oss-sound.cpp:921 +msgid "Reading igain volume on device %1 failed with error code %2" +msgstr "Считывание громкости записи с устройства %1 не удалось (код ошибки %2)" + +#: oss-sound.cpp:928 +msgid "Setting igain volume on device %1 failed with error code %2" +msgstr "Установка громкости записи на устройстве %1 не удалась (код ошибки %2)" + +#: oss-sound.cpp:986 +msgid "OSS Sound Device %1" +msgstr "Устройство OSS: %1" diff --git a/kradio3/plugins/radio/Makefile.am b/kradio3/plugins/radio/Makefile.am new file mode 100644 index 0000000..2481b58 --- /dev/null +++ b/kradio3/plugins/radio/Makefile.am @@ -0,0 +1,18 @@ +SUBDIRS = po . + +INCLUDES = -I$(top_builddir)/kradio3/src -I$(top_srcdir)/kradio3 $(all_includes) +METASOURCES = AUTO + +libkradio_LTLIBRARIES = libradio.la +libradio_la_SOURCES = radio-configuration.cpp radio-configuration-ui.ui \ + radio.cpp +libradio_la_LDFLAGS = -module -avoid-version $(KDE_RPATH) $(all_libraries) + +noinst_HEADERS = radio-configuration.h radio.h + +#messages: rc.cpp +# $(XGETTEXT) *.cpp *.h -o po/kradio-radio.pot + +messages: rc.cpp + $(EXTRACTRC) *.rc *.ui >> rc.cpp + $(XGETTEXT) rc.cpp *.h *.cpp -o po/kradio-radio.pot diff --git a/kradio3/plugins/radio/po/Makefile.am b/kradio3/plugins/radio/po/Makefile.am new file mode 100644 index 0000000..9fedd9c --- /dev/null +++ b/kradio3/plugins/radio/po/Makefile.am @@ -0,0 +1,2 @@ +PACKAGE = kradio-radio +POFILES = AUTO diff --git a/kradio3/plugins/radio/po/de.po b/kradio3/plugins/radio/po/de.po new file mode 100644 index 0000000..5f7553d --- /dev/null +++ b/kradio3/plugins/radio/po/de.po @@ -0,0 +1,185 @@ +# translation of de.po to +# translation of kradio-radio.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: 2006-11-11 18:43+0100\n" +"PO-Revision-Date: 2006-11-06 01:18+0100\n" +"Last-Translator: Ernst Martin Witte <emw@nocabal.de>\n" +"Language-Team: <de@li.org>\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: KBabel 1.11.4\n" + +#. i18n: file radio-configuration-ui.ui line 28 +#: rc.cpp:3 rc.cpp:68 radio-configuration-ui.cpp:325 +#, no-c-format +msgid "Station &Presets" +msgstr "&Voreingestellte Sender" + +#. i18n: file radio-configuration-ui.ui line 53 +#: rc.cpp:6 rc.cpp:71 radio-configuration-ui.cpp:310 +#, no-c-format +msgid "Stations" +msgstr "Sender" + +#. i18n: file radio-configuration-ui.ui line 179 +#: rc.cpp:13 rc.cpp:78 radio-configuration-ui.cpp:315 +#, no-c-format +msgid "&Search Stations" +msgstr "&Sendersuche" + +#. i18n: file radio-configuration-ui.ui line 198 +#: rc.cpp:16 rc.cpp:81 radio-configuration-ui.cpp:316 +#, no-c-format +msgid "Load" +msgstr "Öffnen" + +#. i18n: file radio-configuration-ui.ui line 263 +#: rc.cpp:22 rc.cpp:87 radio-configuration-ui.cpp:318 +#, no-c-format +msgid "Name" +msgstr "Name" + +#. i18n: file radio-configuration-ui.ui line 294 +#: rc.cpp:25 rc.cpp:90 radio-configuration-ui.cpp:319 +#, no-c-format +msgid "Short Name" +msgstr "Kurzname" + +#. i18n: file radio-configuration-ui.ui line 325 +#: rc.cpp:28 rc.cpp:93 radio-configuration-ui.cpp:320 +#, no-c-format +msgid "Pixmap File" +msgstr "Bilddatei" + +#. i18n: file radio-configuration-ui.ui line 457 +#: rc.cpp:32 rc.cpp:97 radio-configuration-ui.cpp:322 +#, no-c-format +msgid " %" +msgstr " %" + +#. i18n: file radio-configuration-ui.ui line 471 +#: rc.cpp:35 rc.cpp:100 radio-configuration-ui.cpp:323 +#, no-c-format +msgid "Volume Preset" +msgstr "Lautstärke" + +#. i18n: file radio-configuration-ui.ui line 508 +#: rc.cpp:38 rc.cpp:103 radio-configuration-ui.cpp:324 +#, no-c-format +msgid "Personal Preset File" +msgstr "Persönliche Senderdatei" + +#. i18n: file radio-configuration-ui.ui line 564 +#: rc.cpp:44 rc.cpp:109 radio-configuration-ui.cpp:326 +#, no-c-format +msgid "City" +msgstr "Stadt" + +#. i18n: file radio-configuration-ui.ui line 577 +#: rc.cpp:47 rc.cpp:112 radio-configuration-ui.cpp:327 +#, no-c-format +msgid "Country" +msgstr "Land" + +#. i18n: file radio-configuration-ui.ui line 617 +#: rc.cpp:50 rc.cpp:115 radio-configuration-ui.cpp:328 +#, no-c-format +msgid "&Now" +msgstr "&Jetzt" + +#. i18n: file radio-configuration-ui.ui line 627 +#: rc.cpp:53 rc.cpp:118 radio-configuration-ui.cpp:329 +#, no-c-format +msgid "Comment" +msgstr "Kommentar" + +#. i18n: file radio-configuration-ui.ui line 640 +#: rc.cpp:56 rc.cpp:121 radio-configuration-ui.cpp:330 +#, no-c-format +msgid "Media" +msgstr "Medium" + +#. i18n: file radio-configuration-ui.ui line 648 +#: rc.cpp:59 rc.cpp:124 radio-configuration-ui.cpp:331 +#, no-c-format +msgid "Maintainer" +msgstr "Maintainer" + +#. i18n: file radio-configuration-ui.ui line 661 +#: rc.cpp:62 rc.cpp:127 radio-configuration-ui.cpp:332 +#, no-c-format +msgid "Last Change" +msgstr "Letzte Änderung" + +#. i18n: file radio-configuration-ui.ui line 698 +#: rc.cpp:65 rc.cpp:130 radio-configuration-ui.cpp:333 +#, no-c-format +msgid "" +"<p align=\"center\">Click on the link below to contribute this station " +"preset file to the kradio project.</p>" +msgstr "" +"<p align=\"center\">Klicke auf den folgenden Link um mit deinen " +"Senderinformationen zum KRadio-Projekt beizutragen.</p>" + +#: _translatorinfo.cpp:1 +msgid "" +"_: NAME OF TRANSLATORS\n" +"Your names" +msgstr "Ernst Martin Witte" + +#: _translatorinfo.cpp:3 +msgid "" +"_: EMAIL OF TRANSLATORS\n" +"Your emails" +msgstr "witte@kawo1.rwth-aachen.de" + +#: radio-configuration.cpp:350 +msgid "Image Selection" +msgstr "Symbolauswahl" + +#: radio-configuration.cpp:355 +msgid "ignoring non-local image" +msgstr "Ignoriere nicht-lokale Symbole" + +#: radio-configuration.cpp:450 radio-configuration.cpp:470 +msgid "KRadio Preset Files" +msgstr "Senderdateien für KRadio" + +#: radio-configuration.cpp:452 radio-configuration.cpp:472 +msgid "Preset File Selection" +msgstr "Auswahl der Senderdatei" + +#: radio-configuration.cpp:455 +msgid "Select Preset File" +msgstr "Wählen Sie eine Senderdatei aus" + +#: radio-configuration.cpp:475 +msgid "Store Preset File" +msgstr "Speichern der Senderdatei" + +#: radio.cpp:34 +msgid "Central Radio Device Multiplexer" +msgstr "Zentraler Radio-Multiplexer" + +#: radio.cpp:39 +msgid "Radio Multiplexer Plugin" +msgstr "Plugin für den Radio-Gerätemultiplexer" + +#: radio.cpp:116 +msgid "Radio Stations" +msgstr "Radiosender" + +#: radio.cpp:117 +msgid "Setup Radio Stations" +msgstr "Einstellung der Radiosender" + +#: radio.cpp:351 +msgid "unknown" +msgstr "unbekannt" diff --git a/kradio3/plugins/radio/po/ru.po b/kradio3/plugins/radio/po/ru.po new file mode 100644 index 0000000..3a403db --- /dev/null +++ b/kradio3/plugins/radio/po/ru.po @@ -0,0 +1,185 @@ +# translation of ru.po to +# translation of kradio-radio.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: 2006-11-11 18:43+0100\n" +"PO-Revision-Date: 2006-11-08 13:00+0300\n" +"Last-Translator: Алексей Кузнецов <Alexey.Kouznetsov@GMail.com>\n" +"Language-Team: <ru@li.org>\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" + +#. i18n: file radio-configuration-ui.ui line 28 +#: rc.cpp:3 rc.cpp:68 radio-configuration-ui.cpp:325 +#, no-c-format +msgid "Station &Presets" +msgstr "Параметры &радиостанций" + +#. i18n: file radio-configuration-ui.ui line 53 +#: rc.cpp:6 rc.cpp:71 radio-configuration-ui.cpp:310 +#, no-c-format +msgid "Stations" +msgstr "Список" + +#. i18n: file radio-configuration-ui.ui line 179 +#: rc.cpp:13 rc.cpp:78 radio-configuration-ui.cpp:315 +#, no-c-format +msgid "&Search Stations" +msgstr "&Поиск" + +#. i18n: file radio-configuration-ui.ui line 198 +#: rc.cpp:16 rc.cpp:81 radio-configuration-ui.cpp:316 +#, no-c-format +msgid "Load" +msgstr "Из файла" + +#. i18n: file radio-configuration-ui.ui line 263 +#: rc.cpp:22 rc.cpp:87 radio-configuration-ui.cpp:318 +#, no-c-format +msgid "Name" +msgstr "Название" + +#. i18n: file radio-configuration-ui.ui line 294 +#: rc.cpp:25 rc.cpp:90 radio-configuration-ui.cpp:319 +#, no-c-format +msgid "Short Name" +msgstr "Сокращённое название" + +#. i18n: file radio-configuration-ui.ui line 325 +#: rc.cpp:28 rc.cpp:93 radio-configuration-ui.cpp:320 +#, no-c-format +msgid "Pixmap File" +msgstr "Пиктограмма" + +#. i18n: file radio-configuration-ui.ui line 457 +#: rc.cpp:32 rc.cpp:97 radio-configuration-ui.cpp:322 +#, no-c-format +msgid " %" +msgstr " %" + +#. i18n: file radio-configuration-ui.ui line 471 +#: rc.cpp:35 rc.cpp:100 radio-configuration-ui.cpp:323 +#, no-c-format +msgid "Volume Preset" +msgstr "Установить громкость (-1=не менять)" + +#. i18n: file radio-configuration-ui.ui line 508 +#: rc.cpp:38 rc.cpp:103 radio-configuration-ui.cpp:324 +#, no-c-format +msgid "Personal Preset File" +msgstr "Пользовательский файл настроек" + +#. i18n: file radio-configuration-ui.ui line 564 +#: rc.cpp:44 rc.cpp:109 radio-configuration-ui.cpp:326 +#, no-c-format +msgid "City" +msgstr "Город" + +#. i18n: file radio-configuration-ui.ui line 577 +#: rc.cpp:47 rc.cpp:112 radio-configuration-ui.cpp:327 +#, no-c-format +msgid "Country" +msgstr "Страна" + +#. i18n: file radio-configuration-ui.ui line 617 +#: rc.cpp:50 rc.cpp:115 radio-configuration-ui.cpp:328 +#, no-c-format +msgid "&Now" +msgstr "&Текущее время" + +#. i18n: file radio-configuration-ui.ui line 627 +#: rc.cpp:53 rc.cpp:118 radio-configuration-ui.cpp:329 +#, no-c-format +msgid "Comment" +msgstr "Описание" + +#. i18n: file radio-configuration-ui.ui line 640 +#: rc.cpp:56 rc.cpp:121 radio-configuration-ui.cpp:330 +#, no-c-format +msgid "Media" +msgstr "Носитель" + +#. i18n: file radio-configuration-ui.ui line 648 +#: rc.cpp:59 rc.cpp:124 radio-configuration-ui.cpp:331 +#, no-c-format +msgid "Maintainer" +msgstr "Автор" + +#. i18n: file radio-configuration-ui.ui line 661 +#: rc.cpp:62 rc.cpp:127 radio-configuration-ui.cpp:332 +#, fuzzy, no-c-format +msgid "Last Change" +msgstr "Последнее изменение" + +#. i18n: file radio-configuration-ui.ui line 698 +#: rc.cpp:65 rc.cpp:130 radio-configuration-ui.cpp:333 +#, no-c-format +msgid "" +"<p align=\"center\">Click on the link below to contribute this station " +"preset file to the kradio project.</p>" +msgstr "" +"<p align=\"center\"> Чтобы добавить этот файл в проект KRadio, щёлкните по " +"ссылке ниже</p>" + +#: _translatorinfo.cpp:1 +msgid "" +"_: NAME OF TRANSLATORS\n" +"Your names" +msgstr "Алексей Кузнецов" + +#: _translatorinfo.cpp:3 +msgid "" +"_: EMAIL OF TRANSLATORS\n" +"Your emails" +msgstr "Alexey.Kouznetsov@GMail.com" + +#: radio-configuration.cpp:350 +msgid "Image Selection" +msgstr "Выбор картинки" + +#: radio-configuration.cpp:355 +msgid "ignoring non-local image" +msgstr "Пропускать не локальные файлы" + +#: radio-configuration.cpp:450 radio-configuration.cpp:470 +msgid "KRadio Preset Files" +msgstr "Файлы KRadio" + +#: radio-configuration.cpp:452 radio-configuration.cpp:472 +msgid "Preset File Selection" +msgstr "Выбор файла радиостанций" + +#: radio-configuration.cpp:455 +msgid "Select Preset File" +msgstr "Выбор файла радиостанций" + +#: radio-configuration.cpp:475 +msgid "Store Preset File" +msgstr "Сохранить файл радиостанций" + +#: radio.cpp:34 +msgid "Central Radio Device Multiplexer" +msgstr "Главный мультиплексор устройства радио" + +#: radio.cpp:39 +msgid "Radio Multiplexer Plugin" +msgstr "Модуль мультиплексирования для KRadio" + +#: radio.cpp:116 +msgid "Radio Stations" +msgstr "Радиостанции" + +#: radio.cpp:117 +msgid "Setup Radio Stations" +msgstr "Настройка радиостанции" + +#: radio.cpp:351 +msgid "unknown" +msgstr "низвестно" diff --git a/kradio3/plugins/radio/radio-configuration-ui.ui b/kradio3/plugins/radio/radio-configuration-ui.ui new file mode 100644 index 0000000..eee95e9 --- /dev/null +++ b/kradio3/plugins/radio/radio-configuration-ui.ui @@ -0,0 +1,774 @@ +<!DOCTYPE UI><UI version="3.0" stdsetdef="1"> +<class>RadioConfigurationUI</class> +<widget class="QWidget"> + <property name="name"> + <cstring>RadioConfigurationUI</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>490</width> + <height>348</height> + </rect> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QTabWidget" row="0" column="0"> + <property name="name"> + <cstring>tabWidget3</cstring> + </property> + <widget class="QWidget"> + <property name="name"> + <cstring>stations</cstring> + </property> + <attribute name="title"> + <string>Station &Presets</string> + </attribute> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>11</number> + </property> + <widget class="QLayoutWidget" row="0" column="0"> + <property name="name"> + <cstring>layout32</cstring> + </property> + <property name="margin" stdset="0"> + <number>6</number> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>labelStationList</cstring> + </property> + <property name="text"> + <string>Stations</string> + </property> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout22</cstring> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout9</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="RadioStationListView"> + <property name="name"> + <cstring>listStations</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>7</hsizetype> + <vsizetype>5</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout5</cstring> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QPushButton"> + <property name="name"> + <cstring>buttonNewStation</cstring> + </property> + <property name="text"> + <string></string> + </property> + <property name="iconSet"> + <iconset>"filenew2"</iconset> + </property> + </widget> + <widget class="QPushButton"> + <property name="name"> + <cstring>buttonDeleteStation</cstring> + </property> + <property name="text"> + <string></string> + </property> + <property name="iconSet"> + <iconset>"editdelete"</iconset> + </property> + </widget> + <spacer> + <property name="name"> + <cstring>spacer4</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>10</height> + </size> + </property> + </spacer> + <widget class="QPushButton"> + <property name="name"> + <cstring>buttonStationUp</cstring> + </property> + <property name="text"> + <string></string> + </property> + <property name="iconSet"> + <iconset>"1uparrow"</iconset> + </property> + </widget> + <widget class="QPushButton"> + <property name="name"> + <cstring>buttonStationDown</cstring> + </property> + <property name="text"> + <string></string> + </property> + <property name="iconSet"> + <iconset>"1downarrow"</iconset> + </property> + </widget> + </vbox> + </widget> + </hbox> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout21</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QPushButton"> + <property name="name"> + <cstring>buttonSearchStations</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>1</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>1</horstretch> + <verstretch>1</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>&Search Stations</string> + </property> + <property name="iconSet"> + <iconset>"find"</iconset> + </property> + </widget> + <widget class="QPushButton"> + <property name="name"> + <cstring>buttonLoadPresets</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>1</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>1</horstretch> + <verstretch>1</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>Load</string> + </property> + <property name="iconSet"> + <iconset>"fileopen"</iconset> + </property> + </widget> + <widget class="QPushButton"> + <property name="name"> + <cstring>buttonStorePresets</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>1</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>1</horstretch> + <verstretch>1</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>Save As</string> + </property> + <property name="iconSet"> + <iconset>"filesaveas"</iconset> + </property> + </widget> + </hbox> + </widget> + </vbox> + </widget> + </vbox> + </widget> + <widget class="QLayoutWidget" row="0" column="1"> + <property name="name"> + <cstring>layout18</cstring> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QWidgetStack"> + <property name="name"> + <cstring>stackStationEdit</cstring> + </property> + <widget class="QWidget"> + <property name="name"> + <cstring>page</cstring> + </property> + <attribute name="id"> + <number>0</number> + </attribute> + </widget> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout7</cstring> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>labelStationName</cstring> + </property> + <property name="text"> + <string>Name</string> + </property> + </widget> + <widget class="QLineEdit"> + <property name="name"> + <cstring>editStationName</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>5</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + </widget> + </vbox> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout32</cstring> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>labelStationShortName</cstring> + </property> + <property name="text"> + <string>Short Name</string> + </property> + </widget> + <widget class="QLineEdit"> + <property name="name"> + <cstring>editStationShortName</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>5</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + </widget> + </vbox> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout6</cstring> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>labelPixmapFile</cstring> + </property> + <property name="text"> + <string>Pixmap File</string> + </property> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout5</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLineEdit"> + <property name="name"> + <cstring>editPixmapFile</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>5</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + </widget> + <widget class="QPushButton"> + <property name="name"> + <cstring>buttonSelectPixmapFile</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>0</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>0</width> + <height>0</height> + </size> + </property> + <property name="text"> + <string></string> + </property> + <property name="iconSet"> + <iconset>"fileopen"</iconset> + </property> + </widget> + </hbox> + </widget> + </vbox> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout19</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>pixmapStation</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>5</hsizetype> + <vsizetype>5</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>20</width> + <height>20</height> + </size> + </property> + <property name="scaledContents"> + <bool>true</bool> + </property> + </widget> + <spacer> + <property name="name"> + <cstring>spacer7</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>10</width> + <height>5</height> + </size> + </property> + </spacer> + </hbox> + </widget> + <spacer> + <property name="name"> + <cstring>spacer4_2</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>10</height> + </size> + </property> + </spacer> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout20</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QSpinBox"> + <property name="name"> + <cstring>editVolumePreset</cstring> + </property> + <property name="suffix"> + <string> %</string> + </property> + <property name="maxValue"> + <number>100</number> + </property> + <property name="minValue"> + <number>-1</number> + </property> + </widget> + <widget class="QLabel"> + <property name="name"> + <cstring>labelVolumePreset</cstring> + </property> + <property name="text"> + <string>Volume Preset</string> + </property> + </widget> + <spacer> + <property name="name"> + <cstring>spacer12</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>21</width> + <height>20</height> + </size> + </property> + </spacer> + </hbox> + </widget> + </vbox> + </widget> + <widget class="QLayoutWidget" row="1" column="0" rowspan="1" colspan="2"> + <property name="name"> + <cstring>layout25</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>editLabelPresetFile</cstring> + </property> + <property name="text"> + <string>Personal Preset File</string> + </property> + </widget> + <widget class="KURLRequester"> + <property name="name"> + <cstring>editPresetFile</cstring> + </property> + </widget> + </hbox> + </widget> + </grid> + </widget> + <widget class="QWidget"> + <property name="name"> + <cstring>About</cstring> + </property> + <attribute name="title"> + <string>A&bout</string> + </attribute> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>11</number> + </property> + <spacer row="5" column="1"> + <property name="name"> + <cstring>spacer6</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>21</width> + <height>20</height> + </size> + </property> + </spacer> + <widget class="QLayoutWidget" row="0" column="0" rowspan="1" colspan="3"> + <property name="name"> + <cstring>layout21</cstring> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel" row="3" column="0"> + <property name="name"> + <cstring>labelCity</cstring> + </property> + <property name="text"> + <string>City</string> + </property> + </widget> + <widget class="QLineEdit" row="2" column="1"> + <property name="name"> + <cstring>editCountry</cstring> + </property> + </widget> + <widget class="QLabel" row="2" column="0"> + <property name="name"> + <cstring>labelCountry</cstring> + </property> + <property name="text"> + <string>Country</string> + </property> + </widget> + <widget class="QLayoutWidget" row="1" column="1"> + <property name="name"> + <cstring>layout19</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QDateTimeEdit"> + <property name="name"> + <cstring>editLastChange</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>7</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="focusPolicy"> + <enum>StrongFocus</enum> + </property> + </widget> + <widget class="QPushButton"> + <property name="name"> + <cstring>buttonLastChangeNow</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>5</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>&Now</string> + </property> + </widget> + </hbox> + </widget> + <widget class="QLabel" row="5" column="0"> + <property name="name"> + <cstring>labelComment</cstring> + </property> + <property name="text"> + <string>Comment</string> + </property> + </widget> + <widget class="QLineEdit" row="5" column="1"> + <property name="name"> + <cstring>editComment</cstring> + </property> + </widget> + <widget class="QLabel" row="4" column="0"> + <property name="name"> + <cstring>labelMedia</cstring> + </property> + <property name="text"> + <string>Media</string> + </property> + </widget> + <widget class="QLabel" row="0" column="0"> + <property name="name"> + <cstring>labelMaintainer</cstring> + </property> + <property name="text"> + <string>Maintainer</string> + </property> + </widget> + <widget class="QLineEdit" row="3" column="1"> + <property name="name"> + <cstring>editCity</cstring> + </property> + </widget> + <widget class="QLabel" row="1" column="0"> + <property name="name"> + <cstring>labelLastChange</cstring> + </property> + <property name="text"> + <string>Last Change</string> + </property> + </widget> + <widget class="QLineEdit" row="0" column="1"> + <property name="name"> + <cstring>editMaintainer</cstring> + </property> + </widget> + <widget class="QLineEdit" row="4" column="1"> + <property name="name"> + <cstring>editMedia</cstring> + </property> + </widget> + </grid> + </widget> + <spacer row="1" column="1"> + <property name="name"> + <cstring>spacer7_2</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>20</height> + </size> + </property> + </spacer> + <widget class="QLabel" row="2" column="0" rowspan="1" colspan="3"> + <property name="name"> + <cstring>textLabel1</cstring> + </property> + <property name="text"> + <string><p align="center">Click on the link below to contribute this station preset file to the kradio project.</p></string> + </property> + <property name="alignment"> + <set>WordBreak|AlignCenter</set> + </property> + </widget> + <widget class="KURLLabel" row="4" column="1"> + <property name="name"> + <cstring>mailLabel</cstring> + </property> + <property name="alignment"> + <set>AlignCenter</set> + </property> + </widget> + </grid> + </widget> + </widget> + </grid> +</widget> +<customwidgets> + <customwidget> + <class>RadioStationListView</class> + <header location="local">src/include/radiostation-listview.h</header> + <sizehint> + <width>-1</width> + <height>-1</height> + </sizehint> + <container>0</container> + <sizepolicy> + <hordata>5</hordata> + <verdata>5</verdata> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + <pixmap>image0</pixmap> + </customwidget> +</customwidgets> +<images> + <image name="image0"> + <data format="XPM.GZ" length="2782">789c8dd4df53e2481007f077ff0aca7eb3ae7a4948425257f78080a2828baebbea5eddc32493c80f110414f1eafef7eb7437dcdd9cd95a478afad47ca733193af97454bb1b0e6a479f0e566bb31e67b56c6496b523fb329b6d7fffe3b73f0f0e7dbf46ff5e3dacf987bf1c1c5ead6b59ed72fe9497800b02d4f9af34cefe6be83b1e3879ebb8e5b8edb8703c743c760c8e73c7a9e389e347c799733fe7cefc83e39163e378eaf8461d68fd253b26c73c1faa637550daab9783f3bc7fbf5e0e9eafab03f57776e2677ec2fe52ba9134e2061b36e2a0ae7e2e1d78413df038ff591d8881cf3730411c18f6bc74e88761c8cd02a84ec4f8956dc8923f565b319e958efcd046b2fe451c8562ecb14d642359cfe7dd6c34bd6683e7afd5a11846ea44bd65a7944fd96fea44fd543a6ec45e2cf5eed9691cc63c8f57ea44eda9ad3a12279e9afb2309923009b87e5b9da8b9ff928c9c713e515b31f07998a0e9697f6cd4a17aab4ed49762131aae8f7c7e26dbe7dfd4bbfcf1dedc4fb0101b63e4faafe2d4579f944effb9debbdaaa9b6293a7727f569cfaea5c6dd4fc7ba6968e437eff85da6abf5c88d328b5ecbedaa84fd5b99a9f972c349ef6d35aadfd03469ce659c87e17679118b9df33bb5f3f57effaef556da4ff70a5ceb51f3b3b6b3f36c4545ff637501b31acd5b9cec762ebeb3cdf1f3d1cbbfadd9db59f3371965bb99f99d8faea953a1223f7b7cdb348fb8bdf3f7964f33c6217e272709e7fef9c667379dfb7d4468cdfd4b9da2f5d44b929647d479d8b612c2e7c35bf5f8b825c70beab8ed4776aa3be5517e2abb53b10d0608a195a77e6a33ca7732cf0014738fe288f139cfec478c499e6a7f884735ce0332e3ffcac708d2f94b2fbfc2b6ef0adf2b3c577fa9e626b9f5ff0faea71ccf3ed7d7eceeb3bd8c5133cc51e9ee1395e601f0778899ff7f3c37d7ec9ebaff01abfe00d7ec56f784be38ed6dee3f7fdfcd0a92fe306ebe8a18f0daa1c90c3cafa534a46b49326c6543ba1da97800095f57b60781f3c20a5dddc4206b6b27e0f72bae33b4a15d8850718c118c674bd8afa30c17b9852e61166d8812798c302afe1b9aa3e2ce90a2baadd410f524a4fe87b0d2fd5e70300af74e62730a3dd4c60036fd88055e5fe6f30802dbcd39e0a68d1d91cd38a0db4ff5f1f3ad4233fe807e83af5d770423d52d19f700a3d67ffd5bda91f38fb57bf3dfeccf302e7fb7e9ea1c516b671f883d1a6843e2f708133e8c38056550e18409f9ec7bf7e3df81bd372939b</data> + </image> +</images> +<tabstops> + <tabstop>tabWidget3</tabstop> + <tabstop>listStations</tabstop> + <tabstop>buttonNewStation</tabstop> + <tabstop>buttonDeleteStation</tabstop> + <tabstop>buttonStationUp</tabstop> + <tabstop>buttonStationDown</tabstop> + <tabstop>buttonSearchStations</tabstop> + <tabstop>buttonLoadPresets</tabstop> + <tabstop>editStationName</tabstop> + <tabstop>editStationShortName</tabstop> + <tabstop>editPixmapFile</tabstop> + <tabstop>buttonSelectPixmapFile</tabstop> + <tabstop>editVolumePreset</tabstop> + <tabstop>editMaintainer</tabstop> + <tabstop>editLastChange</tabstop> + <tabstop>editCountry</tabstop> + <tabstop>editCity</tabstop> + <tabstop>editMedia</tabstop> + <tabstop>editComment</tabstop> +</tabstops> +<includes> + <include location="global" impldecl="in implementation">kiconloader.h</include> + <include location="global" impldecl="in implementation">qwidgetstack.h</include> + <include location="global" impldecl="in implementation">src/include/radiostation-listview.h</include> +</includes> +<pixmapfunction>SmallIconSet</pixmapfunction> +<layoutdefaults spacing="6" margin="0"/> +<includehints> + <includehint>src/include/radiostation-listview.h</includehint> + <includehint>kurlrequester.h</includehint> + <includehint>klineedit.h</includehint> + <includehint>kpushbutton.h</includehint> +</includehints> +</UI> diff --git a/kradio3/plugins/radio/radio-configuration.cpp b/kradio3/plugins/radio/radio-configuration.cpp new file mode 100644 index 0000000..321d17c --- /dev/null +++ b/kradio3/plugins/radio/radio-configuration.cpp @@ -0,0 +1,592 @@ +/*************************************************************************** + radio-configuration.cpp - description + ------------------- + begin : Son Aug 3 2003 + copyright : (C) 2003 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 "../../src/include/radiostation.h" +#include "../../src/include/stationlist.h" +#include "../../src/include/plugins.h" +#include "../../src/include/radiodevice_interfaces.h" +#include "../../src/include/standardscandialog.h" +#include "../../src/include/radiostation-listview.h" +#include "../../src/include/radiostation-config.h" +#include "../../src/include/errorlog-interfaces.h" + +#include "radio-configuration.h" + +#include <math.h> + +#include <qlistbox.h> +#include <klistbox.h> +#include <qdatetimeedit.h> +#include <qlineedit.h> +#include <qlabel.h> +#include <qspinbox.h> +#include <qpushbutton.h> +#include <qpopupmenu.h> +#include <qtoolbutton.h> +#include <qwidgetstack.h> +#include <qimage.h> + +#include <kfiledialog.h> +#include <kstandarddirs.h> +#include <kurllabel.h> +#include <qregexp.h> +#include <krun.h> +#include <kurlrequester.h> +#include <klocale.h> + +RadioConfiguration::RadioConfiguration (QWidget *parent, const IErrorLogClient &logger) + : RadioConfigurationUI(parent), + ignoreChanges(false), + devicePopup(NULL), + m_logger(logger), + m_dirty(true) +{ + QObject::connect(listStations, SIGNAL(sigCurrentStationChanged(int)), + this, SLOT(slotStationSelectionChanged(int))); + QObject::connect(buttonSelectPixmapFile, SIGNAL(clicked()), + this, SLOT(slotSelectPixmap())); + QObject::connect(buttonNewStation, SIGNAL(clicked()), + this, SLOT(slotNewStation())); + QObject::connect(buttonDeleteStation, SIGNAL(clicked()), + this, SLOT(slotDeleteStation())); + QObject::connect(editPixmapFile, SIGNAL(textChanged(const QString &)), + this, SLOT(slotPixmapChanged(const QString &))); + QObject::connect(editStationName, SIGNAL(textChanged(const QString &)), + this, SLOT(slotStationNameChanged(const QString &))); + QObject::connect(editStationShortName, SIGNAL(textChanged(const QString &)), + this, SLOT(slotStationShortNameChanged(const QString &))); + QObject::connect(editVolumePreset, SIGNAL(valueChanged(int)), + this, SLOT(slotVolumePresetChanged(int))); + QObject::connect(buttonStationUp, SIGNAL(clicked()), + this, SLOT(slotStationUp())); + QObject::connect(buttonStationDown, SIGNAL(clicked()), + this, SLOT(slotStationDown())); + QObject::connect(listStations, SIGNAL(sigStationActivated(int)), + this, SLOT(slotActivateStation( int ))); + QObject::connect(buttonLoadPresets, SIGNAL(clicked()), + this, SLOT(slotLoadPresets())); + QObject::connect(buttonStorePresets, SIGNAL(clicked()), + this, SLOT(slotStorePresets())); + QObject::connect(buttonLastChangeNow, SIGNAL(clicked()), + this, SLOT(slotLastChangeNow())); + + connect(editMaintainer, SIGNAL(textChanged(const QString &)), SLOT(slotSetDirty())); + connect(editLastChange, SIGNAL(valueChanged(const QDateTime &)), SLOT(slotSetDirty())); + connect(editCountry, SIGNAL(textChanged(const QString &)), SLOT(slotSetDirty())); + connect(editCity, SIGNAL(textChanged(const QString &)), SLOT(slotSetDirty())); + connect(editMedia, SIGNAL(textChanged(const QString &)), SLOT(slotSetDirty())); + connect(editComment, SIGNAL(textChanged(const QString &)), SLOT(slotSetDirty())); + connect(editPresetFile, SIGNAL(textChanged(const QString &)), SLOT(slotSetDirty())); + + mailLabel->setText("mailto:witte-presets@kawo1.rwth-aachen.de"); + mailLabel->setURL ("mailto:witte-presets@kawo1.rwth-aachen.de"); + QObject::connect(mailLabel, SIGNAL(leftClickedURL(const QString &)), + this, SLOT(slotSendPresetsByMail(const QString &))); + + QObject::connect(buttonSearchStations, SIGNAL(clicked()), + this, SLOT(slotSearchStations0())); + + devicePopup = new QPopupMenu(buttonSearchStations); + buttonSearchStations->setPopup(devicePopup); + QObject::connect(devicePopup, SIGNAL(activated(int)), + this, SLOT(slotSearchStations(int))); +} + + +RadioConfiguration::~RadioConfiguration () +{ +} + + +bool RadioConfiguration::connectI (Interface *i) +{ + bool a = IRadioClient::connectI(i); + bool b = IRadioDevicePoolClient::connectI(i); + + return a || b; +} + +bool RadioConfiguration::disconnectI (Interface *i) +{ + bool a = IRadioClient::disconnectI(i); + bool b = IRadioDevicePoolClient::disconnectI(i); + + return a || b; +} + +// IRadioDevicePoolClient + +bool RadioConfiguration::noticeDevicesChanged(const QPtrList<IRadioDevice> &l) +{ + QPtrListIterator<IRadioDevice> it(l); + devices.clear(); + devicePopup->clear(); + int id = 0; + for (; it.current(); ++it) { + IRadioDevice *d = it.current(); + if (dynamic_cast<ISeekRadio*>(d)) { + devicePopup->insertItem(d->getDescription(), id++); + devices.append(d); + } + } + return true; +} + + +bool RadioConfiguration::noticeDeviceDescriptionChanged(const QString &) +{ + noticeDevicesChanged(queryDevices()); + return true; +} + + +// IRadioClient + +bool RadioConfiguration::noticeStationsChanged(const StationList &sl) +{ + ignoreChanges = true; + + m_stations = sl; + + listStations->setStations(sl); + + StationListMetaData &info = m_stations.metaData(); + + editMaintainer->setText(info.maintainer); + editLastChange->setDateTime(info.lastChange); + editCountry->setText(info.country); + editCity->setText(info.city); + editMedia->setText(info.media); + editComment->setText(info.comment); + + ignoreChanges = false; + + slotStationSelectionChanged(listStations->currentStationIndex()); + + return true; +} + + +bool RadioConfiguration::noticePresetFileChanged(const QString &f) +{ + ignoreChanges = true; + editPresetFile->setURL(f); + ignoreChanges = false; + return true; +} + + +void RadioConfiguration::slotStationSelectionChanged(int idx) +{ + RadioStation *s = NULL; + + if (idx >= 0 && idx < m_stations.count()) { + s = &m_stations.at(idx); + } + + editStationName ->setDisabled(!s); + labelStationName ->setDisabled(!s); + editPixmapFile ->setDisabled(!s); + labelPixmapFile ->setDisabled(!s); + editStationShortName ->setDisabled(!s); + labelStationShortName ->setDisabled(!s); + editVolumePreset ->setDisabled(!s); + labelVolumePreset ->setDisabled(!s); + buttonSelectPixmapFile->setDisabled(!s); + buttonDeleteStation ->setDisabled(!s); + + buttonStationUp ->setDisabled(!s || idx == 0); + buttonStationDown ->setDisabled(!s || idx == m_stations.count()-1); + + if (ignoreChanges) return; + ignoreChanges = true; + + editStationName ->setText (s ? s->name() : QString::null); + editStationShortName ->setText (s ? s->shortName() : QString::null); + editPixmapFile ->setText (s ? s->iconName() : QString::null); + editVolumePreset ->setValue (s ? (int)rint(s->initialVolume()*100) : -1); + + QPixmap pixmap(s ? s->iconName() : QString::null); + if (!pixmap.isNull()) { + pixmapStation->setPixmap(pixmap); + } else { + pixmapStation->setText(""); + } + + + stackStationEdit->setDisabled(!s); + if (s) { + RadioStationConfig *c = stationEditors.find(s->getClassName()); + if (!c) { + c = s->createEditor(); + if (c) { + c->reparent(this, QPoint(0,0), true); + QObject::connect(c, SIGNAL(changed(RadioStationConfig*)), + this, SLOT(slotStationEditorChanged(RadioStationConfig*))); + stationEditors.insert(s->getClassName(), c); + stackStationEdit->addWidget(c); + } + } + if (c) { + c->setStationData(*s); + stackStationEdit->raiseWidget(c); + } + } + + ignoreChanges = false; +} + + +void RadioConfiguration::slotNewStation() +{ + slotSetDirty(); + const RadioStation *st = &queryCurrentStation(); + int n = m_stations.count(); + m_stations.all().append(st); + if (m_stations.count() == n) { + st = st->copyNewID(); + m_stations.all().append(st); + } + if (m_stations.count() > n) { + listStations->appendStation(*st); + listStations->setCurrentStation (listStations->count()-1); + slotStationSelectionChanged(listStations->count()-1); + listStations->ensureItemVisible(listStations->selectedItem()); + } +} + + +void RadioConfiguration::slotDeleteStation() +{ + int idx = listStations->currentStationIndex(); + + if (idx >= 0 && idx < m_stations.count()) { + slotSetDirty(); + m_stations.all().remove(idx); + listStations->removeStation(idx); + } +} + + +void RadioConfiguration::slotStationEditorChanged(RadioStationConfig *c) +{ + if (!c) return; + if (ignoreChanges) return; + + + int idx = listStations->currentStationIndex(); + if (idx >= 0 && idx < m_stations.count()) { + slotSetDirty(); + RadioStation &st = m_stations.at(idx); + + ignoreChanges = true; + bool o = listStations->signalsBlocked(); + listStations->blockSignals(true); + + c->storeStationData(st); + listStations->setStation(idx, st); + + listStations->blockSignals(o); + ignoreChanges = false; + } +} + + +void RadioConfiguration::slotStationNameChanged( const QString & s) +{ + if (ignoreChanges) return; + + int idx = listStations->currentStationIndex(); + if (idx >= 0 && idx < m_stations.count()) { + slotSetDirty(); + RadioStation &st = m_stations.at(idx); + st.setName(s); + ignoreChanges = true; + bool o = listStations->signalsBlocked(); + listStations->blockSignals(true); + listStations->setStation(idx, st); + listStations->blockSignals(o); + ignoreChanges = false; + } +} + + +void RadioConfiguration::slotStationShortNameChanged( const QString & sn) +{ + if (ignoreChanges) return; + + int idx = listStations->currentStationIndex(); + if (idx >= 0 && idx < m_stations.count()) { + slotSetDirty(); + RadioStation &st = m_stations.at(idx); + st.setShortName(sn); + ignoreChanges = true; + bool o = listStations->signalsBlocked(); + listStations->blockSignals(true); + listStations->setStation(idx, st); + listStations->blockSignals(o); + ignoreChanges = false; + } +} + + +void RadioConfiguration::slotSelectPixmap() +{ + KURL url = KFileDialog::getImageOpenURL(QString::null, this, + i18n("Image Selection")); + if (!url.isEmpty()) { + if (url.isLocalFile()) { + editPixmapFile->setText(url.path()); + } else { + m_logger.logWarning(i18n("ignoring non-local image")); + } + } +} + + +void RadioConfiguration::slotPixmapChanged( const QString &s ) +{ + if (ignoreChanges) return; + + int idx = listStations->currentStationIndex(); + if (idx >= 0 && idx < m_stations.count()) { + slotSetDirty(); + RadioStation &st = m_stations.at(idx); + st.setIconName(s); + ignoreChanges = true; + pixmapStation->setPixmap(QPixmap(s)); + bool o = listStations->signalsBlocked(); + listStations->blockSignals(true); + listStations->setStation(idx, st); + listStations->blockSignals(o); + ignoreChanges = false; + } +} + + +void RadioConfiguration::slotVolumePresetChanged(int v) +{ + int idx = listStations->currentStationIndex(); + if (idx >= 0 && idx < m_stations.count()) { + slotSetDirty(); + RadioStation &s = m_stations.at(idx); + s.setInitialVolume(0.01 * (double)v); + } +} + + + +void RadioConfiguration::slotStationUp() +{ + int idx = listStations->currentStationIndex(); + if (idx > 0 && idx < m_stations.count()) { + slotSetDirty(); + RawStationList &sl = m_stations.all(); + + RadioStation *st = sl.take(idx-1); + sl.insert(idx, st); + delete st; + + ignoreChanges = true; +// bool o = listStations->signalsBlocked(); +// listStations->blockSignals(true); + listStations->setStation(idx-1, *sl.at(idx-1)); + listStations->setStation(idx, *sl.at(idx)); + listStations->setCurrentStation(idx-1); +// listStations->blockSignals(o); + ignoreChanges = false; + } +} + + +void RadioConfiguration::slotStationDown() +{ + int idx = listStations->currentStationIndex(); + if (idx >= 0 && idx < m_stations.count() - 1) { + slotSetDirty(); + RawStationList &sl = m_stations.all(); + + RadioStation *st = sl.take(idx); + sl.insert(idx+1, st); + delete st; + + ignoreChanges = true; +// bool o = listStations->signalsBlocked(); +// listStations->blockSignals(true); + listStations->setStation(idx, *sl.at(idx)); + listStations->setStation(idx+1, *sl.at(idx+1)); + listStations->setCurrentStation(idx+1); +// listStations->blockSignals(o); + ignoreChanges = false; + } +} + + +void RadioConfiguration::slotActivateStation(int idx) +{ + if (idx >= 0 && idx < m_stations.count()) { + sendActivateStation(m_stations.at(idx)); + sendPowerOn(); + } +} + +void RadioConfiguration::slotLoadPresets() +{ + KFileDialog fd(locate("data", "kradio/presets/"), + ("*.krp|" + i18n("KRadio Preset Files")).ascii(), + this, + i18n("Preset File Selection").ascii(), + true); + fd.setMode(KFile::File | KFile::ExistingOnly); + fd.setCaption (i18n("Select Preset File")); + + if (fd.exec() == QDialog::Accepted) { + slotSetDirty(); + StationList sl; + if (sl.readXML(fd.selectedURL(), m_logger)) { + noticeStationsChanged(sl); + } + } +} + + +void RadioConfiguration::slotStorePresets() +{ + KFileDialog fd("", + ("*.krp|" + i18n("KRadio Preset Files")).ascii(), + this, + i18n("Preset File Selection").ascii(), + true); + fd.setMode(KFile::File); + fd.setCaption (i18n("Store Preset File")); + + if (fd.exec() == QDialog::Accepted) { + editPresetFile->setURL(fd.selectedURL().url()); + m_stations.writeXML(fd.selectedURL(), m_logger); + } +} + + +void RadioConfiguration::slotLastChangeNow() +{ + slotSetDirty(); + editLastChange->setDateTime(QDateTime::currentDateTime()); +} + + +static QString &urlEscapes(QString &s) +{ + s.replace(QRegExp("%"), "%25"); + s.replace(QRegExp("\t"), "%09"); + s.replace(QRegExp("\n"), "%0A"); + s.replace(QRegExp("\n"), "%0D"); + s.replace(QRegExp(" "), "%20"); + s.replace(QRegExp("\\!"), "%21"); + s.replace(QRegExp("\""), "%22"); + s.replace(QRegExp("#"), "%23"); + s.replace(QRegExp("\\$"), "%24"); + s.replace(QRegExp("\\&"), "%26"); + s.replace(QRegExp("'"), "%27"); + s.replace(QRegExp(","), "%2C"); + s.replace(QRegExp(":"), "%3A"); + s.replace(QRegExp(";"), "%3B"); + s.replace(QRegExp("="), "%3D"); + s.replace(QRegExp("\\?"), "%3F"); + return s; +} + +void RadioConfiguration::slotSendPresetsByMail( const QString &url ) +{ + QString presets = m_stations.writeXML(m_logger); + + urlEscapes(presets); + + // documentation says, krun object deletes itself, + // so we do not need to store the pointer + + QString country = m_stations.metaData().country; + QString city = m_stations.metaData().city; + QString location = city + "/" + country; + urlEscapes(location); + + QString cmd = url + "?subject=station preset file for " + location + "&body="; + + cmd += presets; + new KRun (cmd); +} + + +void RadioConfiguration::slotSearchStations(int idev) +{ + if (idev >= 0 && (unsigned)idev < devices.count()) { + IRadioDevice *dev = devices.at(idev); + + StandardScanDialog *x = new StandardScanDialog(NULL); + x->connectI(dev); // connect device + x->connectI(IRadioDevicePoolClient::iConnections.at(0)); // connect radio to get verbous station information + sendActiveDevice(dev); + x->show(); + x->start(); + if (x->exec() == QDialog::Accepted) { + slotSetDirty(); + m_stations.merge(x->getStations()); + noticeStationsChanged(m_stations); + } + delete x; +// logDebug("scan finished"); + } +// logDebug("scan finished completely"); +} + + +void RadioConfiguration::slotOK() +{ + if (m_dirty) { + StationListMetaData &i = m_stations.metaData(); + + i.maintainer = editMaintainer->text(); + i.lastChange = editLastChange->dateTime(); + i.country = editCountry->text(); + i.city = editCity->text(); + i.media = editMedia->text(); + i.comment = editComment->text(); + + sendStations(m_stations); + sendPresetFile(editPresetFile->url()); + m_dirty = false; + } +} + +void RadioConfiguration::slotCancel() +{ + if (m_dirty) { + noticeStationsChanged(queryStations()); + noticePresetFileChanged(queryPresetFile()); + m_dirty = false; + } +} + + +void RadioConfiguration::slotSetDirty() +{ + if (!ignoreChanges) { + m_dirty = true; + } +} + + +#include "radio-configuration.moc" diff --git a/kradio3/plugins/radio/radio-configuration.h b/kradio3/plugins/radio/radio-configuration.h new file mode 100644 index 0000000..31b29c8 --- /dev/null +++ b/kradio3/plugins/radio/radio-configuration.h @@ -0,0 +1,106 @@ +/*************************************************************************** + radio-configuration.h - description + ------------------- + begin : Son Aug 3 2003 + copyright : (C) 2003 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_RADIO_CONFIGURATION_H +#define KRADIO_RADIO_CONFIGURATION_H + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <qdict.h> + +#include "../../src/include/radio_interfaces.h" +#include "../../src/include/stationlist.h" +#include "../../src/include/radiodevicepool_interfaces.h" +#include "radio-configuration-ui.h" + +class QPopupMenu; +class RadioStationConfig; + +class RadioConfiguration : public RadioConfigurationUI, + public IRadioClient, + public IRadioDevicePoolClient +{ +Q_OBJECT +public : + RadioConfiguration (QWidget *parent, const IErrorLogClient &m_logger); + ~RadioConfiguration (); + + bool connectI (Interface *i); + bool disconnectI (Interface *i); + + // IRadioDevicePoolClient + +RECEIVERS: + bool noticeActiveDeviceChanged(IRadioDevice *) { return false; } + bool noticeDevicesChanged(const QPtrList<IRadioDevice> &); + bool noticeDeviceDescriptionChanged(const QString &); + + // IRadioClient + +RECEIVERS: + bool noticePowerChanged(bool /*on*/) { return false; } // don't care + bool noticeStationChanged (const RadioStation &, int /*idx*/) { return false; } // don't care + bool noticeStationsChanged(const StationList &sl); + bool noticePresetFileChanged(const QString &f); + + bool noticeCurrentSoundStreamIDChanged(SoundStreamID /*id*/) { return false; } + +protected slots: + + void slotStationSelectionChanged(int idx); + void slotNewStation(); + void slotDeleteStation(); + void slotStationEditorChanged(RadioStationConfig *c); + void slotStationNameChanged( const QString & s); + void slotStationShortNameChanged( const QString & sn); + void slotPixmapChanged( const QString &s ); + void slotSelectPixmap(); + void slotVolumePresetChanged(int v); + void slotStationUp(); + void slotStationDown(); + void slotActivateStation( int ); + void slotLoadPresets(); + void slotStorePresets(); + void slotLastChangeNow(); + void slotSendPresetsByMail( const QString &url ); + + void slotSearchStations(int i); + void slotSearchStations0() { slotSearchStations(0); } + + void slotOK(); + void slotCancel(); + void slotSetDirty(); + + +protected: + + StationList m_stations; + bool ignoreChanges; + + QPopupMenu *devicePopup; + QPtrList<IRadioDevice> devices; + + QDict<RadioStationConfig> stationEditors; + + const IErrorLogClient &m_logger; + bool m_dirty; +}; + +#endif + diff --git a/kradio3/plugins/radio/radio.cpp b/kradio3/plugins/radio/radio.cpp new file mode 100644 index 0000000..2320f56 --- /dev/null +++ b/kradio3/plugins/radio/radio.cpp @@ -0,0 +1,497 @@ +/*************************************************************************** + radio.cpp - description + ------------------- + begin : Sat March 29 2003 + copyright : (C) 2003 by Klas Kalass, Ernst Martin Witte + email : klas@kde.org, 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 "../../src/include/radiostation.h" +#include "../../src/include/aboutwidget.h" +#include "../../src/include/radiodevice_interfaces.h" +#include "radio.h" +#include "radio-configuration.h" + +#include <kstandarddirs.h> +#include <kurl.h> +#include <kaboutdata.h> +#include <kconfig.h> + +#include "../../src/include/debug-profiler.h" + +/////////////////////////////////////////////////////////////////////// +//// plugin library functions + +PLUGIN_LIBRARY_FUNCTIONS(Radio, "kradio-radio", i18n("Central Radio Device Multiplexer")); + +///////////////////////////////////////////////////////////////////////////// + +Radio::Radio(const QString &name) + : PluginBase(name, i18n("Radio Multiplexer Plugin")), + IRadioDeviceClient(-1), + m_presetFile(locateLocal("data", "kradio/stations.krp")), + m_activeDevice (NULL) +{ +} + + +Radio::~Radio() +{ +} + + +bool Radio::connectI (Interface *i) +{ + bool a = IRadio::connectI(i); + bool b = IRadioDeviceClient::connectI(i); + bool c = IRadioDevicePool::connectI(i); + bool d = PluginBase::connectI(i); + bool e = ISoundStreamClient::connectI(i); + + // no "return IA::connectI() | return IB::connnectI to + // prevent "early termination" optimization in boolean expressions + return a || b || c || d || e; +} + + +bool Radio::disconnectI (Interface *i) +{ + bool a = IRadio::disconnectI(i); + bool b = IRadioDeviceClient::disconnectI(i); + bool c = IRadioDevicePool::disconnectI(i); + bool d = PluginBase::disconnectI(i); + bool e = ISoundStreamClient::disconnectI(i); + + // no "return IA::disconnectI() | return IB::disconnnectI to + // prevent "early termination" optimization in boolean expressions + return a || b || c || d || e; +} + + +void Radio::saveState (KConfig *config) const +{ + config->setGroup(QString("radio-") + name()); + + config->writeEntry("presetfile", m_presetFile); + + m_stationList.writeXML(m_presetFile, *this); +} + + +void Radio::restoreState (KConfig *config) +{ + config->setGroup(QString("radio-") + name()); + + m_presetFile = config->readEntry("presetfile", + QString::null); + bool first_restore = false; + if (m_presetFile.isNull() || m_presetFile.length() == 0) { + m_presetFile = locateLocal("data", "kradio/stations.krp"); + first_restore = true; + } + + m_stationList.readXML(KURL(m_presetFile), *this, /*enable-messagebox*/ !first_restore); + + notifyStationsChanged(m_stationList); + notifyPresetFileChanged(m_presetFile); +} + + + +ConfigPageInfo Radio::createConfigurationPage() +{ + RadioConfiguration *conf = new RadioConfiguration (NULL, *this); + connectI (conf); + return ConfigPageInfo( + conf, + i18n("Radio Stations"), + i18n("Setup Radio Stations"), + "kradio" + ); +} + + +AboutPageInfo Radio::createAboutPage() +{ +/* KAboutData aboutData("kradio", + NULL, + NULL, + I18N_NOOP("Radio Device Multiplexer and Station Management for KRadio"), + KAboutData::License_GPL, + "(c) 2002-2005 Martin Witte, Klas Kalass", + 0, + "http://sourceforge.net/projects/kradio", + 0); + aboutData.addAuthor("Martin Witte", "", "witte@kawo1.rwth-aachen.de"); + aboutData.addAuthor("Klas Kalass", "", "klas.kalass@gmx.de"); + + return AboutPageInfo( + new KRadioAboutWidget(aboutData, KRadioAboutWidget::AbtTabbed), + i18n("Device and Station Management"), + i18n("Radio Device Multiplexer and Station Management"), + "kradio" + ); +*/ + return AboutPageInfo(); +} + + + + + + +/* IRadio Interface Methods +*/ + +/* offer new station to current device. + if that does not accept, try all other devices. + Any device will be powered off if it does not accept the station +*/ + +bool Radio::activateStation (const RadioStation &rs) { + + if (sendActivateStation(rs)) { // first try activeDevice + + return true; + + } else { // hmm... active device did not want it. Try others... + + int n = 0; + + for (IRadioDeviceClient::IFIterator it(IRadioDeviceClient::iConnections); it.current(); ++it) { + + if (it.current()->activateStation(rs)) { + + setActiveDevice(it.current()); // select new device + ++n; + + } else { + + it.current()->powerOff(); + + } + } + + return n > 0; + } +} + + +bool Radio::activateStation(int index) +{ + if (index < 0 || index >= m_stationList.count()) + return false; + + return activateStation(m_stationList.at(index)); +} + + +bool Radio::setStations(const StationList &sl) +{ + if (true/*m_stationList != sl*/) { + BlockProfiler("Radio::setStations"); + m_stationList = sl; + notifyStationsChanged(m_stationList); + } + return true; +} + +bool Radio::setPresetFile(const QString &presetFile) +{ + if (m_presetFile != presetFile) { + m_presetFile = presetFile; + notifyPresetFileChanged(m_presetFile); + } + return true; +} + +int Radio::getStationIdx(const RadioStation &rs) const +{ + RawStationList &sl = const_cast<RawStationList&>(m_stationList.all()); + return sl.find(&rs); +} + +int Radio::getCurrentStationIdx() const +{ + return getStationIdx(getCurrentStation()); +} + +SoundStreamID Radio::getCurrentSoundStreamID() const +{ + return queryCurrentSoundStreamID(); +} + + +/* IRadioDevicePool Interface Methods + +*/ + + +bool Radio::setActiveDevice(IRadioDevice *rd, bool keepPower) +{ + // do nothing if old == new + if (m_activeDevice == rd) + return true; + + // check if new station is in "connections" + // special case: rd == NULL: power off active device, new active device = NULL + + if (!rd || IRadioDeviceClient::iConnections.containsRef(rd)) { // new device is ok + + // save old power state and power off old device + bool oldPowerOn = false; + if (m_activeDevice) { + oldPowerOn = m_activeDevice->isPowerOn(); + m_activeDevice->powerOff(); + } + + // setup new active device && send notifications + m_activeDevice = rd; + + // send notifications + notifyActiveDeviceChanged(m_activeDevice); + notifyCurrentSoundStreamIDChanged(queryCurrentSoundStreamID()); + const RadioStation &rs = queryCurrentStation(); + notifyStationChanged(rs, getStationIdx(rs)); + + if (keepPower) + oldPowerOn ? sendPowerOn() : sendPowerOff(); + + return true; + + } else { + return false; + } +} + + +IRadioDevice *Radio::getActiveDevice() const +{ + return m_activeDevice; +} + + +const QPtrList<IRadioDevice> &Radio::getDevices() const +{ + return IRadioDeviceClient::iConnections; +} + + +const QString &Radio::getDeviceDescription() const +{ + return queryDescription(); +} + + + +/* IRadioDeviceClient Interface Methods + + Many things are overwritten, particularly all sending methods + +*/ + +int Radio::sendPowerOn() const +{ + return m_activeDevice ? m_activeDevice->powerOn() : 0; +} + + +int Radio::sendPowerOff() const +{ + return m_activeDevice ? m_activeDevice->powerOff() : 0; +} + +int Radio::sendActivateStation (const RadioStation &rs) const +{ + return m_activeDevice ? m_activeDevice->activateStation(rs) : 0; +} + + + +bool Radio::queryIsPowerOn() const +{ + return m_activeDevice ? m_activeDevice->isPowerOn() : false; +} + + +bool Radio::queryIsPowerOff() const +{ + return m_activeDevice ? m_activeDevice->isPowerOff() : true; +} + + +const RadioStation & Radio::queryCurrentStation() const +{ + if (m_activeDevice) { + RadioStation &rs = const_cast<RadioStation&>(m_activeDevice->getCurrentStation()); + int idx = getStationIdx(rs); + + if (idx >= 0) { + rs.copyDescriptionFrom(m_stationList.at(idx)); + } else { + rs.copyDescriptionFrom(undefinedRadioStation); + } + + return rs; + } else { + return undefinedRadioStation; + } +} + + +static QString qstrUnknown(I18N_NOOP("unknown")); +static QString i18nqstrUnknown; +const QString &Radio::queryDescription() const +{ + return m_activeDevice ? m_activeDevice->getDescription() : (i18nqstrUnknown = i18n(qstrUnknown.ascii())); +} + + + +bool Radio::noticePowerChanged (bool on, const IRadioDevice *sender) +{ + if (on) { + setActiveDevice(const_cast<IRadioDevice*>(sender), false); + // false: do not set power state on new device + // constcast valid because power-state of sender is not changed + notifyPowerChanged(true); + return true; + + } else { + if (sender == m_activeDevice) { + sendStopCountdown(); + notifyPowerChanged(false); + return true; + } + return false; + } +} + + +bool Radio::noticeStationChanged (const RadioStation &_rs, const IRadioDevice *sender) +{ + RadioStation &rs = const_cast<RadioStation&>(_rs); + int idx = getStationIdx(rs); + + RadioStation &known = (idx >= 0) ? (RadioStation&)m_stationList.at(idx) : + (RadioStation&)undefinedRadioStation; + rs.copyDescriptionFrom(known); + + if (sender == m_activeDevice) + notifyStationChanged(rs, idx); + return true; +} + + +bool Radio::noticeDescriptionChanged (const QString &s, const IRadioDevice *sender) +{ + if (sender == m_activeDevice) + notifyDeviceDescriptionChanged(s); + return true; +} + + +bool Radio::noticeCurrentSoundStreamIDChanged(SoundStreamID id, const IRadioDevice *sender) +{ + if (sender == m_activeDevice) + notifyCurrentSoundStreamIDChanged(id); + return true; +} + + +SoundStreamID Radio::queryCurrentSoundStreamID() const +{ + return m_activeDevice ? m_activeDevice->getCurrentSoundStreamID() : SoundStreamID::InvalidID; +} + + + +void Radio::noticeConnectedI(IRadioDeviceClient::cmplInterface *dev, bool pointer_valid) +{ + IRadioDeviceClient::noticeConnectedI(dev, pointer_valid); + + if (! m_activeDevice && pointer_valid) + setActiveDevice (dev, false); + + notifyDevicesChanged(IRadioDeviceClient::iConnections); +} + + +void Radio::noticeDisconnectI(IRadioDeviceClient::cmplInterface *rd, bool pointer_valid) +{ + IRadioDeviceClient::noticeDisconnectI(rd, pointer_valid); + + if (rd == m_activeDevice) { + + // search a new active device + if (IRadioDeviceClient::iConnections.findRef(rd) >= 0) { + + IRadioDevice *new_rd = NULL; + + new_rd = IRadioDeviceClient::iConnections.next(); // choose next device as active device if next exists + if (!new_rd) { + IRadioDeviceClient::iConnections.findRef(rd); + new_rd = IRadioDeviceClient::iConnections.prev(); // otherwise try prev then, may be NULL (no connections) + } + setActiveDevice(new_rd); + + } else { + // strange error occurred, m_activeDevice not in connections... set to first. + + setActiveDevice(IRadioDeviceClient::iConnections.first()); + } + } + notifyDevicesChanged(IRadioDeviceClient::iConnections); +} + + +// ITimeControlClient + +bool Radio::noticeAlarm(const Alarm &a) +{ + if (a.alarmType() == Alarm::StartPlaying || + a.alarmType() == Alarm::StartRecording) + { + const RawStationList &sl = getStations().all(); + const RadioStation &rs = sl.stationWithID(a.stationID()); + activateStation(rs); + powerOn(); + + if (a.volumePreset() >= 0) + sendPlaybackVolume(getCurrentSoundStreamID(), a.volumePreset()); + + SoundStreamID id = getCurrentSoundStreamID(); + bool r = false; + SoundFormat sf; + queryIsRecordingRunning(id, r, sf); + if (a.alarmType() == Alarm::StartRecording && !r) + sendStartRecording(id); + + } else { + powerOff(); + } + return true; +} + + +bool Radio::noticeCountdownZero() +{ + powerOff(); + return true; +} + + +void Radio::aboutToQuit() +{ + sendPowerOff(); +} + diff --git a/kradio3/plugins/radio/radio.h b/kradio3/plugins/radio/radio.h new file mode 100644 index 0000000..7913c16 --- /dev/null +++ b/kradio3/plugins/radio/radio.h @@ -0,0 +1,167 @@ +/*************************************************************************** + radio.h - description + ------------------- + begin : Sat March 29 2003 + copyright : (C) 2003 by Klas Kalass, Ernst Martin Witte + email : klas@kde.org, 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_RADIO_H +#define KRADIO_RADIO_H + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + + +#include "../../src/include/radio_interfaces.h" +#include "../../src/include/radiodevicepool_interfaces.h" +#include "../../src/include/radiodevice_interfaces.h" +#include "../../src/include/timecontrol_interfaces.h" +#include "../../src/include/soundstreamclient_interfaces.h" +#include "../../src/include/stationlist.h" +#include "../../src/include/plugins.h" + +/** + * The main Radio class, which is used as the interface of the radio functionality + * to the GUI parts of the application + * @author Klas Kalass, Ernst Martin Witte + */ + +///////////////////////////////////////////////////////////////////////////// + +/* A class, that is able to manage more than one radio device, one of those + is active at a time. This class behaves represents the active device, + the active devices can be changed either by selecting a station or by + explicitly changing the devices. + + At any time a valid active device exists as long as any device is connected. + +*/ + +class Radio : public PluginBase, + public IRadio, + public IRadioDevicePool, + public IRadioDeviceClient, + public ITimeControlClient, + public ISoundStreamClient +{ +public: + Radio(const QString &name); + ~Radio(); + + + // PluginBase + +public: + virtual void saveState (KConfig *) const; + virtual void restoreState (KConfig *); + + virtual QString pluginClassName() const { return "Radio"; } + + virtual const QString &name() const { return PluginBase::name(); } + virtual QString &name() { return PluginBase::name(); } + + virtual ConfigPageInfo createConfigurationPage(); + virtual AboutPageInfo createAboutPage(); + + virtual void aboutToQuit(); + + // IRadio methods + +RECEIVERS: + bool powerOn() { return sendPowerOn() > 0; } + bool powerOff() { return sendPowerOff() > 0; } + bool activateStation(const RadioStation &rs); + bool activateStation(int index); + bool setStations(const StationList &sl); + bool setPresetFile(const QString &presetFile); + +ANSWERS: + bool isPowerOn() const { return queryIsPowerOn(); } + bool isPowerOff() const { return queryIsPowerOff(); } + const RadioStation & getCurrentStation() const { return queryCurrentStation(); } + int getStationIdx(const RadioStation &) const; + int getCurrentStationIdx() const; + const StationList & getStations() const { return m_stationList; } + const QString & getPresetFile() const { return m_presetFile; } + + SoundStreamID getCurrentSoundStreamID() const; + + +public: + bool connectI (Interface *i); + bool disconnectI (Interface *i); + + void noticeConnectedI (IRadioDeviceClient::cmplInterface *i, bool pointer_valid); + void noticeDisconnectI(IRadioDeviceClient::cmplInterface *i, bool pointer_valid); + + // IRadioDevicePool methods + +RECEIVERS: + bool setActiveDevice(IRadioDevice *rd, bool keepPower = true); + +ANSWERS: + IRadioDevice * getActiveDevice() const; + const QPtrList<IRadioDevice> & getDevices() const; + const QString & getDeviceDescription() const; + + + + // IRadioDeviceClient methods, even sending methods overwritten + // to provide "1-of-N" functionality + +SENDERS: + IF_SENDER ( sendPowerOn() ) + IF_SENDER ( sendPowerOff() ) + IF_SENDER ( sendActivateStation (const RadioStation &rs) ) + +QUERIES: + IF_QUERY ( bool queryIsPowerOn() ) + IF_QUERY ( bool queryIsPowerOff() ) + IF_QUERY ( const RadioStation & queryCurrentStation() ) + IF_QUERY ( const QString & queryDescription() ) + IF_QUERY ( SoundStreamID queryCurrentSoundStreamID() ) + +RECEIVERS: + virtual bool noticePowerChanged (bool on, const IRadioDevice *sender = NULL); + virtual bool noticeStationChanged (const RadioStation &rs, const IRadioDevice *sender = NULL); + virtual bool noticeDescriptionChanged (const QString &, const IRadioDevice *sender = NULL); + + virtual bool noticeCurrentSoundStreamIDChanged(SoundStreamID id, const IRadioDevice *sender = NULL); + + // ITimeControlClient + +RECEIVERS: + bool noticeAlarmsChanged(const AlarmVector &) { return false; } // ignore + bool noticeAlarm(const Alarm &); + bool noticeNextAlarmChanged(const Alarm *) { return false; } // ignore + bool noticeCountdownStarted(const QDateTime &/*end*/){ return false; } // ignore + bool noticeCountdownStopped() { return false; } // ignore + bool noticeCountdownZero(); + bool noticeCountdownSecondsChanged(int /*n*/) { return false; } // ignore + + // ISoundStreamClient + +RECEIVERS: + + // ... + +protected: + + QString m_presetFile; + StationList m_stationList; + IRadioDevice *m_activeDevice; +}; + + +#endif diff --git a/kradio3/plugins/recording/Makefile.am b/kradio3/plugins/recording/Makefile.am new file mode 100644 index 0000000..1cbd6aa --- /dev/null +++ b/kradio3/plugins/recording/Makefile.am @@ -0,0 +1,22 @@ +SUBDIRS = po icons . + +INCLUDES = $(all_includes) +METASOURCES = AUTO + +libkradio_LTLIBRARIES = librecording.la +librecording_la_SOURCES = recording-configuration.cpp \ + recording-configuration-ui.ui recording.cpp recording-config.cpp reccfg_interfaces.cpp encoder.cpp \ + recording-datamonitor.cpp recording-monitor.cpp encoder_mp3.cpp encoder_ogg.cpp encoder_pcm.cpp +librecording_la_LDFLAGS = -module -avoid-version $(KDE_RPATH) $(all_libraries) +librecording_la_LIBADD = $(LIB_OGG) $(LIB_LAME) + +noinst_HEADERS = recording-configuration.h recording.h recording-config.h \ + reccfg_interfaces.h encoder.h soundstreamevent.h recording-datamonitor.h \ + recording-monitor.h encoder_mp3.h encoder_ogg.h encoder_pcm.h + +#messages: rc.cpp +# $(XGETTEXT) *.cpp *.h -o po/kradio-recording.pot + +messages: rc.cpp + $(EXTRACTRC) *.rc *.ui >> rc.cpp + $(XGETTEXT) rc.cpp *.h *.cpp -o po/kradio-recording.pot diff --git a/kradio3/plugins/recording/encoder.cpp b/kradio3/plugins/recording/encoder.cpp new file mode 100644 index 0000000..b33a8c3 --- /dev/null +++ b/kradio3/plugins/recording/encoder.cpp @@ -0,0 +1,172 @@ +/*************************************************************************** + encoder.cpp - description + ------------------- + begin : Thu May 05 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 "../../src/include/radiostation.h" +#include "../../src/include/errorlog-interfaces.h" +#include "../../src/include/aboutwidget.h" + +#include "recording.h" +#include "recording-configuration.h" +#include "soundstreamevent.h" + +#include <qsocketnotifier.h> +#include <qevent.h> +#include <qapplication.h> +#include <qregexp.h> + +#include <kconfig.h> +#include <kdeversion.h> +#include <klocale.h> + +RecordingEncoding::RecordingEncoding(QObject *parent, SoundStreamID ssid, + const RecordingConfig &cfg, const RadioStation *rs, + const QString &filename) + : + m_parent(parent), + m_config(cfg), + m_RadioStation(rs ? rs->copy() : NULL), + m_SoundStreamID(ssid), + m_error(false), + m_errorString(QString::null), + m_done(false), + m_InputBuffers(m_config.m_EncodeBufferCount < 3 ? 3 : m_config.m_EncodeBufferCount, + m_config.m_EncodeBufferSize < 4096 ? 4096 : m_config.m_EncodeBufferSize), + m_buffersMetaData(NULL), + m_encodedSize(0), + m_InputStartTime(0), + m_InputStartPosition(0), + m_outputURL(filename) +{ + + if (m_config.m_EncodeBufferCount < 3) + m_config.m_EncodeBufferCount = 3; + if (m_config.m_EncodeBufferSize < 4096) + m_config.m_EncodeBufferSize = 4096; + + m_buffersMetaData = new QPtrList<BufferSoundMetaData> *[m_config.m_EncodeBufferCount]; + for (size_t i = 0; i < m_config.m_EncodeBufferCount; ++i) { + m_buffersMetaData [i] = new QPtrList<BufferSoundMetaData>; + m_buffersMetaData [i]->setAutoDelete(true); + } +} + + +RecordingEncoding::~RecordingEncoding() +{ + for (size_t i = 0; i < m_config.m_EncodeBufferCount; ++i) { + delete m_buffersMetaData[i]; + } + delete m_buffersMetaData; + delete m_RadioStation; +} + + +char *RecordingEncoding::lockInputBuffer(size_t &bufferSize) +{ + if (m_done || m_error) + return NULL; + char * retval = m_InputBuffers.lockWriteBuffer(bufferSize); + + m_error |= m_InputBuffers.hasError(); + m_errorString += m_InputBuffers.getErrorString(); + m_InputBuffers.resetError(); + + return retval; +} + + +void RecordingEncoding::unlockInputBuffer(size_t bufferSize, const SoundMetaData &md) +{ + if (m_done) + return; + size_t bufidx = m_InputBuffers.getCurrentWriteBufferIdx(); + size_t buffill = m_InputBuffers.getWriteBufferFill(); + m_InputBuffers.unlockWriteBuffer(bufferSize); + + if (!m_InputBuffers.hasError()) { + if (!m_InputStartTime) { + m_InputStartTime = md.absoluteTimestamp(); + m_InputStartPosition = md.position(); + } + BufferSoundMetaData *bmd = new BufferSoundMetaData( + md.position() - m_InputStartPosition, + md.absoluteTimestamp() - m_InputStartTime, + md.absoluteTimestamp(), + md.url(), + buffill); + m_buffersMetaData[bufidx]->append(bmd); + } else { + m_error = true; + m_errorString += m_InputBuffers.getErrorString(); + m_InputBuffers.resetError(); + } +} + + +void RecordingEncoding::setDone() +{ + m_done = true; + m_InputBuffers.unlockAllWriteBuffers(); +} + + + +void RecordingEncoding::run() +{ + BufferSoundMetaData last_md; + + while (!m_error) { + char *buffer = NULL; + size_t buffer_fill = 0; + if (!m_done) { + buffer = m_InputBuffers.wait4ReadBuffer(buffer_fill); + } + + if (!buffer_fill) { + if (m_done) + break; + else + continue; + } + + char *export_buffer = NULL; + size_t export_buffer_size = 0; + + Q_UINT64 old_pos = m_encodedSize; + + encode(buffer, buffer_fill, export_buffer, export_buffer_size); + + SoundStreamEncodingStepEvent *step_event = NULL; + + if (!m_error) { + last_md = *m_buffersMetaData[m_InputBuffers.getCurrentReadBufferIdx()]->first(); + SoundMetaData md(old_pos, last_md.relativeTimestamp(), last_md.absoluteTimestamp(), m_outputURL); + step_event = new SoundStreamEncodingStepEvent(m_SoundStreamID, export_buffer, export_buffer_size, md); + } + + if (step_event) + QApplication::postEvent(m_parent, step_event); + } + m_done = true; + closeOutput(); + + SoundMetaData md(m_encodedSize, last_md.relativeTimestamp(), last_md.absoluteTimestamp(), m_outputURL); + QApplication::postEvent(m_parent, new SoundStreamEncodingStepEvent(m_SoundStreamID, NULL, 0, md)); + + QApplication::postEvent(m_parent, new SoundStreamEncodingTerminatedEvent(m_SoundStreamID)); +} + diff --git a/kradio3/plugins/recording/encoder.h b/kradio3/plugins/recording/encoder.h new file mode 100644 index 0000000..271cf83 --- /dev/null +++ b/kradio3/plugins/recording/encoder.h @@ -0,0 +1,101 @@ +/*************************************************************************** + encoder.h - description + ------------------- + begin : Thu May 05 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_RECORDING_ENCODER_H +#define KRADIO_RECORDING_ENCODER_H + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + + +#include <qobject.h> +#include <qstring.h> +#include <qthread.h> + +#include "../../src/include/radiostation.h" +#include "../../src/include/multibuffer.h" +#include "../../src/include/sound_metadata.h" +#include "../../src/include/soundstreamid.h" +#include "recording-config.h" + +class BufferSoundMetaData : public SoundMetaData +{ +public: + BufferSoundMetaData() + : SoundMetaData(0, 0, 0, KURL()), m_BufferPosition(0) {} + BufferSoundMetaData(const SoundMetaData &md, size_t bufferpos) + : SoundMetaData(md), m_BufferPosition(bufferpos) {} + BufferSoundMetaData(Q_INT64 pos, time_t rel, time_t abs, const KURL &url, size_t bufferpos) + : SoundMetaData(pos, rel, abs, url), m_BufferPosition(bufferpos) {} + + size_t bufferPosition() const { return m_BufferPosition; } + +protected: + size_t m_BufferPosition; +}; + + +class RecordingEncoding : public QThread +{ +public: + RecordingEncoding(QObject *parent, SoundStreamID id, const RecordingConfig &cfg, const RadioStation *rs, const QString &filename); + virtual ~RecordingEncoding(); + + void run(); + + char *lockInputBuffer(size_t &bufferSize); // bytes we whish to write, returns number of bytes available + void unlockInputBuffer(size_t bufferSize, const SoundMetaData &md); // bytes we actually wrote + + bool error() const { return m_error; } + const QString &errorString() const { return m_errorString; } + + void setDone(); + bool IsDone() { return m_done; } + + virtual bool openOutput(const QString &outputFile) = 0; + virtual void closeOutput() = 0; + + Q_UINT64 encodedSize() const { return m_encodedSize; } + + const RecordingConfig &config() const { return m_config; } + +protected: + virtual void encode(const char *_buffer, size_t buffer_size, char *&export_buffer, size_t &export_buffer_size) = 0; + + QObject *m_parent; + RecordingConfig m_config; + RadioStation *m_RadioStation; + SoundStreamID m_SoundStreamID; + + bool m_error; + QString m_errorString; + bool m_done; + + MultiBuffer m_InputBuffers; + QPtrList<BufferSoundMetaData> + **m_buffersMetaData; + Q_UINT64 m_encodedSize; + + time_t m_InputStartTime; + Q_UINT64 m_InputStartPosition; + + KURL m_outputURL; +}; + + +#endif diff --git a/kradio3/plugins/recording/encoder_mp3.cpp b/kradio3/plugins/recording/encoder_mp3.cpp new file mode 100644 index 0000000..5ba0bc2 --- /dev/null +++ b/kradio3/plugins/recording/encoder_mp3.cpp @@ -0,0 +1,214 @@ +/*************************************************************************** + encoder_mp3.cpp + ------------------- + begin : Sat Aug 20 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 "encoder_mp3.h" + +#include <qmutex.h> +#include <klocale.h> + +RecordingEncodingMP3::RecordingEncodingMP3(QObject *parent, SoundStreamID ssid, + const RecordingConfig &cfg, const RadioStation *rs, + const QString &filename) + : RecordingEncoding(parent, ssid, cfg, rs, filename) +#ifdef HAVE_LAME + , + m_MP3Buffer(NULL), + m_MP3BufferSize(0), + m_MP3Output(NULL), + m_ID3Tags(NULL), + m_LAMEFlags(NULL), + m_MP3LBuffer(NULL), + m_MP3RBuffer(NULL) +#endif +{ + m_config.m_OutputFormat = RecordingConfig::outputMP3; + m_config.m_SoundFormat.m_Encoding = "mp3"; + openOutput(filename); +} + + +RecordingEncodingMP3::~RecordingEncodingMP3() +{ + closeOutput(); +} + + +static QMutex lameSerialization; + +void RecordingEncodingMP3::encode(const char *_buffer, size_t buffer_size, char *&export_buffer, size_t &export_buffer_size) +{ + if (m_error) + return; + +#ifdef HAVE_LAME + short int *buffer = (short int*)_buffer; + size_t j = 0, + j_inc = (m_config.m_SoundFormat.m_Channels == 1) ? 1 : 2, + dj = (m_config.m_SoundFormat.m_Channels == 1) ? 0 : 1, + samples = buffer_size / m_config.m_SoundFormat.frameSize(); + + for (size_t i = 0; i < samples; ++i, j+=j_inc) { + m_MP3LBuffer[i] = buffer[j]; + m_MP3RBuffer[i] = buffer[j+dj]; + } + + int n = 0; + lameSerialization.lock(); + n = lame_encode_buffer(m_LAMEFlags, + m_MP3LBuffer, + m_MP3RBuffer, + samples, + m_MP3Buffer, + m_MP3BufferSize); + lameSerialization.unlock(); + if (n < 0) { + m_errorString += i18n("Error %1 while encoding mp3. ").arg(QString().setNum(n)); + m_error = true; + } else if (n > 0) { + m_encodedSize += n; + + export_buffer = (char*)m_MP3Buffer; + export_buffer_size = n; + int r = fwrite(m_MP3Buffer, 1, n, m_MP3Output); + + if (r <= 0) { + m_errorString += i18n("Error %1 writing output. ").arg(QString().setNum(r)); + m_error = true; + } + } +#endif +} + + + +bool RecordingEncodingMP3::openOutput(const QString &output) +{ +#ifdef HAVE_LAME +// m_output = NULL; + m_LAMEFlags = lame_init(); + + if (!m_LAMEFlags) { + m_error = true; + m_errorString += i18n("Cannot initialize lalibmp3lame. "); + } else { + lame_set_in_samplerate(m_LAMEFlags, m_config.m_SoundFormat.m_SampleRate); + lame_set_num_channels(m_LAMEFlags, 2); + //lame_set_quality(m_LAMEFlags, m_config.mp3Quality); + + lame_set_mode(m_LAMEFlags, m_config.m_SoundFormat.m_Channels == 1 ? MONO : JOINT_STEREO); + + // lame_seterrorf(m_LAMEFlags, ...); + // lame_setdebugf(m_LAMEFlags, ...); + // lame_setmsgf(m_LAMEFlags, ...); + + lame_set_VBR(m_LAMEFlags, vbr_default); + lame_set_VBR_q(m_LAMEFlags, m_config.m_mp3Quality); + + if (lame_init_params(m_LAMEFlags) < 0) { + m_error = true; + m_errorString += i18n("Cannot initialize libmp3lame parameters. ").arg(output); + } + + if (!m_error) { + id3tag_init(m_LAMEFlags); + id3tag_add_v2(m_LAMEFlags); + QString title = m_RadioStation->name() + QString().sprintf(" - %s", (QDateTime::currentDateTime().toString(Qt::ISODate)).ascii()); + QString comment = i18n("Recorded by KRadio"); + size_t l = title.length() + comment.length() + 10; + m_ID3Tags = new char[l]; + char *ctitle = m_ID3Tags; + strcpy(ctitle, title.latin1()); + char *ccomment = m_ID3Tags + strlen(ctitle) + 1; + strcpy(ccomment, comment.latin1()); + id3tag_set_title(m_LAMEFlags, ctitle); + id3tag_set_comment(m_LAMEFlags, ccomment); + } + + m_MP3Output = fopen(output.ascii(), "wb+"); + if (!m_MP3Output) { + m_errorString += i18n("Cannot open output file %1. ").arg(output); + m_error = true; + } + + size_t nSamples = m_config.m_EncodeBufferSize / m_config.m_SoundFormat.frameSize(); + m_MP3BufferSize = nSamples + nSamples / 4 + 7200; + m_MP3Buffer = new unsigned char[m_MP3BufferSize]; + + m_MP3LBuffer = new short int[nSamples]; + m_MP3RBuffer = new short int[nSamples]; + + if (!m_MP3Buffer || !m_MP3LBuffer || !m_MP3RBuffer) { + m_error = true; + m_errorString += i18n("Cannot allocate buffers for mp3 encoding. "); + } + } + + if (m_error) { + if (m_LAMEFlags) lame_close(m_LAMEFlags); + m_LAMEFlags = NULL; + if (m_MP3Output) fclose(m_MP3Output); + m_MP3Output = NULL; + if (m_MP3Buffer) delete [] m_MP3Buffer; + m_MP3Buffer = NULL; + m_MP3BufferSize = 0; + if (m_ID3Tags) delete [] m_ID3Tags; + m_ID3Tags = NULL; + if (m_MP3LBuffer) delete[] m_MP3LBuffer; + if (m_MP3RBuffer) delete[] m_MP3RBuffer; + m_MP3LBuffer = m_MP3RBuffer = NULL; + } +#endif + return !m_error; +} + + +void RecordingEncodingMP3::closeOutput() +{ +#ifdef HAVE_LAME + if (m_LAMEFlags) { + if (m_config.m_OutputFormat == RecordingConfig::outputMP3) { + int n = lame_encode_flush(m_LAMEFlags, + m_MP3Buffer, + m_MP3BufferSize); + if (n < 0) { + m_error = true; + m_errorString += i18n("Error %1 while encoding mp3. ").arg(QString().setNum(n)); + } else if (n > 0) { + int r = fwrite(m_MP3Buffer, 1, n, m_MP3Output); + if (r <= 0) { + m_error = true; + m_errorString += i18n("Error %1 writing output. ").arg(QString().setNum(r)); + } else { + lame_mp3_tags_fid(m_LAMEFlags, m_MP3Output); + } + } + } + if (m_LAMEFlags) lame_close(m_LAMEFlags); + m_LAMEFlags = NULL; + if (m_MP3Output) fclose(m_MP3Output); + m_MP3Output = NULL; + m_MP3BufferSize = 0; + if (m_MP3Buffer) delete [] m_MP3Buffer; + m_MP3Buffer = NULL; + if (m_ID3Tags) delete [] m_ID3Tags; + m_ID3Tags = NULL; + if (m_MP3LBuffer) delete[] m_MP3LBuffer; + if (m_MP3RBuffer) delete[] m_MP3RBuffer; + m_MP3LBuffer = m_MP3RBuffer = NULL; + } +#endif +} diff --git a/kradio3/plugins/recording/encoder_mp3.h b/kradio3/plugins/recording/encoder_mp3.h new file mode 100644 index 0000000..2a41832 --- /dev/null +++ b/kradio3/plugins/recording/encoder_mp3.h @@ -0,0 +1,56 @@ +/*************************************************************************** + encoder_mp3.h + ------------------- + begin : Sat Aug 20 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_RECORDING_ENCODER_MP3_H +#define KRADIO_RECORDING_ENCODER_MP3_H + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "encoder.h" + +#ifdef HAVE_LAME + #include <lame/lame.h> +#endif + +class RecordingEncodingMP3 : public RecordingEncoding +{ +public: + RecordingEncodingMP3(QObject *parent, SoundStreamID id, const RecordingConfig &cfg, const RadioStation *rs, const QString &filename); + virtual ~RecordingEncodingMP3(); + + bool openOutput(const QString &outputFile); + void closeOutput(); + +protected: + void encode(const char *_buffer, size_t buffer_size, char *&export_buffer, size_t &export_buffer_size); + +#ifdef HAVE_LAME + unsigned char *m_MP3Buffer; + size_t m_MP3BufferSize; + FILE *m_MP3Output; + char *m_ID3Tags; + lame_global_flags *m_LAMEFlags; + short int *m_MP3LBuffer, + *m_MP3RBuffer; +#endif +}; + + + +#endif diff --git a/kradio3/plugins/recording/encoder_ogg.cpp b/kradio3/plugins/recording/encoder_ogg.cpp new file mode 100644 index 0000000..e3db6cc --- /dev/null +++ b/kradio3/plugins/recording/encoder_ogg.cpp @@ -0,0 +1,250 @@ +/*************************************************************************** + encoder_ogg.cpp + ------------------- + begin : Sat Aug 20 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 "encoder_ogg.h" + +#include <klocale.h> +#include <stdlib.h> + +RecordingEncodingOgg::RecordingEncodingOgg(QObject *parent, SoundStreamID ssid, + const RecordingConfig &cfg, const RadioStation *rs, + const QString &filename) + : RecordingEncoding(parent, ssid, cfg, rs, filename) +#ifdef HAVE_OGG + , + m_OggOutput(NULL), + m_OggExportBuffer(NULL), + m_OggExportBufferSize(0) +#endif +{ + m_config.m_OutputFormat = RecordingConfig::outputOGG; + m_config.m_SoundFormat.m_Encoding = "ogg"; + openOutput(filename); +} + + +RecordingEncodingOgg::~RecordingEncodingOgg() +{ + closeOutput(); +} + +void RecordingEncodingOgg::encode(const char *_buffer, size_t buffer_size, char *&export_buffer, size_t &export_buffer_size) +{ + if (m_error) + return; + +#ifdef HAVE_OGG + SoundFormat &sf = m_config.m_SoundFormat; + ogg_page ogg_pg; + ogg_packet ogg_pkt; + + size_t samples = buffer_size / sf.frameSize(); + + // buffer[channel][sample], normalized to -1..0..+1 + float **buffer = vorbis_analysis_buffer(&m_VorbisDSP, (samples < 512 ? 512 : samples)); + + sf.convertSamplesToFloat(_buffer, buffer, samples); + + /* Tell the library how many samples (per channel) we wrote + into the supplied buffer */ + vorbis_analysis_wrote(&m_VorbisDSP, samples); + + /* While we can get enough data from the library to analyse, one + block at a time... */ + + bool eos = false; + while(!m_error && !eos && vorbis_analysis_blockout(&m_VorbisDSP, &m_VorbisBlock) == 1) { + + /* Do the main analysis, creating a packet */ + vorbis_analysis(&m_VorbisBlock, NULL); + vorbis_bitrate_addblock(&m_VorbisBlock); + + while(!m_error && vorbis_bitrate_flushpacket(&m_VorbisDSP, &ogg_pkt)) { + /* Add packet to bitstream */ + ogg_stream_packetin(&m_OggStream,&ogg_pkt); + + /* If we've gone over a page boundary, we can do actual output, + so do so (for however many pages are available) */ + + while(!m_error && !eos) { + int result = ogg_stream_pageout(&m_OggStream, &ogg_pg); + if (!result) break; + + int n = fwrite(ogg_pg.header, 1, ogg_pg.header_len, m_OggOutput); + n += fwrite(ogg_pg.body, 1, ogg_pg.body_len, m_OggOutput); + + m_encodedSize += n; + + if (n != (ogg_pg.header_len + ogg_pg.body_len)) { + m_error = true; + m_errorString += i18n("Failed writing data to ogg/vorbis output stream. "); + break; + } else { + + if (m_OggExportBufferSize < export_buffer_size + n) { + m_OggExportBuffer = (char*)realloc(m_OggExportBuffer, m_OggExportBufferSize + 2 * n); + m_OggExportBufferSize += 2 * n; + } + + memcpy (m_OggExportBuffer + export_buffer_size, ogg_pg.header, ogg_pg.header_len); + export_buffer_size += ogg_pg.header_len; + memcpy (m_OggExportBuffer + export_buffer_size, ogg_pg.body, ogg_pg.body_len); + export_buffer_size += ogg_pg.body_len; + + } + if (ogg_page_eos(&ogg_pg)) + eos = 1; + } + } + } + + export_buffer = m_OggExportBuffer; +#endif +} + + +#ifdef HAVE_OGG +static void vorbis_comment_add_tag_new(vorbis_comment *vc, const QString &tag, const QString &value) +{ + char *stag = strdup(tag.ascii()); + char *svalue = strdup(value.utf8()); + vorbis_comment_add_tag(vc, stag, svalue); + delete stag; + delete svalue; +} +#endif + +bool RecordingEncodingOgg::openOutput(const QString &output) +{ +#ifdef HAVE_OGG + m_OggOutput = fopen(output.ascii(), "wb+"); + if (!m_OggOutput) { + m_errorString += i18n("Cannot open Ogg/Vorbis output file %1. ").arg(output); + m_error = true; + } + + m_OggExportBuffer = (char*)malloc(m_OggExportBufferSize = 65536); // start with a 64k buffer + + + /* Have vorbisenc choose a mode for us */ + vorbis_info_init(&m_VorbisInfo); + + SoundFormat &sf = m_config.m_SoundFormat; + if (vorbis_encode_setup_vbr(&m_VorbisInfo, sf.m_Channels, sf.m_SampleRate, m_config.m_oggQuality)) { + m_error = true; + m_errorString = i18n("Ogg/Vorbis Mode initialisation failed: invalid parameters for quality\n"); + vorbis_info_clear(&m_VorbisInfo); + return false; + } + + /* Turn off management entirely (if it was turned on). */ + vorbis_encode_ctl(&m_VorbisInfo, OV_ECTL_RATEMANAGE_SET, NULL); + vorbis_encode_setup_init(&m_VorbisInfo); + + /* Now, set up the analysis engine, stream encoder, and other + preparation before the encoding begins. + */ + + vorbis_analysis_init(&m_VorbisDSP, &m_VorbisInfo); + vorbis_block_init(&m_VorbisDSP, &m_VorbisBlock); + + ogg_stream_init (&m_OggStream, m_SoundStreamID.getID()); + + /* Now, build the three header packets and send through to the stream + output stage (but defer actual file output until the main encode loop) */ + + ogg_packet header_main; + ogg_packet header_comments; + ogg_packet header_codebooks; + + /* Build the packets */ + vorbis_comment vc; + vorbis_comment_init (&vc); + vorbis_comment_add_tag_new(&vc, "creator", "KRadio" VERSION); + vorbis_comment_add_tag_new(&vc, "title", m_RadioStation->longName().utf8()); + vorbis_comment_add_tag_new(&vc, "date", QDateTime::currentDateTime().toString(Qt::ISODate)); + + vorbis_analysis_headerout(&m_VorbisDSP, &vc, + &header_main, &header_comments, &header_codebooks); + + /* And stream them out */ + ogg_stream_packetin(&m_OggStream, &header_main); + ogg_stream_packetin(&m_OggStream, &header_comments); + ogg_stream_packetin(&m_OggStream, &header_codebooks); + + int result; + ogg_page ogg_page; + while((result = ogg_stream_flush(&m_OggStream, &ogg_page))) { + + if (!result) break; + + int n = fwrite(ogg_page.header, 1, ogg_page.header_len, m_OggOutput); + n += fwrite(ogg_page.body, 1, ogg_page.body_len, m_OggOutput); + + if(n != ogg_page.header_len + ogg_page.body_len) { + m_error = true; + m_errorString += i18n("Failed writing Ogg/Vorbis header to output stream\n"); + break; + } + } + + vorbis_comment_clear (&vc); + + if (m_error) { + if (m_OggOutput) fclose (m_OggOutput); + m_OggOutput = NULL; + free(m_OggExportBuffer); + m_OggExportBuffer = NULL; + m_OggExportBufferSize = 0; + + ogg_stream_clear(&m_OggStream); + vorbis_block_clear(&m_VorbisBlock); + vorbis_dsp_clear(&m_VorbisDSP); + vorbis_info_clear(&m_VorbisInfo); + } + + return !m_error; +#endif +} + + +void RecordingEncodingOgg::closeOutput() +{ +#ifdef HAVE_OGG + if (m_OggOutput) { + + char *tmp_buf = NULL; + size_t tmp_size = 0; + // flush buffer + encode(tmp_buf, tmp_size, tmp_buf, tmp_size); + + fclose(m_OggOutput); + m_OggOutput = NULL; + + free(m_OggExportBuffer); + m_OggExportBuffer = NULL; + m_OggExportBufferSize = 0; + + ogg_stream_clear(&m_OggStream); + vorbis_block_clear(&m_VorbisBlock); + vorbis_dsp_clear(&m_VorbisDSP); + vorbis_info_clear(&m_VorbisInfo); + } +#endif +} + + diff --git a/kradio3/plugins/recording/encoder_ogg.h b/kradio3/plugins/recording/encoder_ogg.h new file mode 100644 index 0000000..55cf8e6 --- /dev/null +++ b/kradio3/plugins/recording/encoder_ogg.h @@ -0,0 +1,55 @@ +/*************************************************************************** + encoder_ogg.h + ------------------- + begin : Sat Aug 20 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_RECORDING_ENCODER_OGG_H +#define KRADIO_RECORDING_ENCODER_OGG_H + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "encoder.h" + +#ifdef HAVE_OGG + #include <vorbis/vorbisenc.h> +#endif + +class RecordingEncodingOgg : public RecordingEncoding +{ +public: + RecordingEncodingOgg(QObject *parent, SoundStreamID id, const RecordingConfig &cfg, const RadioStation *rs, const QString &filename); + virtual ~RecordingEncodingOgg(); + + bool openOutput(const QString &outputFile); + void closeOutput(); + +protected: + void encode(const char *_buffer, size_t buffer_size, char *&export_buffer, size_t &export_buffer_size); + +#ifdef HAVE_OGG + FILE *m_OggOutput; + char *m_OggExportBuffer; + size_t m_OggExportBufferSize; + ogg_stream_state m_OggStream; + vorbis_dsp_state m_VorbisDSP; + vorbis_block m_VorbisBlock; + vorbis_info m_VorbisInfo; +#endif +}; + + +#endif diff --git a/kradio3/plugins/recording/encoder_pcm.cpp b/kradio3/plugins/recording/encoder_pcm.cpp new file mode 100644 index 0000000..27c671b --- /dev/null +++ b/kradio3/plugins/recording/encoder_pcm.cpp @@ -0,0 +1,78 @@ +/*************************************************************************** + encoder_pcm.cpp + ------------------- + begin : Sat Aug 20 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 "encoder_pcm.h" + + +#include <klocale.h> + +RecordingEncodingPCM::RecordingEncodingPCM(QObject *parent, SoundStreamID ssid, + const RecordingConfig &cfg, const RadioStation *rs, + const QString &filename) + : RecordingEncoding(parent, ssid, cfg, rs, filename), + m_output(NULL) +{ + m_config.m_SoundFormat.m_Encoding = "raw"; + openOutput(filename); +} + + +RecordingEncodingPCM::~RecordingEncodingPCM() +{ + closeOutput(); +} + + + +void RecordingEncodingPCM::encode(const char *buffer, size_t buffer_size, char *&export_buffer, size_t &export_buffer_size) +{ + if (m_error) + return; + m_encodedSize += buffer_size; + + export_buffer = const_cast<char*>(buffer); + export_buffer_size = buffer_size; + int err = sf_write_raw(m_output, const_cast<char*>(buffer), buffer_size); + + if (err != (int)buffer_size) { + m_error = true; + m_errorString += i18n("Error %1 writing output. ").arg(QString().setNum(err)); + } +} + + +bool RecordingEncodingPCM::openOutput(const QString &output) +{ + SF_INFO sinfo; + m_config.getSoundFileInfo(sinfo, false); + m_output = sf_open(output.ascii(), SFM_WRITE, &sinfo); + + if (!m_output) { + m_error = true; + m_errorString += i18n("Cannot open output file %1. ").arg(output); + } + return !m_error; +} + + +void RecordingEncodingPCM::closeOutput() +{ + if (m_output) sf_close (m_output); + m_output = NULL; +} + + diff --git a/kradio3/plugins/recording/encoder_pcm.h b/kradio3/plugins/recording/encoder_pcm.h new file mode 100644 index 0000000..e768bba --- /dev/null +++ b/kradio3/plugins/recording/encoder_pcm.h @@ -0,0 +1,46 @@ +/*************************************************************************** + encoder_pcm.h + ------------------- + begin : Sat Aug 20 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_RECORDING_ENCODER_PCM_H +#define KRADIO_RECORDING_ENCODER_PCM_H + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "encoder.h" + +#include <sndfile.h> + +class RecordingEncodingPCM : public RecordingEncoding +{ +public: + RecordingEncodingPCM(QObject *parent, SoundStreamID id, const RecordingConfig &cfg, const RadioStation *rs, const QString &filename); + virtual ~RecordingEncodingPCM(); + + bool openOutput(const QString &outputFile); + void closeOutput(); + +protected: + void encode(const char *_buffer, size_t buffer_size, char *&export_buffer, size_t &export_buffer_size); + + + SNDFILE *m_output; +}; + + +#endif diff --git a/kradio3/plugins/recording/icons/Makefile.am b/kradio3/plugins/recording/icons/Makefile.am new file mode 100644 index 0000000..b3f2583 --- /dev/null +++ b/kradio3/plugins/recording/icons/Makefile.am @@ -0,0 +1,2 @@ +icons_ICON = AUTO +iconsdir = $(kde_datadir)/kradio/icons diff --git a/kradio3/plugins/recording/icons/hi16-action-kradio_record.png b/kradio3/plugins/recording/icons/hi16-action-kradio_record.png Binary files differnew file mode 100644 index 0000000..a9e4d3c --- /dev/null +++ b/kradio3/plugins/recording/icons/hi16-action-kradio_record.png diff --git a/kradio3/plugins/recording/icons/hi16-app-kradio_plus_rec.png b/kradio3/plugins/recording/icons/hi16-app-kradio_plus_rec.png Binary files differnew file mode 100644 index 0000000..11a9395 --- /dev/null +++ b/kradio3/plugins/recording/icons/hi16-app-kradio_plus_rec.png diff --git a/kradio3/plugins/recording/icons/hi22-action-kradio_record.png b/kradio3/plugins/recording/icons/hi22-action-kradio_record.png Binary files differnew file mode 100644 index 0000000..bf57538 --- /dev/null +++ b/kradio3/plugins/recording/icons/hi22-action-kradio_record.png diff --git a/kradio3/plugins/recording/icons/hi22-app-kradio_plus_rec.png b/kradio3/plugins/recording/icons/hi22-app-kradio_plus_rec.png Binary files differnew file mode 100644 index 0000000..d17e9db --- /dev/null +++ b/kradio3/plugins/recording/icons/hi22-app-kradio_plus_rec.png diff --git a/kradio3/plugins/recording/icons/hi256-action-kradio_record.png b/kradio3/plugins/recording/icons/hi256-action-kradio_record.png Binary files differnew file mode 100644 index 0000000..a122d45 --- /dev/null +++ b/kradio3/plugins/recording/icons/hi256-action-kradio_record.png diff --git a/kradio3/plugins/recording/icons/hi32-action-kradio_record.png b/kradio3/plugins/recording/icons/hi32-action-kradio_record.png Binary files differnew file mode 100644 index 0000000..117202c --- /dev/null +++ b/kradio3/plugins/recording/icons/hi32-action-kradio_record.png diff --git a/kradio3/plugins/recording/icons/hi32-app-kradio_plus_rec.png b/kradio3/plugins/recording/icons/hi32-app-kradio_plus_rec.png Binary files differnew file mode 100644 index 0000000..436746e --- /dev/null +++ b/kradio3/plugins/recording/icons/hi32-app-kradio_plus_rec.png diff --git a/kradio3/plugins/recording/icons/hi48-action-kradio_record.png b/kradio3/plugins/recording/icons/hi48-action-kradio_record.png Binary files differnew file mode 100644 index 0000000..5a0c38d --- /dev/null +++ b/kradio3/plugins/recording/icons/hi48-action-kradio_record.png diff --git a/kradio3/plugins/recording/icons/hi48-app-kradio_plus_rec.png b/kradio3/plugins/recording/icons/hi48-app-kradio_plus_rec.png Binary files differnew file mode 100644 index 0000000..20388ee --- /dev/null +++ b/kradio3/plugins/recording/icons/hi48-app-kradio_plus_rec.png diff --git a/kradio3/plugins/recording/icons/hi64-action-kradio_record.png b/kradio3/plugins/recording/icons/hi64-action-kradio_record.png Binary files differnew file mode 100644 index 0000000..28d354d --- /dev/null +++ b/kradio3/plugins/recording/icons/hi64-action-kradio_record.png diff --git a/kradio3/plugins/recording/icons/hi64-app-kradio_plus_rec.png b/kradio3/plugins/recording/icons/hi64-app-kradio_plus_rec.png Binary files differnew file mode 100644 index 0000000..7240ed2 --- /dev/null +++ b/kradio3/plugins/recording/icons/hi64-app-kradio_plus_rec.png diff --git a/kradio3/plugins/recording/po/Makefile.am b/kradio3/plugins/recording/po/Makefile.am new file mode 100644 index 0000000..80443c3 --- /dev/null +++ b/kradio3/plugins/recording/po/Makefile.am @@ -0,0 +1,2 @@ +PACKAGE = kradio-recording +POFILES = AUTO diff --git a/kradio3/plugins/recording/po/de.po b/kradio3/plugins/recording/po/de.po new file mode 100644 index 0000000..7368347 --- /dev/null +++ b/kradio3/plugins/recording/po/de.po @@ -0,0 +1,435 @@ +# translation of de.po to +# translation of kradio-recording.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: 2006-11-11 18:43+0100\n" +"PO-Revision-Date: 2006-11-06 00:57+0100\n" +"Last-Translator: Ernst Martin Witte <emw@nocabal.de>\n" +"Language-Team: <de@li.org>\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: KBabel 1.11.4\n" + +#. i18n: file recording-configuration-ui.ui line 16 +#: rc.cpp:3 rc.cpp:117 recording-configuration-ui.cpp:244 +#, no-c-format +msgid "RecordingConfigurationUI" +msgstr "RecordingConfigurationUI" + +#. i18n: file recording-configuration-ui.ui line 34 +#: rc.cpp:6 rc.cpp:120 recording-configuration-ui.cpp:256 +#, no-c-format +msgid "Output" +msgstr "Ausgabe" + +#. i18n: file recording-configuration-ui.ui line 138 +#: rc.cpp:9 rc.cpp:123 recording-configuration-ui.cpp:245 +#, no-c-format +msgid "MP3 Quality(0 - high, 9 - low)" +msgstr "MP3 Qualität(0 - hoch, 9 - niedrig)" + +#. i18n: file recording-configuration-ui.ui line 149 +#: rc.cpp:12 rc.cpp:126 recording-configuration-ui.cpp:247 +#, no-c-format +msgid "raw pcm output (.raw)" +msgstr "reine PCM-Ausgabe (.raw)" + +#. i18n: file recording-configuration-ui.ui line 154 +#: rc.cpp:15 rc.cpp:129 recording-configuration-ui.cpp:248 +#, no-c-format +msgid "Microsoft Wave (.wav)" +msgstr "Microsoft Wave (.wav)" + +#. i18n: file recording-configuration-ui.ui line 159 +#: rc.cpp:18 rc.cpp:132 recording-configuration-ui.cpp:249 +#, no-c-format +msgid "Apple/SGI (.aiff)" +msgstr "Apple/SGI (.aiff)" + +#. i18n: file recording-configuration-ui.ui line 164 +#: rc.cpp:21 rc.cpp:135 recording-configuration-ui.cpp:250 +#, no-c-format +msgid "Sun/NeXT (.au)" +msgstr "Sun/NeXT (.au)" + +#. i18n: file recording-configuration-ui.ui line 169 +#: rc.cpp:24 rc.cpp:138 recording-configuration-ui.cpp:251 +#, no-c-format +msgid "MP3 Compressed (.mp3)" +msgstr "MP3 komprimiert (.mp3)" + +#. i18n: file recording-configuration-ui.ui line 174 +#: rc.cpp:27 rc.cpp:141 recording-configuration-ui.cpp:252 +#, no-c-format +msgid "Ogg/Vorbis Compressed (.ogg)" +msgstr "Ogg/Vorbis komprimiert (.ogg)" + +#. i18n: file recording-configuration-ui.ui line 194 +#: rc.cpp:30 rc.cpp:144 recording-configuration-ui.cpp:253 +#, no-c-format +msgid "Recording Directory" +msgstr "Aufnahme-Verzeichnis" + +#. i18n: file recording-configuration-ui.ui line 202 +#: rc.cpp:33 rc.cpp:147 recording-configuration-ui.cpp:254 +#, no-c-format +msgid "File Format" +msgstr "Dateiformat" + +#. i18n: file recording-configuration-ui.ui line 210 +#: rc.cpp:36 rc.cpp:150 recording-configuration-ui.cpp:255 +#, no-c-format +msgid "Ogg Quality(0 - low, 9 - high)" +msgstr "Ogg Qualität(0 - niedrig, 9 - hoch)" + +#. i18n: file recording-configuration-ui.ui line 239 +#: rc.cpp:39 rc.cpp:153 recording-configuration-ui.cpp:278 +#, no-c-format +msgid "I&nput" +msgstr "Quelle" + +#. i18n: file recording-configuration-ui.ui line 276 +#: rc.cpp:42 rc.cpp:156 recording-configuration-ui.cpp:258 +#, no-c-format +msgid "48000" +msgstr "48000" + +#. i18n: file recording-configuration-ui.ui line 281 +#: rc.cpp:45 rc.cpp:159 recording-configuration-ui.cpp:259 +#, no-c-format +msgid "44100" +msgstr "44100" + +#. i18n: file recording-configuration-ui.ui line 286 +#: rc.cpp:48 rc.cpp:162 recording-configuration-ui.cpp:260 +#, no-c-format +msgid "22050" +msgstr "22050" + +#. i18n: file recording-configuration-ui.ui line 291 +#: rc.cpp:51 rc.cpp:165 recording-configuration-ui.cpp:261 +#, no-c-format +msgid "11025" +msgstr "11025" + +#. i18n: file recording-configuration-ui.ui line 311 +#: rc.cpp:54 rc.cpp:168 recording-configuration-ui.cpp:262 +#, no-c-format +msgid "Endianess" +msgstr "Byte-Reihenfolge" + +#. i18n: file recording-configuration-ui.ui line 334 +#: rc.cpp:57 rc.cpp:171 recording-configuration-ui.cpp:264 +#, no-c-format +msgid "Stereo" +msgstr "Stereo" + +#. i18n: file recording-configuration-ui.ui line 339 +#: rc.cpp:60 rc.cpp:174 recording-configuration-ui.cpp:265 +#, no-c-format +msgid "Mono" +msgstr "Mono" + +#. i18n: file recording-configuration-ui.ui line 359 +#: rc.cpp:63 rc.cpp:177 recording-configuration-ui.cpp:266 +#: recording-monitor.cpp:53 +#, no-c-format +msgid "Sample Rate" +msgstr "Abtastrate" + +#. i18n: file recording-configuration-ui.ui line 365 +#: rc.cpp:66 rc.cpp:180 recording-configuration-ui.cpp:268 +#, no-c-format +msgid "Little Endian" +msgstr "Little Endian" + +#. i18n: file recording-configuration-ui.ui line 370 +#: rc.cpp:69 rc.cpp:183 recording-configuration-ui.cpp:269 +#, no-c-format +msgid "Big Endian" +msgstr "Big Endian" + +#. i18n: file recording-configuration-ui.ui line 388 +#: rc.cpp:72 rc.cpp:186 recording-configuration-ui.cpp:271 +#, no-c-format +msgid "16" +msgstr "16" + +#. i18n: file recording-configuration-ui.ui line 393 +#: rc.cpp:75 rc.cpp:189 recording-configuration-ui.cpp:272 +#, no-c-format +msgid "8" +msgstr "8" + +#. i18n: file recording-configuration-ui.ui line 413 +#: rc.cpp:78 rc.cpp:192 recording-configuration-ui.cpp:273 +#, no-c-format +msgid "Channels" +msgstr "Kanäle" + +#. i18n: file recording-configuration-ui.ui line 421 +#: rc.cpp:81 rc.cpp:195 recording-configuration-ui.cpp:274 +#, no-c-format +msgid "Sample Bits" +msgstr "Quantisierungs-Bits" + +#. i18n: file recording-configuration-ui.ui line 427 +#: rc.cpp:84 rc.cpp:198 recording-configuration-ui.cpp:276 +#, no-c-format +msgid "Signed" +msgstr "Vorzeichenbehaftet" + +#. i18n: file recording-configuration-ui.ui line 432 +#: rc.cpp:87 rc.cpp:201 recording-configuration-ui.cpp:277 +#, no-c-format +msgid "Unsigned" +msgstr "Vorzeichenlos" + +#. i18n: file recording-configuration-ui.ui line 490 +#: rc.cpp:90 rc.cpp:204 recording-configuration-ui.cpp:282 +#, no-c-format +msgid "&Buffers" +msgstr "&Puffer" + +#. i18n: file recording-configuration-ui.ui line 512 +#: rc.cpp:93 rc.cpp:207 recording-configuration-ui.cpp:279 +#, no-c-format +msgid " kB" +msgstr " kB" + +#. i18n: file recording-configuration-ui.ui line 532 +#: rc.cpp:96 rc.cpp:210 recording-configuration-ui.cpp:280 +#, no-c-format +msgid "Encoding Buffer Size" +msgstr "Codierungs-Puffergröße" + +#. i18n: file recording-configuration-ui.ui line 551 +#: rc.cpp:99 rc.cpp:213 recording-configuration-ui.cpp:281 +#, no-c-format +msgid "Number of Buffers" +msgstr "Anzahl der Puffer" + +#. i18n: file recording-configuration-ui.ui line 580 +#: rc.cpp:102 rc.cpp:216 recording-configuration-ui.cpp:287 +#, no-c-format +msgid "Pre-Recordin&g" +msgstr "Aufnahme&vorlaufs" + +#. i18n: file recording-configuration-ui.ui line 610 +#: rc.cpp:105 rc.cpp:219 recording-configuration-ui.cpp:283 +#, no-c-format +msgid "E&nable" +msgstr "&Einschalten" + +#. i18n: file recording-configuration-ui.ui line 613 +#: rc.cpp:108 rc.cpp:222 recording-configuration-ui.cpp:284 +#, no-c-format +msgid "Alt+N" +msgstr "Alt+N" + +#. i18n: file recording-configuration-ui.ui line 651 +#: rc.cpp:111 rc.cpp:225 recording-configuration-ui.cpp:285 +#, no-c-format +msgid "PreRecording Time" +msgstr "Dauer des Aufnahmevorlaufs" + +#. i18n: file recording-configuration-ui.ui line 662 +#: rc.cpp:114 rc.cpp:228 recording-configuration-ui.cpp:286 +#, no-c-format +msgid " s" +msgstr " s" + +#: _translatorinfo.cpp:1 +msgid "" +"_: NAME OF TRANSLATORS\n" +"Your names" +msgstr "Ernst Martin Witte" + +#: _translatorinfo.cpp:3 +msgid "" +"_: EMAIL OF TRANSLATORS\n" +"Your emails" +msgstr "emw@nocabal.de" + +#: encoder_mp3.cpp:79 encoder_mp3.cpp:189 +msgid "Error %1 while encoding mp3. " +msgstr "Fehler %1 beim Codieren des MP3-Streams. " + +#: encoder_mp3.cpp:89 encoder_mp3.cpp:194 encoder_pcm.cpp:53 +msgid "Error %1 writing output. " +msgstr "Fehler %1 beim Schreiben der Ausgabedatei. " + +#: encoder_mp3.cpp:106 +msgid "Cannot initialize lalibmp3lame. " +msgstr "Die Funktionsbibliothek libmp3lame kann nicht initialisiert werden. " + +#: encoder_mp3.cpp:123 +msgid "Cannot initialize libmp3lame parameters. " +msgstr "" +"Die Parameter der Funktionsbibliothek libmp3lame konnten nicht initialisiert " +"werden." + +#: encoder_mp3.cpp:130 +msgid "Recorded by KRadio" +msgstr "Aufzeichnung durch KRadio" + +#: encoder_mp3.cpp:143 encoder_pcm.cpp:66 +msgid "Cannot open output file %1. " +msgstr "Die Ausgabedatei %1 kann nicht geöffnet werden. " + +#: encoder_mp3.cpp:156 +msgid "Cannot allocate buffers for mp3 encoding. " +msgstr "" +"Die Puffer für das Codieren des MP3-Streams konnten nicht angelegt werden. " + +#: encoder_ogg.cpp:94 +msgid "Failed writing data to ogg/vorbis output stream. " +msgstr "Das schreiben der Ogg/Vorbis-Daten schlug fehl. " + +#: encoder_ogg.cpp:136 +msgid "Cannot open Ogg/Vorbis output file %1. " +msgstr "Die Ogg/Vorbis-Ausgabedatei %1 konnte nicht geöffnet werden. " + +#: encoder_ogg.cpp:149 +msgid "Ogg/Vorbis Mode initialisation failed: invalid parameters for quality\n" +msgstr "" +"Die Initialisierung des Ogg/Vorbis-Modes schlug fehl: Ungültiger Qualitäts-" +"Parameter\n" + +#: encoder_ogg.cpp:200 +msgid "Failed writing Ogg/Vorbis header to output stream\n" +msgstr "Das Schreiben der Ogg/Vorbis-Kopfdaten der Ausgabedatei schlug fehl\n" + +#: recording-datamonitor.cpp:174 recording-datamonitor.cpp:179 +msgid "%1 dB" +msgstr "%1 dB" + +#: recording-monitor.cpp:34 +msgid "Recording Monitor" +msgstr "Aufnahme-Überwachung" + +#: recording-monitor.cpp:38 recording.cpp:47 +msgid "KRadio Recording Monitor" +msgstr "KRadio Aufnahme-Überwachung" + +#: recording-monitor.cpp:43 +msgid "SoundStream" +msgstr "Aufnahmedatenstrom" + +#: recording-monitor.cpp:45 +msgid "Status" +msgstr "Status" + +#: recording-monitor.cpp:46 recording-monitor.cpp:48 recording-monitor.cpp:50 +#: recording-monitor.cpp:52 recording-monitor.cpp:54 +msgid "<undefined>" +msgstr "<undefiniert>" + +#: recording-monitor.cpp:47 +msgid "Recording File" +msgstr "Aufnahmedatei" + +#: recording-monitor.cpp:49 +msgid "File Size" +msgstr "Dateigröße" + +#: recording-monitor.cpp:51 +msgid "Recording Time" +msgstr "Aufnahmezeit" + +#: recording-monitor.cpp:57 recording-monitor.cpp:393 +#: recording-monitor.cpp:396 +msgid "&Record" +msgstr "&Aufnehmen" + +#: recording-monitor.cpp:74 recording-monitor.cpp:118 +#: recording-monitor.cpp:141 +msgid "nothing" +msgstr "nichts" + +#: recording-monitor.cpp:339 +msgid "%1 Byte" +msgstr "%1 Byte" + +#: recording-monitor.cpp:340 +msgid "%1 kB" +msgstr "%1 kB" + +#: recording-monitor.cpp:341 +msgid "%1 MB" +msgstr "%1 MB" + +#: recording-monitor.cpp:342 +msgid "%1 GB" +msgstr "%1 GB" + +#: recording-monitor.cpp:345 +msgid "%1 Hz" +msgstr "%1 Hz" + +#: recording-monitor.cpp:393 +msgid "&Stop Recording" +msgstr "Aufnahme anhalten" + +#: recording.cpp:46 recording.cpp:54 +msgid "KRadio Recording Plugin" +msgstr "KRadio Aufnahme-Plugin" + +#: recording.cpp:131 recording.cpp:132 +msgid "Recording" +msgstr "Aufnahme" + +#: recording.cpp:360 +msgid "start capture not handled" +msgstr "Der Aufnahmestart wurde ignoriert" + +#: recording.cpp:367 +msgid "Recording starting" +msgstr "Die Aufnahme wird gestartet" + +#: recording.cpp:369 +msgid "starting encoding thread failed" +msgstr "Das Starten des Aufnahme-Threads schlug fehl" + +#: recording.cpp:451 +msgid "could not read suffient data" +msgstr "es konnten nicht ausreichend Daten gelesen werden" + +#: recording.cpp:482 +msgid "" +"Encoder input buffer overflow (buffer configuration problem?). Skipped %1 " +"input bytes" +msgstr "" +"Pufferüberlauf des Aufnahmepuffers des Kodierers/Komprimierers (Fehlerhafte " +"Konfiguration der Puffer?). Es wurden %1 Bytes ignoriert." + +#: recording.cpp:544 +msgid "Recording::outputFile: " +msgstr "Aufnahme::Ausgabedatei: " + +#: recording.cpp:595 +msgid "The encoding thread did not finish. It will be killed now." +msgstr "" +"Der Codierungs-Thread beendete sich nicht selber. Er wird jetzt mit roher " +"Gewalt beendet." + +#: recording.cpp:600 +msgid "Waiting for encoding thread to terminate." +msgstr "Warte auf die Beendigung des Codierungs-Threads." + +#: recording.cpp:619 +msgid "Recording stopped" +msgstr "Die Aufnahme wurde beendet" + +#: recording.cpp:652 +msgid "" +"Recording::notifySoundStreamData(encoded data): Receivers skipped %1 Bytes" +msgstr "" +"Recording::notifySoundStreamData(Kodierte Daten): Die Empfängermodule " +"übersprangen %1 Bytess" diff --git a/kradio3/plugins/recording/po/ru.po b/kradio3/plugins/recording/po/ru.po new file mode 100644 index 0000000..293e22b --- /dev/null +++ b/kradio3/plugins/recording/po/ru.po @@ -0,0 +1,432 @@ +# translation of ru.po to +# translation of kradio-recording.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: 2006-11-11 18:43+0100\n" +"PO-Revision-Date: 2006-11-08 12:35+0300\n" +"Last-Translator: Алексей Кузнецов <Alexey.Kouznetsov@GMail.com>\n" +"Language-Team: <ru@li.org>\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" + +#. i18n: file recording-configuration-ui.ui line 16 +#: rc.cpp:3 rc.cpp:117 recording-configuration-ui.cpp:244 +#, no-c-format +msgid "RecordingConfigurationUI" +msgstr "RecordingConfigurationUI" + +#. i18n: file recording-configuration-ui.ui line 34 +#: rc.cpp:6 rc.cpp:120 recording-configuration-ui.cpp:256 +#, no-c-format +msgid "Output" +msgstr "Выход" + +#. i18n: file recording-configuration-ui.ui line 138 +#: rc.cpp:9 rc.cpp:123 recording-configuration-ui.cpp:245 +#, no-c-format +msgid "MP3 Quality(0 - high, 9 - low)" +msgstr "Качество MP3 (0 — высокое, 9 — низкое)" + +#. i18n: file recording-configuration-ui.ui line 149 +#: rc.cpp:12 rc.cpp:126 recording-configuration-ui.cpp:247 +#, no-c-format +msgid "raw pcm output (.raw)" +msgstr "Неформатированный вывод (.raw)" + +#. i18n: file recording-configuration-ui.ui line 154 +#: rc.cpp:15 rc.cpp:129 recording-configuration-ui.cpp:248 +#, no-c-format +msgid "Microsoft Wave (.wav)" +msgstr "Microsoft Wave (.wav)" + +#. i18n: file recording-configuration-ui.ui line 159 +#: rc.cpp:18 rc.cpp:132 recording-configuration-ui.cpp:249 +#, no-c-format +msgid "Apple/SGI (.aiff)" +msgstr "Apple/SGI (.aiff)" + +#. i18n: file recording-configuration-ui.ui line 164 +#: rc.cpp:21 rc.cpp:135 recording-configuration-ui.cpp:250 +#, no-c-format +msgid "Sun/NeXT (.au)" +msgstr "Sun/NeXT (.au)" + +#. i18n: file recording-configuration-ui.ui line 169 +#: rc.cpp:24 rc.cpp:138 recording-configuration-ui.cpp:251 +#, no-c-format +msgid "MP3 Compressed (.mp3)" +msgstr "Сжатый MP3 (.mp3)" + +#. i18n: file recording-configuration-ui.ui line 174 +#: rc.cpp:27 rc.cpp:141 recording-configuration-ui.cpp:252 +#, no-c-format +msgid "Ogg/Vorbis Compressed (.ogg)" +msgstr "Сжатый Ogg Vorbis (.ogg)" + +#. i18n: file recording-configuration-ui.ui line 194 +#: rc.cpp:30 rc.cpp:144 recording-configuration-ui.cpp:253 +#, no-c-format +msgid "Recording Directory" +msgstr "Каталог для сохранения" + +#. i18n: file recording-configuration-ui.ui line 202 +#: rc.cpp:33 rc.cpp:147 recording-configuration-ui.cpp:254 +#, no-c-format +msgid "File Format" +msgstr "Формат файла" + +#. i18n: file recording-configuration-ui.ui line 210 +#: rc.cpp:36 rc.cpp:150 recording-configuration-ui.cpp:255 +#, no-c-format +msgid "Ogg Quality(0 - low, 9 - high)" +msgstr "Качество Ogg (0 — ниже, 9 — выше)" + +#. i18n: file recording-configuration-ui.ui line 239 +#: rc.cpp:39 rc.cpp:153 recording-configuration-ui.cpp:278 +#, no-c-format +msgid "I&nput" +msgstr "В&вод" + +#. i18n: file recording-configuration-ui.ui line 276 +#: rc.cpp:42 rc.cpp:156 recording-configuration-ui.cpp:258 +#, no-c-format +msgid "48000" +msgstr "48000" + +#. i18n: file recording-configuration-ui.ui line 281 +#: rc.cpp:45 rc.cpp:159 recording-configuration-ui.cpp:259 +#, no-c-format +msgid "44100" +msgstr "44100" + +#. i18n: file recording-configuration-ui.ui line 286 +#: rc.cpp:48 rc.cpp:162 recording-configuration-ui.cpp:260 +#, no-c-format +msgid "22050" +msgstr "22050" + +#. i18n: file recording-configuration-ui.ui line 291 +#: rc.cpp:51 rc.cpp:165 recording-configuration-ui.cpp:261 +#, no-c-format +msgid "11025" +msgstr "11025" + +#. i18n: file recording-configuration-ui.ui line 311 +#: rc.cpp:54 rc.cpp:168 recording-configuration-ui.cpp:262 +#, no-c-format +msgid "Endianess" +msgstr "Порядок байтов" + +#. i18n: file recording-configuration-ui.ui line 334 +#: rc.cpp:57 rc.cpp:171 recording-configuration-ui.cpp:264 +#, no-c-format +msgid "Stereo" +msgstr "2 (Стерео)" + +#. i18n: file recording-configuration-ui.ui line 339 +#: rc.cpp:60 rc.cpp:174 recording-configuration-ui.cpp:265 +#, no-c-format +msgid "Mono" +msgstr "1 (Моно)" + +#. i18n: file recording-configuration-ui.ui line 359 +#: rc.cpp:63 rc.cpp:177 recording-configuration-ui.cpp:266 +#: recording-monitor.cpp:53 +#, no-c-format +msgid "Sample Rate" +msgstr "Частота дискретизации" + +#. i18n: file recording-configuration-ui.ui line 365 +#: rc.cpp:66 rc.cpp:180 recording-configuration-ui.cpp:268 +#, no-c-format +msgid "Little Endian" +msgstr "Little Endian" + +#. i18n: file recording-configuration-ui.ui line 370 +#: rc.cpp:69 rc.cpp:183 recording-configuration-ui.cpp:269 +#, fuzzy, no-c-format +msgid "Big Endian" +msgstr "Big Endian" + +#. i18n: file recording-configuration-ui.ui line 388 +#: rc.cpp:72 rc.cpp:186 recording-configuration-ui.cpp:271 +#, no-c-format +msgid "16" +msgstr "16" + +#. i18n: file recording-configuration-ui.ui line 393 +#: rc.cpp:75 rc.cpp:189 recording-configuration-ui.cpp:272 +#, no-c-format +msgid "8" +msgstr "8" + +#. i18n: file recording-configuration-ui.ui line 413 +#: rc.cpp:78 rc.cpp:192 recording-configuration-ui.cpp:273 +#, no-c-format +msgid "Channels" +msgstr "Число каналов" + +#. i18n: file recording-configuration-ui.ui line 421 +#: rc.cpp:81 rc.cpp:195 recording-configuration-ui.cpp:274 +#, no-c-format +msgid "Sample Bits" +msgstr "Бит на элемент выборки" + +#. i18n: file recording-configuration-ui.ui line 427 +#: rc.cpp:84 rc.cpp:198 recording-configuration-ui.cpp:276 +#, no-c-format +msgid "Signed" +msgstr "Со знаком" + +#. i18n: file recording-configuration-ui.ui line 432 +#: rc.cpp:87 rc.cpp:201 recording-configuration-ui.cpp:277 +#, no-c-format +msgid "Unsigned" +msgstr "Без знака" + +#. i18n: file recording-configuration-ui.ui line 490 +#: rc.cpp:90 rc.cpp:204 recording-configuration-ui.cpp:282 +#, no-c-format +msgid "&Buffers" +msgstr "&Буферы" + +#. i18n: file recording-configuration-ui.ui line 512 +#: rc.cpp:93 rc.cpp:207 recording-configuration-ui.cpp:279 +#, no-c-format +msgid " kB" +msgstr " кБ" + +#. i18n: file recording-configuration-ui.ui line 532 +#: rc.cpp:96 rc.cpp:210 recording-configuration-ui.cpp:280 +#, no-c-format +msgid "Encoding Buffer Size" +msgstr "Размер буфера для записи" + +#. i18n: file recording-configuration-ui.ui line 551 +#: rc.cpp:99 rc.cpp:213 recording-configuration-ui.cpp:281 +#, no-c-format +msgid "Number of Buffers" +msgstr "Количество буферов" + +#. i18n: file recording-configuration-ui.ui line 580 +#: rc.cpp:102 rc.cpp:216 recording-configuration-ui.cpp:287 +#, no-c-format +msgid "Pre-Recordin&g" +msgstr "&Упреждающая запись" + +#. i18n: file recording-configuration-ui.ui line 610 +#: rc.cpp:105 rc.cpp:219 recording-configuration-ui.cpp:283 +#, no-c-format +msgid "E&nable" +msgstr "Включить" + +#. i18n: file recording-configuration-ui.ui line 613 +#: rc.cpp:108 rc.cpp:222 recording-configuration-ui.cpp:284 +#, no-c-format +msgid "Alt+N" +msgstr "Alt+N" + +#. i18n: file recording-configuration-ui.ui line 651 +#: rc.cpp:111 rc.cpp:225 recording-configuration-ui.cpp:285 +#, no-c-format +msgid "PreRecording Time" +msgstr "Упреждение" + +#. i18n: file recording-configuration-ui.ui line 662 +#: rc.cpp:114 rc.cpp:228 recording-configuration-ui.cpp:286 +#, no-c-format +msgid " s" +msgstr " с" + +#: _translatorinfo.cpp:1 +msgid "" +"_: NAME OF TRANSLATORS\n" +"Your names" +msgstr "Алексей Кузнецов" + +#: _translatorinfo.cpp:3 +msgid "" +"_: EMAIL OF TRANSLATORS\n" +"Your emails" +msgstr "Alexey.Kouznetsov@GMail.com" + +#: encoder_mp3.cpp:79 encoder_mp3.cpp:189 +msgid "Error %1 while encoding mp3. " +msgstr "При кодировании MP3 произошла ошибка: %1. " + +#: encoder_mp3.cpp:89 encoder_mp3.cpp:194 encoder_pcm.cpp:53 +msgid "Error %1 writing output. " +msgstr "Во время записи произошла ошибка: %1" + +#: encoder_mp3.cpp:106 +msgid "Cannot initialize lalibmp3lame. " +msgstr "" +"Не могу инициализировать lalibmp3lame — необходимо для кодирования в MP3." + +#: encoder_mp3.cpp:123 +msgid "Cannot initialize libmp3lame parameters. " +msgstr "" +"Не могу инициализировать параметры libmp3lame — необходимо для кодирования в " +"MP3." + +#: encoder_mp3.cpp:130 +msgid "Recorded by KRadio" +msgstr "Запись KRadio" + +#: encoder_mp3.cpp:143 encoder_pcm.cpp:66 +msgid "Cannot open output file %1. " +msgstr "Не могу открыть выходной файл %1. " + +#: encoder_mp3.cpp:156 +msgid "Cannot allocate buffers for mp3 encoding. " +msgstr "Не могу разместить в памяти буферы для кодирования MP3." + +#: encoder_ogg.cpp:94 +msgid "Failed writing data to ogg/vorbis output stream. " +msgstr "Ошибка записи данных в выходной поток ogg/vorbis. " + +#: encoder_ogg.cpp:136 +msgid "Cannot open Ogg/Vorbis output file %1. " +msgstr "Не могу открыть выходной файл Ogg/Vorbis \"%1\". " + +#: encoder_ogg.cpp:149 +msgid "Ogg/Vorbis Mode initialisation failed: invalid parameters for quality\n" +msgstr "" +"Инициализация режима Ogg/Vorbis не удалась: качество записи указано неверно\n" + +#: encoder_ogg.cpp:200 +msgid "Failed writing Ogg/Vorbis header to output stream\n" +msgstr "Ошибка записи заголовка Ogg/Vorbis в выходной поток\n" + +#: recording-datamonitor.cpp:174 recording-datamonitor.cpp:179 +msgid "%1 dB" +msgstr "%1 дБ" + +#: recording-monitor.cpp:34 +msgid "Recording Monitor" +msgstr "Монитор записи" + +#: recording-monitor.cpp:38 recording.cpp:47 +msgid "KRadio Recording Monitor" +msgstr "Монитор записи для KRadio" + +#: recording-monitor.cpp:43 +msgid "SoundStream" +msgstr "Источник" + +#: recording-monitor.cpp:45 +msgid "Status" +msgstr "Состояние" + +#: recording-monitor.cpp:46 recording-monitor.cpp:48 recording-monitor.cpp:50 +#: recording-monitor.cpp:52 recording-monitor.cpp:54 +msgid "<undefined>" +msgstr "<не определено>" + +#: recording-monitor.cpp:47 +msgid "Recording File" +msgstr "Файл" + +#: recording-monitor.cpp:49 +msgid "File Size" +msgstr "Размер файла" + +#: recording-monitor.cpp:51 +msgid "Recording Time" +msgstr "Длительность записи" + +#: recording-monitor.cpp:57 recording-monitor.cpp:393 +#: recording-monitor.cpp:396 +msgid "&Record" +msgstr "&Начать запись" + +#: recording-monitor.cpp:74 recording-monitor.cpp:118 +#: recording-monitor.cpp:141 +msgid "nothing" +msgstr "(нет)" + +#: recording-monitor.cpp:339 +msgid "%1 Byte" +msgstr "%1 байт" + +#: recording-monitor.cpp:340 +msgid "%1 kB" +msgstr "%1 кБ" + +#: recording-monitor.cpp:341 +msgid "%1 MB" +msgstr "%1 МБ" + +#: recording-monitor.cpp:342 +msgid "%1 GB" +msgstr "%1 ГБ" + +#: recording-monitor.cpp:345 +msgid "%1 Hz" +msgstr "%1 Гц" + +#: recording-monitor.cpp:393 +msgid "&Stop Recording" +msgstr "&Остановить запись" + +#: recording.cpp:46 recording.cpp:54 +msgid "KRadio Recording Plugin" +msgstr "Модуль записи звука для KRadio" + +#: recording.cpp:131 recording.cpp:132 +msgid "Recording" +msgstr "Запись" + +#: recording.cpp:360 +msgid "start capture not handled" +msgstr "" + +#: recording.cpp:367 +msgid "Recording starting" +msgstr "Запись запущена" + +#: recording.cpp:369 +msgid "starting encoding thread failed" +msgstr "Не смог запустить процесс кодирования" + +#: recording.cpp:451 +msgid "could not read suffient data" +msgstr "Не смог прочесть достаточно данных" + +#: recording.cpp:482 +msgid "" +"Encoder input buffer overflow (buffer configuration problem?). Skipped %1 " +"input bytes" +msgstr "" +"Переполнение на входе кодировщика (вероятно, неправильно настроен буфер). " +"Пропускаю %1 байт на входе." + +#: recording.cpp:544 +msgid "Recording::outputFile: " +msgstr "Recording::outputFile (выходной файл записи):" + +#: recording.cpp:595 +msgid "The encoding thread did not finish. It will be killed now." +msgstr "Нить кодировщика не завершилась. Процесс будет уничтожен." + +#: recording.cpp:600 +msgid "Waiting for encoding thread to terminate." +msgstr "Жду завершения нити кодировщика" + +#: recording.cpp:619 +#, fuzzy +msgid "Recording stopped" +msgstr "Запись заершена" + +#: recording.cpp:652 +msgid "" +"Recording::notifySoundStreamData(encoded data): Receivers skipped %1 Bytes" +msgstr "" +"Recording::notifySoundStreamData(encoded data): Приёмник пропустил %1 байт" diff --git a/kradio3/plugins/recording/reccfg_interfaces.cpp b/kradio3/plugins/recording/reccfg_interfaces.cpp new file mode 100644 index 0000000..3b5f32f --- /dev/null +++ b/kradio3/plugins/recording/reccfg_interfaces.cpp @@ -0,0 +1,151 @@ +/*************************************************************************** + reccfg_interfaces.cpp - description + ------------------- + begin : Sun May 01 2005 + copyright : (C) 2005by 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 <linux/soundcard.h> +#include "reccfg_interfaces.h" + +// IRecCfg + +IF_IMPL_SENDER ( IRecCfg::notifyEncoderBufferChanged (size_t BufferSize, size_t BufferCount), + noticeEncoderBufferChanged(BufferSize, BufferCount) + ); +IF_IMPL_SENDER ( IRecCfg::notifySoundFormatChanged(const SoundFormat &sf), + noticeSoundFormatChanged(sf) + ); +IF_IMPL_SENDER ( IRecCfg::notifyMP3QualityChanged(int q), + noticeMP3QualityChanged(q) + ); +IF_IMPL_SENDER ( IRecCfg::notifyOggQualityChanged(float q), + noticeOggQualityChanged(q) + ); +IF_IMPL_SENDER ( IRecCfg::notifyRecordingDirectoryChanged(const QString &dir), + noticeRecordingDirectoryChanged(dir) + ); +IF_IMPL_SENDER ( IRecCfg::notifyOutputFormatChanged(RecordingConfig::OutputFormat of), + noticeOutputFormatChanged(of) + ); +IF_IMPL_SENDER ( IRecCfg::notifyPreRecordingChanged(bool enable, int seconds), + noticePreRecordingChanged(enable, seconds) + ); +IF_IMPL_SENDER ( IRecCfg::notifyRecordingConfigChanged (const RecordingConfig &cfg), + noticeRecordingConfigChanged(cfg) + ); + +// IRecCfgClient + +IF_IMPL_SENDER ( IRecCfgClient::sendEncoderBuffer (size_t BufferSize, size_t BufferCount), + setEncoderBuffer(BufferSize, BufferCount) + ); +IF_IMPL_SENDER ( IRecCfgClient::sendSoundFormat(const SoundFormat &sf), + setSoundFormat(sf) + ); +IF_IMPL_SENDER ( IRecCfgClient::sendMP3Quality(int q), + setMP3Quality(q) + ); +IF_IMPL_SENDER ( IRecCfgClient::sendOggQuality(float q), + setOggQuality(q) + ); +IF_IMPL_SENDER ( IRecCfgClient::sendRecordingDirectory(const QString &dir), + setRecordingDirectory(dir) + ); +IF_IMPL_SENDER ( IRecCfgClient::sendOutputFormat(RecordingConfig::OutputFormat of), + setOutputFormat(of) + ); +IF_IMPL_SENDER ( IRecCfgClient::sendPreRecording(bool enable, int seconds), + setPreRecording(enable, seconds) + ); +IF_IMPL_SENDER ( IRecCfgClient::sendRecordingConfig(const RecordingConfig &cfg), + setRecordingConfig(cfg) + ); + +IF_IMPL_QUERY ( void IRecCfgClient::queryEncoderBuffer(size_t &BufferSize, size_t &BufferCount), + getEncoderBuffer(BufferSize, BufferCount), + + ); + +static SoundFormat defaultSoundFormat; +IF_IMPL_QUERY ( const SoundFormat &IRecCfgClient::querySoundFormat (), + getSoundFormat(), + defaultSoundFormat + ); + +IF_IMPL_QUERY ( int IRecCfgClient::queryMP3Quality (), + getMP3Quality(), + 7 + ); + +IF_IMPL_QUERY ( float IRecCfgClient::queryOggQuality (), + getOggQuality(), + 7 + ); + +static QString defaultRecDir("/tmp"); +IF_IMPL_QUERY ( const QString &IRecCfgClient::queryRecordingDirectory(), + getRecordingDirectory(), + defaultRecDir + ); + +IF_IMPL_QUERY ( RecordingConfig::OutputFormat IRecCfgClient::queryOutputFormat(), + getOutputFormat(), + RecordingConfig::outputWAV + ); + +IF_IMPL_QUERY ( bool IRecCfgClient::queryPreRecording(int &seconds), + getPreRecording(seconds), + false + ); + +static RecordingConfig defaultRecConfig; +IF_IMPL_QUERY ( const RecordingConfig &IRecCfgClient::queryRecordingConfig(), + getRecordingConfig(), + defaultRecConfig + ); + +void IRecCfgClient::noticeConnectedI (cmplInterface *, bool /*pointer_valid*/) +{ + size_t bs = 0, bc = 0; + queryEncoderBuffer(bs, bc); + noticeEncoderBufferChanged(bs, bc); + noticeSoundFormatChanged(querySoundFormat()); + noticeMP3QualityChanged (queryMP3Quality()); + noticeOggQualityChanged (queryOggQuality()); + noticeRecordingDirectoryChanged(queryRecordingDirectory()); + noticeOutputFormatChanged(queryOutputFormat()); + int s = 0; + bool e = queryPreRecording(s); + noticePreRecordingChanged(e, s); + noticeRecordingConfigChanged(queryRecordingConfig()); +} + + +void IRecCfgClient::noticeDisconnectedI (cmplInterface *, bool /*pointer_valid*/) +{ + size_t bs = 0, bc = 0; + queryEncoderBuffer(bs, bc); + noticeEncoderBufferChanged(bs, bc); + noticeSoundFormatChanged(querySoundFormat()); + noticeMP3QualityChanged (queryMP3Quality()); + noticeOggQualityChanged (queryOggQuality()); + noticeRecordingDirectoryChanged(queryRecordingDirectory()); + noticeOutputFormatChanged(queryOutputFormat()); + int s = 0; + bool e = queryPreRecording(s); + noticePreRecordingChanged(e, s); + noticeRecordingConfigChanged(queryRecordingConfig()); +} + + diff --git a/kradio3/plugins/recording/reccfg_interfaces.h b/kradio3/plugins/recording/reccfg_interfaces.h new file mode 100644 index 0000000..907f494 --- /dev/null +++ b/kradio3/plugins/recording/reccfg_interfaces.h @@ -0,0 +1,102 @@ +/*************************************************************************** + reccfg_interfaces.h - description + ------------------- + begin : Sun May 01 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_RECCFG_INTERFACES_H +#define KRADIO_RECCFG_INTERFACES_H + +#include "../../src/include/interfaces.h" +#include "recording-config.h" + +INTERFACE(IRecCfg, IRecCfgClient) +{ +public: + IF_CON_DESTRUCTOR(IRecCfg, -1) + +RECEIVERS: + IF_RECEIVER( setEncoderBuffer (size_t BufferSize, size_t BufferCount) ) + IF_RECEIVER( setSoundFormat (const SoundFormat &sf) ) + IF_RECEIVER( setMP3Quality (int q) ) + IF_RECEIVER( setOggQuality (float q) ) + IF_RECEIVER( setRecordingDirectory(const QString &dir) ) + IF_RECEIVER( setOutputFormat (RecordingConfig::OutputFormat of) ) + IF_RECEIVER( setPreRecording (bool enable, int seconds) ) + IF_RECEIVER( setRecordingConfig (const RecordingConfig &cfg) ) + +SENDERS: + IF_SENDER ( notifyEncoderBufferChanged (size_t BufferSize, size_t BufferCount) ) + IF_SENDER ( notifySoundFormatChanged (const SoundFormat &sf) ) + IF_SENDER ( notifyMP3QualityChanged (int q) ) + IF_SENDER ( notifyOggQualityChanged (float q) ) + IF_SENDER ( notifyRecordingDirectoryChanged(const QString &dir) ) + IF_SENDER ( notifyOutputFormatChanged (RecordingConfig::OutputFormat of) ) + IF_SENDER ( notifyPreRecordingChanged (bool enable, int seconds) ) + IF_SENDER ( notifyRecordingConfigChanged (const RecordingConfig &cfg) ) + +ANSWERS: + IF_ANSWER ( void getEncoderBuffer(size_t &BufferSize, size_t &BufferCount) const ) + IF_ANSWER ( const SoundFormat &getSoundFormat () const ) + IF_ANSWER ( int getMP3Quality () const ) + IF_ANSWER ( float getOggQuality () const ) + IF_ANSWER ( const QString &getRecordingDirectory() const ) + IF_ANSWER ( RecordingConfig::OutputFormat getOutputFormat() const ) + IF_ANSWER ( bool getPreRecording(int &seconds) const ) + IF_ANSWER ( const RecordingConfig &getRecordingConfig() const ) +}; + + + +INTERFACE(IRecCfgClient, IRecCfg) +{ +public: + IF_CON_DESTRUCTOR(IRecCfgClient, 1) + +SENDERS: + IF_SENDER ( sendEncoderBuffer (size_t BufferSize, size_t BufferCount) ) + IF_SENDER ( sendSoundFormat (const SoundFormat &sf) ) + IF_SENDER ( sendMP3Quality (int q) ) + IF_SENDER ( sendOggQuality (float q) ) + IF_SENDER ( sendRecordingDirectory(const QString &dir) ) + IF_SENDER ( sendOutputFormat (RecordingConfig::OutputFormat of) ) + IF_SENDER ( sendPreRecording (bool enable, int seconds) ) + IF_SENDER ( sendRecordingConfig (const RecordingConfig &cfg) ) + +RECEIVERS: + IF_RECEIVER( noticeEncoderBufferChanged (size_t BufferSize, size_t BufferCount) ) + IF_RECEIVER( noticeSoundFormatChanged (const SoundFormat &sf) ) + IF_RECEIVER( noticeMP3QualityChanged (int q) ) + IF_RECEIVER( noticeOggQualityChanged (float q) ) + IF_RECEIVER( noticeRecordingDirectoryChanged(const QString &dir) ) + IF_RECEIVER( noticeOutputFormatChanged (RecordingConfig::OutputFormat of) ) + IF_RECEIVER( noticePreRecordingChanged (bool enable, int seconds) ) + IF_RECEIVER( noticeRecordingConfigChanged (const RecordingConfig &cfg) ) + +QUERIES: + IF_QUERY ( void queryEncoderBuffer(size_t &BufferSize, size_t &BufferCount) ) + IF_QUERY ( const SoundFormat &querySoundFormat () ) + IF_QUERY ( int queryMP3Quality () ) + IF_QUERY ( float queryOggQuality () ) + IF_QUERY ( const QString &queryRecordingDirectory() ) + IF_QUERY ( RecordingConfig::OutputFormat queryOutputFormat() ) + IF_QUERY ( bool queryPreRecording(int &seconds) ) + IF_QUERY ( const RecordingConfig &queryRecordingConfig() ) + +RECEIVERS: + virtual void noticeConnectedI (cmplInterface *, bool /*pointer_valid*/); + virtual void noticeDisconnectedI (cmplInterface *, bool /*pointer_valid*/); +}; + +#endif diff --git a/kradio3/plugins/recording/recording-config.cpp b/kradio3/plugins/recording/recording-config.cpp new file mode 100644 index 0000000..131953f --- /dev/null +++ b/kradio3/plugins/recording/recording-config.cpp @@ -0,0 +1,215 @@ +/*************************************************************************** + recording-config.cpp - description + ------------------- + begin : Mi Apr 30 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 "recording-config.h" + +#include <sndfile.h> + +RecordingConfig::RecordingConfig () +: m_EncodeBufferSize(256*1024), + m_EncodeBufferCount(3), + m_mp3Quality(7), + m_oggQuality(1.0), + m_Directory("/tmp"), + m_OutputFormat(outputWAV), + m_PreRecordingEnable (false), + m_PreRecordingSeconds(10) +{ + checkFormatSettings(); +} + +RecordingConfig::RecordingConfig (const QString &directory, + OutputFormat of, + const SoundFormat &sf, int mp3_q, float ogg_q) +: m_EncodeBufferSize(256*1024), + m_EncodeBufferCount(3), + m_SoundFormat(sf), + m_mp3Quality(mp3_q), + m_oggQuality(ogg_q), + m_Directory(directory), + m_OutputFormat(of), + m_PreRecordingEnable (false), + m_PreRecordingSeconds(10) +{ + checkFormatSettings(); +} + + +RecordingConfig::RecordingConfig (const RecordingConfig &c) + : + m_EncodeBufferSize(c.m_EncodeBufferSize), + m_EncodeBufferCount(c.m_EncodeBufferCount), + m_SoundFormat(c.m_SoundFormat), + m_mp3Quality(c.m_mp3Quality), + m_oggQuality(c.m_oggQuality), + m_Directory(c.m_Directory), + m_OutputFormat(c.m_OutputFormat), + m_PreRecordingEnable (false), + m_PreRecordingSeconds(10) +{ + checkFormatSettings(); +} + + +void RecordingConfig::restoreConfig(KConfig *c) +{ + m_EncodeBufferSize = c->readNumEntry("encodeBufferSize", 256*1024); + m_EncodeBufferCount = c->readNumEntry("encodeBufferCount", 3); + + m_SoundFormat.restoreConfig("", c); + m_Directory = c->readEntry("directory", "/tmp"); + m_mp3Quality = c->readNumEntry("mp3quality", 7); + m_oggQuality = c->readDoubleNumEntry("oggquality", 1.0); + QString of = c->readEntry("outputFormat", ".wav"); + + if (of == ".wav") + m_OutputFormat = outputWAV; + else if (of == ".aiff") + m_OutputFormat = outputAIFF; + else if (of == ".au") + m_OutputFormat = outputAU; +#ifdef HAVE_LAME + else if (of == ".mp3") + m_OutputFormat = outputMP3; +#endif +#ifdef HAVE_OGG + else if (of == ".ogg") + m_OutputFormat = outputOGG; +#endif + else if (of == ".raw") + m_OutputFormat = outputRAW; + + // if there was any unknown format + else + m_OutputFormat = outputWAV; + + m_PreRecordingEnable = c->readBoolEntry("prerecording-enable", false); + m_PreRecordingSeconds = c->readNumEntry("prerecording-seconds", 10); + + checkFormatSettings(); +} + + +void RecordingConfig::saveConfig(KConfig *c) const +{ + c->writeEntry("encodeBufferSize", m_EncodeBufferSize); + c->writeEntry("encodeBufferCount", m_EncodeBufferCount); + m_SoundFormat.saveConfig("", c); + c->writeEntry("directory", m_Directory); + c->writeEntry("mp3quality", m_mp3Quality); + c->writeEntry("oggquality", m_oggQuality); + + switch(m_OutputFormat) { + case outputWAV: c->writeEntry("outputFormat", ".wav"); break; + case outputAIFF: c->writeEntry("outputFormat", ".aiff"); break; + case outputAU: c->writeEntry("outputFormat", ".au"); break; + case outputMP3: c->writeEntry("outputFormat", ".mp3"); break; + case outputOGG: c->writeEntry("outputFormat", ".ogg"); break; + case outputRAW: c->writeEntry("outputFormat", ".raw"); break; + default: c->writeEntry("outputFormat", ".wav"); break; + } + + c->writeEntry("prerecording-enable", m_PreRecordingEnable); + c->writeEntry("prerecording-seconds", m_PreRecordingSeconds); +} + + +void RecordingConfig::getSoundFileInfo(SF_INFO &sinfo, bool input) +{ + checkFormatSettings(); + + sinfo.samplerate = m_SoundFormat.m_SampleRate; + sinfo.channels = m_SoundFormat.m_Channels; + sinfo.format = 0; + sinfo.seekable = !input; + + // U8 only supported for RAW and WAV + if (m_SoundFormat.m_SampleBits == 8) { + if ((m_SoundFormat.m_IsSigned && + m_OutputFormat != outputWAV) || + m_OutputFormat == outputAU + ) { + sinfo.format |= SF_FORMAT_PCM_S8; + } else { + sinfo.format |= SF_FORMAT_PCM_U8; + } + } + if (m_SoundFormat.m_SampleBits == 16) + sinfo.format |= SF_FORMAT_PCM_16; + + if (m_SoundFormat.m_Endianess == LITTLE_ENDIAN) + sinfo.format |= SF_ENDIAN_LITTLE; + else + sinfo.format |= SF_ENDIAN_BIG; + + if (input) { + sinfo.format |= SF_FORMAT_RAW; + } else { + switch (m_OutputFormat) { + case outputWAV: sinfo.format |= SF_FORMAT_WAV; break; + case outputAIFF: sinfo.format |= SF_FORMAT_AIFF; break; + case outputAU: sinfo.format |= SF_FORMAT_AU; break; + case outputRAW: sinfo.format |= SF_FORMAT_RAW; break; + default: sinfo.format |= SF_FORMAT_WAV; break; + } + } +} + + +void RecordingConfig::checkFormatSettings() +{ + // correct Endianess and Signs for specific formats + switch (m_OutputFormat) { + case outputWAV: + m_SoundFormat.m_Endianess = LITTLE_ENDIAN; + if (m_SoundFormat.m_SampleBits == 8) + m_SoundFormat.m_IsSigned = false; + // libsndfile only supports signed 16 bit samples + if (m_SoundFormat.m_SampleBits == 16) + m_SoundFormat.m_IsSigned = true; + break; + case outputAIFF: + m_SoundFormat.m_Endianess = BIG_ENDIAN; + // libsndfile only supports signed 16 bit samples + if (m_SoundFormat.m_SampleBits == 16) + m_SoundFormat.m_IsSigned = true; + break; + case outputAU: + m_SoundFormat.m_Endianess = BIG_ENDIAN; + m_SoundFormat.m_IsSigned = true; + // libsndfile only supports signed 16 bit samples + if (m_SoundFormat.m_SampleBits == 16) + m_SoundFormat.m_IsSigned = true; + break; + case outputMP3: + m_SoundFormat.m_IsSigned = true; + m_SoundFormat.m_SampleBits = 16; + break; + case outputOGG: + m_SoundFormat.m_IsSigned = true; + m_SoundFormat.m_SampleBits = 16; + break; + case outputRAW: + // libsndfile only supports signed 16 bit samples + if (m_SoundFormat.m_SampleBits == 16) + m_SoundFormat.m_IsSigned = true; + break; + default: + break; + } +} + diff --git a/kradio3/plugins/recording/recording-config.h b/kradio3/plugins/recording/recording-config.h new file mode 100644 index 0000000..bccbb93 --- /dev/null +++ b/kradio3/plugins/recording/recording-config.h @@ -0,0 +1,73 @@ +/*************************************************************************** + recording-config.h - description + ------------------- + begin : Mi Apr 30 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_RECORDING_CONFIG_H +#define KRADIO_RECORDING_CONFIG_H + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "../../src/include/soundformat.h" + +class KConfig; +struct SF_INFO; + +class RecordingConfig +{ +public: + enum OutputFormat { + outputWAV, + outputAIFF, + outputAU, + outputMP3, + outputOGG, + outputRAW + }; + +public: + RecordingConfig (); + RecordingConfig (const QString &directory, + OutputFormat of, + const SoundFormat &, int mp3_q, float ogg_q); + RecordingConfig (const RecordingConfig &c); + + void restoreConfig(KConfig *c); + void saveConfig(KConfig *c) const; + + void getSoundFileInfo(SF_INFO &info, bool input); + + void checkFormatSettings(); + +public: + size_t m_EncodeBufferSize; + size_t m_EncodeBufferCount; + + SoundFormat m_SoundFormat; + int m_mp3Quality; + float m_oggQuality; + QString m_Directory; + OutputFormat m_OutputFormat; + + bool m_PreRecordingEnable; + int m_PreRecordingSeconds; +}; + + + + +#endif diff --git a/kradio3/plugins/recording/recording-configuration-ui.ui b/kradio3/plugins/recording/recording-configuration-ui.ui new file mode 100644 index 0000000..a80fece --- /dev/null +++ b/kradio3/plugins/recording/recording-configuration-ui.ui @@ -0,0 +1,731 @@ +<!DOCTYPE UI><UI version="3.3" stdsetdef="1"> +<class>RecordingConfigurationUI</class> +<widget class="QWidget"> + <property name="name"> + <cstring>RecordingConfigurationUI</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>468</width> + <height>197</height> + </rect> + </property> + <property name="caption"> + <string>RecordingConfigurationUI</string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <widget class="QTabWidget" row="0" column="0"> + <property name="name"> + <cstring>kTabWidget13</cstring> + </property> + <widget class="QWidget"> + <property name="name"> + <cstring>TabPage_2</cstring> + </property> + <attribute name="title"> + <string>Output</string> + </attribute> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>11</number> + </property> + <widget class="QLayoutWidget" row="0" column="0"> + <property name="name"> + <cstring>layout7</cstring> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLayoutWidget" row="2" column="1" rowspan="1" colspan="2"> + <property name="name"> + <cstring>layout3_2</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <spacer> + <property name="name"> + <cstring>spacer5_2</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>141</width> + <height>20</height> + </size> + </property> + </spacer> + <widget class="QSpinBox"> + <property name="name"> + <cstring>editOggQuality</cstring> + </property> + <property name="maxValue"> + <number>9</number> + </property> + <property name="minValue"> + <number>0</number> + </property> + <property name="value"> + <number>7</number> + </property> + </widget> + </hbox> + </widget> + <widget class="QLayoutWidget" row="1" column="2"> + <property name="name"> + <cstring>layout3</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <spacer> + <property name="name"> + <cstring>spacer5</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>141</width> + <height>20</height> + </size> + </property> + </spacer> + <widget class="QSpinBox"> + <property name="name"> + <cstring>editMP3Quality</cstring> + </property> + <property name="maxValue"> + <number>9</number> + </property> + <property name="minValue"> + <number>0</number> + </property> + <property name="value"> + <number>5</number> + </property> + </widget> + </hbox> + </widget> + <widget class="QLabel" row="1" column="0" rowspan="1" colspan="2"> + <property name="name"> + <cstring>labelMP3Quality</cstring> + </property> + <property name="text"> + <string>MP3 Quality(0 - high, 9 - low)</string> + </property> + </widget> + <widget class="KURLRequester" row="3" column="2"> + <property name="name"> + <cstring>editDirectory</cstring> + </property> + </widget> + <widget class="KComboBox" row="0" column="2"> + <item> + <property name="text"> + <string>raw pcm output (.raw)</string> + </property> + </item> + <item> + <property name="text"> + <string>Microsoft Wave (.wav)</string> + </property> + </item> + <item> + <property name="text"> + <string>Apple/SGI (.aiff)</string> + </property> + </item> + <item> + <property name="text"> + <string>Sun/NeXT (.au)</string> + </property> + </item> + <item> + <property name="text"> + <string>MP3 Compressed (.mp3)</string> + </property> + </item> + <item> + <property name="text"> + <string>Ogg/Vorbis Compressed (.ogg)</string> + </property> + </item> + <property name="name"> + <cstring>editFileFormat</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>7</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + </widget> + <widget class="QLabel" row="3" column="0" rowspan="1" colspan="2"> + <property name="name"> + <cstring>lableDirectory</cstring> + </property> + <property name="text"> + <string>Recording Directory</string> + </property> + </widget> + <widget class="QLabel" row="0" column="0" rowspan="1" colspan="2"> + <property name="name"> + <cstring>lableFileFormat</cstring> + </property> + <property name="text"> + <string>File Format</string> + </property> + </widget> + <widget class="QLabel" row="2" column="0"> + <property name="name"> + <cstring>labelOggQuality</cstring> + </property> + <property name="text"> + <string>Ogg Quality(0 - low, 9 - high)</string> + </property> + </widget> + </grid> + </widget> + <spacer row="1" column="0"> + <property name="name"> + <cstring>spacer132</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> + </grid> + </widget> + <widget class="QWidget"> + <property name="name"> + <cstring>TabPage</cstring> + </property> + <attribute name="title"> + <string>I&nput</string> + </attribute> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>11</number> + </property> + <widget class="QLayoutWidget" row="0" column="0"> + <property name="name"> + <cstring>layout69</cstring> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <spacer row="0" column="2"> + <property name="name"> + <cstring>spacer1</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Minimum</enum> + </property> + <property name="sizeHint"> + <size> + <width>225</width> + <height>20</height> + </size> + </property> + </spacer> + <widget class="KComboBox" row="0" column="1"> + <item> + <property name="text"> + <string>48000</string> + </property> + </item> + <item> + <property name="text"> + <string>44100</string> + </property> + </item> + <item> + <property name="text"> + <string>22050</string> + </property> + </item> + <item> + <property name="text"> + <string>11025</string> + </property> + </item> + <property name="name"> + <cstring>editRate</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>3</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + </widget> + <widget class="QLabel" row="2" column="0"> + <property name="name"> + <cstring>lableEndianess</cstring> + </property> + <property name="text"> + <string>Endianess</string> + </property> + </widget> + <spacer row="3" column="2"> + <property name="name"> + <cstring>spacer1_3</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Minimum</enum> + </property> + <property name="sizeHint"> + <size> + <width>225</width> + <height>20</height> + </size> + </property> + </spacer> + <widget class="KComboBox" row="3" column="1"> + <item> + <property name="text"> + <string>Stereo</string> + </property> + </item> + <item> + <property name="text"> + <string>Mono</string> + </property> + </item> + <property name="name"> + <cstring>editChannels</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>3</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + </widget> + <widget class="QLabel" row="0" column="0"> + <property name="name"> + <cstring>labelRate</cstring> + </property> + <property name="text"> + <string>Sample Rate</string> + </property> + </widget> + <widget class="KComboBox" row="2" column="1"> + <item> + <property name="text"> + <string>Little Endian</string> + </property> + </item> + <item> + <property name="text"> + <string>Big Endian</string> + </property> + </item> + <property name="name"> + <cstring>editEndianess</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>3</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + </widget> + <widget class="KComboBox" row="1" column="1"> + <item> + <property name="text"> + <string>16</string> + </property> + </item> + <item> + <property name="text"> + <string>8</string> + </property> + </item> + <property name="name"> + <cstring>editBits</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>3</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + </widget> + <widget class="QLabel" row="3" column="0"> + <property name="name"> + <cstring>lableChannels</cstring> + </property> + <property name="text"> + <string>Channels</string> + </property> + </widget> + <widget class="QLabel" row="1" column="0"> + <property name="name"> + <cstring>lableBits</cstring> + </property> + <property name="text"> + <string>Sample Bits</string> + </property> + </widget> + <widget class="KComboBox" row="1" column="2"> + <item> + <property name="text"> + <string>Signed</string> + </property> + </item> + <item> + <property name="text"> + <string>Unsigned</string> + </property> + </item> + <property name="name"> + <cstring>editSign</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>3</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + </widget> + <spacer row="2" column="2"> + <property name="name"> + <cstring>spacer1_2</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Minimum</enum> + </property> + <property name="sizeHint"> + <size> + <width>225</width> + <height>20</height> + </size> + </property> + </spacer> + </grid> + </widget> + <spacer row="1" column="0"> + <property name="name"> + <cstring>spacer131</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> + </grid> + </widget> + <widget class="QWidget"> + <property name="name"> + <cstring>TabPage_3</cstring> + </property> + <attribute name="title"> + <string>&Buffers</string> + </attribute> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>11</number> + </property> + <widget class="QLayoutWidget" row="0" column="0"> + <property name="name"> + <cstring>layout5</cstring> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QSpinBox" row="0" column="1"> + <property name="name"> + <cstring>editBufferSize</cstring> + </property> + <property name="suffix"> + <string> kB</string> + </property> + <property name="maxValue"> + <number>2048</number> + </property> + <property name="minValue"> + <number>64</number> + </property> + <property name="lineStep"> + <number>16</number> + </property> + <property name="value"> + <number>256</number> + </property> + </widget> + <widget class="QLabel" row="0" column="0"> + <property name="name"> + <cstring>labelEditBufferSize</cstring> + </property> + <property name="text"> + <string>Encoding Buffer Size</string> + </property> + </widget> + <widget class="QSpinBox" row="1" column="1"> + <property name="name"> + <cstring>editBufferCount</cstring> + </property> + <property name="minValue"> + <number>3</number> + </property> + <property name="value"> + <number>3</number> + </property> + </widget> + <widget class="QLabel" row="1" column="0"> + <property name="name"> + <cstring>labelEditBufferCount</cstring> + </property> + <property name="text"> + <string>Number of Buffers</string> + </property> + </widget> + </grid> + </widget> + <spacer row="1" column="0"> + <property name="name"> + <cstring>spacer132_2</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>16</height> + </size> + </property> + </spacer> + </grid> + </widget> + <widget class="QWidget"> + <property name="name"> + <cstring>TabPage_4</cstring> + </property> + <attribute name="title"> + <string>Pre-Recordin&g</string> + </attribute> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>11</number> + </property> + <widget class="QLayoutWidget" row="0" column="0"> + <property name="name"> + <cstring>layout68</cstring> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout6</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QCheckBox"> + <property name="name"> + <cstring>m_checkboxPreRecordingEnable</cstring> + </property> + <property name="text"> + <string>E&nable</string> + </property> + <property name="accel"> + <string>Alt+N</string> + </property> + </widget> + <spacer> + <property name="name"> + <cstring>spacer7</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>380</width> + <height>20</height> + </size> + </property> + </spacer> + </hbox> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout7</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>m_labelPreRecordingTime</cstring> + </property> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="text"> + <string>PreRecording Time</string> + </property> + </widget> + <widget class="QSpinBox"> + <property name="name"> + <cstring>m_spinboxPreRecordingSeconds</cstring> + </property> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="suffix"> + <string> s</string> + </property> + <property name="maxValue"> + <number>999</number> + </property> + <property name="minValue"> + <number>1</number> + </property> + <property name="lineStep"> + <number>1</number> + </property> + <property name="value"> + <number>10</number> + </property> + </widget> + </hbox> + </widget> + </vbox> + </widget> + <spacer row="1" column="0"> + <property name="name"> + <cstring>spacer132_3</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>16</height> + </size> + </property> + </spacer> + </grid> + </widget> + </widget> + </grid> +</widget> +<customwidgets> +</customwidgets> +<connections> + <connection> + <sender>m_checkboxPreRecordingEnable</sender> + <signal>toggled(bool)</signal> + <receiver>m_spinboxPreRecordingSeconds</receiver> + <slot>setEnabled(bool)</slot> + </connection> + <connection> + <sender>m_checkboxPreRecordingEnable</sender> + <signal>toggled(bool)</signal> + <receiver>m_labelPreRecordingTime</receiver> + <slot>setEnabled(bool)</slot> + </connection> +</connections> +<layoutdefaults spacing="6" margin="0"/> +<includehints> + <includehint>kurlrequester.h</includehint> + <includehint>klineedit.h</includehint> + <includehint>kpushbutton.h</includehint> + <includehint>kcombobox.h</includehint> + <includehint>kcombobox.h</includehint> + <includehint>kcombobox.h</includehint> + <includehint>kcombobox.h</includehint> + <includehint>kcombobox.h</includehint> + <includehint>kcombobox.h</includehint> +</includehints> +</UI> diff --git a/kradio3/plugins/recording/recording-configuration.cpp b/kradio3/plugins/recording/recording-configuration.cpp new file mode 100644 index 0000000..d41bf01 --- /dev/null +++ b/kradio3/plugins/recording/recording-configuration.cpp @@ -0,0 +1,414 @@ +/*************************************************************************** + recording-configuration.cpp - description + ------------------- + begin : So Aug 31 2003 + copyright : (C) 2003 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 "recording-configuration.h" +//#include "recording-context.h" + +#include <kurlrequester.h> +#include <kcombobox.h> +#include <qspinbox.h> +#include <qlabel.h> +#include <qcheckbox.h> + +#include <ktabwidget.h> + + +RecordingConfiguration::RecordingConfiguration (QWidget *parent) + : RecordingConfigurationUI(parent), + m_dirty(true), + m_ignore_gui_updates(false) +{ + editDirectory->setMode(KFile::Directory | KFile::ExistingOnly); + + QObject::connect(editFileFormat, SIGNAL(activated(int)), + this, SLOT(slotFormatSelectionChanged())); + QObject::connect(editBits, SIGNAL(activated(int)), + this, SLOT(slotFormatSelectionChanged())); + + connect(editRate, SIGNAL(activated(int)), SLOT(slotSetDirty())); + connect(editBits, SIGNAL(activated(int)), SLOT(slotSetDirty())); + connect(editSign, SIGNAL(activated(int)), SLOT(slotSetDirty())); + connect(editEndianess, SIGNAL(activated(int)), SLOT(slotSetDirty())); + connect(editChannels, SIGNAL(activated(int)), SLOT(slotSetDirty())); + connect(editFileFormat, SIGNAL(activated(int)), SLOT(slotSetDirty())); + connect(editMP3Quality, SIGNAL(valueChanged(int)), SLOT(slotSetDirty())); + connect(editOggQuality, SIGNAL(valueChanged(int)), SLOT(slotSetDirty())); + connect(editDirectory, SIGNAL(textChanged(const QString &)), SLOT(slotSetDirty())); + connect(editBufferSize, SIGNAL(valueChanged(int)), SLOT(slotSetDirty())); + connect(editBufferCount, SIGNAL(valueChanged(int)), SLOT(slotSetDirty())); + connect(m_spinboxPreRecordingSeconds, SIGNAL(valueChanged(int)), SLOT(slotSetDirty())); + connect(m_checkboxPreRecordingEnable, SIGNAL(toggled(bool)), SLOT(slotSetDirty())); + +// attention: remove items with higher index first ;-) otherwise indexes are not valid +#ifndef HAVE_OGG + editFileFormat->removeItem(FORMAT_OGG_IDX_ORG); + delete editOggQuality; + editOggQuality = NULL; + delete labelOggQuality; + labelOggQuality = NULL; +#endif +#ifndef HAVE_LAME + editFileFormat->removeItem(FORMAT_MP3_IDX_ORG); + delete editMP3Quality; + editMP3Quality = NULL; + delete labelMP3Quality; + labelMP3Quality = NULL; +#endif +} + + +RecordingConfiguration::~RecordingConfiguration () +{ +} + + +void RecordingConfiguration::setGUIBuffers(const RecordingConfig &c) +{ + editBufferSize->setValue(c.m_EncodeBufferSize / 1024); + editBufferCount->setValue(c.m_EncodeBufferCount); +} + +void RecordingConfiguration::setGUIDirectories(const RecordingConfig &c) +{ + editDirectory->setURL(c.m_Directory); +} + +void RecordingConfiguration::setGUISoundFormat(const RecordingConfig &c) +{ + switch (c.m_SoundFormat.m_SampleBits) { + case 8 : editBits->setCurrentItem(BITS_8_IDX ); break; + case 16: editBits->setCurrentItem(BITS_16_IDX); break; + default: editBits->setCurrentItem(BITS_16_IDX); + } + switch (c.m_SoundFormat.m_Channels) { + case 1 : editChannels->setCurrentItem(CHANNELS_MONO_IDX); break; + case 2 : editChannels->setCurrentItem(CHANNELS_STEREO_IDX); break; + default: editChannels->setCurrentItem(CHANNELS_STEREO_IDX); break; + } + switch (c.m_SoundFormat.m_IsSigned) { + case 0 : editSign->setCurrentItem(SIGN_UNSIGNED_IDX); break; + case 1 : editSign->setCurrentItem(SIGN_SIGNED_IDX); break; + default: editSign->setCurrentItem(SIGN_SIGNED_IDX); break; + } + switch (c.m_SoundFormat.m_SampleRate) { + case 48000: editRate->setCurrentItem(RATE_48000_IDX); break; + case 44100: editRate->setCurrentItem(RATE_44100_IDX); break; + case 22050: editRate->setCurrentItem(RATE_22050_IDX); break; + case 11025: editRate->setCurrentItem(RATE_11025_IDX); break; + default: editRate->setCurrentItem(RATE_44100_IDX); break; + } + switch (c.m_SoundFormat.m_Endianess) { + case BIG_ENDIAN : editEndianess->setCurrentItem(ENDIAN_BIG_IDX); break; + case LITTLE_ENDIAN : editEndianess->setCurrentItem(ENDIAN_LITTLE_IDX); break; + default: editEndianess->setCurrentItem(ENDIAN_LITTLE_IDX); break; + } +} + +void RecordingConfiguration::setGUIOutputFormat(const RecordingConfig &c) +{ + switch (c.m_OutputFormat) { + case RecordingConfig::outputWAV: editFileFormat->setCurrentItem(FORMAT_WAV_IDX); break; + case RecordingConfig::outputAIFF: editFileFormat->setCurrentItem(FORMAT_AIFF_IDX); break; + case RecordingConfig::outputAU: editFileFormat->setCurrentItem(FORMAT_AU_IDX); break; + case RecordingConfig::outputRAW: editFileFormat->setCurrentItem(FORMAT_RAW_IDX); break; +#ifdef HAVE_LAME + case RecordingConfig::outputMP3: editFileFormat->setCurrentItem(FORMAT_MP3_IDX); break; +#endif +#ifdef HAVE_OGG + case RecordingConfig::outputOGG: editFileFormat->setCurrentItem(FORMAT_OGG_IDX); break; +#endif + default: editFileFormat->setCurrentItem(FORMAT_WAV_IDX); break; + } +} + +void RecordingConfiguration::setGUIEncoderQuality(const RecordingConfig &c) +{ +#ifdef HAVE_LAME + editMP3Quality->setValue(c.m_mp3Quality); +#endif +#ifdef HAVE_OGG + editOggQuality->setValue((int)(c.m_oggQuality * 9)); +#endif +} + + +void RecordingConfiguration::setGUIPreRecording(const RecordingConfig &c) +{ + m_spinboxPreRecordingSeconds->setValue(c.m_PreRecordingSeconds); + m_checkboxPreRecordingEnable->setChecked(c.m_PreRecordingEnable); +} + + +void RecordingConfiguration::slotOK() +{ + if (m_dirty) { + storeConfig(); + sendRecordingConfig(m_RecordingConfig); + m_dirty = false; + } +} + + +void RecordingConfiguration::storeConfig() +{ + RecordingConfig &c = m_RecordingConfig; + + c.m_EncodeBufferSize = editBufferSize->value() * 1024; + c.m_EncodeBufferCount = editBufferCount->value(); + + c.m_Directory = editDirectory->url(); + + switch(editRate->currentItem()) { + case RATE_48000_IDX: c.m_SoundFormat.m_SampleRate = 48000; break; + case RATE_44100_IDX: c.m_SoundFormat.m_SampleRate = 44100; break; + case RATE_22050_IDX: c.m_SoundFormat.m_SampleRate = 22050; break; + case RATE_11025_IDX: c.m_SoundFormat.m_SampleRate = 11025; break; + default: c.m_SoundFormat.m_SampleRate = 44100; break; + } + switch(editChannels->currentItem()) { + case CHANNELS_MONO_IDX: c.m_SoundFormat.m_Channels = 1; break; + case CHANNELS_STEREO_IDX: c.m_SoundFormat.m_Channels = 2; break; + default: c.m_SoundFormat.m_Channels = 2; break; + } + switch(editSign->currentItem()) { + case SIGN_UNSIGNED_IDX: c.m_SoundFormat.m_IsSigned = false; break; + case SIGN_SIGNED_IDX: c.m_SoundFormat.m_IsSigned = true; break; + default: c.m_SoundFormat.m_IsSigned = true; break; + } + switch(editEndianess->currentItem()) { + case ENDIAN_LITTLE_IDX: c.m_SoundFormat.m_Endianess = LITTLE_ENDIAN; break; + case ENDIAN_BIG_IDX: c.m_SoundFormat.m_Endianess = BIG_ENDIAN; break; + default: c.m_SoundFormat.m_Endianess = LITTLE_ENDIAN; break; + } + switch(editBits->currentItem()) { + case BITS_8_IDX: c.m_SoundFormat.m_SampleBits = 8; break; + case BITS_16_IDX: c.m_SoundFormat.m_SampleBits = 16; break; + default: c.m_SoundFormat.m_SampleBits = 16; break; + } + switch(editFileFormat->currentItem()) { + case FORMAT_WAV_IDX: c.m_OutputFormat = RecordingConfig::outputWAV; break; + case FORMAT_AIFF_IDX: c.m_OutputFormat = RecordingConfig::outputAIFF; break; + case FORMAT_AU_IDX: c.m_OutputFormat = RecordingConfig::outputAU; break; + case FORMAT_RAW_IDX: c.m_OutputFormat = RecordingConfig::outputRAW; break; +#ifdef HAVE_LAME + case FORMAT_MP3_IDX: c.m_OutputFormat = RecordingConfig::outputMP3; break; +#endif +#ifdef HAVE_OGG + case FORMAT_OGG_IDX: c.m_OutputFormat = RecordingConfig::outputOGG; break; +#endif + default: c.m_OutputFormat = RecordingConfig::outputWAV; break; + } +#ifdef HAVE_LAME + c.m_mp3Quality = editMP3Quality->value(); +#endif +#ifdef HAVE_OGG + c.m_oggQuality = ((float)editOggQuality->value()) / 9.0f; +#endif + + c.m_PreRecordingEnable = m_checkboxPreRecordingEnable->isChecked(); + c.m_PreRecordingSeconds = m_spinboxPreRecordingSeconds->value(); + + c.checkFormatSettings(); +} + + +void RecordingConfiguration::slotCancel() +{ + if (m_dirty) { + noticeRecordingConfigChanged(m_RecordingConfig); + m_dirty = false; + } +} + + +void RecordingConfiguration::slotFormatSelectionChanged() +{ + int bitsIDX = editBits->currentItem(); + int formatIDX = editFileFormat->currentItem(); + + int endianTest = 0x04030201; + bool littleEndian = ((char*)&endianTest)[0] == 0x01; + +#ifdef HAVE_LAME + editMP3Quality ->setEnabled(false); + labelMP3Quality->setEnabled(false); +#endif +#ifdef HAVE_OGG + editOggQuality ->setEnabled(false); + labelOggQuality->setEnabled(false); +#endif + + editBits->setEnabled(true); + + if (formatIDX == FORMAT_MP3_IDX) { + editBits->setDisabled(true); + editBits->setCurrentItem(BITS_16_IDX); + editSign->setDisabled(true); + editSign->setCurrentItem(SIGN_SIGNED_IDX); +#ifdef HAVE_LAME + editMP3Quality ->setEnabled(true); + labelMP3Quality->setEnabled(true); +#endif + } else if (formatIDX == FORMAT_OGG_IDX) { + editBits->setDisabled(true); + editBits->setCurrentItem(BITS_16_IDX); + editSign->setDisabled(true); + editSign->setCurrentItem(SIGN_SIGNED_IDX); +#ifdef HAVE_OGG + editOggQuality ->setEnabled(true); + labelOggQuality->setEnabled(true); +#endif + } else { + if (bitsIDX == BITS_8_IDX) { + if (formatIDX == FORMAT_RAW_IDX || formatIDX == FORMAT_AIFF_IDX) { + editSign->setDisabled(false); + } else { + editSign->setDisabled(true); + editSign->setCurrentItem(formatIDX == FORMAT_WAV_IDX ? SIGN_UNSIGNED_IDX : SIGN_SIGNED_IDX); + } + } else { + editSign->setDisabled(true); + editSign->setCurrentItem(SIGN_SIGNED_IDX); + } + } + + switch (formatIDX) { + case FORMAT_RAW_IDX : + editEndianess->setDisabled(false); + break; +#ifdef HAVE_LAME + case FORMAT_MP3_IDX : + editEndianess->setCurrentItem(littleEndian ? ENDIAN_LITTLE_IDX : ENDIAN_BIG_IDX); + editEndianess->setDisabled(true); + break; +#endif +#ifdef HAVE_OGG + case FORMAT_OGG_IDX : + editEndianess->setCurrentItem(littleEndian ? ENDIAN_LITTLE_IDX : ENDIAN_BIG_IDX); + editEndianess->setDisabled(true); + break; +#endif + default: + editEndianess->setDisabled(true); + if (formatIDX == FORMAT_AIFF_IDX || formatIDX == FORMAT_AU_IDX) { + editEndianess->setCurrentItem(ENDIAN_BIG_IDX); + } else { + editEndianess->setCurrentItem(ENDIAN_LITTLE_IDX); + } + break; + } +} + + + +bool RecordingConfiguration::noticeEncoderBufferChanged (size_t BufferSize, size_t BufferCount) +{ + m_ignore_gui_updates = true; + m_RecordingConfig.m_EncodeBufferSize = BufferSize; + m_RecordingConfig.m_EncodeBufferCount = BufferCount; + setGUIBuffers(m_RecordingConfig); + slotFormatSelectionChanged(); + m_ignore_gui_updates = false; + return true; +} + + +bool RecordingConfiguration::noticeSoundFormatChanged (const SoundFormat &sf) +{ + m_ignore_gui_updates = true; + m_RecordingConfig.m_SoundFormat = sf; + setGUISoundFormat(m_RecordingConfig); + slotFormatSelectionChanged(); + m_ignore_gui_updates = false; + return true; +} + + +bool RecordingConfiguration::noticeMP3QualityChanged (int q) +{ + m_ignore_gui_updates = true; + m_RecordingConfig.m_mp3Quality = q; + setGUIEncoderQuality(m_RecordingConfig); + slotFormatSelectionChanged(); + m_ignore_gui_updates = false; + return true; +} + +bool RecordingConfiguration::noticeOggQualityChanged (float q) +{ + m_ignore_gui_updates = true; + m_RecordingConfig.m_oggQuality = q; + setGUIEncoderQuality(m_RecordingConfig); + slotFormatSelectionChanged(); + m_ignore_gui_updates = false; + return true; +} + +bool RecordingConfiguration::noticeRecordingDirectoryChanged(const QString &dir) +{ + m_ignore_gui_updates = true; + m_RecordingConfig.m_Directory = dir; + setGUIDirectories(m_RecordingConfig); + slotFormatSelectionChanged(); + m_ignore_gui_updates = false; + return true; +} + +bool RecordingConfiguration::noticeOutputFormatChanged (RecordingConfig::OutputFormat of) +{ + m_ignore_gui_updates = true; + m_RecordingConfig.m_OutputFormat = of; + setGUIOutputFormat(m_RecordingConfig); + slotFormatSelectionChanged(); + m_ignore_gui_updates = false; + return true; +} + +bool RecordingConfiguration::noticePreRecordingChanged (bool enable, int seconds) +{ + m_ignore_gui_updates = true; + m_RecordingConfig.m_PreRecordingEnable = enable; + m_RecordingConfig.m_PreRecordingSeconds = seconds; + setGUIPreRecording(m_RecordingConfig); + m_ignore_gui_updates = false; + return true; +} + +bool RecordingConfiguration::noticeRecordingConfigChanged(const RecordingConfig &c) +{ + m_ignore_gui_updates = true; + m_RecordingConfig = c; + setGUIBuffers(c); + setGUIDirectories(c); + setGUISoundFormat(c); + setGUIOutputFormat(c); + setGUIEncoderQuality(c); + setGUIPreRecording(c); + slotFormatSelectionChanged(); + m_ignore_gui_updates = false; + return true; +} + +void RecordingConfiguration::slotSetDirty() +{ + if (!m_ignore_gui_updates) { + m_dirty = true; + } +} + + +#include "recording-configuration.moc" diff --git a/kradio3/plugins/recording/recording-configuration.h b/kradio3/plugins/recording/recording-configuration.h new file mode 100644 index 0000000..bf1b8f6 --- /dev/null +++ b/kradio3/plugins/recording/recording-configuration.h @@ -0,0 +1,126 @@ +/*************************************************************************** + recording-configuration.h - description + ------------------- + begin : So Aug 31 2003 + copyright : (C) 2003 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_RECORDING_CONFIGURATION_H +#define KRADIO_RECORDING_CONFIGURATION_H + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "../../src/include/soundformat.h" + +#include "recording-config.h" +#include "reccfg_interfaces.h" +#include "recording-configuration-ui.h" + +#define RATE_48000_IDX 0 +#define RATE_44100_IDX 1 +#define RATE_22050_IDX 2 +#define RATE_11025_IDX 3 + +#define CHANNELS_STEREO_IDX 0 +#define CHANNELS_MONO_IDX 1 + +#define SIGN_SIGNED_IDX 0 +#define SIGN_UNSIGNED_IDX 1 + +#define BITS_16_IDX 0 +#define BITS_8_IDX 1 + +#define ENDIAN_LITTLE_IDX 0 +#define ENDIAN_BIG_IDX 1 + +#define FORMAT_RAW_IDX 0 +#define FORMAT_WAV_IDX 1 +#define FORMAT_AIFF_IDX 2 +#define FORMAT_AU_IDX 3 +#define NEXT_IDX1 4 + +#define FORMAT_MP3_IDX_ORG 4 +#define FORMAT_OGG_IDX_ORG 5 + + +#ifdef HAVE_LAME + #define FORMAT_MP3_IDX NEXT_IDX1 + #define NEXT_IDX2 (NEXT_IDX1+1) +#else + #define FORMAT_MP3_IDX (-1) + #define NEXT_IDX2 NEXT_IDX1 +#endif + +#ifdef HAVE_OGG + #define FORMAT_OGG_IDX NEXT_IDX2 + #define NEXT_IDX3 (NEXT_IDX2+1) +#else + #define FORMAT_OGG_IDX (-1) + #define NEXT_IDX3 NEXT_IDX2 +#endif + + + + + + +class RecordingConfiguration : public RecordingConfigurationUI, + public IRecCfgClient +{ +Q_OBJECT +public : + RecordingConfiguration (QWidget *parent); + ~RecordingConfiguration (); + +// IRecCfgClient + + bool noticeEncoderBufferChanged (size_t BufferSize, size_t BufferCount); + bool noticeSoundFormatChanged (const SoundFormat &sf); + bool noticeMP3QualityChanged (int q); + bool noticeOggQualityChanged (float q); + bool noticeRecordingDirectoryChanged(const QString &dir); + bool noticeOutputFormatChanged (RecordingConfig::OutputFormat of); + bool noticePreRecordingChanged (bool enable, int seconds); + bool noticeRecordingConfigChanged (const RecordingConfig &cfg); + +protected slots: + + void slotOK(); + void slotCancel(); + void slotSetDirty(); + + void slotFormatSelectionChanged(); + +protected: + + void storeConfig(); + + void setGUIBuffers(const RecordingConfig &c); + void setGUIDirectories(const RecordingConfig &c); + void setGUISoundFormat(const RecordingConfig &c); + void setGUIOutputFormat(const RecordingConfig &c); + void setGUIPreRecording(const RecordingConfig &c); + void setGUIEncoderQuality(const RecordingConfig &c); + + RecordingConfig m_RecordingConfig; + + bool m_dirty; + bool m_ignore_gui_updates; +}; + + + + +#endif diff --git a/kradio3/plugins/recording/recording-datamonitor.cpp b/kradio3/plugins/recording/recording-datamonitor.cpp new file mode 100644 index 0000000..cd8e0f5 --- /dev/null +++ b/kradio3/plugins/recording/recording-datamonitor.cpp @@ -0,0 +1,278 @@ +/*************************************************************************** + recording-monitor-widget.cpp - description + ------------------- + begin : So Sep 7 2003 + copyright : (C) 2003 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 "recording-datamonitor.h" +//#include "recording-context.h" +#include <math.h> + +#include <qpainter.h> +#include <qimage.h> +#include <qpixmap.h> +#include <kimageeffect.h> // fading, blending, ... +#include <kpixmapio.h> // fast conversion between QPixmap/QImage +#include <limits.h> +#include <stdlib.h> + +#include <klocale.h> + +#define CHANNEL_H_MIN 20 +#define BLOCK_W_MIN 10 +#define W_MIN (20 * (BLOCK_W_MIN)) + +RecordingDataMonitor::RecordingDataMonitor(QWidget *parent, const char *name) + : QFrame(parent, name), + m_channelsMax(NULL), + m_channelsAvg(NULL), + m_maxValue(INT_MAX), + m_channels(0), + m_pActiveBlocks(NULL) +{ + setFrameStyle(Box | Sunken); + setLineWidth(1); + setMidLineWidth(1); + + setChannels(2); + + setColors(QColor(20, 244, 20), + QColor(10, 117, 10)); + + setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding)); +} + + +RecordingDataMonitor::~RecordingDataMonitor() +{ + if (m_channelsMax) delete[] m_channelsMax; + if (m_channelsAvg) delete[] m_channelsAvg; + if (m_pActiveBlocks) delete[] m_pActiveBlocks; +} + + + +// own stuff + +void RecordingDataMonitor::setChannels(int n) +{ + if (n != m_channels) { + if (m_channelsMax) delete[] m_channelsMax; + if (m_channelsAvg) delete[] m_channelsAvg; + if (m_pActiveBlocks) delete[] m_pActiveBlocks; + m_channels = n > 0 ? n : 0; + if (m_channels > 0) { + m_channelsMax = new int[m_channels]; + m_channelsAvg = new double[m_channels]; + m_pActiveBlocks = new int[m_channels]; + for (int i = 0; i < m_channels; ++i) { + m_pActiveBlocks[i] = 0; + } + } else { + m_channelsMax = NULL; + m_channelsAvg = NULL; + m_pActiveBlocks = NULL; + } + } + + for (int i = 0; i < m_channels; ++i) { + m_channelsMax[i] = 0; + m_channelsAvg[i] = 0; + } + setMinimumSize(QSize(W_MIN, (m_channels + 1 )* CHANNEL_H_MIN)); +} + + +// QT/KDE ... + +void RecordingDataMonitor::drawContents(QPainter *painter) +{ + if (painter) + internalDrawContents(*painter, true); +} + +void RecordingDataMonitor::internalDrawContents(QPainter &painter, bool repaintAll) +{ + if (m_channels <= 0) return; + QRect r = contentsRect(); + + QPen activePen (colorGroup().color(QColorGroup::Text), 1); + QPen inactivePen (colorGroup().color(QColorGroup::Mid), 1); + QBrush activeBrush = colorGroup().brush(QColorGroup::Text); + QBrush inactiveBrush = colorGroup().brush(QColorGroup::Mid); + QBrush yellowBrush(QColor(255,255,0)); + QBrush orangeBrush(QColor(255,192,0)); + QBrush redBrush (QColor(255,0, 0)); + + + double ranges [5] = { 0.75, 0.83, 0.91, 1.0, 999 }; + QBrush *brushes[5] = { &activeBrush, &yellowBrush, &orangeBrush, &redBrush, &redBrush }; + + painter.setBrush( isEnabled() ? activeBrush : inactiveBrush); + + int nBlocks = (r.width()-1) / BLOCK_W_MIN; + int xoffs = (r.width()-1) % BLOCK_W_MIN; + int chHeight = (r.height()-1-CHANNEL_H_MIN) / m_channels; + int yoffs = (r.height()-1) % m_channels; + + double min_dB = 20*log10(1 / (double)m_maxValue ); + + int x0 = xoffs/2 + r.top(); + int y = yoffs/2 + r.left(); + for (int c = 0; c < m_channels; ++c) { + int x = x0; + + + int startBlock = 0; + int endBlock = nBlocks - 1; + int oldActiveBlocks = m_pActiveBlocks[c]; + + double dBMax = isEnabled() ? 20*log10(m_channelsMax[c] / (double)m_maxValue ) : min_dB; + + m_pActiveBlocks[c] = m_channelsMax[c] ? (int)rint(nBlocks * (min_dB - dBMax) / min_dB) : 0; + + if (!repaintAll) { + if (oldActiveBlocks > m_pActiveBlocks[c]) { + startBlock = m_pActiveBlocks[c]; + endBlock = oldActiveBlocks - 1; + } else { + startBlock = oldActiveBlocks; + endBlock = m_pActiveBlocks[c]-1; + } + } + + int range = 0; + + x += BLOCK_W_MIN * startBlock; + for (int b = startBlock; b <= endBlock; ++b) { + while (b >= nBlocks * ranges[range]) ++range; + painter.fillRect(x+1, y+1, BLOCK_W_MIN-1, chHeight-1, + b < m_pActiveBlocks[c] ? *brushes[range] : inactiveBrush); + x += BLOCK_W_MIN; + } + + y += chHeight; + } + + if (repaintAll) { + QFont f("Helvetica"); + painter.setPen (activePen); + f.setPixelSize(CHANNEL_H_MIN); + painter.setFont(f); + + int maxW = QFontMetrics(f).width(i18n("%1 dB").arg((int)min_dB)); + int delta_dB = 5; + while (abs((long)min_dB) / delta_dB * maxW * 2 > r.width()) delta_dB *= 2; + + for (int dB = 0; dB >= min_dB; dB -= delta_dB) { + QString txt = i18n("%1 dB").arg(dB); + int w = QFontMetrics(f).width(txt); + int x = x0 + (int)(nBlocks * BLOCK_W_MIN * (min_dB - dB) / min_dB) - w; + if (x < x0) continue; + painter.drawText(x, y + CHANNEL_H_MIN, txt); + } + } +} + + +bool RecordingDataMonitor::setColors(const QColor &activeText, + const QColor &button) +{ + m_colorActiveText = activeText; + m_colorButton = button; + + QPalette pl = palette(); + QColorGroup cg = pl.inactive(); + + QBrush fg = cg.brush(QColorGroup::Foreground), + btn = cg.brush(QColorGroup::Button), + lgt = cg.brush(QColorGroup::Light), + drk = cg.brush(QColorGroup::Dark), + mid = cg.brush(QColorGroup::Mid), + txt = cg.brush(QColorGroup::Text), + btx = cg.brush(QColorGroup::BrightText), + bas = cg.brush(QColorGroup::Base), + bg = cg.brush(QColorGroup::Background); + + fg.setColor (m_colorActiveText); + btn.setColor(m_colorButton); + lgt.setColor(m_colorButton.light(180)); + drk.setColor(m_colorButton.light( 50)); + mid.setColor(m_colorButton.light( 75)); + txt.setColor(m_colorActiveText); + btx.setColor(m_colorActiveText); + bas.setColor(m_colorButton); + bg.setColor (m_colorButton); + + QColorGroup ncg(fg, btn, lgt, drk, mid, txt, btx, bas, bg); + pl.setInactive(ncg); + pl.setActive(ncg); + setPalette(pl); + + if (parentWidget() && parentWidget()->backgroundPixmap() ){ + KPixmapIO io; + QImage i = io.convertToImage(*parentWidget()->backgroundPixmap()); + KImageEffect::fade(i, 0.5, colorGroup().color(QColorGroup::Dark)); + setPaletteBackgroundPixmap(io.convertToPixmap(i)); + setBackgroundOrigin(WindowOrigin); + } else { + setBackgroundColor(colorGroup().color(QColorGroup::Button)); + } + + return true; +} + + +bool RecordingDataMonitor::noticeSoundStreamData(SoundStreamID /*id*/, + const SoundFormat &sf, const char *data, size_t size, size_t &/*consumed_size*/, + const SoundMetaData &/*md*/ +) +{ + if (!isEnabled()) + return false; + int nSamples = size / sf.frameSize(); + int sample_size = sf.sampleSize(); + + int bias = 0; + setChannels(sf.m_Channels); + int old_max = m_maxValue; + m_maxValue = sf.maxValue(); + if (!sf.m_IsSigned) { + m_maxValue /= 2; + bias = -m_maxValue; + } + + int c = 0; + for (int s = 0; s < nSamples; ++s, ++c, data += sample_size) { + if (c >= m_channels) c -= m_channels; // avoid slow c = s % m_channels + + int &m = m_channelsMax[c]; + int x = abs(sf.convertSampleToInt(data, false) + bias); + if (m < x) m = x; + m_channelsAvg[c] += x; + } + for (int i = 0; i < m_channels; ++i) + m_channelsAvg[i] /= nSamples; + + QPainter paint(this); + if (m_maxValue != old_max) { + repaint(true); + } else { + internalDrawContents(paint, false); + } + return true; +} + + +#include "recording-datamonitor.moc" diff --git a/kradio3/plugins/recording/recording-datamonitor.h b/kradio3/plugins/recording/recording-datamonitor.h new file mode 100644 index 0000000..c0b7c40 --- /dev/null +++ b/kradio3/plugins/recording/recording-datamonitor.h @@ -0,0 +1,66 @@ +/*************************************************************************** + recording-monitor-widget.h - description + ------------------- + begin : So Sep 7 2003 + copyright : (C) 2003 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_RECORDING_DATA_MONITOR +#define KRADIO_RECORDING_DATA_MONITOR + +#include <qframe.h> +#include <qcolor.h> + +//#include <kradio/interfaces/recording-interfaces.h> +#include "../../src/include/soundstreamclient_interfaces.h" + +class RecordingDataMonitor : public QFrame//, + //public ISoundStreamClient + //public IRecordingClient +{ +Q_OBJECT +public: + RecordingDataMonitor(QWidget *parent, const char *name); + ~RecordingDataMonitor(); + + bool noticeSoundStreamData(SoundStreamID id, + const SoundFormat &sf, const char *data, size_t size, size_t &consumed_size, + const SoundMetaData &md); + +// QT/KDE ... + +protected: + + void drawContents(QPainter *p); + void internalDrawContents(QPainter &painter, bool repaintAll); +// own stuff ... + +protected: + + void setChannels(int n); + bool setColors(const QColor &activeColor, const QColor &bkgnd); + +// data +protected: + + int *m_channelsMax; // maximum absolute value recorded on each channel + double *m_channelsAvg; // average value recorded on each channel + int m_maxValue; // maximum absolute value possible for samples + int m_channels; + + QColor m_colorActiveText, m_colorButton; + + int *m_pActiveBlocks; +}; + +#endif diff --git a/kradio3/plugins/recording/recording-monitor.cpp b/kradio3/plugins/recording/recording-monitor.cpp new file mode 100644 index 0000000..5d6dbf9 --- /dev/null +++ b/kradio3/plugins/recording/recording-monitor.cpp @@ -0,0 +1,402 @@ +/*************************************************************************** + recording-monitor.cpp - description + ------------------- + begin : Mo Sep 1 2003 + copyright : (C) 2003 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 "recording-monitor.h" +#include "recording-datamonitor.h" +#include "../../src/include/aboutwidget.h" + +#include <qlabel.h> +#include <qpushbutton.h> +#include <qlayout.h> +#include <qcheckbox.h> +#include <kcombobox.h> + +#include <klocale.h> +#include <kconfig.h> +#include <kaboutdata.h> + +RecordingMonitor::RecordingMonitor(const QString &name) + : QWidget(NULL, name.ascii()), + WidgetPluginBase(name, i18n("Recording Monitor")), + m_recording(false), + m_defaultStreamDescription(QString::null) +{ + setCaption(i18n("KRadio Recording Monitor")); + + QVBoxLayout *l = new QVBoxLayout(this, 10, 4); + QGridLayout *l0 = new QGridLayout(l, 6, 2); + + l0->addWidget( new QLabel(i18n("SoundStream"), this), 0, 0); + l0->addWidget(m_comboSoundStreamSelector = new KComboBox( this), 0, 1); + l0->addWidget( new QLabel(i18n("Status"), this), 1, 0); + l0->addWidget(m_labelStatus = new QLabel(i18n("<undefined>"), this), 1, 1); + l0->addWidget( new QLabel(i18n("Recording File"), this), 2, 0); + l0->addWidget(m_labelFileName = new QLabel(i18n("<undefined>"), this), 2, 1); + l0->addWidget( new QLabel(i18n("File Size"), this), 3, 0); + l0->addWidget(m_labelSize = new QLabel(i18n("<undefined>"), this), 3, 1); + l0->addWidget( new QLabel(i18n("Recording Time"), this), 4, 0); + l0->addWidget(m_labelTime = new QLabel(i18n("<undefined>"), this), 4, 1); + l0->addWidget( new QLabel(i18n("Sample Rate"), this), 5, 0); + l0->addWidget(m_labelRate = new QLabel(i18n("<undefined>"), this), 5, 1); + + QPushButton *close = new QPushButton(i18n("&Close"), this); + m_btnStartStop = new QPushButton(i18n("&Record"), this); + QObject::connect(close, SIGNAL(clicked()), this, SLOT(hide())); + QObject::connect(m_btnStartStop, SIGNAL(clicked()), this, SLOT(slotStartStopRecording())); + + m_dataMonitor = new RecordingDataMonitor(this, NULL); + m_dataMonitor->setEnabled(false); + + QHBoxLayout *hl0 = new QHBoxLayout(l); + hl0->addWidget(m_dataMonitor); + + QHBoxLayout *hl2 = new QHBoxLayout(l); + hl2->addItem(new QSpacerItem(10, 1)); + hl2->addWidget(close); + hl2->addWidget(m_btnStartStop); + hl2->addItem(new QSpacerItem(10, 1)); + + + m_comboSoundStreamSelector->insertItem(i18n("nothing")); + QObject::connect(m_comboSoundStreamSelector, SIGNAL(activated(int)), this, SLOT(slotStreamSelected(int))); + + updateRecordingButton(); +} + + +RecordingMonitor::~RecordingMonitor() +{ +} + +// WidgetPluginBase + +void RecordingMonitor::saveState (KConfig *config) const +{ + config->setGroup(QString("recordingmonitor-") + name()); + + WidgetPluginBase::saveState(config); +} + + +void RecordingMonitor::restoreState (KConfig *config) +{ + config->setGroup(QString("recordingmonitor-") + name()); + + WidgetPluginBase::restoreState(config, false); +} + + +bool RecordingMonitor::connectI(Interface *i) +{ + bool a = ISoundStreamClient::connectI(i); + bool b = WidgetPluginBase::connectI(i); + return a || b; +} + +bool RecordingMonitor::disconnectI(Interface *i) +{ + bool a = ISoundStreamClient::disconnectI(i); + bool b = WidgetPluginBase::disconnectI(i); + if (a) { + m_comboSoundStreamSelector->clear(); + m_SoundStreamID2idx.clear(); + m_idx2SoundStreamID.clear(); + m_comboSoundStreamSelector->insertItem(i18n("nothing")); + } + return a || b; +} + + +void RecordingMonitor::noticeConnectedI (ISoundStreamServer *s, bool pointer_valid) +{ + ISoundStreamClient::noticeConnectedI(s, pointer_valid); + if (s && pointer_valid) { + s->register4_notifySoundStreamCreated(this); + s->register4_notifySoundStreamClosed(this); + s->register4_notifySoundStreamChanged(this); + s->register4_notifySoundStreamData(this); + s->register4_sendStartRecordingWithFormat(this); + s->register4_sendStopRecording(this); + + QMap<QString, SoundStreamID> tmp; + queryEnumerateSoundStreams(tmp); + + m_comboSoundStreamSelector->clear(); + m_SoundStreamID2idx.clear(); + m_idx2SoundStreamID.clear(); + m_comboSoundStreamSelector->insertItem(i18n("nothing")); + QMapConstIterator<QString, SoundStreamID> end = tmp.end(); + for (QMapConstIterator<QString, SoundStreamID> it = tmp.begin(); it != end; ++it) { + int idx = m_comboSoundStreamSelector->count(); + m_comboSoundStreamSelector->insertItem(it.key()); + m_idx2SoundStreamID[idx] = *it; + m_SoundStreamID2idx[*it] = idx; + } + } +} + +ConfigPageInfo RecordingMonitor::createConfigurationPage() +{ + return ConfigPageInfo(); +} + +AboutPageInfo RecordingMonitor::createAboutPage() +{ +/* KAboutData aboutData("kradio", + NULL, + NULL, + I18N_NOOP("Recording Monitor Plugin for KRadio"), + KAboutData::License_GPL, + "(c) 2002-2005 Martin Witte", + 0, + "http://sourceforge.net/projects/kradio", + 0); + aboutData.addAuthor("Martin Witte", "", "witte@kawo1.rwth-aachen.de"); + + return AboutPageInfo( + new KRadioAboutWidget(aboutData, KRadioAboutWidget::AbtTabbed), + i18n("Recording Monitor"), + i18n("Recording Monitor Plugin"), + "goto" + ); +*/ + return AboutPageInfo(); +} + + +void RecordingMonitor::show() +{ + WidgetPluginBase::pShow(); + QWidget::show(); +} + + +void RecordingMonitor::showOnOrgDesktop() +{ + WidgetPluginBase::pShowOnOrgDesktop(); + //QWidget::show(); +} + +void RecordingMonitor::hide() +{ + WidgetPluginBase::pHide(); + QWidget::hide(); +} + + +void RecordingMonitor::showEvent(QShowEvent *e) +{ + QWidget::showEvent(e); + WidgetPluginBase::pShowEvent(e); + //m_comboSoundStreamSelector->setCurrentItem(1); + //slotStreamSelected(1); +} + + +void RecordingMonitor::hideEvent(QHideEvent *e) +{ + QWidget::hideEvent(e); + WidgetPluginBase::pHideEvent(e); + m_comboSoundStreamSelector->setCurrentItem(0); + slotStreamSelected(0); +} + + +void RecordingMonitor::slotStartStopRecording() +{ + if (m_currentStream.isValid()) { + if (m_recording) { + sendStopRecording(m_currentStream); + } else { + sendStartRecording(m_currentStream); + } + } + updateRecordingButton(); +} + + +bool RecordingMonitor::noticeSoundStreamCreated(SoundStreamID id) +{ + QString tmp = QString::null; + querySoundStreamDescription(id, tmp); + + int idx = m_comboSoundStreamSelector->count(); + m_comboSoundStreamSelector->insertItem(tmp); + m_idx2SoundStreamID[idx] = id; + m_SoundStreamID2idx[id] = idx; + + if (tmp == m_defaultStreamDescription) { + m_comboSoundStreamSelector->setCurrentItem(idx); + slotStreamSelected(idx); + } + return true; +} + + +bool RecordingMonitor::noticeSoundStreamClosed(SoundStreamID id) +{ + if (m_SoundStreamID2idx.contains(id)) { + int idx = m_SoundStreamID2idx[id]; + m_idx2SoundStreamID.clear(); + m_SoundStreamID2idx.remove(id); + QMapIterator<SoundStreamID, int> end = m_SoundStreamID2idx.end(); + for (QMapIterator<SoundStreamID, int> it = m_SoundStreamID2idx.begin(); it != end; ++it) { + if (*it > idx) { + (*it)--; + } + m_idx2SoundStreamID[*it] = it.key(); + } + m_comboSoundStreamSelector->removeItem(idx); + slotStreamSelected(m_comboSoundStreamSelector->currentItem()); + return true; + } + return false; +} + + +bool RecordingMonitor::noticeSoundStreamChanged(SoundStreamID id) +{ + if (m_SoundStreamID2idx.contains(id)) { + int idx = m_SoundStreamID2idx[id]; + QString tmp = QString::null; + querySoundStreamDescription(id, tmp); + m_comboSoundStreamSelector->changeItem(tmp, idx); + if (idx == m_comboSoundStreamSelector->currentItem()) { + m_defaultStreamDescription = tmp; + } + return true; + } + return false; +} + +bool RecordingMonitor::startRecordingWithFormat(SoundStreamID id, const SoundFormat &/*sf*/, SoundFormat &/*real_format*/) +{ + if (id == m_currentStream) { + m_recording = true; + updateRecordingButton(); + } + return false; +} + +bool RecordingMonitor::stopRecording(SoundStreamID id) +{ + if (id == m_currentStream) { + m_recording = false; + updateRecordingButton(); + } + return false; +} + +bool RecordingMonitor::noticeSoundStreamData(SoundStreamID id, + const SoundFormat &sf, const char *data, size_t size, size_t &consumed_size, + const SoundMetaData &md +) +{ + if (m_idx2SoundStreamID[m_comboSoundStreamSelector->currentItem()] == id) { + + m_labelFileName->setText(md.url().url()); + + double B = (double)md.position() + (double)size; + + double s = md.relativeTimestamp(); + + int m = (int)(s / 60); s -= 60 * m; + int h = m / 60; m %= 60; + int d = h / 24; h %= 24; + QString time; + if (d) { + time.sprintf("%dd - %02d:%02d:%05.2f", d, h, m, s); + } else { + time.sprintf("%02d:%02d:%05.2f", h, m, s); + } + m_labelTime->setText(time); + + if (sf.m_Encoding == "raw") { + m_dataMonitor->setEnabled(true); + m_dataMonitor->noticeSoundStreamData(id, sf, data, size, consumed_size, md); + } else { + m_dataMonitor->setEnabled(false); + } + + double kB = B / 1024; + double MB = kB / 1024; + double GB = MB / 1024; + QString str_size; + str_size = i18n("%1 Byte").arg(KGlobal::locale()->formatNumber((int)B, 0)); + if (kB > 1) str_size = i18n("%1 kB").arg(KGlobal::locale()->formatNumber(kB, 3)); + if (MB > 1) str_size = i18n("%1 MB").arg(KGlobal::locale()->formatNumber(MB, 3)); + if (GB > 1) str_size = i18n("%1 GB").arg(KGlobal::locale()->formatNumber(GB, 3)); + m_labelSize->setText(str_size); + + m_labelRate->setText(i18n("%1 Hz").arg(sf.m_SampleRate)); + return true; + } + return false; +} + + +void RecordingMonitor::slotStreamSelected(int idx) +{ + SoundStreamID old_id = m_currentStream; + if (old_id.isValid()) { + sendStopCapture(old_id); + } + + SoundStreamID id = m_idx2SoundStreamID.contains(idx) ? m_idx2SoundStreamID[idx] : SoundStreamID::InvalidID; + if (id.isValid()) { + + m_defaultStreamDescription = m_comboSoundStreamSelector->text(idx); + + SoundFormat sf; + sendStartCaptureWithFormat(id, sf, sf); + m_dataMonitor ->setEnabled(true); + m_labelSize ->setEnabled(true); + m_labelSize ->setEnabled(true); + m_labelTime ->setEnabled(true); + m_labelRate ->setEnabled(true); + m_labelFileName ->setEnabled(true); + m_labelStatus ->setEnabled(true); + } else { + m_dataMonitor ->setEnabled(false); + m_labelSize ->setEnabled(false); + m_labelSize ->setEnabled(false); + m_labelTime ->setEnabled(false); + m_labelRate ->setEnabled(false); + m_labelFileName ->setEnabled(false); + m_labelStatus ->setEnabled(false); + } + m_currentStream = id; + m_recording = false; + SoundFormat sf; + queryIsRecordingRunning(m_currentStream, m_recording, sf); + updateRecordingButton(); +} + + +void RecordingMonitor::updateRecordingButton() +{ + if (m_currentStream.isValid()) { + m_btnStartStop->setText(!m_recording ? i18n("&Record") : i18n("&Stop Recording")); + m_btnStartStop->setEnabled(true); + } else { + m_btnStartStop->setText(i18n("&Record")); + m_btnStartStop->setEnabled(false); + } +} + + +#include "recording-monitor.moc" diff --git a/kradio3/plugins/recording/recording-monitor.h b/kradio3/plugins/recording/recording-monitor.h new file mode 100644 index 0000000..c34e927 --- /dev/null +++ b/kradio3/plugins/recording/recording-monitor.h @@ -0,0 +1,124 @@ +/*************************************************************************** + recording-monitor.h - description + ------------------- + begin : Mo Sep 1 2003 + copyright : (C) 2003 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_RECORDING_MONITOR_H +#define KRADIO_RECORDING_MONITOR_H + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <qwidget.h> + +#include "../../src/include/widgetplugins.h" +#include "../../src/include/soundstreamclient_interfaces.h" +//#include <kradio/interfaces/recording-interfaces.h> + + +class QLabel; +class QPushButton; +class QCheckBox; +class RecordingDataMonitor; +class KComboBox; + +class RecordingMonitor : public QWidget, + public WidgetPluginBase, + public ISoundStreamClient + //public IRecordingClient +{ +Q_OBJECT +public: + + RecordingMonitor(const QString &name); + virtual ~RecordingMonitor(); + + const QString &name() const { return PluginBase::name(); } + QString &name() { return PluginBase::name(); } + + virtual QString pluginClassName() const { return "RecordingMonitor"; } + + // WidgetPluginBase + +public: + virtual void saveState (KConfig *) const; + virtual void restoreState (KConfig *); + + virtual bool connectI(Interface *i); + virtual bool disconnectI(Interface *i); + + virtual ConfigPageInfo createConfigurationPage(); + virtual AboutPageInfo createAboutPage(); + + // IRecordingClient + + void noticeConnectedI (ISoundStreamServer *s, bool pointer_valid); + + bool noticeSoundStreamCreated(SoundStreamID id); + bool noticeSoundStreamClosed(SoundStreamID id); + bool noticeSoundStreamChanged(SoundStreamID id); + + bool startRecordingWithFormat(SoundStreamID id, const SoundFormat &sf, SoundFormat &real_format); + bool stopRecording(SoundStreamID id); + + bool noticeSoundStreamData(SoundStreamID id, const SoundFormat &sf, const char *data, size_t size, size_t &consumed_size, const SoundMetaData &md); + +public slots: + + void toggleShown() { WidgetPluginBase::pToggleShown(); } + void showOnOrgDesktop(); + void show(); + void hide(); + + void slotStartStopRecording(); + + void slotStreamSelected(int idx); + +protected: + + virtual void updateRecordingButton(); + + virtual void showEvent(QShowEvent *); + virtual void hideEvent(QHideEvent *); + + const QWidget *getWidget() const { return this; } + QWidget *getWidget() { return this; } + + +protected: + + QLabel *m_labelSize; + QLabel *m_labelTime; + QLabel *m_labelRate; + QLabel *m_labelFileName; + QLabel *m_labelStatus; + QPushButton *m_btnStartStop; + + KComboBox *m_comboSoundStreamSelector; + QMap<SoundStreamID, int> m_SoundStreamID2idx; + QMap<int, SoundStreamID> m_idx2SoundStreamID; + + SoundStreamID m_currentStream; + RecordingDataMonitor *m_dataMonitor; + + bool m_recording; + QString m_defaultStreamDescription; +}; + + + + +#endif diff --git a/kradio3/plugins/recording/recording.cpp b/kradio3/plugins/recording/recording.cpp new file mode 100644 index 0000000..b2222ab --- /dev/null +++ b/kradio3/plugins/recording/recording.cpp @@ -0,0 +1,736 @@ +/*************************************************************************** + recording.cpp - description + ------------------- + begin : Mi Aug 27 2003 + copyright : (C) 2003 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 "../../src/include/radiostation.h" +#include "../../src/include/errorlog-interfaces.h" +#include "../../src/include/aboutwidget.h" +#include "../../src/include/fileringbuffer.h" +#include "../../src/include/utils.h" + +#include "recording.h" +#include "recording-configuration.h" +#include "soundstreamevent.h" +#include "recording-monitor.h" +#include "encoder_mp3.h" +#include "encoder_ogg.h" +#include "encoder_pcm.h" + +#include <qevent.h> +#include <qapplication.h> +#include <qregexp.h> + +#include <kconfig.h> +#include <kdeversion.h> + +#include <kaboutdata.h> + + +/////////////////////////////////////////////////////////////////////// +//// plugin library functions + +PLUGIN_LIBRARY_FUNCTIONS2( + Recording, "kradio-recording", i18n("KRadio Recording Plugin"), + RecordingMonitor, i18n("KRadio Recording Monitor") +); + +/////////////////////////////////////////////////////////////////////// + +Recording::Recording(const QString &name) + : QObject(NULL, NULL), + PluginBase(name, i18n("KRadio Recording Plugin")), + m_config() +{ +} + + +Recording::~Recording() +{ + QMapIterator<SoundStreamID, RecordingEncoding*> it = m_EncodingThreads.begin(); + QMapIterator<SoundStreamID, RecordingEncoding*> end = m_EncodingThreads.end(); + for (; it != end; ++it) { + sendStopRecording(it.key()); + } +} + + +bool Recording::connectI(Interface *i) +{ + bool a = IRecCfg::connectI(i); + bool b = PluginBase::connectI(i); + bool c = ISoundStreamClient::connectI(i); + return a || b || c; +} + + +bool Recording::disconnectI(Interface *i) +{ + bool a = IRecCfg::disconnectI(i); + bool b = PluginBase::disconnectI(i); + bool c = ISoundStreamClient::disconnectI(i); + return a || b || c; +} + + +void Recording::noticeConnectedI (ISoundStreamServer *s, bool pointer_valid) +{ + ISoundStreamClient::noticeConnectedI(s, pointer_valid); + if (s && pointer_valid) { + s->register4_sendStartPlayback(this); + s->register4_sendStopPlayback(this); + s->register4_sendStartRecording(this); + s->register4_sendStartRecordingWithFormat(this); + s->register4_notifySoundStreamData(this); + s->register4_sendStopRecording(this); + s->register4_queryIsRecordingRunning(this); + s->register4_querySoundStreamDescription(this); + s->register4_querySoundStreamRadioStation(this); + s->register4_queryEnumerateSoundStreams(this); + s->register4_notifySoundStreamChanged(this); + s->register4_notifySoundStreamClosed(this); + } +} + +// PluginBase + +void Recording::saveState (KConfig *c) const +{ + c->setGroup(QString("recording-") + PluginBase::name()); + m_config.saveConfig(c); +} + + +void Recording::restoreState (KConfig *c) +{ + c->setGroup(QString("recording-") + PluginBase::name()); + RecordingConfig cfg; + cfg.restoreConfig(c); + setRecordingConfig(cfg); + //notifyRecordingConfigChanged(m_config); +} + + +ConfigPageInfo Recording::createConfigurationPage() +{ + RecordingConfiguration *c = new RecordingConfiguration(NULL); + connectI(c); + return ConfigPageInfo(c, + i18n("Recording"), + i18n("Recording"), + "kradio_record"); +} + + +AboutPageInfo Recording::createAboutPage() +{ +/* KAboutData aboutData("kradio", + NULL, + NULL, + I18N_NOOP("Recording Monitor for KRadio"), + KAboutData::License_GPL, + "(c) 2002-2005 Martin Witte", + 0, + "http://sourceforge.net/projects/kradio", + 0); + aboutData.addAuthor("Martin Witte", "", "witte@kawo1.rwth-aachen.de"); + + return AboutPageInfo( + new KRadioAboutWidget(aboutData, KRadioAboutWidget::AbtTabbed), + i18n("Recording"), + i18n("Recording Plugin"), + "kradio_record" + );*/ + return AboutPageInfo(); +} + + +// IRecCfg + +bool Recording::setEncoderBuffer (size_t BufferSize, size_t BufferCount) +{ + if (m_config.m_EncodeBufferSize != BufferSize || + m_config.m_EncodeBufferCount != BufferCount) + { + m_config.m_EncodeBufferSize = BufferSize; + m_config.m_EncodeBufferCount = BufferCount; + notifyEncoderBufferChanged(BufferSize, BufferCount); + } + return true; +} + +bool Recording::setSoundFormat (const SoundFormat &sf) +{ + if (m_config.m_SoundFormat != sf) { + m_config.m_SoundFormat = sf; + notifySoundFormatChanged(sf); + } + return true; +} + +bool Recording::setMP3Quality (int q) +{ + if (m_config.m_mp3Quality != q) { + m_config.m_mp3Quality = q; + notifyMP3QualityChanged(q); + } + return true; +} + +bool Recording::setOggQuality (float q) +{ + if (m_config.m_oggQuality != q) { + m_config.m_oggQuality = q; + notifyOggQualityChanged(q); + } + return true; +} + +bool Recording::setRecordingDirectory(const QString &dir) +{ + if (m_config.m_Directory != dir) { + m_config.m_Directory = dir; + notifyRecordingDirectoryChanged(dir); + } + return true; +} + +bool Recording::setOutputFormat (RecordingConfig::OutputFormat of) +{ + if (m_config.m_OutputFormat != of) { + m_config.m_OutputFormat = of; + notifyOutputFormatChanged(of); + } + return true; +} + +bool Recording::setPreRecording (bool enable, int seconds) +{ + if (m_config.m_PreRecordingEnable != enable || m_config.m_PreRecordingSeconds != seconds) { + m_config.m_PreRecordingEnable = enable; + m_config.m_PreRecordingSeconds = seconds; + + if (enable) { + for (QMapIterator<SoundStreamID,FileRingBuffer*> it = m_PreRecordingBuffers.begin(); it != m_PreRecordingBuffers.end(); ++it) { + if (*it != NULL) { + delete *it; + } + *it = new FileRingBuffer(m_config.m_Directory + "/kradio-prerecord-"+QString::number(it.key().getID()), m_config.m_PreRecordingSeconds * m_config.m_SoundFormat.m_SampleRate * m_config.m_SoundFormat.frameSize()); + SoundFormat sf = m_config.m_SoundFormat; + sendStartCaptureWithFormat(it.key(), sf, sf, false); + } + } + else { + for (QMapIterator<SoundStreamID,FileRingBuffer*> it = m_PreRecordingBuffers.begin(); it != m_PreRecordingBuffers.end(); ++it) { + if (*it != NULL) { + sendStopCapture(it.key()); + delete *it; + } + } + m_PreRecordingBuffers.clear(); + } + + notifyPreRecordingChanged(enable, seconds); + } + return true; +} + +void Recording::getEncoderBuffer(size_t &BufferSize, size_t &BufferCount) const +{ + BufferSize = m_config.m_EncodeBufferSize; + BufferCount = m_config.m_EncodeBufferCount; +} + +const SoundFormat &Recording::getSoundFormat () const +{ + return m_config.m_SoundFormat; +} + +int Recording::getMP3Quality () const +{ + return m_config.m_mp3Quality; +} + +float Recording::getOggQuality () const +{ + return m_config.m_oggQuality; +} + +const QString &Recording::getRecordingDirectory() const +{ + return m_config.m_Directory; +} + +RecordingConfig::OutputFormat Recording::getOutputFormat() const +{ + return m_config.m_OutputFormat; +} + +bool Recording::getPreRecording(int &seconds) const +{ + seconds = m_config.m_PreRecordingSeconds; + return m_config.m_PreRecordingEnable; +} + +const RecordingConfig &Recording::getRecordingConfig() const +{ + return m_config; +} + +bool Recording::setRecordingConfig(const RecordingConfig &c) +{ + setEncoderBuffer (c.m_EncodeBufferSize, c.m_EncodeBufferCount); + setSoundFormat (c.m_SoundFormat); + setMP3Quality (c.m_mp3Quality); + setOggQuality (c.m_oggQuality); + setRecordingDirectory(c.m_Directory); + setOutputFormat (c.m_OutputFormat); + setPreRecording (c.m_PreRecordingEnable, c.m_PreRecordingSeconds); + + m_config = c; + + notifyRecordingConfigChanged(m_config); + + return true; +} + + +// ISoundStreamClient +bool Recording::startPlayback(SoundStreamID id) +{ + if (m_PreRecordingBuffers.contains(id)) + delete m_PreRecordingBuffers[id]; + m_PreRecordingBuffers[id] = NULL; + if (m_config.m_PreRecordingEnable) { + m_PreRecordingBuffers[id] = new FileRingBuffer(m_config.m_Directory + "/kradio-prerecord-"+QString::number(id.getID()), m_config.m_PreRecordingSeconds * m_config.m_SoundFormat.m_SampleRate * m_config.m_SoundFormat.frameSize()); + SoundFormat sf = m_config.m_SoundFormat; + sendStartCaptureWithFormat(id, sf, sf, false); + } + return false; +} + +bool Recording::stopPlayback(SoundStreamID id) +{ + if (m_PreRecordingBuffers.contains(id)) { + if (m_PreRecordingBuffers[id]) + delete m_PreRecordingBuffers[id]; + m_PreRecordingBuffers.remove(id); + sendStopCapture(id); + } + return false; +} + +bool Recording::startRecording(SoundStreamID id) +{ + +/* FileRingBuffer *test = new FileRingBuffer("/tmp/ringbuffertest", 2048); + char buffer1[1024]; + char buffer2[1024]; + char buffer3[1024]; + for (int i = 0; i < 1024; ++i) { + buffer1[i] = 'a'; + buffer2[i] = 'b'; + buffer3[i] = 'c'; + } + test->addData(buffer1, 1024); + test->addData(buffer2, 1024); + test->removeData(1024); + test->addData(buffer3, 1024); +*/ + + SoundFormat realFormat = m_config.m_SoundFormat; + return sendStartRecordingWithFormat(id, realFormat, realFormat); +} + +bool Recording::startRecordingWithFormat(SoundStreamID id, const SoundFormat &sf, SoundFormat &real_format) +{ + if (!sendStartCaptureWithFormat(id, sf, real_format, /* force_format = */ true)) { + logError(i18n("start capture not handled")); + return false; + } + + RecordingConfig cfg = m_config; + cfg.m_SoundFormat = real_format; + + logInfo(i18n("Recording starting")); + if (!startEncoder(id, cfg)) { + logError(i18n("starting encoding thread failed")); + sendStopCapture(id); + return false; + } + + return true; +} + + +bool Recording::stopRecording(SoundStreamID id) +{ + if (m_EncodingThreads.contains(id)) { + sendStopCapture(id); + if (m_config.m_PreRecordingEnable) { + if (!m_PreRecordingBuffers.contains(id)) { + if (m_PreRecordingBuffers[id] != NULL) { + delete m_PreRecordingBuffers[id]; + } + bool b = false; + queryIsPlaybackRunning(id, b); + if (b) { + m_PreRecordingBuffers[id] = new FileRingBuffer(m_config.m_Directory + "/kradio-prerecord-"+QString::number(id.getID()), m_config.m_PreRecordingSeconds * m_config.m_SoundFormat.m_SampleRate * m_config.m_SoundFormat.frameSize()); + } else { + m_PreRecordingBuffers[id] = NULL; + } + } + } + stopEncoder(id); + return true; + } + return false; +} + + + +bool Recording::noticeSoundStreamData(SoundStreamID id, + const SoundFormat &/*sf*/, const char *data, size_t size, size_t &consumed_size, + const SoundMetaData &md +) +{ + if (m_PreRecordingBuffers.contains(id) && m_PreRecordingBuffers[id] != NULL) { + + FileRingBuffer &fbuf = *m_PreRecordingBuffers[id]; + if (fbuf.getFreeSize() < size) { + fbuf.removeData(size - fbuf.getFreeSize()); + } + size_t n = fbuf.addData(data, size); + consumed_size = (consumed_size == SIZE_T_DONT_CARE) ? n : min(consumed_size, n); +// if (n != size) { +// logDebug("recording packet: was not written completely to tmp buf"); +// } + +// //BEGIN DEBUG +// char tmp[4096]; +// for (unsigned int i = 0; i < sizeof(tmp); ++i) { tmp[i] = 0; } +// if (fbuf.getFreeSize() < sizeof(tmp)) { +// fbuf.removeData(sizeof(tmp) - fbuf.getFreeSize()); +// } +// fbuf.addData((char*)tmp, sizeof(tmp)); +// //END DEBUG + + if (m_EncodingThreads.contains(id)) { + + //logDebug("recording packet: " + QString::number(size)); + + RecordingEncoding *thread = m_EncodingThreads[id]; + + //logDebug("noticeSoundStreamData thread = " + QString::number((long long)thread, 16)); + + size_t remSize = fbuf.getFillSize(); + + while (remSize > 0) { + size_t bufferSize = remSize; + char *buf = thread->lockInputBuffer(bufferSize); + if (!buf) { + // Encoder buffer is full and bigger than remaining data + break; + } + if (bufferSize > remSize) { + bufferSize = remSize; + } + if (fbuf.takeData(buf, bufferSize) != bufferSize) { + logError(i18n("could not read suffient data")); + } + + thread->unlockInputBuffer(bufferSize, md); + remSize -= bufferSize; + } + + if (remSize == 0) { + delete m_PreRecordingBuffers[id]; + m_PreRecordingBuffers.remove(id); + } + } + + return true; + } + + else if (m_EncodingThreads.contains(id)) { + + //logDebug("recording packet: " + QString::number(size)); + + RecordingEncoding *thread = m_EncodingThreads[id]; + + //logDebug("noticeSoundStreamData thread = " + QString::number((long long)thread, 16)); + + size_t remSize = size; + const char *remData = data; + + while (remSize > 0) { + size_t bufferSize = remSize; + char *buf = thread->lockInputBuffer(bufferSize); + if (!buf) { + logWarning(i18n("Encoder input buffer overflow (buffer configuration problem?). Skipped %1 input bytes").arg(QString::number(remSize))); + break; + } + if (bufferSize > remSize) { + bufferSize = remSize; + } + memcpy(buf, remData, bufferSize); + + thread->unlockInputBuffer(bufferSize, md); + remSize -= bufferSize; + remData += bufferSize; + } + consumed_size = (consumed_size == SIZE_T_DONT_CARE) ? size - remSize : min(consumed_size, size - remSize); + + return true; + } + return false; +} + + + + +bool Recording::startEncoder(SoundStreamID ssid, const RecordingConfig &cfg) +{ + if (m_EncodingThreads.contains(ssid)) + return false; + + SoundStreamID encID = createNewSoundStream(ssid, false); + m_RawStreams2EncodedStreams[ssid] = encID; + m_EncodedStreams2RawStreams[encID] = ssid; + + QString ext = ".wav"; + switch (m_config.m_OutputFormat) { + case RecordingConfig::outputWAV: ext = ".wav"; break; + case RecordingConfig::outputAIFF: ext = ".aiff"; break; + case RecordingConfig::outputAU: ext = ".au"; break; +#ifdef HAVE_LAME + case RecordingConfig::outputMP3: ext = ".mp3"; break; +#endif +#ifdef HAVE_LAME + case RecordingConfig::outputOGG: ext = ".ogg"; break; +#endif + case RecordingConfig::outputRAW: ext = ".raw"; break; + default: ext = ".wav"; break; + } + const RadioStation *rs = NULL; + querySoundStreamRadioStation(ssid, rs); + QString station = rs ? rs->name() + "-" : ""; + station.replace(QRegExp("[/*?]"), "_"); + + QDate date = QDate::currentDate(); + QTime time = QTime::currentTime(); + QString sdate; + + sdate.sprintf("%d.%d.%d.%d.%d",date.year(),date.month(),date.day(),time.hour(),time.minute()); + + QString output = m_config.m_Directory + + "/kradio-recording-" + + station + + sdate + + ext; + + logInfo(i18n("Recording::outputFile: ") + output); + + RecordingEncoding *thread = NULL; + switch (m_config.m_OutputFormat) { +#ifdef HAVE_LAME + case RecordingConfig::outputMP3: + thread = new RecordingEncodingMP3(this, ssid, cfg, rs, output); + break; +#endif +#ifdef HAVE_OGG + case RecordingConfig::outputOGG: + thread = new RecordingEncodingOgg(this, ssid, cfg, rs, output); + break; +#endif + default: + thread = new RecordingEncodingPCM(this, ssid, cfg, rs, output); + } + + //m_encodingThread->openOutput(output, rs); + + if (thread->error()) { + //m_context.setError(); + logError(thread->errorString()); + } else { + thread->start(); + } + // store thread even if it has indicated an error + m_EncodingThreads[ssid] = thread; + + //logDebug("startEncoder thread = " + QString::number((long long)thread, 16)); + + notifySoundStreamCreated(encID); + return !thread->error(); +} + + +void Recording::stopEncoder(SoundStreamID id) +{ + if (m_EncodingThreads.contains(id)) { + + RecordingEncoding *thread = m_EncodingThreads[id]; + + thread->setDone(); + + //logDebug("stopEncoder thread = " + QString::number((long long)thread, 16)); + //logDebug("stopEncoder thread error = " + QString::number(thread->error(), 16)); + +#if (KDE_VERSION_MAJOR >= 3) && (KDE_VERSION_MINOR >= 1) + // FIXME: set a timer and do waiting "in background" + if (!thread->wait(5000)) { + //m_context.setError(); + logError(i18n("The encoding thread did not finish. It will be killed now.")); + thread->terminate(); + thread->wait(); + } else { +#else + logError(i18n("Waiting for encoding thread to terminate.")); + thread->wait(); +#endif + if (thread->error()) { + //m_context.setError(); + logError(thread->errorString()); + } else { + //Q_UINT64 size = thread->encodedSize(); + //m_context.setEncodedSize(low, high); + //notifyRecordingContextChanged(m_context); + } + } + delete thread; + m_EncodingThreads.remove(id); + SoundStreamID encID = m_RawStreams2EncodedStreams[id]; + m_EncodedStreams2RawStreams.remove(encID); + m_RawStreams2EncodedStreams.remove(id); + sendStopPlayback(encID); + closeSoundStream(encID); + logInfo(i18n("Recording stopped")); + } +} + + +bool Recording::event(QEvent *_e) +{ + if (SoundStreamEvent::isSoundStreamEvent(_e)) { + SoundStreamEvent *e = static_cast<SoundStreamEvent*>(_e); + SoundStreamID id = e->getSoundStreamID(); + + if (m_EncodingThreads.contains(id)) { + + RecordingEncoding *thread = m_EncodingThreads[id]; + + //logDebug("Recording::event: thread = " + QString::number((long long)thread, 16)); + + if (thread->error()) { + logError(thread->errorString()); + //m_context.setError(); + stopEncoder(id); + } else { + //Q_UINT64 size = thread->encodedSize(); + //m_context.setEncodedSize(low, high); + //notifyRecordingContextChanged(m_context); + if (e->type() == EncodingTerminated) { + stopEncoder(id); + } else if (e->type() == EncodingStep) { + SoundStreamEncodingStepEvent *step = static_cast<SoundStreamEncodingStepEvent*>(e); + size_t consumed_size = SIZE_T_DONT_CARE; + notifySoundStreamData(m_RawStreams2EncodedStreams[id], thread->config().m_SoundFormat, + step->data(), step->size(), consumed_size, step->metaData()); + if (consumed_size != SIZE_T_DONT_CARE && consumed_size < step->size()) { + logError(i18n("Recording::notifySoundStreamData(encoded data): Receivers skipped %1 Bytes").arg(step->size() - consumed_size)); + } + } + } + } + return true; + } else { + return QObject::event(_e); + } +} + + +bool Recording::getSoundStreamDescription(SoundStreamID id, QString &descr) const +{ + if (m_EncodedStreams2RawStreams.contains(id)) { + if (querySoundStreamDescription(m_EncodedStreams2RawStreams[id], descr)) { + descr = name() + " - " + descr; + return true; + } + } + return false; +} + + +bool Recording::getSoundStreamRadioStation(SoundStreamID id, const RadioStation *&rs) const +{ + if (m_EncodedStreams2RawStreams.contains(id)) { + if (querySoundStreamRadioStation(m_EncodedStreams2RawStreams[id], rs)) { + return true; + } + } + return false; +} + + +bool Recording::enumerateSoundStreams(QMap<QString, SoundStreamID> &list) const +{ + QMapConstIterator<SoundStreamID,SoundStreamID> end = m_RawStreams2EncodedStreams.end(); + for (QMapConstIterator<SoundStreamID,SoundStreamID> it = m_RawStreams2EncodedStreams.begin(); it != end; ++it) { + QString tmp = QString::null; + getSoundStreamDescription(*it, tmp); + list[tmp] = *it; + } + return m_RawStreams2EncodedStreams.count() > 0; +} + + +bool Recording::noticeSoundStreamChanged(SoundStreamID id) +{ + if (m_RawStreams2EncodedStreams.contains(id)) { + notifySoundStreamChanged(m_RawStreams2EncodedStreams[id]); + return true; + } + return false; +} + + +bool Recording::isRecordingRunning(SoundStreamID id, bool &b, SoundFormat &sf) const +{ + if (m_EncodingThreads.contains(id)) { + b = m_EncodingThreads[id]->running(); + sf = getSoundFormat(); + return true; + } + return false; +} + + +bool Recording::noticeSoundStreamClosed(SoundStreamID id) +{ + if (m_PreRecordingBuffers.contains(id)) { + if (m_PreRecordingBuffers[id]) + delete m_PreRecordingBuffers[id]; + m_PreRecordingBuffers.remove(id); + } + + if (m_EncodingThreads.contains(id)) { + sendStopRecording(id); + return true; + } + return false; +} + + +#include "recording.moc" diff --git a/kradio3/plugins/recording/recording.h b/kradio3/plugins/recording/recording.h new file mode 100644 index 0000000..bef3a3a --- /dev/null +++ b/kradio3/plugins/recording/recording.h @@ -0,0 +1,148 @@ +/*************************************************************************** + recording.h - description + ------------------- + begin : Mi Aug 27 2003 + copyright : (C) 2003 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_RECORDING_H +#define KRADIO_RECORDING_H + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + + +#include <qobject.h> +#include <qstring.h> +#include <qmap.h> + +#include "../../src/include/plugins.h" +#include "../../src/include/timecontrol_interfaces.h" +#include "../../src/include/soundstreamclient_interfaces.h" + +#include "recording-config.h" +#include "reccfg_interfaces.h" +#include "encoder.h" + +class RadioStation; +class StationList; +class QSocketNotifier; +class RecordingEncoding; +class FileRingBuffer; + +class Recording : public QObject, + public PluginBase, + public ISoundStreamClient, + public IRecCfg +{ +Q_OBJECT +public: + Recording(const QString &name); + ~Recording(); + + virtual QString pluginClassName() const { return "Recording"; } + + virtual const QString &name() const { return PluginBase::name(); } + virtual QString &name() { return PluginBase::name(); } + + virtual bool connectI(Interface *i); + virtual bool disconnectI(Interface *i); + + + bool isRecording () const; + + + // PluginBase + +public: + virtual void saveState (KConfig *) const; + virtual void restoreState (KConfig *); + + virtual ConfigPageInfo createConfigurationPage(); + virtual AboutPageInfo createAboutPage(); + +protected: + +// IRecCfg + + bool setEncoderBuffer (size_t BufferSize, size_t BufferCount); + bool setSoundFormat (const SoundFormat &sf); + bool setMP3Quality (int q); + bool setOggQuality (float q); + bool setRecordingDirectory(const QString &dir); + bool setOutputFormat (RecordingConfig::OutputFormat of); + bool setPreRecording (bool enable, int seconds); + bool setRecordingConfig (const RecordingConfig &cfg); + + void getEncoderBuffer(size_t &BufferSize, size_t &BufferCount) const; + const SoundFormat &getSoundFormat () const; + int getMP3Quality () const; + float getOggQuality () const; + const QString &getRecordingDirectory() const; + RecordingConfig::OutputFormat getOutputFormat() const; + bool getPreRecording(int &seconds) const; + const RecordingConfig &getRecordingConfig() const; + +// ISoundStreamClient + + void noticeConnectedI (ISoundStreamServer *s, bool pointer_valid); + + bool startPlayback(SoundStreamID id); + bool stopPlayback(SoundStreamID id); + + bool startRecording(SoundStreamID id); + bool startRecordingWithFormat(SoundStreamID id, const SoundFormat &sf, SoundFormat &real_format); + bool noticeSoundStreamData(SoundStreamID id, const SoundFormat &sf, const char *data, size_t size, size_t &consumed_size, const SoundMetaData &md); + bool stopRecording(SoundStreamID id); + bool isRecordingRunning(SoundStreamID id, bool &b, SoundFormat &sf) const; + + bool getSoundStreamDescription(SoundStreamID id, QString &descr) const; + bool getSoundStreamRadioStation(SoundStreamID id, const RadioStation *&rs) const; + + bool noticeSoundStreamClosed(SoundStreamID id); + bool noticeSoundStreamChanged(SoundStreamID id); + + bool enumerateSoundStreams(QMap<QString, SoundStreamID> &list) const; + +protected slots: + + bool event(QEvent *e); + +protected: + + bool startEncoder(SoundStreamID ssid, const RecordingConfig &cfg); + void stopEncoder(SoundStreamID ssid); + +protected: + + RecordingConfig m_config; + QMap<SoundStreamID, FileRingBuffer*> m_PreRecordingBuffers; + + QMap<SoundStreamID, RecordingEncoding*> m_EncodingThreads; + QMap<SoundStreamID, SoundStreamID> m_RawStreams2EncodedStreams; + QMap<SoundStreamID, SoundStreamID> m_EncodedStreams2RawStreams; +}; + +/* PreRecording Notes: listen for startplayback, stopplayback, closestream + manage map streamid => buffer + set each started stream into capture mode + put data into ringbuffers + on capture start, feed everything into the encoder buffer, + if encoderbuffer < prerecbuffer => + put as much as possible into encoder + put new audio data into ring buffer + +*/ + +#endif diff --git a/kradio3/plugins/recording/soundstreamevent.h b/kradio3/plugins/recording/soundstreamevent.h new file mode 100644 index 0000000..0cf6cdd --- /dev/null +++ b/kradio3/plugins/recording/soundstreamevent.h @@ -0,0 +1,87 @@ +/*************************************************************************** + soundstreamevent.h - description + ------------------- + begin : Fri May 06 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_RECORDING_SOUNDSTREAM_EVENT_H +#define KRADIO_RECORDING_SOUNDSTREAM_EVENT_H + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <qevent.h> + +#include "../../src/include/sound_metadata.h" + +const QEvent::Type EncodingTerminated = (QEvent::Type)(QEvent::User+1); +const QEvent::Type EncodingStep = (QEvent::Type)(QEvent::User+2); + +class SoundStreamEvent : public QEvent +{ +public: + SoundStreamEvent(QEvent::Type t, SoundStreamID id) : QEvent(t), m_SSID(id) {} + const SoundStreamID &getSoundStreamID() const { return m_SSID; } + + static bool isSoundStreamEvent (const QEvent *e) { return e && ((e->type() == EncodingTerminated) || (e->type() == EncodingStep)); } + +protected: + SoundStreamID m_SSID; +}; + + + + + + +class SoundStreamEncodingTerminatedEvent : public SoundStreamEvent +{ +public: + SoundStreamEncodingTerminatedEvent(SoundStreamID id) : SoundStreamEvent(EncodingTerminated, id) {} +}; + + + + + + +class SoundStreamEncodingStepEvent : public SoundStreamEvent +{ +public: + SoundStreamEncodingStepEvent(SoundStreamID id, const char *data, size_t size, const SoundMetaData &md) + : SoundStreamEvent(EncodingStep, id), + m_Size(size), + m_MetaData(md) + { + m_Data = new char [m_Size]; + memcpy (m_Data, data, m_Size); + } + virtual ~SoundStreamEncodingStepEvent() { freeData(); } + + void freeData() { if (m_Data) delete m_Data; m_Data = NULL; m_Size = 0; } // _MUST_ be called by event receiver + + const char *data() const { return m_Data; } + size_t size() const { return m_Size; } + const SoundMetaData &metaData() const { return m_MetaData; } + + static bool isSoundStreamEncodingStep (const QEvent *e) { return e && (e->type() == EncodingStep); } + +protected: + char *m_Data; + size_t m_Size; + SoundMetaData m_MetaData; +}; + +#endif diff --git a/kradio3/plugins/soundserver/Makefile.am b/kradio3/plugins/soundserver/Makefile.am new file mode 100644 index 0000000..17c5946 --- /dev/null +++ b/kradio3/plugins/soundserver/Makefile.am @@ -0,0 +1,18 @@ +SUBDIRS = po . + +INCLUDES = $(all_includes) +METASOURCES = AUTO + +libkradio_LTLIBRARIES = libsoundserver.la + +libsoundserver_la_SOURCES = soundserver.cpp +libsoundserver_la_LDFLAGS = -module -avoid-version $(KDE_RPATH) $(all_libraries) + +noinst_HEADERS = soundserver.h + +#messages: rc.cpp +# $(XGETTEXT) *.cpp *.h -o po/kradio-sound-server.pot + +messages: rc.cpp + $(EXTRACTRC) *.rc *.ui >> rc.cpp + $(XGETTEXT) rc.cpp *.h *.cpp -o po/kradio-soundserver.pot diff --git a/kradio3/plugins/soundserver/po/Makefile.am b/kradio3/plugins/soundserver/po/Makefile.am new file mode 100644 index 0000000..22b977e --- /dev/null +++ b/kradio3/plugins/soundserver/po/Makefile.am @@ -0,0 +1,2 @@ +PACKAGE = kradio-soundserver +POFILES = AUTO diff --git a/kradio3/plugins/soundserver/po/de.po b/kradio3/plugins/soundserver/po/de.po new file mode 100644 index 0000000..1d43376 --- /dev/null +++ b/kradio3/plugins/soundserver/po/de.po @@ -0,0 +1,29 @@ +# translation of de.po to +# translation of kradio-sound-server.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: 2006-11-06 01:32+0100\n" +"PO-Revision-Date: 2006-11-06 01:06+0100\n" +"Last-Translator: Ernst Martin Witte <emw@nocabal.de>\n" +"Language-Team: <de@li.org>\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: KBabel 1.11.4\n" + +#: soundserver.cpp:27 +msgid "SoundServer" +msgstr "SoundServer" + +#: soundserver.cpp:32 +msgid "SoundServer Plugin" +msgstr "SoundServer Plugin" + +#: soundserver.cpp:34 +msgid "initializing kradio soundserver" +msgstr "Initialisierung des KRadio-Soundservers" diff --git a/kradio3/plugins/soundserver/po/ru.po b/kradio3/plugins/soundserver/po/ru.po new file mode 100644 index 0000000..14b5bfc --- /dev/null +++ b/kradio3/plugins/soundserver/po/ru.po @@ -0,0 +1,29 @@ +# translation of ru.po to +# translation of kradio-soundserver.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: 2006-11-11 02:11+0100\n" +"PO-Revision-Date: 2006-11-08 12:46+0300\n" +"Last-Translator: Алексей Кузнецов <Alexey.Kouznetsov@GMail.com>\n" +"Language-Team: <ru@li.org>\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" + +#: soundserver.cpp:27 +msgid "SoundServer" +msgstr "SoundServer" + +#: soundserver.cpp:32 +msgid "SoundServer Plugin" +msgstr "Модуль звукового сервера" + +#: soundserver.cpp:34 +msgid "initializing kradio soundserver" +msgstr "Включение звукового сервера KRadio" diff --git a/kradio3/plugins/soundserver/soundserver.cpp b/kradio3/plugins/soundserver/soundserver.cpp new file mode 100644 index 0000000..448bf14 --- /dev/null +++ b/kradio3/plugins/soundserver/soundserver.cpp @@ -0,0 +1,74 @@ +/*************************************************************************** + soundserver.cpp - description + ------------------- + begin : Sun Apr 17 2005 + copyright : (C) 2003 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 "soundserver.h" + +#include <kapplication.h> +#include <klocale.h> + + +/////////////////////////////////////////////////////////////////////// +//// plugin library functions + +PLUGIN_LIBRARY_FUNCTIONS(SoundServer, "kradio-soundserver", i18n("SoundServer")); + +///////////////////////////////////////////////////////////////////////////// + +SoundServer::SoundServer(const QString &name) + : PluginBase(name, i18n("SoundServer Plugin")) +{ + logDebug(i18n("initializing kradio soundserver")); +} + +SoundServer::~SoundServer() +{ +} + +bool SoundServer::connectI (Interface *i) +{ + bool a = PluginBase::connectI(i); + bool b = ISoundStreamServer::connectI(i); + return a || b; +} + + +bool SoundServer::disconnectI (Interface *i) +{ + bool a = PluginBase::disconnectI(i); + bool b = ISoundStreamServer::disconnectI(i); + return a || b; +} + + + +void SoundServer::saveState (KConfig *) const +{ +} + +void SoundServer::restoreState (KConfig *) +{ +} + +ConfigPageInfo SoundServer::createConfigurationPage() +{ + return ConfigPageInfo (); +} + +AboutPageInfo SoundServer::createAboutPage() +{ + return AboutPageInfo(); +} diff --git a/kradio3/plugins/soundserver/soundserver.h b/kradio3/plugins/soundserver/soundserver.h new file mode 100644 index 0000000..01f2377 --- /dev/null +++ b/kradio3/plugins/soundserver/soundserver.h @@ -0,0 +1,54 @@ +/*************************************************************************** + soundserver.h - description + ------------------- + begin : Sun Apr 17 2005 + copyright : (C) 2003 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_SOUNDSERVER_H +#define KRADIO_SOUNDSERVER_H + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "../../src/include/soundstreamclient_interfaces.h" +#include "../../src/include/plugins.h" + + +class SoundServer : public PluginBase, + public ISoundStreamServer +{ +public: + SoundServer(const QString &name); + ~SoundServer(); + + virtual bool connectI (Interface *); + virtual bool disconnectI (Interface *); + + virtual QString pluginClassName() const { return "SoundServer"; } + + virtual const QString &name() const { return PluginBase::name(); } + virtual QString &name() { return PluginBase::name(); } + + // PluginBase + +public: + virtual void saveState (KConfig *) const; + virtual void restoreState (KConfig *); + + virtual ConfigPageInfo createConfigurationPage(); + virtual AboutPageInfo createAboutPage(); +}; + +#endif diff --git a/kradio3/plugins/streaming/Makefile.am b/kradio3/plugins/streaming/Makefile.am new file mode 100644 index 0000000..0e5ed11 --- /dev/null +++ b/kradio3/plugins/streaming/Makefile.am @@ -0,0 +1,18 @@ +SUBDIRS = po icons . + +INCLUDES = $(all_includes) +METASOURCES = AUTO + +libkradio_LTLIBRARIES = libstreaming.la +libstreaming_la_SOURCES = streaming.cpp streaming-configuration-ui.ui \ + streaming-configuration.cpp streaming-job.cpp +libstreaming_la_LDFLAGS = -module -avoid-version $(KDE_RPATH) $(all_libraries) + +noinst_HEADERS = streaming.h streaming-configuration.h streaming-job.h + +#messages: rc.cpp +# $(XGETTEXT) *.cpp *.h -o po/kradio-streaming.pot + +messages: rc.cpp + $(EXTRACTRC) *.rc *.ui >> rc.cpp + $(XGETTEXT) rc.cpp *.h *.cpp -o po/kradio-streaming.pot diff --git a/kradio3/plugins/streaming/icons/Makefile.am b/kradio3/plugins/streaming/icons/Makefile.am new file mode 100644 index 0000000..b3f2583 --- /dev/null +++ b/kradio3/plugins/streaming/icons/Makefile.am @@ -0,0 +1,2 @@ +icons_ICON = AUTO +iconsdir = $(kde_datadir)/kradio/icons diff --git a/kradio3/plugins/streaming/icons/hi16-action-kradio_streaming.png b/kradio3/plugins/streaming/icons/hi16-action-kradio_streaming.png Binary files differnew file mode 100644 index 0000000..af7de60 --- /dev/null +++ b/kradio3/plugins/streaming/icons/hi16-action-kradio_streaming.png diff --git a/kradio3/plugins/streaming/icons/hi22-action-kradio_streaming.png b/kradio3/plugins/streaming/icons/hi22-action-kradio_streaming.png Binary files differnew file mode 100644 index 0000000..c737464 --- /dev/null +++ b/kradio3/plugins/streaming/icons/hi22-action-kradio_streaming.png diff --git a/kradio3/plugins/streaming/icons/hi32-action-kradio_streaming.png b/kradio3/plugins/streaming/icons/hi32-action-kradio_streaming.png Binary files differnew file mode 100644 index 0000000..d3ce851 --- /dev/null +++ b/kradio3/plugins/streaming/icons/hi32-action-kradio_streaming.png diff --git a/kradio3/plugins/streaming/icons/hi48-action-kradio_streaming.png b/kradio3/plugins/streaming/icons/hi48-action-kradio_streaming.png Binary files differnew file mode 100644 index 0000000..2e1ff2a --- /dev/null +++ b/kradio3/plugins/streaming/icons/hi48-action-kradio_streaming.png diff --git a/kradio3/plugins/streaming/icons/hi64-action-kradio_streaming.png b/kradio3/plugins/streaming/icons/hi64-action-kradio_streaming.png Binary files differnew file mode 100644 index 0000000..465cda6 --- /dev/null +++ b/kradio3/plugins/streaming/icons/hi64-action-kradio_streaming.png diff --git a/kradio3/plugins/streaming/po/Makefile.am b/kradio3/plugins/streaming/po/Makefile.am new file mode 100644 index 0000000..e1b5685 --- /dev/null +++ b/kradio3/plugins/streaming/po/Makefile.am @@ -0,0 +1,2 @@ +PACKAGE = kradio-streaming +POFILES = AUTO diff --git a/kradio3/plugins/streaming/po/de.po b/kradio3/plugins/streaming/po/de.po new file mode 100644 index 0000000..aaa1e2e --- /dev/null +++ b/kradio3/plugins/streaming/po/de.po @@ -0,0 +1,226 @@ +# translation of de.po to +# translation of kradio-streaming.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: 2006-11-12 18:41+0100\n" +"PO-Revision-Date: 2006-11-12 18:24+0100\n" +"Last-Translator: Ernst Martin Witte <emw@nocabal.de>\n" +"Language-Team: <de@li.org>\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: KBabel 1.11.4\n" + +#. i18n: file streaming-configuration-ui.ui line 16 +#: rc.cpp:3 rc.cpp:95 streaming-configuration-ui.cpp:253 +#, no-c-format +msgid "StreamingConfigurationUI" +msgstr "StreamingConfigurationUI" + +#. i18n: file streaming-configuration-ui.ui line 33 +#. i18n: file streaming-configuration-ui.ui line 74 +#. i18n: file streaming-configuration-ui.ui line 33 +#. i18n: file streaming-configuration-ui.ui line 74 +#: rc.cpp:6 rc.cpp:12 rc.cpp:98 rc.cpp:104 streaming-configuration-ui.cpp:43 +#: streaming-configuration-ui.cpp:52 streaming-configuration-ui.cpp:254 +#: streaming-configuration-ui.cpp:256 +#, no-c-format +msgid "No." +msgstr "Nr." + +#. i18n: file streaming-configuration-ui.ui line 44 +#. i18n: file streaming-configuration-ui.ui line 85 +#. i18n: file streaming-configuration-ui.ui line 44 +#. i18n: file streaming-configuration-ui.ui line 85 +#: rc.cpp:9 rc.cpp:15 rc.cpp:101 rc.cpp:107 streaming-configuration-ui.cpp:44 +#: streaming-configuration-ui.cpp:53 streaming-configuration-ui.cpp:255 +#: streaming-configuration-ui.cpp:257 +#, no-c-format +msgid "URL" +msgstr "URL" + +#. i18n: file streaming-configuration-ui.ui line 114 +#: rc.cpp:18 rc.cpp:110 streaming-configuration-ui.cpp:258 +#, no-c-format +msgid "Capture URLs" +msgstr "Aufnahme-URL" + +#. i18n: file streaming-configuration-ui.ui line 122 +#: rc.cpp:21 rc.cpp:113 streaming-configuration-ui.cpp:259 +#, no-c-format +msgid "Playback URLs" +msgstr "Wiedergabe-URL" + +#. i18n: file streaming-configuration-ui.ui line 434 +#: rc.cpp:32 rc.cpp:124 streaming-configuration-ui.cpp:268 +#, no-c-format +msgid "URL Properties" +msgstr "URL-Eigenschaften" + +#. i18n: file streaming-configuration-ui.ui line 446 +#: rc.cpp:35 rc.cpp:127 streaming-configuration-ui.cpp:270 +#, no-c-format +msgid "Stereo" +msgstr "Stereo" + +#. i18n: file streaming-configuration-ui.ui line 451 +#: rc.cpp:38 rc.cpp:130 streaming-configuration-ui.cpp:271 +#, no-c-format +msgid "Mono" +msgstr "Mono" + +#. i18n: file streaming-configuration-ui.ui line 471 +#: rc.cpp:41 rc.cpp:133 streaming-configuration-ui.cpp:272 +#, no-c-format +msgid "Sample Bits" +msgstr "Quantisierungs-Bits" + +#. i18n: file streaming-configuration-ui.ui line 479 +#: rc.cpp:44 rc.cpp:136 streaming-configuration-ui.cpp:273 +#, no-c-format +msgid "Channels" +msgstr "Kanäle" + +#. i18n: file streaming-configuration-ui.ui line 487 +#: rc.cpp:47 rc.cpp:139 streaming-configuration-ui.cpp:274 +#, no-c-format +msgid "Endianess" +msgstr "Byte-Reihenfolge" + +#. i18n: file streaming-configuration-ui.ui line 493 +#: rc.cpp:50 rc.cpp:142 streaming-configuration-ui.cpp:276 +#, no-c-format +msgid "Little Endian" +msgstr "Little Endian" + +#. i18n: file streaming-configuration-ui.ui line 498 +#: rc.cpp:53 rc.cpp:145 streaming-configuration-ui.cpp:277 +#, no-c-format +msgid "Big Endian" +msgstr "Big Endian" + +#. i18n: file streaming-configuration-ui.ui line 516 +#: rc.cpp:56 rc.cpp:148 streaming-configuration-ui.cpp:279 +#, no-c-format +msgid "48000" +msgstr "48000" + +#. i18n: file streaming-configuration-ui.ui line 521 +#: rc.cpp:59 rc.cpp:151 streaming-configuration-ui.cpp:280 +#, no-c-format +msgid "44100" +msgstr "44100" + +#. i18n: file streaming-configuration-ui.ui line 526 +#: rc.cpp:62 rc.cpp:154 streaming-configuration-ui.cpp:281 +#, no-c-format +msgid "22050" +msgstr "22050" + +#. i18n: file streaming-configuration-ui.ui line 531 +#: rc.cpp:65 rc.cpp:157 streaming-configuration-ui.cpp:282 +#, no-c-format +msgid "11025" +msgstr "11025" + +#. i18n: file streaming-configuration-ui.ui line 549 +#: rc.cpp:68 rc.cpp:160 streaming-configuration-ui.cpp:284 +#, no-c-format +msgid "16" +msgstr "16" + +#. i18n: file streaming-configuration-ui.ui line 554 +#: rc.cpp:71 rc.cpp:163 streaming-configuration-ui.cpp:285 +#, no-c-format +msgid "8" +msgstr "8" + +#. i18n: file streaming-configuration-ui.ui line 572 +#: rc.cpp:74 rc.cpp:166 streaming-configuration-ui.cpp:287 +#, no-c-format +msgid "Raw" +msgstr "Rohdaten" + +#. i18n: file streaming-configuration-ui.ui line 592 +#: rc.cpp:77 rc.cpp:169 streaming-configuration-ui.cpp:288 +#, no-c-format +msgid "kB" +msgstr "kB" + +#. i18n: file streaming-configuration-ui.ui line 609 +#: rc.cpp:80 rc.cpp:172 streaming-configuration-ui.cpp:289 +#, no-c-format +msgid "Buffer Size" +msgstr "Puffergröße" + +#. i18n: file streaming-configuration-ui.ui line 617 +#: rc.cpp:83 rc.cpp:175 streaming-configuration-ui.cpp:290 +#, no-c-format +msgid "Format" +msgstr "Format" + +#. i18n: file streaming-configuration-ui.ui line 625 +#: rc.cpp:86 rc.cpp:178 streaming-configuration-ui.cpp:291 +#, no-c-format +msgid "Sample Rate" +msgstr "Abtastrate" + +#. i18n: file streaming-configuration-ui.ui line 631 +#: rc.cpp:89 rc.cpp:181 streaming-configuration-ui.cpp:293 +#, no-c-format +msgid "Signed" +msgstr "Vorzeichenbehaftet" + +#. i18n: file streaming-configuration-ui.ui line 636 +#: rc.cpp:92 rc.cpp:184 streaming-configuration-ui.cpp:294 +#, no-c-format +msgid "Unsigned" +msgstr "Vorzeichenlos" + +#: streaming-configuration.cpp:155 streaming-configuration.cpp:259 +msgid "new channel" +msgstr "Neuer Kanal" + +#: streaming-job.cpp:204 +msgid "skipped %1 bytes" +msgstr "%1 bytes wurden übersprungen" + +#: streaming.cpp:33 +msgid "Streaming Support" +msgstr "Unterstützung für das Streaming" + +#: streaming.cpp:42 +msgid "KRadio Streaming Plugin" +msgstr "KRadio Streaming-Plugin" + +#: streaming.cpp:172 +msgid "Streaming" +msgstr "Streaming" + +#: streaming.cpp:173 +msgid "Streaming Device Options" +msgstr "Geräteoptionen für das Streaming" + +#: streaming.cpp:393 +msgid "internal stream, not stored (%1)" +msgstr "interner, nicht aufgezeichneter Datenstrom (%1)" + +#: streaming.cpp:403 +msgid "" +"StreamingDevice %1::notifySoundStreamData: Playback Clients skipped %2 bytes" +msgstr "" +"Streaminggerät %1::notifySoundStreamData: Die Wiedergabe-Module haben %2 " +"bytes übersprungen." + +#: streaming.cpp:426 +msgid "Streaming Device %1" +msgstr "Streaming-Gerät %1" + +#: streaming.cpp:432 streaming.cpp:437 +msgid "Streaming Device %1, %2: %3" +msgstr "Streaming-Gerät %1, %2: %3" diff --git a/kradio3/plugins/streaming/po/ru.po b/kradio3/plugins/streaming/po/ru.po new file mode 100644 index 0000000..c46978a --- /dev/null +++ b/kradio3/plugins/streaming/po/ru.po @@ -0,0 +1,228 @@ +# translation of ru.po to +# translation of kradio-streaming.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: 2006-11-12 18:20+0100\n" +"PO-Revision-Date: 2006-11-08 12:25+0300\n" +"Last-Translator: Алексей Кузнецов <Alexey.Kouznetsov@GMail.com>\n" +"Language-Team: <ru@li.org>\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" + +#. i18n: file streaming-configuration-ui.ui line 16 +#: rc.cpp:3 rc.cpp:95 streaming-configuration-ui.cpp:253 +#, no-c-format +msgid "StreamingConfigurationUI" +msgstr "StreamingConfigurationUI" + +#. i18n: file streaming-configuration-ui.ui line 33 +#. i18n: file streaming-configuration-ui.ui line 74 +#. i18n: file streaming-configuration-ui.ui line 33 +#. i18n: file streaming-configuration-ui.ui line 74 +#: rc.cpp:6 rc.cpp:12 rc.cpp:98 rc.cpp:104 streaming-configuration-ui.cpp:43 +#: streaming-configuration-ui.cpp:52 streaming-configuration-ui.cpp:254 +#: streaming-configuration-ui.cpp:256 +#, no-c-format +msgid "No." +msgstr "No " + +#. i18n: file streaming-configuration-ui.ui line 44 +#. i18n: file streaming-configuration-ui.ui line 85 +#. i18n: file streaming-configuration-ui.ui line 44 +#. i18n: file streaming-configuration-ui.ui line 85 +#: rc.cpp:9 rc.cpp:15 rc.cpp:101 rc.cpp:107 streaming-configuration-ui.cpp:44 +#: streaming-configuration-ui.cpp:53 streaming-configuration-ui.cpp:255 +#: streaming-configuration-ui.cpp:257 +#, no-c-format +msgid "URL" +msgstr "Адрес" + +#. i18n: file streaming-configuration-ui.ui line 114 +#: rc.cpp:18 rc.cpp:110 streaming-configuration-ui.cpp:258 +#, no-c-format +msgid "Capture URLs" +msgstr "Адреса для записи" + +#. i18n: file streaming-configuration-ui.ui line 122 +#: rc.cpp:21 rc.cpp:113 streaming-configuration-ui.cpp:259 +#, no-c-format +msgid "Playback URLs" +msgstr "Адреса для воспроизведения" + +#. i18n: file streaming-configuration-ui.ui line 434 +#: rc.cpp:32 rc.cpp:124 streaming-configuration-ui.cpp:268 +#, no-c-format +msgid "URL Properties" +msgstr "Параметры для URL" + +#. i18n: file streaming-configuration-ui.ui line 446 +#: rc.cpp:35 rc.cpp:127 streaming-configuration-ui.cpp:270 +#, no-c-format +msgid "Stereo" +msgstr "2 (Стерео)" + +#. i18n: file streaming-configuration-ui.ui line 451 +#: rc.cpp:38 rc.cpp:130 streaming-configuration-ui.cpp:271 +#, no-c-format +msgid "Mono" +msgstr "1 (Моно)" + +#. i18n: file streaming-configuration-ui.ui line 471 +#: rc.cpp:41 rc.cpp:133 streaming-configuration-ui.cpp:272 +#, no-c-format +msgid "Sample Bits" +msgstr "Бит на элемент выборки" + +#. i18n: file streaming-configuration-ui.ui line 479 +#: rc.cpp:44 rc.cpp:136 streaming-configuration-ui.cpp:273 +#, no-c-format +msgid "Channels" +msgstr "Число каналов" + +#. i18n: file streaming-configuration-ui.ui line 487 +#: rc.cpp:47 rc.cpp:139 streaming-configuration-ui.cpp:274 +#, no-c-format +msgid "Endianess" +msgstr "Порядок байтов" + +#. i18n: file streaming-configuration-ui.ui line 493 +#: rc.cpp:50 rc.cpp:142 streaming-configuration-ui.cpp:276 +#, no-c-format +msgid "Little Endian" +msgstr "Little Endian" + +#. i18n: file streaming-configuration-ui.ui line 498 +#: rc.cpp:53 rc.cpp:145 streaming-configuration-ui.cpp:277 +#, no-c-format +msgid "Big Endian" +msgstr "Big Endian" + +#. i18n: file streaming-configuration-ui.ui line 516 +#: rc.cpp:56 rc.cpp:148 streaming-configuration-ui.cpp:279 +#, no-c-format +msgid "48000" +msgstr "48000" + +#. i18n: file streaming-configuration-ui.ui line 521 +#: rc.cpp:59 rc.cpp:151 streaming-configuration-ui.cpp:280 +#, no-c-format +msgid "44100" +msgstr "44100" + +#. i18n: file streaming-configuration-ui.ui line 526 +#: rc.cpp:62 rc.cpp:154 streaming-configuration-ui.cpp:281 +#, no-c-format +msgid "22050" +msgstr "22050" + +#. i18n: file streaming-configuration-ui.ui line 531 +#: rc.cpp:65 rc.cpp:157 streaming-configuration-ui.cpp:282 +#, no-c-format +msgid "11025" +msgstr "11025" + +#. i18n: file streaming-configuration-ui.ui line 549 +#: rc.cpp:68 rc.cpp:160 streaming-configuration-ui.cpp:284 +#, no-c-format +msgid "16" +msgstr "16" + +#. i18n: file streaming-configuration-ui.ui line 554 +#: rc.cpp:71 rc.cpp:163 streaming-configuration-ui.cpp:285 +#, no-c-format +msgid "8" +msgstr "8" + +#. i18n: file streaming-configuration-ui.ui line 572 +#: rc.cpp:74 rc.cpp:166 streaming-configuration-ui.cpp:287 +#, no-c-format +msgid "Raw" +msgstr "Raw" + +#. i18n: file streaming-configuration-ui.ui line 592 +#: rc.cpp:77 rc.cpp:169 streaming-configuration-ui.cpp:288 +#, no-c-format +msgid "kB" +msgstr "kB" + +#. i18n: file streaming-configuration-ui.ui line 609 +#: rc.cpp:80 rc.cpp:172 streaming-configuration-ui.cpp:289 +#, no-c-format +msgid "Buffer Size" +msgstr "Размер буфера" + +#. i18n: file streaming-configuration-ui.ui line 617 +#: rc.cpp:83 rc.cpp:175 streaming-configuration-ui.cpp:290 +#, no-c-format +msgid "Format" +msgstr "Формат" + +#. i18n: file streaming-configuration-ui.ui line 625 +#: rc.cpp:86 rc.cpp:178 streaming-configuration-ui.cpp:291 +#, no-c-format +msgid "Sample Rate" +msgstr "Частота дискретизации" + +#. i18n: file streaming-configuration-ui.ui line 631 +#: rc.cpp:89 rc.cpp:181 streaming-configuration-ui.cpp:293 +#, no-c-format +msgid "Signed" +msgstr "Со знаком" + +#. i18n: file streaming-configuration-ui.ui line 636 +#: rc.cpp:92 rc.cpp:184 streaming-configuration-ui.cpp:294 +#, no-c-format +msgid "Unsigned" +msgstr "Без знака" + +#: streaming-configuration.cpp:155 streaming-configuration.cpp:259 +msgid "new channel" +msgstr "новый канал" + +#: streaming-job.cpp:204 +msgid "skipped %1 bytes" +msgstr "Пропущено %1 байт" + +#: streaming.cpp:33 +msgid "Streaming Support" +msgstr "" +"Сетевое\n" +"вещание" + +#: streaming.cpp:42 +msgid "KRadio Streaming Plugin" +msgstr "Модуль сетевого вещания для KRadio" + +#: streaming.cpp:172 +msgid "Streaming" +msgstr "" +"Сетевое\n" +"вещание" + +#: streaming.cpp:173 +msgid "Streaming Device Options" +msgstr "Параметры сетевого вещания" + +#: streaming.cpp:393 +msgid "internal stream, not stored (%1)" +msgstr "" + +#: streaming.cpp:403 +msgid "" +"StreamingDevice %1::notifySoundStreamData: Playback Clients skipped %2 bytes" +msgstr "StreamingDevice %1::notifySoundStreamData: Клиенты пропустили %2 байт" + +#: streaming.cpp:426 +msgid "Streaming Device %1" +msgstr "Устройство вещания %1" + +#: streaming.cpp:432 streaming.cpp:437 +msgid "Streaming Device %1, %2: %3" +msgstr "Устройство вещания %1, %2: %3" diff --git a/kradio3/plugins/streaming/streaming-configuration-ui.ui b/kradio3/plugins/streaming/streaming-configuration-ui.ui new file mode 100644 index 0000000..001d4ae --- /dev/null +++ b/kradio3/plugins/streaming/streaming-configuration-ui.ui @@ -0,0 +1,777 @@ +<!DOCTYPE UI><UI version="3.3" stdsetdef="1"> +<class>StreamingConfigurationUI</class> +<widget class="QWidget"> + <property name="name"> + <cstring>StreamingConfigurationUI</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>397</width> + <height>423</height> + </rect> + </property> + <property name="caption"> + <string>StreamingConfigurationUI</string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLayoutWidget" row="0" column="0"> + <property name="name"> + <cstring>layout48</cstring> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="KListView" row="1" column="0"> + <column> + <property name="text"> + <string>No.</string> + </property> + <property name="clickable"> + <bool>true</bool> + </property> + <property name="resizable"> + <bool>true</bool> + </property> + </column> + <column> + <property name="text"> + <string>URL</string> + </property> + <property name="clickable"> + <bool>true</bool> + </property> + <property name="resizable"> + <bool>true</bool> + </property> + </column> + <property name="name"> + <cstring>m_ListPlaybackURLs</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>7</hsizetype> + <vsizetype>7</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="selectionMode" stdset="0"> + <enum>Single</enum> + </property> + <property name="defaultRenameAction"> + <enum>Accept</enum> + </property> + </widget> + <widget class="KListView" row="1" column="2"> + <column> + <property name="text"> + <string>No.</string> + </property> + <property name="clickable"> + <bool>true</bool> + </property> + <property name="resizable"> + <bool>true</bool> + </property> + </column> + <column> + <property name="text"> + <string>URL</string> + </property> + <property name="clickable"> + <bool>true</bool> + </property> + <property name="resizable"> + <bool>true</bool> + </property> + </column> + <property name="name"> + <cstring>m_ListCaptureURLs</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>7</hsizetype> + <vsizetype>7</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="defaultRenameAction"> + <enum>Accept</enum> + </property> + </widget> + <widget class="QLabel" row="0" column="2"> + <property name="name"> + <cstring>textLabel1_2</cstring> + </property> + <property name="text"> + <string>Capture URLs</string> + </property> + </widget> + <widget class="QLabel" row="0" column="0"> + <property name="name"> + <cstring>textLabel1</cstring> + </property> + <property name="text"> + <string>Playback URLs</string> + </property> + </widget> + <widget class="QLayoutWidget" row="1" column="3"> + <property name="name"> + <cstring>layout38_2</cstring> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QPushButton"> + <property name="name"> + <cstring>m_pbNewCaptureURL</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>0</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>30</width> + <height>30</height> + </size> + </property> + <property name="maximumSize"> + <size> + <width>30</width> + <height>30</height> + </size> + </property> + <property name="text"> + <string></string> + </property> + <property name="iconSet"> + <iconset>"filenew2"</iconset> + </property> + </widget> + <widget class="QPushButton"> + <property name="name"> + <cstring>m_pbDeleteCaptureURL</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>0</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>30</width> + <height>30</height> + </size> + </property> + <property name="maximumSize"> + <size> + <width>30</width> + <height>30</height> + </size> + </property> + <property name="text"> + <string></string> + </property> + <property name="iconSet"> + <iconset>"editdelete"</iconset> + </property> + </widget> + <spacer> + <property name="name"> + <cstring>spacer46_2</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>10</width> + <height>10</height> + </size> + </property> + </spacer> + <widget class="QPushButton"> + <property name="name"> + <cstring>m_pbUpCaptureURL</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>0</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>30</width> + <height>30</height> + </size> + </property> + <property name="maximumSize"> + <size> + <width>30</width> + <height>30</height> + </size> + </property> + <property name="text"> + <string></string> + </property> + <property name="iconSet"> + <iconset>"1uparrow"</iconset> + </property> + </widget> + <widget class="QPushButton"> + <property name="name"> + <cstring>m_pbDownCaptureURL</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>0</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>30</width> + <height>30</height> + </size> + </property> + <property name="maximumSize"> + <size> + <width>30</width> + <height>30</height> + </size> + </property> + <property name="text"> + <string></string> + </property> + <property name="iconSet"> + <iconset>"1downarrow"</iconset> + </property> + </widget> + </vbox> + </widget> + <widget class="QLayoutWidget" row="1" column="1"> + <property name="name"> + <cstring>layout38</cstring> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QPushButton"> + <property name="name"> + <cstring>m_pbNewPlaybackURL</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>0</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>30</width> + <height>30</height> + </size> + </property> + <property name="maximumSize"> + <size> + <width>30</width> + <height>30</height> + </size> + </property> + <property name="text"> + <string></string> + </property> + <property name="iconSet"> + <iconset>"filenew2"</iconset> + </property> + </widget> + <widget class="QPushButton"> + <property name="name"> + <cstring>m_pbDeletePlaybackURL</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>0</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>30</width> + <height>30</height> + </size> + </property> + <property name="maximumSize"> + <size> + <width>30</width> + <height>30</height> + </size> + </property> + <property name="text"> + <string></string> + </property> + <property name="iconSet"> + <iconset>"editdelete"</iconset> + </property> + </widget> + <spacer> + <property name="name"> + <cstring>spacer46</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>10</width> + <height>10</height> + </size> + </property> + </spacer> + <widget class="QPushButton"> + <property name="name"> + <cstring>m_pbUpPlaybackURL</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>0</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>30</width> + <height>30</height> + </size> + </property> + <property name="maximumSize"> + <size> + <width>30</width> + <height>30</height> + </size> + </property> + <property name="text"> + <string></string> + </property> + <property name="iconSet"> + <iconset>"1uparrow"</iconset> + </property> + </widget> + <widget class="QPushButton"> + <property name="name"> + <cstring>m_pbDownPlaybackURL</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>0</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>30</width> + <height>30</height> + </size> + </property> + <property name="maximumSize"> + <size> + <width>30</width> + <height>30</height> + </size> + </property> + <property name="text"> + <string></string> + </property> + <property name="iconSet"> + <iconset>"1downarrow"</iconset> + </property> + </widget> + </vbox> + </widget> + </grid> + </widget> + <widget class="QGroupBox" row="1" column="0"> + <property name="name"> + <cstring>groupBox3</cstring> + </property> + <property name="title"> + <string>URL Properties</string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>10</number> + </property> + <widget class="KComboBox" row="5" column="1"> + <item> + <property name="text"> + <string>Stereo</string> + </property> + </item> + <item> + <property name="text"> + <string>Mono</string> + </property> + </item> + <property name="name"> + <cstring>m_cbChannels</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>3</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + </widget> + <widget class="QLabel" row="3" column="0"> + <property name="name"> + <cstring>lableBits</cstring> + </property> + <property name="text"> + <string>Sample Bits</string> + </property> + </widget> + <widget class="QLabel" row="5" column="0"> + <property name="name"> + <cstring>lableChannels</cstring> + </property> + <property name="text"> + <string>Channels</string> + </property> + </widget> + <widget class="QLabel" row="4" column="0"> + <property name="name"> + <cstring>lableEndianess</cstring> + </property> + <property name="text"> + <string>Endianess</string> + </property> + </widget> + <widget class="KComboBox" row="4" column="1"> + <item> + <property name="text"> + <string>Little Endian</string> + </property> + </item> + <item> + <property name="text"> + <string>Big Endian</string> + </property> + </item> + <property name="name"> + <cstring>m_cbEndianess</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>3</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + </widget> + <widget class="KComboBox" row="2" column="1"> + <item> + <property name="text"> + <string>48000</string> + </property> + </item> + <item> + <property name="text"> + <string>44100</string> + </property> + </item> + <item> + <property name="text"> + <string>22050</string> + </property> + </item> + <item> + <property name="text"> + <string>11025</string> + </property> + </item> + <property name="name"> + <cstring>m_cbRate</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>3</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + </widget> + <widget class="KComboBox" row="3" column="1"> + <item> + <property name="text"> + <string>16</string> + </property> + </item> + <item> + <property name="text"> + <string>8</string> + </property> + </item> + <property name="name"> + <cstring>m_cbBits</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>3</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + </widget> + <widget class="KComboBox" row="1" column="1"> + <item> + <property name="text"> + <string>Raw</string> + </property> + </item> + <property name="name"> + <cstring>m_cbFormat</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>3</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + </widget> + <widget class="KIntSpinBox" row="0" column="1"> + <property name="name"> + <cstring>m_sbBufferSize</cstring> + </property> + <property name="suffix"> + <string>kB</string> + </property> + <property name="maxValue"> + <number>1024</number> + </property> + <property name="minValue"> + <number>4</number> + </property> + <property name="lineStep"> + <number>4</number> + </property> + </widget> + <widget class="QLabel" row="0" column="0"> + <property name="name"> + <cstring>labelRate_2</cstring> + </property> + <property name="text"> + <string>Buffer Size</string> + </property> + </widget> + <widget class="QLabel" row="1" column="0"> + <property name="name"> + <cstring>labelRate_2_2</cstring> + </property> + <property name="text"> + <string>Format</string> + </property> + </widget> + <widget class="QLabel" row="2" column="0"> + <property name="name"> + <cstring>labelRate</cstring> + </property> + <property name="text"> + <string>Sample Rate</string> + </property> + </widget> + <widget class="KComboBox" row="3" column="2"> + <item> + <property name="text"> + <string>Signed</string> + </property> + </item> + <item> + <property name="text"> + <string>Unsigned</string> + </property> + </item> + <property name="name"> + <cstring>m_cbSign</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>3</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + </widget> + <spacer row="2" column="2"> + <property name="name"> + <cstring>spacer1</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Minimum</enum> + </property> + <property name="sizeHint"> + <size> + <width>140</width> + <height>20</height> + </size> + </property> + </spacer> + <spacer row="1" column="2"> + <property name="name"> + <cstring>spacer1_4</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Minimum</enum> + </property> + <property name="sizeHint"> + <size> + <width>140</width> + <height>20</height> + </size> + </property> + </spacer> + <spacer row="0" column="2"> + <property name="name"> + <cstring>spacer1_4_2</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Minimum</enum> + </property> + <property name="sizeHint"> + <size> + <width>140</width> + <height>20</height> + </size> + </property> + </spacer> + <spacer row="4" column="2"> + <property name="name"> + <cstring>spacer1_2</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Minimum</enum> + </property> + <property name="sizeHint"> + <size> + <width>140</width> + <height>20</height> + </size> + </property> + </spacer> + <spacer row="5" column="2"> + <property name="name"> + <cstring>spacer1_3</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Minimum</enum> + </property> + <property name="sizeHint"> + <size> + <width>140</width> + <height>20</height> + </size> + </property> + </spacer> + </grid> + </widget> + </grid> +</widget> +<customwidgets> +</customwidgets> +<tabstops> + <tabstop>m_ListPlaybackURLs</tabstop> + <tabstop>m_pbNewPlaybackURL</tabstop> + <tabstop>m_pbDeletePlaybackURL</tabstop> + <tabstop>m_pbUpPlaybackURL</tabstop> + <tabstop>m_pbDownPlaybackURL</tabstop> + <tabstop>m_ListCaptureURLs</tabstop> + <tabstop>m_pbNewCaptureURL</tabstop> + <tabstop>m_pbDeleteCaptureURL</tabstop> + <tabstop>m_pbUpCaptureURL</tabstop> + <tabstop>m_pbDownCaptureURL</tabstop> + <tabstop>m_sbBufferSize</tabstop> + <tabstop>m_cbFormat</tabstop> + <tabstop>m_cbRate</tabstop> + <tabstop>m_cbBits</tabstop> + <tabstop>m_cbSign</tabstop> + <tabstop>m_cbEndianess</tabstop> + <tabstop>m_cbChannels</tabstop> +</tabstops> +<includes> + <include location="global" impldecl="in implementation">kiconloader.h</include> +</includes> +<pixmapfunction>SmallIconSet</pixmapfunction> +<layoutdefaults spacing="6" margin="0"/> +<includehints> + <includehint>klistview.h</includehint> + <includehint>klistview.h</includehint> + <includehint>kcombobox.h</includehint> + <includehint>kcombobox.h</includehint> + <includehint>kcombobox.h</includehint> + <includehint>kcombobox.h</includehint> + <includehint>kcombobox.h</includehint> + <includehint>knuminput.h</includehint> + <includehint>kcombobox.h</includehint> +</includehints> +</UI> diff --git a/kradio3/plugins/streaming/streaming-configuration.cpp b/kradio3/plugins/streaming/streaming-configuration.cpp new file mode 100644 index 0000000..ea1801d --- /dev/null +++ b/kradio3/plugins/streaming/streaming-configuration.cpp @@ -0,0 +1,567 @@ +/*************************************************************************** + streaming-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 <qcheckbox.h> + +#include <kurlrequester.h> +#include <knuminput.h> +#include <klistview.h> +#include <kcombobox.h> +#include <knuminput.h> + +#include <klocale.h> + +#include "streaming-configuration.h" +#include "streaming.h" + +StreamingConfiguration::StreamingConfiguration (QWidget *parent, StreamingDevice *streamer) + : StreamingConfigurationUI(parent), + m_ignore_updates(false), + m_dirty(true), + m_StreamingDevice(streamer) +{ + connect(m_pbNewPlaybackURL, SIGNAL(clicked()), this, SLOT(slotNewPlaybackChannel())); + connect(m_pbDeletePlaybackURL, SIGNAL(clicked()), this, SLOT(slotDeletePlaybackChannel())); + connect(m_pbUpPlaybackURL, SIGNAL(clicked()), this, SLOT(slotUpPlaybackChannel())); + connect(m_pbDownPlaybackURL, SIGNAL(clicked()), this, SLOT(slotDownPlaybackChannel())); + connect(m_ListPlaybackURLs, SIGNAL(selectionChanged()), this, SLOT(slotPlaybackSelectionChanged())); + connect(m_ListPlaybackURLs, SIGNAL(itemRenamed(QListViewItem *)), this, SLOT(slotSetDirty())); + + connect(m_pbNewCaptureURL, SIGNAL(clicked()), this, SLOT(slotNewCaptureChannel())); + connect(m_pbDeleteCaptureURL, SIGNAL(clicked()), this, SLOT(slotDeleteCaptureChannel())); + connect(m_pbUpCaptureURL, SIGNAL(clicked()), this, SLOT(slotUpCaptureChannel())); + connect(m_pbDownCaptureURL, SIGNAL(clicked()), this, SLOT(slotDownCaptureChannel())); + connect(m_ListCaptureURLs, SIGNAL(selectionChanged()), this, SLOT(slotCaptureSelectionChanged())); + connect(m_ListCaptureURLs, SIGNAL(itemRenamed(QListViewItem *)), this, SLOT(slotSetDirty())); + + connect(m_cbBits, SIGNAL(activated(int)), this, SLOT(slotUpdateSoundFormat())); + connect(m_cbChannels, SIGNAL(activated(int)), this, SLOT(slotUpdateSoundFormat())); + connect(m_cbEndianess, SIGNAL(activated(int)), this, SLOT(slotUpdateSoundFormat())); + connect(m_cbFormat, SIGNAL(activated(int)), this, SLOT(slotUpdateSoundFormat())); + connect(m_cbRate, SIGNAL(activated(int)), this, SLOT(slotUpdateSoundFormat())); + connect(m_cbSign, SIGNAL(activated(int)), this, SLOT(slotUpdateSoundFormat())); + connect(m_sbBufferSize, SIGNAL(valueChanged(int)), this, SLOT(slotUpdateSoundFormat())); + + m_ListPlaybackURLs->setAllColumnsShowFocus(true); + m_ListPlaybackURLs->setSorting(-1); + m_ListCaptureURLs->setAllColumnsShowFocus(true); + m_ListCaptureURLs->setSorting(-1); + + slotCancel(); +} + + +StreamingConfiguration::~StreamingConfiguration () +{ +} + + +void StreamingConfiguration::slotOK() +{ + if (!m_dirty) + return; + + m_StreamingDevice->resetPlaybackStreams(false); + m_StreamingDevice->resetCaptureStreams(false); + + QListViewItem *item = m_ListPlaybackURLs->firstChild(); + for (int i = 0; item; ++i, item = item->nextSibling()) { + m_StreamingDevice->addPlaybackStream(item->text(1), m_PlaybackSoundFormats[i], m_PlaybackBufferSizes[i], !item->nextSibling()); + } + + item = m_ListCaptureURLs->firstChild(); + for (int i = 0; item; ++i, item = item->nextSibling()) { + m_StreamingDevice->addCaptureStream(item->text(1), m_CaptureSoundFormats[i], m_CaptureBufferSizes[i], !item->nextSibling()); + } + + m_dirty = false; +} + + +void StreamingConfiguration::slotCancel() +{ + if (!m_dirty) + return; + + const QStringList &playbackChannels = m_StreamingDevice->getPlaybackChannels(); + const QStringList &captureChannels = m_StreamingDevice->getCaptureChannels(); + + m_ListPlaybackURLs->clear(); + m_PlaybackBufferSizes.clear(); + m_PlaybackSoundFormats.clear(); + + for (unsigned int i = 0; i < playbackChannels.size(); ++i) { + SoundFormat sf; + size_t buffer_size; + QString url; + m_StreamingDevice->getPlaybackStreamOptions(playbackChannels[i], url, sf, buffer_size); + m_PlaybackSoundFormats.append(sf); + m_PlaybackBufferSizes.append(buffer_size); + + QListViewItem *item = new QListViewItem(m_ListPlaybackURLs, m_ListPlaybackURLs->lastChild()); + item->setText(0, QString::number(m_ListPlaybackURLs->childCount())); + item->setText(1, url); + item->setRenameEnabled(1, true); + } + + m_ListCaptureURLs->clear(); + m_CaptureBufferSizes.clear(); + m_CaptureSoundFormats.clear(); + + for (unsigned int i = 0; i < captureChannels.size(); ++i) { + SoundFormat sf; + size_t buffer_size; + QString url; + m_StreamingDevice->getCaptureStreamOptions(captureChannels[i], url, sf, buffer_size); + m_CaptureSoundFormats.append(sf); + m_CaptureBufferSizes.append(buffer_size); + + QListViewItem *item = new QListViewItem(m_ListCaptureURLs, m_ListCaptureURLs->lastChild()); + item->setText(0, QString::number(m_ListCaptureURLs->childCount())); + item->setText(1, url); + item->setRenameEnabled(1, true); + } + slotPlaybackSelectionChanged(); + slotCaptureSelectionChanged(); + + m_dirty = false; +} + +void StreamingConfiguration::slotUpdateConfig() +{ + slotSetDirty(); + slotCancel(); +} + +void StreamingConfiguration::slotNewPlaybackChannel() +{ + slotSetDirty(); + QListViewItem *item = new QListViewItem(m_ListPlaybackURLs, m_ListPlaybackURLs->lastChild()); + item->setText(0, QString::number(m_ListPlaybackURLs->childCount())); + item->setText(1, i18n("new channel")); + item->setRenameEnabled(1,true); + item->startRename(1); + + m_PlaybackSoundFormats.append(SoundFormat()); + m_PlaybackBufferSizes.append(64*1024); + int n = m_PlaybackSoundFormats.size(); + setStreamOptions(m_PlaybackSoundFormats[n-1], m_PlaybackBufferSizes[n-1]); +} + + +void StreamingConfiguration::slotDeletePlaybackChannel() +{ + slotSetDirty(); + QListViewItem *item = m_ListPlaybackURLs->selectedItem(); + if (item) { + int idx = 0; + QListViewItem *i = m_ListPlaybackURLs->firstChild(), + *prev = NULL, + *next = item->nextSibling(); + for (; i && i != item; i = i->nextSibling()) { + prev = i; + ++idx; + } + if(next) { + m_ListPlaybackURLs->setSelected(next, true); + } else if (prev){ + m_ListPlaybackURLs->setSelected(prev, true); + } + int x = item->text(0).toUInt(); + for (i = next; i; i = i->nextSibling(), ++x) { + i->setText(0, QString::number(x)); + } + m_ListPlaybackURLs->takeItem(item); + delete item; + + int n = m_PlaybackSoundFormats.size(); + m_PlaybackSoundFormats.remove(m_PlaybackSoundFormats.at(idx)); + m_PlaybackBufferSizes .remove(m_PlaybackBufferSizes.at(idx)); + idx = idx < n - 1 ? idx : n - 1; + setStreamOptions( m_PlaybackSoundFormats[idx], m_PlaybackBufferSizes[idx]); + slotPlaybackSelectionChanged(); + } +} + + +void StreamingConfiguration::slotUpPlaybackChannel() +{ + slotSetDirty(); + QListViewItem *prev = NULL; + QListViewItem *i = m_ListPlaybackURLs->firstChild(); + QListViewItem *item = m_ListPlaybackURLs->selectedItem(); + int idx = 0; + for (; i && i != item; i = i->nextSibling(), ++idx) { + prev = i; + } + if (prev && item) { + QString s = prev->text(1); + prev->setText(1, item->text(1)); + item->setText(1, s); + SoundFormat sf = m_PlaybackSoundFormats[idx]; + m_PlaybackSoundFormats[idx] = m_PlaybackSoundFormats[idx-1]; + m_PlaybackSoundFormats[idx-1] = sf; + size_t size = m_PlaybackBufferSizes[idx]; + m_PlaybackBufferSizes[idx] = m_PlaybackBufferSizes[idx-1]; + m_PlaybackBufferSizes[idx-1] = size; + m_ListPlaybackURLs->setSelected(prev, true); + } + m_ListPlaybackURLs->ensureItemVisible(prev); +} + + +void StreamingConfiguration::slotDownPlaybackChannel() +{ + slotSetDirty(); + QListViewItem *item = m_ListPlaybackURLs->selectedItem(); + QListViewItem *next = item ? item->nextSibling() : NULL; + QListViewItem *i = m_ListPlaybackURLs->firstChild(); + int idx = 0; + for (; i && i != item; i = i->nextSibling()) { + ++idx; + } + if (next && item) { + QString s = next->text(1); + next->setText(1, item->text(1)); + item->setText(1, s); + SoundFormat sf = m_PlaybackSoundFormats[idx]; + m_PlaybackSoundFormats[idx] = m_PlaybackSoundFormats[idx+1]; + m_PlaybackSoundFormats[idx+1] = sf; + size_t size = m_PlaybackBufferSizes[idx]; + m_PlaybackBufferSizes[idx] = m_PlaybackBufferSizes[idx+1]; + m_PlaybackBufferSizes[idx+1] = size; + m_ListPlaybackURLs->setSelected(next, true); + } + m_ListPlaybackURLs->ensureItemVisible(next); +} + + + +void StreamingConfiguration::slotNewCaptureChannel() +{ + slotSetDirty(); + QListViewItem *item = new QListViewItem(m_ListCaptureURLs, m_ListCaptureURLs->lastChild()); + item->setText(0, QString::number(m_ListCaptureURLs->childCount())); + item->setText(1, i18n("new channel")); + item->setRenameEnabled(1,true); + item->startRename(1); + + m_CaptureSoundFormats.append(SoundFormat()); + m_CaptureBufferSizes.append(64*1024); + int n = m_CaptureSoundFormats.size(); + setStreamOptions(m_CaptureSoundFormats[n-1], m_CaptureBufferSizes[n-1]); +} + + +void StreamingConfiguration::slotDeleteCaptureChannel() +{ + slotSetDirty(); + QListViewItem *item = m_ListCaptureURLs->selectedItem(); + if (item) { + int idx = 0; + QListViewItem *i = m_ListCaptureURLs->firstChild(), + *prev = NULL, + *next = item->nextSibling(); + for (; i && i != item; i = i->nextSibling()) { + prev = i; + ++idx; + } + if (next) { + m_ListCaptureURLs->setSelected(next, true); + } else if (prev){ + m_ListCaptureURLs->setSelected(prev, true); + } + int x = item->text(0).toUInt(); + for (i = next; i; i = i->nextSibling(), ++x) { + i->setText(0, QString::number(x)); + } + m_ListCaptureURLs->takeItem(item); + delete item; + + int n = m_CaptureSoundFormats.size(); + m_CaptureSoundFormats.remove(m_CaptureSoundFormats.at(idx)); + m_CaptureBufferSizes .remove(m_CaptureBufferSizes.at(idx)); + idx = idx < n - 1 ? idx : n - 1; + setStreamOptions( m_CaptureSoundFormats[idx], m_CaptureBufferSizes[idx]); + slotCaptureSelectionChanged(); + } +} + + +void StreamingConfiguration::slotUpCaptureChannel() +{ + slotSetDirty(); + QListViewItem *prev = NULL; + QListViewItem *i = m_ListCaptureURLs->firstChild(); + QListViewItem *item = m_ListCaptureURLs->selectedItem(); + int idx = 0; + for (; i && i != item; i = i->nextSibling(), ++idx) { + prev = i; + } + if (prev && item) { + QString s = prev->text(1); + prev->setText(1, item->text(1)); + item->setText(1, s); + SoundFormat sf = m_CaptureSoundFormats[idx]; + m_CaptureSoundFormats[idx] = m_CaptureSoundFormats[idx-1]; + m_CaptureSoundFormats[idx-1] = sf; + size_t size = m_CaptureBufferSizes[idx]; + m_CaptureBufferSizes[idx] = m_CaptureBufferSizes[idx-1]; + m_CaptureBufferSizes[idx-1] = size; + m_ListCaptureURLs->setSelected(prev, true); + } + m_ListCaptureURLs->ensureItemVisible(prev); +} + + +void StreamingConfiguration::slotDownCaptureChannel() +{ + slotSetDirty(); + QListViewItem *item = m_ListCaptureURLs->selectedItem(); + QListViewItem *next = item ? item->nextSibling() : NULL; + QListViewItem *i = m_ListCaptureURLs->firstChild(); + int idx = 0; + for (; i && i != item; i = i->nextSibling()) { + ++idx; + } + if (next && item) { + QString s = next->text(1); + next->setText(1, item->text(1)); + item->setText(1, s); + SoundFormat sf = m_CaptureSoundFormats[idx]; + m_CaptureSoundFormats[idx] = m_CaptureSoundFormats[idx+1]; + m_CaptureSoundFormats[idx+1] = sf; + size_t size = m_CaptureBufferSizes[idx]; + m_CaptureBufferSizes[idx] = m_CaptureBufferSizes[idx+1]; + m_CaptureBufferSizes[idx+1] = size; + m_ListCaptureURLs->setSelected(next, true); + } + m_ListCaptureURLs->ensureItemVisible(next); +} + + + + + +void StreamingConfiguration::slotPlaybackSelectionChanged() +{ + QListViewItem *item = m_ListPlaybackURLs->selectedItem(); + bool up_possible = false; + bool down_possible = false; + if (item) { + int idx = 0; + QListViewItem *i = m_ListPlaybackURLs->firstChild(); + for (; i && i != item; i = i->nextSibling()) { + ++idx; + } + up_possible = idx > 0; + down_possible = idx < m_ListPlaybackURLs->childCount() - 1; + setStreamOptions(m_PlaybackSoundFormats[idx], m_PlaybackBufferSizes[idx]); + + item = m_ListCaptureURLs->selectedItem(); + if (item) + m_ListCaptureURLs->setSelected(item, false); + } + QListViewItem *playback_item = m_ListPlaybackURLs->selectedItem(); + QListViewItem *capture_item = m_ListCaptureURLs->selectedItem(); + bool e = (playback_item || capture_item); + m_cbFormat ->setEnabled(e); + m_cbRate ->setEnabled(e); + m_cbBits ->setEnabled(e); + m_cbSign ->setEnabled(e); + m_cbChannels ->setEnabled(e); + m_cbEndianess ->setEnabled(e); + m_sbBufferSize->setEnabled(e); + m_pbUpPlaybackURL ->setEnabled(up_possible); + m_pbDownPlaybackURL->setEnabled(down_possible); +} + + +void StreamingConfiguration::slotCaptureSelectionChanged() +{ + QListViewItem *item = m_ListCaptureURLs->selectedItem(); + bool up_possible = false; + bool down_possible = false; + if (item) { + int idx = 0; + QListViewItem *i = m_ListCaptureURLs->firstChild(); + for (; i && i != item; i = i->nextSibling()) { + ++idx; + } + up_possible = idx > 0; + down_possible = idx < m_ListCaptureURLs->childCount() - 1; + setStreamOptions(m_CaptureSoundFormats[idx], m_CaptureBufferSizes[idx]); + + item = m_ListPlaybackURLs->selectedItem(); + if (item) + m_ListPlaybackURLs->setSelected(item, false); + } + QListViewItem *playback_item = m_ListPlaybackURLs->selectedItem(); + QListViewItem *capture_item = m_ListCaptureURLs->selectedItem(); + bool e = (playback_item || capture_item); + m_cbFormat ->setEnabled(e); + m_cbRate ->setEnabled(e); + m_cbBits ->setEnabled(e); + m_cbSign ->setEnabled(e); + m_cbChannels ->setEnabled(e); + m_cbEndianess ->setEnabled(e); + m_sbBufferSize->setEnabled(e); + m_pbUpCaptureURL ->setEnabled(up_possible); + m_pbDownCaptureURL->setEnabled(down_possible); +} + +void StreamingConfiguration::slotSetDirty() +{ + m_dirty = true; +} + +void StreamingConfiguration::slotUpdateSoundFormat() +{ + if (m_ignore_updates) + return; + + slotSetDirty(); + QListViewItem *playback_item = m_ListPlaybackURLs->selectedItem(); + QListViewItem *capture_item = m_ListCaptureURLs->selectedItem(); + if (playback_item) { + int idx = 0; + QListViewItem *i = m_ListPlaybackURLs->firstChild(); + for (; i && i != playback_item; i = i->nextSibling()) { + ++idx; + } + getStreamOptions(m_PlaybackSoundFormats[idx], m_PlaybackBufferSizes[idx]); + } + else if (capture_item) { + int idx = 0; + QListViewItem *i = m_ListCaptureURLs->firstChild(); + for (; i && i != capture_item; i = i->nextSibling()) { + ++idx; + } + getStreamOptions(m_CaptureSoundFormats[idx], m_CaptureBufferSizes[idx]); + } +} + + +void StreamingConfiguration::setStreamOptions(const SoundFormat &sf, int BufferSize) +{ + m_ignore_updates = true; + + int idx_Format = FORMAT_RAW_IDX; + int idx_Rate = RATE_44100_IDX; + int idx_Bits = BITS_16_IDX; + int idx_Sign = SIGN_SIGNED_IDX; + int idx_Channels = CHANNELS_STEREO_IDX; + int idx_Endianess = ENDIAN_LITTLE_IDX; + + if (sf.m_Encoding == "raw") { + idx_Format = FORMAT_RAW_IDX; + } + else { + // ... + } + + switch(sf.m_SampleRate) { + case 48000 : idx_Rate = RATE_48000_IDX; break; + case 44100 : idx_Rate = RATE_44100_IDX; break; + case 22050 : idx_Rate = RATE_22050_IDX; break; + case 11025 : idx_Rate = RATE_11025_IDX; break; + } + + switch(sf.m_SampleBits) { + case 8 : idx_Bits = BITS_8_IDX; break; + case 16 : idx_Bits = BITS_16_IDX; break; + } + + switch(sf.m_IsSigned) { + case true : idx_Sign = SIGN_SIGNED_IDX; break; + case false : idx_Sign = SIGN_UNSIGNED_IDX; break; + } + + switch(sf.m_Channels) { + case 2: idx_Channels = CHANNELS_STEREO_IDX; break; + case 1: idx_Channels = CHANNELS_MONO_IDX; break; + } + + switch(sf.m_Endianess) { + case LITTLE_ENDIAN: idx_Endianess = ENDIAN_LITTLE_IDX; break; + case BIG_ENDIAN: idx_Endianess = ENDIAN_BIG_IDX; break; + } + + m_cbFormat ->setCurrentItem(idx_Format); + m_cbRate ->setCurrentItem(idx_Rate); + m_cbBits ->setCurrentItem(idx_Bits); + m_cbSign ->setCurrentItem(idx_Sign); + m_cbChannels ->setCurrentItem(idx_Channels); + m_cbEndianess ->setCurrentItem(idx_Endianess); + m_sbBufferSize->setValue(BufferSize / 1024); + + m_ignore_updates = false; +} + + +void StreamingConfiguration::getStreamOptions(SoundFormat &sf, int &BufferSize) const +{ + int idx_Format = m_cbFormat ->currentItem(); + int idx_Rate = m_cbRate ->currentItem(); + int idx_Bits = m_cbBits ->currentItem(); + int idx_Sign = m_cbSign ->currentItem(); + int idx_Channels = m_cbChannels ->currentItem(); + int idx_Endianess = m_cbEndianess ->currentItem(); + + BufferSize = m_sbBufferSize->value() * 1024; + + if (idx_Format == FORMAT_RAW_IDX) { + sf.m_Encoding = "raw"; + } + else { + // ... + } + + switch(idx_Rate) { + case RATE_48000_IDX : sf.m_SampleRate = 48000; break; + case RATE_44100_IDX : sf.m_SampleRate = 44100; break; + case RATE_22050_IDX : sf.m_SampleRate = 22050; break; + case RATE_11025_IDX : sf.m_SampleRate = 11025; break; + default : sf.m_SampleRate = 44100; break; + } + + switch(idx_Bits) { + case BITS_8_IDX : sf.m_SampleBits = 8; break; + case BITS_16_IDX : sf.m_SampleBits = 16; break; + default : sf.m_SampleBits = 16; break; + } + + switch(idx_Sign) { + case SIGN_SIGNED_IDX : sf.m_IsSigned = true; break; + case SIGN_UNSIGNED_IDX : sf.m_IsSigned = false; break; + default : sf.m_IsSigned = true; break; + } + + switch(idx_Channels) { + case CHANNELS_STEREO_IDX : sf.m_Channels = 2; break; + case CHANNELS_MONO_IDX : sf.m_Channels = 1; break; + default : sf.m_Channels = 2; break; + } + + switch(idx_Endianess) { + case ENDIAN_LITTLE_IDX : sf.m_Endianess = LITTLE_ENDIAN; break; + case ENDIAN_BIG_IDX : sf.m_Endianess = BIG_ENDIAN; break; + default : sf.m_Endianess = BYTE_ORDER; break; + } +} + +#include "streaming-configuration.moc" diff --git a/kradio3/plugins/streaming/streaming-configuration.h b/kradio3/plugins/streaming/streaming-configuration.h new file mode 100644 index 0000000..f40a0cb --- /dev/null +++ b/kradio3/plugins/streaming/streaming-configuration.h @@ -0,0 +1,97 @@ +/*************************************************************************** + oss-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_STREAMING_CONFIGURATION_H +#define KRADIO_STREAMING_CONFIGURATION_H + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "streaming-configuration-ui.h" +#include "streaming.h" + + + +#define RATE_48000_IDX 0 +#define RATE_44100_IDX 1 +#define RATE_22050_IDX 2 +#define RATE_11025_IDX 3 + +#define CHANNELS_STEREO_IDX 0 +#define CHANNELS_MONO_IDX 1 + +#define SIGN_SIGNED_IDX 0 +#define SIGN_UNSIGNED_IDX 1 + +#define BITS_16_IDX 0 +#define BITS_8_IDX 1 + +#define ENDIAN_LITTLE_IDX 0 +#define ENDIAN_BIG_IDX 1 + +#define FORMAT_RAW_IDX 0 + + +class StreamingConfiguration : public StreamingConfigurationUI +{ +Q_OBJECT +public : + StreamingConfiguration (QWidget *parent, StreamingDevice *streamer); + ~StreamingConfiguration (); + +protected slots: + + void slotOK(); + void slotCancel(); + + void slotUpdateConfig(); + + + + void slotNewPlaybackChannel(); + void slotDeletePlaybackChannel(); + void slotUpPlaybackChannel(); + void slotDownPlaybackChannel(); + + void slotNewCaptureChannel(); + void slotDeleteCaptureChannel(); + void slotUpCaptureChannel(); + void slotDownCaptureChannel(); + + void slotPlaybackSelectionChanged(); + void slotCaptureSelectionChanged(); + + void slotUpdateSoundFormat(); + void slotSetDirty(); + +protected: + + void setStreamOptions(const SoundFormat &sf, int BufferSize); + void getStreamOptions(SoundFormat &sf, int &BufferSize) const ; + + + QValueList<SoundFormat> m_PlaybackSoundFormats, m_CaptureSoundFormats; + QValueList<int> m_PlaybackBufferSizes, m_CaptureBufferSizes; + + bool m_ignore_updates; + bool m_dirty; + StreamingDevice *m_StreamingDevice; + +}; + +#endif diff --git a/kradio3/plugins/streaming/streaming-job.cpp b/kradio3/plugins/streaming/streaming-job.cpp new file mode 100644 index 0000000..0c3736a --- /dev/null +++ b/kradio3/plugins/streaming/streaming-job.cpp @@ -0,0 +1,279 @@ +/*************************************************************************** + streaming-job.cpp - description + ------------------- + begin : Sun Sept 3 2006 + copyright : (C) 2006 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 "streaming-job.h" + +#include "../../src/include/utils.h" +#include <kurl.h> + +#include <kio/job.h> + + +StreamingJob::StreamingJob() + : QObject(), + m_URL(QString::null), + m_SoundFormat(), + m_BufferSize(65536), + m_Buffer(m_BufferSize), + m_OpenCounter(0), + m_StreamPos(0), + m_StartTime(0), + m_SkipCount(0), + m_KIO_Job(NULL), + m_capturing(false) +{ +} + +StreamingJob::StreamingJob(const QString &_URL, const SoundFormat &_SoundFormat, size_t _bufferSize) + : QObject(), + m_URL(_URL), + m_SoundFormat(_SoundFormat), + m_BufferSize(_bufferSize), + m_Buffer(m_BufferSize), + m_OpenCounter(0), + m_StreamPos(0), + m_StartTime(0), + m_SkipCount(0), + m_KIO_Job(NULL), + m_capturing(false) +{ +} + +StreamingJob::StreamingJob(const StreamingJob &c) + : QObject(), + m_URL(c.m_URL), + m_SoundFormat(c.m_SoundFormat), + m_BufferSize(c.m_BufferSize), + m_Buffer(m_BufferSize), + m_OpenCounter(0), + m_StreamPos(0), + m_StartTime(0), + m_SkipCount(0), + m_KIO_Job(NULL), + m_capturing(c.m_capturing) +{ +} + +StreamingJob::~StreamingJob() +{ +} + + +void StreamingJob::setURL(const QString &url) +{ + if (m_URL != url) { + m_URL = url; + delete m_KIO_Job; + m_KIO_Job = NULL; + if (!m_capturing) { + startPutJob(); + } else { + startGetJob(); + } + } +} + + +void StreamingJob::setSoundFormat(const SoundFormat &sf) +{ + m_SoundFormat = sf; +} + + +void StreamingJob::setBufferSize(size_t buffer_size) +{ + if (m_BufferSize != buffer_size) { + m_Buffer.clear(); + m_Buffer.resize(m_BufferSize = buffer_size); + } +} + + +bool StreamingJob::startPutJob() +{ + m_KIO_Job = KIO::put(m_URL, -1, true, false, false); + if (!m_KIO_Job) + return false; + m_KIO_Job->setAsyncDataEnabled(true); + connect (m_KIO_Job, SIGNAL(dataReq(KIO::Job *job, QByteArray &data)), + this, SLOT(slotWriteData (KIO::Job *job, QByteArray &data))); + connect (m_KIO_Job, SIGNAL(result(KIO::Job *)), + this, SLOT(slotIOJobResult(KIO::Job *))); + return true; +} + + +bool StreamingJob::startPlayback() +{ + if (!m_OpenCounter) { + m_Buffer.clear(); + m_OpenCounter = 1; + if (!startPutJob()) + return false; + m_StartTime = time(NULL); + m_StreamPos = 0; + if (m_KIO_Job->error()) { + emit logStreamError(m_URL, m_KIO_Job->errorString()); + } + return m_KIO_Job->error() == 0; + } + else { + return true; + } +} + +bool StreamingJob::stopPlayback() +{ + if (m_OpenCounter) { + if (!--m_OpenCounter) { + delete m_KIO_Job; + m_KIO_Job = NULL; + } + } + return true; +} + + +bool StreamingJob::startGetJob() +{ + m_KIO_Job = KIO::get(m_URL, false, false); + if (!m_KIO_Job) + return false; + m_KIO_Job->setAsyncDataEnabled(true); + connect (m_KIO_Job, SIGNAL(data(KIO::Job *, const QByteArray &)), + this, SLOT(slotReadData(KIO::Job *, const QByteArray &))); + connect (m_KIO_Job, SIGNAL(result(KIO::Job *)), + this, SLOT(slotIOJobResult(KIO::Job *))); + return true; +} + + +bool StreamingJob::startCapture(const SoundFormat &/*proposed_format*/, + SoundFormat &real_format, + bool /*force_format*/) +{ + if (!m_OpenCounter) { + m_capturing = true; + m_Buffer.clear(); + if (!startGetJob()) + return false; + m_StartTime = time(NULL); + m_StreamPos = 0; + if (m_KIO_Job->error()) { + emit logStreamError(m_URL, m_KIO_Job->errorString()); + } + return m_KIO_Job->error() == 0; + } + ++m_OpenCounter; + real_format = m_SoundFormat; + return true; +} + + +bool StreamingJob::stopCapture() +{ + if (m_OpenCounter) { + if (!--m_OpenCounter) { + delete m_KIO_Job; + m_KIO_Job = NULL; + } + } + return true; +} + + +void StreamingJob::slotReadData (KIO::Job */*job*/, const QByteArray &data) +{ + size_t free = m_Buffer.getFreeSize(); + if (free < data.size()) { + m_SkipCount += data.size() - free; + emit logStreamWarning(m_URL, i18n("skipped %1 bytes").arg(data.size() - free)); + } + else { + free = data.size(); + } + + m_Buffer.addData(data.data(), free); + m_StreamPos += free; + + if (m_Buffer.getFreeSize() < data.size()) { + m_KIO_Job->suspend(); + } +} + + +void StreamingJob::slotWriteData (KIO::Job */*job*/, QByteArray &) +{ + size_t size = m_Buffer.getFillSize(); + if (size) { + char *buf = new char [size]; + size = m_Buffer.takeData(buf, size); + QByteArray data; + data.assign(buf, size); + m_KIO_Job->sendAsyncData(data); + m_StreamPos += size; + } + else { + // does a warning really make sense here? + //emit logStreamWarning(m_URL, i18n("buffer underrun")); + m_SkipCount++; + } +} + + +void StreamingJob::playData(const char *data, size_t size, size_t &consumed_size) +{ + size_t free = m_Buffer.getFreeSize(); + consumed_size = (consumed_size == SIZE_T_DONT_CARE) ? free : min(consumed_size, free); + if (free > size) { + free = size; + } + m_Buffer.addData(data, free); +} + + +bool StreamingJob::hasRecordedData() const +{ + return m_Buffer.getFillSize() > m_Buffer.getSize() / 3; +} + + +void StreamingJob::lockData(const char *&data, size_t &size, SoundMetaData &meta_data) +{ + data = m_Buffer.getData(size); + time_t cur_time = time(NULL); + meta_data = SoundMetaData(m_StreamPos, cur_time - m_StartTime, cur_time, m_URL); +} + + +void StreamingJob::removeData(size_t size) +{ + m_Buffer.removeData(size); + if (m_Buffer.getFreeSize() > m_Buffer.getSize() / 2) { + m_KIO_Job->resume(); + } +} + +void StreamingJob::slotIOJobResult (KIO::Job *job) +{ + if (job && job->error()) { + emit logStreamError(m_URL, job->errorString()); + } +} + +#include "streaming-job.moc" + diff --git a/kradio3/plugins/streaming/streaming-job.h b/kradio3/plugins/streaming/streaming-job.h new file mode 100644 index 0000000..b88c32a --- /dev/null +++ b/kradio3/plugins/streaming/streaming-job.h @@ -0,0 +1,100 @@ +/*************************************************************************** + streaming-job.h - description + ------------------- + begin : Sun Sept 3 2006 + copyright : (C) 2006 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_STREAMING_JOB_H +#define _KRADIO_STREAMING_JOB_H + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "../../src/include/ringbuffer.h" +#include "../../src/include/soundformat.h" +#include "../../src/include/soundstreamclient_interfaces.h" + +#include <qobject.h> + +#include <kio/jobclasses.h> + +class StreamingJob : public QObject +{ +Q_OBJECT +public: + StreamingJob(); + StreamingJob(const QString &_URL, const SoundFormat &_SoundFormat, size_t _bufferSize); + StreamingJob(const StreamingJob &c); + + virtual ~StreamingJob(); + + const QString &getURL() const { return m_URL; } + const SoundFormat &getSoundFormat() const { return m_SoundFormat; } + int getBufferSize() const { return m_BufferSize; } + + void setURL(const QString &); + void setSoundFormat(const SoundFormat &); + void setBufferSize(size_t buffer_size); + + bool startPlayback(); + bool stopPlayback(); + + bool startCapture(const SoundFormat &proposed_format, + SoundFormat &real_format, + bool force_format); + bool stopCapture(); + + + void playData(const char *data, size_t size, size_t &consumed_size); + bool hasRecordedData() const; + void lockData(const char *&data, size_t &size, SoundMetaData &meta_data); + void removeData(size_t); + +protected slots: + + void slotReadData (KIO::Job *job, const QByteArray &data); + void slotWriteData (KIO::Job *job, QByteArray &data); + void slotIOJobResult (KIO::Job *job); + +signals: + + void logStreamError(const KURL &url, const QString &s); + void logStreamWarning(const KURL &url, const QString &s); + +protected: + + bool startGetJob(); + bool startPutJob(); + + + QString m_URL; + SoundFormat m_SoundFormat; + + size_t m_BufferSize; + RingBuffer m_Buffer; + + unsigned m_OpenCounter; + Q_UINT64 m_StreamPos; + time_t m_StartTime; + + size_t m_SkipCount; + + KIO::TransferJob *m_KIO_Job; + bool m_capturing; +}; + + + +#endif diff --git a/kradio3/plugins/streaming/streaming.cpp b/kradio3/plugins/streaming/streaming.cpp new file mode 100644 index 0000000..5f5431c --- /dev/null +++ b/kradio3/plugins/streaming/streaming.cpp @@ -0,0 +1,526 @@ +/*************************************************************************** + streaming.cpp - description + ------------------- + begin : Sun Sept 3 2006 + copyright : (C) 2006 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 "streaming.h" + +#include "../../src/include/aboutwidget.h" +#include "../../src/include/utils.h" +#include <klocale.h> +#include <kaboutdata.h> +#include <kurl.h> +#include <klocale.h> + +#include "streaming-job.h" +#include "streaming-configuration.h" + +/////////////////////////////////////////////////////////////////////// +//// plugin library functions + +PLUGIN_LIBRARY_FUNCTIONS(StreamingDevice, "kradio-streaming", i18n("Streaming Support")); + +///////////////////////////////////////////////////////////////////////////// + + + + +StreamingDevice::StreamingDevice(const QString &name) + : QObject(NULL, NULL), + PluginBase(name, i18n("KRadio Streaming Plugin")) +{ + m_CaptureChannels.setAutoDelete(true); + m_PlaybackChannels.setAutoDelete(true); +} + + +StreamingDevice::~StreamingDevice() +{ + resetPlaybackStreams(); + resetCaptureStreams(); +} + + +bool StreamingDevice::connectI(Interface *i) +{ + bool a = PluginBase::connectI(i); + bool b = ISoundStreamClient::connectI(i); + return a || b; +} + + +bool StreamingDevice::disconnectI(Interface *i) +{ + bool a = PluginBase::disconnectI(i); + bool b = ISoundStreamClient::disconnectI(i); + return a || b; +} + +void StreamingDevice::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_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); + s->register4_notifyReadyForPlaybackData(this); + } +} + +// PluginBase + +void StreamingDevice::saveState (KConfig *c) const +{ + c->setGroup(QString("streaming-") + PluginBase::name()); + c->writeEntry("soundstreamclient-id", m_SoundStreamClientID); + + c->writeEntry("playback-channels", m_PlaybackChannelList.size()); + for (unsigned int i = 0; i < m_PlaybackChannelList.size(); ++i) { + QString s = m_PlaybackChannelList[i]; + const StreamingJob *j = m_PlaybackChannels[s]; + + const SoundFormat &sf = j->getSoundFormat(); + KURL url = j->getURL(); + size_t buffer_size = j->getBufferSize(); + + sf.saveConfig("playback-channel-" + QString::number(i), c); + c->writeEntry("playback-channel-" + QString::number(i) + "-url", url.url()); + c->writeEntry("playback-channel-" + QString::number(i) + "-buffer-size", buffer_size); + } + + c->writeEntry("capture-channels", m_CaptureChannelList.size()); + for (unsigned int i = 0; i < m_CaptureChannelList.size(); ++i) { + QString s = m_CaptureChannelList[i]; + const StreamingJob *j = m_CaptureChannels[s]; + + const SoundFormat &sf = j->getSoundFormat(); + KURL url = j->getURL(); + size_t buffer_size = j->getBufferSize(); + + sf.saveConfig("capture-channel-" + QString::number(i), c); + c->writeEntry("capture-channel-" + QString::number(i) + "-url", url.url()); + c->writeEntry("capture-channel-" + QString::number(i) + "-buffer-size", buffer_size); + } +} + +void StreamingDevice::restoreState (KConfig *c) +{ + c->setGroup(QString("streaming-") + PluginBase::name()); + setSoundStreamClientID(c->readEntry("soundstreamclient-id", getSoundStreamClientID())); + + resetPlaybackStreams(false); + resetCaptureStreams(false); + + int n = c->readNumEntry("playback-channels", 0); + for (int i = 0; i < n; ++i) { + SoundFormat sf; + sf.restoreConfig("playback-channel-" + QString::number(i), c); + QString url = c->readEntry("playback-channel-" + QString::number(i) + "-url", QString::null); + size_t buffer_size = c->readNum64Entry("playback-channel-" + QString::number(i) + "-buffer-size", 32*1024); + + if (!url.isNull()) { + addPlaybackStream(url, sf, buffer_size, i == n-1); + } + } + + n = c->readNumEntry("capture-channels", 0); + for (int i = 0; i < n; ++i) { + SoundFormat sf; + sf.restoreConfig("capture-channel-" + QString::number(i), c); + QString url = c->readEntry("capture-channel-" + QString::number(i) + "-url", QString::null); + size_t buffer_size = c->readNum64Entry("capture-channel-" + QString::number(i) + "-buffer-size", 32*1024); + + if (!url.isNull()) { + addCaptureStream(url, sf, buffer_size, i == n-1); + } + } + + if (!m_CaptureChannelList.size()) { + addCaptureStream("/dev/video24", SoundFormat(48000, 2, 16, true, BYTE_ORDER, "raw"), 65536); + } + + emit sigUpdateConfig(); +} + + +ConfigPageInfo StreamingDevice::createConfigurationPage() +{ + StreamingConfiguration *conf = new StreamingConfiguration(NULL, this); + QObject::connect(this, SIGNAL(sigUpdateConfig()), conf, SLOT(slotUpdateConfig())); + return ConfigPageInfo (conf, + i18n("Streaming"), + i18n("Streaming Device Options"), + "kradio_streaming"); +} + + +AboutPageInfo StreamingDevice::createAboutPage() +{ + return AboutPageInfo(); +} + + + +bool StreamingDevice::preparePlayback(SoundStreamID id, const QString &channel, bool /*active_mode*/, bool start_immediately) +{ + if (id.isValid() && m_PlaybackChannels.find(channel)) { + m_AllPlaybackStreams.insert(id, channel); + if (start_immediately) + startPlayback(id); + return true; + } + return false; +} + + +bool StreamingDevice::prepareCapture(SoundStreamID id, const QString &channel) +{ + logDebug("StreamingDevice::prepareCapture"); + if (id.isValid() && m_CaptureChannels.find(channel)) { + m_AllCaptureStreams.insert(id, channel); + return true; + } + return false; +} + +bool StreamingDevice::releasePlayback(SoundStreamID id) +{ + if (id.isValid() && m_AllPlaybackStreams.contains(id)) { + stopPlayback(id); + if (!m_EnabledPlaybackStreams.contains(id)) + m_AllPlaybackStreams.remove(id); + return true; + } + return false; +} + +bool StreamingDevice::releaseCapture(SoundStreamID id) +{ + logDebug("StreamingDevice::releaseCapture"); + if (id.isValid() && m_AllCaptureStreams.contains(id)) { + stopCapture(id); + if (!m_EnabledCaptureStreams.contains(id)) + m_AllCaptureStreams.remove(id); + return true; + } + return false; +} + +bool StreamingDevice::supportsPlayback() const +{ + return m_PlaybackChannels.size() > 0; +} + + +bool StreamingDevice::supportsCapture() const +{ + return m_CaptureChannels.size() > 0; +} + + +bool StreamingDevice::startPlayback(SoundStreamID id) +{ + if (id.isValid() && m_AllPlaybackStreams.contains(id)) { + m_EnabledPlaybackStreams.insert(id, m_AllPlaybackStreams[id]); + StreamingJob &x = *m_PlaybackChannels.find(m_AllPlaybackStreams[id]); + x.startPlayback(); + return true; + } else { + return false; + } +} + + +bool StreamingDevice::pausePlayback(SoundStreamID /*id*/) +{ + //return stopPlayback(id); + return false; +} + + +bool StreamingDevice::stopPlayback(SoundStreamID id) +{ + if (id.isValid() && m_EnabledPlaybackStreams.contains(id)) { + StreamingJob &x = *m_PlaybackChannels.find(m_AllPlaybackStreams[id]); + if (x.stopPlayback()) { + m_EnabledPlaybackStreams.remove(id); + } + return true; + } else { + return false; + } +} + + +bool StreamingDevice::isPlaybackRunning(SoundStreamID id, bool &b) const +{ + if (id.isValid() && m_EnabledPlaybackStreams.contains(id)) { + b = true; + return true; + } else { + return false; + } +} + +bool StreamingDevice::startCaptureWithFormat(SoundStreamID id, + const SoundFormat &proposed_format, + SoundFormat &real_format, + bool force_format) +{ + logDebug("StreamingDevice::startCaptureWithFormat"); + if (id.isValid() && m_AllCaptureStreams.contains(id)) { + m_EnabledCaptureStreams.insert(id, m_AllCaptureStreams[id]); + StreamingJob &x = *m_CaptureChannels.find(m_AllCaptureStreams[id]); + x.startCapture(proposed_format, real_format, force_format); + return true; + } else { + return false; + } +} + + +bool StreamingDevice::stopCapture(SoundStreamID id) +{ + if (id.isValid() && m_EnabledCaptureStreams.contains(id)) { + StreamingJob &x = *m_CaptureChannels.find(m_AllCaptureStreams[id]); + if (x.stopCapture()) { + m_EnabledCaptureStreams.remove(id); + } + return true; + } else { + return false; + } +} + + +bool StreamingDevice::isCaptureRunning(SoundStreamID id, bool &b, SoundFormat &sf) const +{ + if (id.isValid() && m_EnabledCaptureStreams.contains(id)) { + StreamingJob &x = *m_CaptureChannels.find(m_AllCaptureStreams[id]); + sf = x.getSoundFormat(); + b = true; + return true; + } else { + return false; + } +} + + +bool StreamingDevice::noticeSoundStreamClosed(SoundStreamID id) +{ + bool found = (stopCapture(id) && releaseCapture(id)) || + (stopPlayback(id) && releasePlayback(id)); + return found; +} + + +bool StreamingDevice::noticeSoundStreamRedirected(SoundStreamID oldID, SoundStreamID newID) +{ + bool found = false; + if (newID != oldID) { + if (m_AllPlaybackStreams.contains(oldID)) { + m_AllPlaybackStreams.insert(newID, m_AllPlaybackStreams[oldID]); + m_AllPlaybackStreams.remove(oldID); + found = true; + } + if (m_EnabledPlaybackStreams.contains(oldID)) { + m_EnabledPlaybackStreams.insert(newID, m_EnabledPlaybackStreams[oldID]); + m_EnabledPlaybackStreams.remove(oldID); + found = true; + } + if (m_AllCaptureStreams.contains(oldID)) { + m_AllCaptureStreams.insert(newID, m_AllCaptureStreams[oldID]); + m_AllCaptureStreams.remove(oldID); + found = true; + } + if (m_EnabledCaptureStreams.contains(oldID)) { + m_EnabledCaptureStreams.insert(newID, m_EnabledCaptureStreams[oldID]); + m_EnabledCaptureStreams.remove(oldID); + found = true; + } + } + return found; +} + + +bool StreamingDevice::noticeSoundStreamData(SoundStreamID id, + const SoundFormat &/*format*/, + const char *data, size_t size, size_t &consumed_size, + const SoundMetaData &/*md*/ + ) +{ + if (id.isValid() && m_EnabledPlaybackStreams.contains(id)) { + StreamingJob &x = *m_CaptureChannels.find(m_AllCaptureStreams[id]); + x.playData(data, size, consumed_size); + return true; + } + else { + return false; + } +} + +bool StreamingDevice::noticeReadyForPlaybackData(SoundStreamID id, size_t free_size) +{ + if (!id.isValid() || !m_AllCaptureStreams.contains(id)) + return false; + StreamingJob &x = *m_CaptureChannels.find(m_AllCaptureStreams[id]); + + while (x.hasRecordedData() && free_size > 0) { + const char *buffer = NULL; + size_t size = SIZE_T_DONT_CARE; + size_t consumed_size = SIZE_T_DONT_CARE; + SoundMetaData meta_data(0,0,0, i18n("internal stream, not stored (%1)").arg(m_AllCaptureStreams[id])); + x.lockData(buffer, size, meta_data); // get pointer to data and meta-data content + if (size > free_size) + size = free_size; + notifySoundStreamData(id, x.getSoundFormat(), buffer, size, consumed_size, meta_data); + if (consumed_size == SIZE_T_DONT_CARE) + consumed_size = size; + x.removeData(consumed_size); + free_size -= consumed_size; + if (consumed_size < size) { + logWarning(i18n("StreamingDevice %1::notifySoundStreamData: Playback Clients skipped %2 bytes").arg(name()).arg(size-consumed_size)); + break; + } + } + return true; +} + + + +const QStringList &StreamingDevice::getPlaybackChannels() const +{ + return m_PlaybackChannelList; +} + + +const QStringList &StreamingDevice::getCaptureChannels() const +{ + return m_CaptureChannelList; +} + + +QString StreamingDevice::getSoundStreamClientDescription() const +{ + return i18n("Streaming Device %1").arg(PluginBase::name()); +} + + +void StreamingDevice::logStreamError(const KURL &url, const QString &s) +{ + logError(i18n("Streaming Device %1, %2: %3").arg(name()).arg(url.url()).arg(s)); +} + +void StreamingDevice::logStreamWarning(const KURL &url, const QString &s) +{ + logWarning(i18n("Streaming Device %1, %2: %3").arg(name()).arg(url.url()).arg(s)); +} + + +bool StreamingDevice::getPlaybackStreamOptions(const QString &channel, QString &url, SoundFormat &sf, size_t &buffer_size) const +{ + if (m_PlaybackChannels.find(channel)) { + const StreamingJob *j = m_PlaybackChannels[channel]; + url = j->getURL(); + sf = j->getSoundFormat(); + buffer_size = j->getBufferSize(); + return true; + } + return false; +} + + +bool StreamingDevice::getCaptureStreamOptions(const QString &channel, QString &url, SoundFormat &sf, size_t &buffer_size) const +{ + if (m_CaptureChannels.find(channel)) { + const StreamingJob *j = m_CaptureChannels[channel]; + url = j->getURL(); + sf = j->getSoundFormat(); + buffer_size = j->getBufferSize(); + return true; + } + return false; +} + +void StreamingDevice::resetPlaybackStreams(bool notification_enabled) +{ + while (m_EnabledPlaybackStreams.begin() != m_EnabledPlaybackStreams.end()) { + sendStopPlayback(m_EnabledPlaybackStreams.begin().key()); + } + while (m_AllPlaybackStreams.begin() != m_AllPlaybackStreams.end()) { + releasePlayback(m_AllPlaybackStreams.begin().key()); + } + m_PlaybackChannelList.clear(); + m_PlaybackChannels.clear(); + if (notification_enabled) { + notifyPlaybackChannelsChanged(m_SoundStreamClientID, m_PlaybackChannelList); + } +} + + +void StreamingDevice::resetCaptureStreams(bool notification_enabled) +{ + while (m_EnabledCaptureStreams.begin() != m_EnabledCaptureStreams.end()) { + sendStopCapture(m_EnabledCaptureStreams.begin().key()); + } + while (m_AllCaptureStreams.begin() != m_AllCaptureStreams.end()) { + releaseCapture(m_AllCaptureStreams.begin().key()); + } + m_CaptureChannelList.clear(); + m_CaptureChannels.clear(); + if (notification_enabled) { + notifyCaptureChannelsChanged(m_SoundStreamClientID, m_CaptureChannelList); + } +} + + +void StreamingDevice::addPlaybackStream(const QString &url, const SoundFormat &sf, size_t buffer_size, bool notification_enabled) +{ + StreamingJob *x = new StreamingJob(url, sf, buffer_size); + connect(x, SIGNAL(logStreamError(const KURL &, const QString &)), + this, SLOT (logStreamError(const KURL &, const QString &))); + + m_PlaybackChannelList.append(url); + m_PlaybackChannels.insert(url, x); + if (notification_enabled) { + notifyPlaybackChannelsChanged(m_SoundStreamClientID, m_PlaybackChannelList); + } +} + + +void StreamingDevice::addCaptureStream (const QString &url, const SoundFormat &sf, size_t buffer_size, bool notification_enabled) +{ + StreamingJob *x = new StreamingJob(url, sf, buffer_size); + connect(x, SIGNAL(logStreamError(const KURL &, const QString &)), + this, SLOT (logStreamError(const KURL &, const QString &))); + + m_CaptureChannelList.append(url); + m_CaptureChannels.insert(url, x); + if (notification_enabled) { + notifyCaptureChannelsChanged(m_SoundStreamClientID, m_CaptureChannelList); + } +} + + +#include "streaming.moc" diff --git a/kradio3/plugins/streaming/streaming.h b/kradio3/plugins/streaming/streaming.h new file mode 100644 index 0000000..430ab7b --- /dev/null +++ b/kradio3/plugins/streaming/streaming.h @@ -0,0 +1,145 @@ +/*************************************************************************** + streaming.h - description + ------------------- + begin : Sun Sept 3 2006 + copyright : (C) 2006 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_STREAMING_H +#define _KRADIO_STREAMING_H + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "../../src/include/plugins.h" +#include "../../src/include/soundformat.h" +#include "../../src/include/soundstreamclient_interfaces.h" + +#include <qobject.h> +#include <qdict.h> + +class StreamingJob; + +class StreamingDevice : public QObject, + public PluginBase, + public ISoundStreamClient +{ +Q_OBJECT + +public: + StreamingDevice (const QString &name); + virtual ~StreamingDevice (); + + virtual bool connectI(Interface *i); + virtual bool disconnectI(Interface *i); + + bool getPlaybackStreamOptions(const QString &channel, QString &url, SoundFormat &sf, size_t &buffer_size) const; + bool getCaptureStreamOptions (const QString &channel, QString &url, SoundFormat &sf, size_t &buffer_size) const; + + void resetPlaybackStreams(bool notification_enabled = true); + void resetCaptureStreams(bool notification_enabled = true); + void addPlaybackStream(const QString &url, const SoundFormat &sf, size_t buffer_size, bool notification_enabled = true); + void addCaptureStream (const QString &url, const SoundFormat &sf, size_t buffer_size, bool notification_enabled = true); + + // PluginBase + +public: + virtual void saveState (KConfig *) const; + virtual void restoreState (KConfig *); + + virtual QString pluginClassName() const { return "StreamingDevice"; } + + virtual const QString &name() const { return PluginBase::name(); } + virtual QString &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 QString &channel, bool active_mode, bool start_immediately); + bool prepareCapture(SoundStreamID id, const QString &channel); + bool releasePlayback(SoundStreamID id); + bool releaseCapture(SoundStreamID id); + +ANSWERS: + bool supportsPlayback() const; + bool supportsCapture() const; + + QString getSoundStreamClientDescription() const; + + // ISoundStreamClient: mixer access + +protected: + +ANSWERS: + const QStringList &getPlaybackChannels() const; + const QStringList &getCaptureChannels() 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 noticeReadyForPlaybackData(SoundStreamID id, size_t size); + + bool noticeSoundStreamData(SoundStreamID id, + const SoundFormat &, + const char *data, size_t size, size_t &consumed_size, + const SoundMetaData &md + ); + +public slots: + + void logStreamError(const KURL &url, const QString &s); + void logStreamWarning(const KURL &url, const QString &s); + +signals: + + void sigUpdateConfig(); + +protected: + + QStringList m_PlaybackChannelList, + m_CaptureChannelList; + + QDict<StreamingJob> + m_PlaybackChannels, + m_CaptureChannels; + + QMap<SoundStreamID, QString> + m_AllPlaybackStreams, + m_AllCaptureStreams, + m_EnabledPlaybackStreams, + m_EnabledCaptureStreams; +}; + + + +#endif diff --git a/kradio3/plugins/timecontrol/Makefile.am b/kradio3/plugins/timecontrol/Makefile.am new file mode 100644 index 0000000..0ac954f --- /dev/null +++ b/kradio3/plugins/timecontrol/Makefile.am @@ -0,0 +1,17 @@ +SUBDIRS = po icons . + +INCLUDES = $(all_includes) +METASOURCES = AUTO + +libkradio_LTLIBRARIES = libtimecontrol.la +libtimecontrol_la_SOURCES = timecontrol-configuration.cpp \ + timecontrol-configuration-ui.ui timecontrol.cpp +libtimecontrol_la_LDFLAGS = -module -avoid-version $(KDE_RPATH) $(all_libraries) +noinst_HEADERS = timecontrol-configuration.h timecontrol.h + +#messages: rc.cpp +# $(XGETTEXT) *.cpp *.h -o po/kradio-timecontrol.pot + +messages: rc.cpp + $(EXTRACTRC) *.rc *.ui >> rc.cpp + $(XGETTEXT) rc.cpp *.h *.cpp -o po/kradio-timecontrol.pot diff --git a/kradio3/plugins/timecontrol/icons/Makefile.am b/kradio3/plugins/timecontrol/icons/Makefile.am new file mode 100644 index 0000000..b3f2583 --- /dev/null +++ b/kradio3/plugins/timecontrol/icons/Makefile.am @@ -0,0 +1,2 @@ +icons_ICON = AUTO +iconsdir = $(kde_datadir)/kradio/icons diff --git a/kradio3/plugins/timecontrol/icons/hi16-action-kradio_kalarm.png b/kradio3/plugins/timecontrol/icons/hi16-action-kradio_kalarm.png Binary files differnew file mode 100644 index 0000000..d87e1c4 --- /dev/null +++ b/kradio3/plugins/timecontrol/icons/hi16-action-kradio_kalarm.png diff --git a/kradio3/plugins/timecontrol/icons/hi16-action-kradio_zzz.png b/kradio3/plugins/timecontrol/icons/hi16-action-kradio_zzz.png Binary files differnew file mode 100644 index 0000000..c7184d5 --- /dev/null +++ b/kradio3/plugins/timecontrol/icons/hi16-action-kradio_zzz.png diff --git a/kradio3/plugins/timecontrol/icons/hi22-action-kradio_kalarm.png b/kradio3/plugins/timecontrol/icons/hi22-action-kradio_kalarm.png Binary files differnew file mode 100644 index 0000000..874fa0a --- /dev/null +++ b/kradio3/plugins/timecontrol/icons/hi22-action-kradio_kalarm.png diff --git a/kradio3/plugins/timecontrol/icons/hi22-action-kradio_zzz.png b/kradio3/plugins/timecontrol/icons/hi22-action-kradio_zzz.png Binary files differnew file mode 100644 index 0000000..f2184dd --- /dev/null +++ b/kradio3/plugins/timecontrol/icons/hi22-action-kradio_zzz.png diff --git a/kradio3/plugins/timecontrol/icons/hi32-action-kradio_kalarm.png b/kradio3/plugins/timecontrol/icons/hi32-action-kradio_kalarm.png Binary files differnew file mode 100644 index 0000000..5547387 --- /dev/null +++ b/kradio3/plugins/timecontrol/icons/hi32-action-kradio_kalarm.png diff --git a/kradio3/plugins/timecontrol/icons/hi32-action-kradio_zzz.png b/kradio3/plugins/timecontrol/icons/hi32-action-kradio_zzz.png Binary files differnew file mode 100644 index 0000000..5ddb326 --- /dev/null +++ b/kradio3/plugins/timecontrol/icons/hi32-action-kradio_zzz.png diff --git a/kradio3/plugins/timecontrol/icons/hi330-action-kradio_zzz.png b/kradio3/plugins/timecontrol/icons/hi330-action-kradio_zzz.png Binary files differnew file mode 100644 index 0000000..bb4b6e3 --- /dev/null +++ b/kradio3/plugins/timecontrol/icons/hi330-action-kradio_zzz.png diff --git a/kradio3/plugins/timecontrol/icons/hi48-action-kradio_kalarm.png b/kradio3/plugins/timecontrol/icons/hi48-action-kradio_kalarm.png Binary files differnew file mode 100644 index 0000000..c3b8dd5 --- /dev/null +++ b/kradio3/plugins/timecontrol/icons/hi48-action-kradio_kalarm.png diff --git a/kradio3/plugins/timecontrol/icons/hi48-action-kradio_zzz.png b/kradio3/plugins/timecontrol/icons/hi48-action-kradio_zzz.png Binary files differnew file mode 100644 index 0000000..d443b05 --- /dev/null +++ b/kradio3/plugins/timecontrol/icons/hi48-action-kradio_zzz.png diff --git a/kradio3/plugins/timecontrol/po/Makefile.am b/kradio3/plugins/timecontrol/po/Makefile.am new file mode 100644 index 0000000..35fe6fd --- /dev/null +++ b/kradio3/plugins/timecontrol/po/Makefile.am @@ -0,0 +1,2 @@ +PACKAGE = kradio-timecontrol +POFILES = AUTO diff --git a/kradio3/plugins/timecontrol/po/de.po b/kradio3/plugins/timecontrol/po/de.po new file mode 100644 index 0000000..71a84f6 --- /dev/null +++ b/kradio3/plugins/timecontrol/po/de.po @@ -0,0 +1,129 @@ +# translation of de.po to +# translation of kradio-timecontrol.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: 2006-11-11 18:43+0100\n" +"PO-Revision-Date: 2006-11-06 01:16+0100\n" +"Last-Translator: Ernst Martin Witte <emw@nocabal.de>\n" +"Language-Team: <de@li.org>\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: KBabel 1.11.4\n" + +#. i18n: file timecontrol-configuration-ui.ui line 32 +#: rc.cpp:3 rc.cpp:68 timecontrol-configuration-ui.cpp:189 +#, no-c-format +msgid "sleep countdown" +msgstr "Schlummermodus" + +#. i18n: file timecontrol-configuration-ui.ui line 40 +#: rc.cpp:6 rc.cpp:71 timecontrol-configuration-ui.cpp:190 +#, no-c-format +msgid " min" +msgstr " min" + +#. i18n: file timecontrol-configuration-ui.ui line 117 +#: rc.cpp:9 rc.cpp:74 timecontrol-configuration-ui.cpp:191 timecontrol.cpp:270 +#, no-c-format +msgid "Alarms" +msgstr "Wecker" + +#. i18n: file timecontrol-configuration-ui.ui line 180 +#: rc.cpp:14 rc.cpp:79 timecontrol-configuration-ui.cpp:194 +#, no-c-format +msgid "Date" +msgstr "Datum" + +#. i18n: file timecontrol-configuration-ui.ui line 203 +#: rc.cpp:17 rc.cpp:82 timecontrol-configuration-ui.cpp:195 +#, no-c-format +msgid "Time" +msgstr "Uhrzeit" + +#. i18n: file timecontrol-configuration-ui.ui line 226 +#: rc.cpp:20 rc.cpp:85 timecontrol-configuration-ui.cpp:196 +#, no-c-format +msgid "Volume" +msgstr "Lautstärke" + +#. i18n: file timecontrol-configuration-ui.ui line 234 +#: rc.cpp:23 rc.cpp:88 timecontrol-configuration-ui.cpp:197 +#, no-c-format +msgid " %" +msgstr " %" + +#. i18n: file timecontrol-configuration-ui.ui line 263 +#: rc.cpp:26 rc.cpp:91 timecontrol-configuration-ui.cpp:198 +#, no-c-format +msgid "enabled" +msgstr "aktiv" + +#. i18n: file timecontrol-configuration-ui.ui line 331 +#: rc.cpp:50 rc.cpp:115 timecontrol-configuration-ui.cpp:207 +#, no-c-format +msgid "daily" +msgstr "täglich" + +#. i18n: file timecontrol-configuration-ui.ui line 341 +#: rc.cpp:53 rc.cpp:118 timecontrol-configuration-ui.cpp:208 +#, no-c-format +msgid "Radio Station" +msgstr "Sender" + +#. i18n: file timecontrol-configuration-ui.ui line 393 +#: rc.cpp:56 rc.cpp:121 timecontrol-configuration-ui.cpp:210 +#, no-c-format +msgid "Start Playing" +msgstr "Radio einschalten" + +#. i18n: file timecontrol-configuration-ui.ui line 401 +#: rc.cpp:59 rc.cpp:124 timecontrol-configuration-ui.cpp:211 +#, no-c-format +msgid "Stop Playing" +msgstr "Radio ausschalten" + +#. i18n: file timecontrol-configuration-ui.ui line 409 +#: rc.cpp:62 rc.cpp:127 timecontrol-configuration-ui.cpp:212 +#, no-c-format +msgid "Start Recording" +msgstr "Aufnahme starten" + +#. i18n: file timecontrol-configuration-ui.ui line 417 +#: rc.cpp:65 rc.cpp:130 timecontrol-configuration-ui.cpp:213 +#, no-c-format +msgid "Stop Recording" +msgstr "Aufnahme beenden" + +#: _translatorinfo.cpp:1 +msgid "" +"_: NAME OF TRANSLATORS\n" +"Your names" +msgstr "Ernst Martin Witte" + +#: _translatorinfo.cpp:3 +msgid "" +"_: EMAIL OF TRANSLATORS\n" +"Your emails" +msgstr "emw@nocabal.de" + +#: timecontrol-configuration.cpp:181 +msgid "<don't change>" +msgstr "<nicht verändern>" + +#: timecontrol.cpp:42 +msgid "Time Control and Alarm Functions" +msgstr "Zeitsteurungs- und Weckfunktionen" + +#: timecontrol.cpp:48 +msgid "TimeControl Plugin" +msgstr "Zeitsteuerungs-Plugin" + +#: timecontrol.cpp:270 +msgid "Setup Alarms" +msgstr "Wecker einrichten" diff --git a/kradio3/plugins/timecontrol/po/ru.po b/kradio3/plugins/timecontrol/po/ru.po new file mode 100644 index 0000000..6f95f37 --- /dev/null +++ b/kradio3/plugins/timecontrol/po/ru.po @@ -0,0 +1,129 @@ +# translation of ru.po to +# translation of kradio-timecontrol.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: 2006-11-11 18:43+0100\n" +"PO-Revision-Date: 2006-11-08 12:57+0300\n" +"Last-Translator: Алексей Кузнецов <Alexey.Kouznetsov@GMail.com>\n" +"Language-Team: <ru@li.org>\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" + +#. i18n: file timecontrol-configuration-ui.ui line 32 +#: rc.cpp:3 rc.cpp:68 timecontrol-configuration-ui.cpp:189 +#, no-c-format +msgid "sleep countdown" +msgstr "Период таймера отключения" + +#. i18n: file timecontrol-configuration-ui.ui line 40 +#: rc.cpp:6 rc.cpp:71 timecontrol-configuration-ui.cpp:190 +#, no-c-format +msgid " min" +msgstr " мин" + +#. i18n: file timecontrol-configuration-ui.ui line 117 +#: rc.cpp:9 rc.cpp:74 timecontrol-configuration-ui.cpp:191 timecontrol.cpp:270 +#, no-c-format +msgid "Alarms" +msgstr "Расписание" + +#. i18n: file timecontrol-configuration-ui.ui line 180 +#: rc.cpp:14 rc.cpp:79 timecontrol-configuration-ui.cpp:194 +#, no-c-format +msgid "Date" +msgstr "Дата" + +#. i18n: file timecontrol-configuration-ui.ui line 203 +#: rc.cpp:17 rc.cpp:82 timecontrol-configuration-ui.cpp:195 +#, no-c-format +msgid "Time" +msgstr "Время" + +#. i18n: file timecontrol-configuration-ui.ui line 226 +#: rc.cpp:20 rc.cpp:85 timecontrol-configuration-ui.cpp:196 +#, no-c-format +msgid "Volume" +msgstr "Громкость" + +#. i18n: file timecontrol-configuration-ui.ui line 234 +#: rc.cpp:23 rc.cpp:88 timecontrol-configuration-ui.cpp:197 +#, no-c-format +msgid " %" +msgstr " %" + +#. i18n: file timecontrol-configuration-ui.ui line 263 +#: rc.cpp:26 rc.cpp:91 timecontrol-configuration-ui.cpp:198 +#, no-c-format +msgid "enabled" +msgstr "Включено" + +#. i18n: file timecontrol-configuration-ui.ui line 331 +#: rc.cpp:50 rc.cpp:115 timecontrol-configuration-ui.cpp:207 +#, no-c-format +msgid "daily" +msgstr "Ежедневно" + +#. i18n: file timecontrol-configuration-ui.ui line 341 +#: rc.cpp:53 rc.cpp:118 timecontrol-configuration-ui.cpp:208 +#, no-c-format +msgid "Radio Station" +msgstr "Радиостанция" + +#. i18n: file timecontrol-configuration-ui.ui line 393 +#: rc.cpp:56 rc.cpp:121 timecontrol-configuration-ui.cpp:210 +#, no-c-format +msgid "Start Playing" +msgstr "Начать воспроизведение" + +#. i18n: file timecontrol-configuration-ui.ui line 401 +#: rc.cpp:59 rc.cpp:124 timecontrol-configuration-ui.cpp:211 +#, no-c-format +msgid "Stop Playing" +msgstr "Остановить воспроизведение" + +#. i18n: file timecontrol-configuration-ui.ui line 409 +#: rc.cpp:62 rc.cpp:127 timecontrol-configuration-ui.cpp:212 +#, no-c-format +msgid "Start Recording" +msgstr "Начать запись" + +#. i18n: file timecontrol-configuration-ui.ui line 417 +#: rc.cpp:65 rc.cpp:130 timecontrol-configuration-ui.cpp:213 +#, no-c-format +msgid "Stop Recording" +msgstr "Остановить запись" + +#: _translatorinfo.cpp:1 +msgid "" +"_: NAME OF TRANSLATORS\n" +"Your names" +msgstr "Алексей Кузнецов" + +#: _translatorinfo.cpp:3 +msgid "" +"_: EMAIL OF TRANSLATORS\n" +"Your emails" +msgstr "Alexey.Kouznetsov@GMail.com" + +#: timecontrol-configuration.cpp:181 +msgid "<don't change>" +msgstr "<не менять>" + +#: timecontrol.cpp:42 +msgid "Time Control and Alarm Functions" +msgstr "Функции таймера и работы по расписанию" + +#: timecontrol.cpp:48 +msgid "TimeControl Plugin" +msgstr "Модуль ремени" + +#: timecontrol.cpp:270 +msgid "Setup Alarms" +msgstr "Расписание" diff --git a/kradio3/plugins/timecontrol/timecontrol-configuration-ui.ui b/kradio3/plugins/timecontrol/timecontrol-configuration-ui.ui new file mode 100644 index 0000000..8b2b768 --- /dev/null +++ b/kradio3/plugins/timecontrol/timecontrol-configuration-ui.ui @@ -0,0 +1,452 @@ +<!DOCTYPE UI><UI version="3.0" stdsetdef="1"> +<class>TimeControlConfigurationUI</class> +<widget class="QWidget"> + <property name="name"> + <cstring>TimeControlConfigurationUI</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>374</width> + <height>261</height> + </rect> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLayoutWidget" row="2" column="0" rowspan="1" colspan="2"> + <property name="name"> + <cstring>layout13</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>labelSleep</cstring> + </property> + <property name="text"> + <string>sleep countdown</string> + </property> + </widget> + <widget class="QSpinBox"> + <property name="name"> + <cstring>editSleep</cstring> + </property> + <property name="suffix"> + <string> min</string> + </property> + <property name="maxValue"> + <number>200</number> + </property> + <property name="minValue"> + <number>1</number> + </property> + <property name="lineStep"> + <number>5</number> + </property> + <property name="value"> + <number>30</number> + </property> + </widget> + <spacer> + <property name="name"> + <cstring>spacer6_2</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </hbox> + </widget> + <widget class="Line" row="1" column="0" rowspan="1" colspan="2"> + <property name="name"> + <cstring>line1</cstring> + </property> + <property name="frameShape"> + <enum>HLine</enum> + </property> + <property name="frameShadow"> + <enum>Sunken</enum> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + </widget> + <widget class="QLayoutWidget" row="0" column="0"> + <property name="name"> + <cstring>layout15</cstring> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout14</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>labelAlarmList</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>7</hsizetype> + <vsizetype>5</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>Alarms</string> + </property> + </widget> + <widget class="QPushButton"> + <property name="name"> + <cstring>buttonAlarmNew</cstring> + </property> + <property name="text"> + <string></string> + </property> + <property name="iconSet"> + <iconset>"filenew2"</iconset> + </property> + </widget> + <widget class="QPushButton"> + <property name="name"> + <cstring>buttonDeleteAlarm</cstring> + </property> + <property name="text"> + <string></string> + </property> + <property name="iconSet"> + <iconset>"editdelete"</iconset> + </property> + </widget> + </hbox> + </widget> + <widget class="QListBox"> + <property name="name"> + <cstring>listAlarms</cstring> + </property> + </widget> + </vbox> + </widget> + <widget class="QLayoutWidget" row="0" column="1"> + <property name="name"> + <cstring>layout17</cstring> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout28</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout27</cstring> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>labelAlarmDate</cstring> + </property> + <property name="text"> + <string>Date</string> + </property> + </widget> + <widget class="QDateEdit"> + <property name="name"> + <cstring>editAlarmDate</cstring> + </property> + </widget> + </vbox> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout28</cstring> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>labelAlarmTime</cstring> + </property> + <property name="text"> + <string>Time</string> + </property> + </widget> + <widget class="QTimeEdit"> + <property name="name"> + <cstring>editAlarmTime</cstring> + </property> + </widget> + </vbox> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout29</cstring> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>labelAlarmVolume</cstring> + </property> + <property name="text"> + <string>Volume</string> + </property> + </widget> + <widget class="QSpinBox"> + <property name="name"> + <cstring>editAlarmVolume</cstring> + </property> + <property name="suffix"> + <string> %</string> + </property> + <property name="maxValue"> + <number>100</number> + </property> + <property name="minValue"> + <number>-1</number> + </property> + <property name="value"> + <number>-1</number> + </property> + </widget> + </vbox> + </widget> + </hbox> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout16</cstring> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QCheckBox" row="0" column="0"> + <property name="name"> + <cstring>checkboxAlarmEnable</cstring> + </property> + <property name="text"> + <string>enabled</string> + </property> + </widget> + <spacer row="2" column="0"> + <property name="name"> + <cstring>spacer6</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>100</height> + </size> + </property> + </spacer> + <widget class="KListBox" row="0" column="1" rowspan="3" colspan="1"> + <item> + <property name="text"> + <string>Monday</string> + </property> + </item> + <item> + <property name="text"> + <string>Tuesday</string> + </property> + </item> + <item> + <property name="text"> + <string>Wednesday</string> + </property> + </item> + <item> + <property name="text"> + <string>Thursday</string> + </property> + </item> + <item> + <property name="text"> + <string>Friday</string> + </property> + </item> + <item> + <property name="text"> + <string>Saturday</string> + </property> + </item> + <item> + <property name="text"> + <string>Sunday</string> + </property> + </item> + <property name="name"> + <cstring>listWeekdays</cstring> + </property> + <property name="selectionMode"> + <enum>Multi</enum> + </property> + </widget> + <widget class="QCheckBox" row="1" column="0"> + <property name="name"> + <cstring>checkboxAlarmDaily</cstring> + </property> + <property name="text"> + <string>daily</string> + </property> + </widget> + </grid> + </widget> + <widget class="QLabel"> + <property name="name"> + <cstring>labelStationSelection</cstring> + </property> + <property name="text"> + <string>Radio Station</string> + </property> + </widget> + <widget class="QComboBox"> + <property name="name"> + <cstring>comboStationSelection</cstring> + </property> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout20</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>pixmapAlarmStation</cstring> + </property> + <property name="minimumSize"> + <size> + <width>20</width> + <height>20</height> + </size> + </property> + <property name="scaledContents"> + <bool>true</bool> + </property> + </widget> + <spacer> + <property name="name"> + <cstring>spacer8</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>150</width> + <height>20</height> + </size> + </property> + </spacer> + </hbox> + </widget> + <widget class="QComboBox"> + <item> + <property name="text"> + <string>Start Playing</string> + </property> + <property name="pixmap"> + <pixmap>"kradio_muteoff"</pixmap> + </property> + </item> + <item> + <property name="text"> + <string>Stop Playing</string> + </property> + <property name="pixmap"> + <pixmap>"kradio_muteon"</pixmap> + </property> + </item> + <item> + <property name="text"> + <string>Start Recording</string> + </property> + <property name="pixmap"> + <pixmap>"kradio_record"</pixmap> + </property> + </item> + <item> + <property name="text"> + <string>Stop Recording</string> + </property> + <property name="pixmap"> + <pixmap>"kradio_muteon"</pixmap> + </property> + </item> + <property name="name"> + <cstring>comboAlarmType</cstring> + </property> + </widget> + </vbox> + </widget> + </grid> +</widget> +<customwidgets> +</customwidgets> +<tabstops> + <tabstop>listAlarms</tabstop> + <tabstop>buttonAlarmNew</tabstop> + <tabstop>buttonDeleteAlarm</tabstop> + <tabstop>editAlarmDate</tabstop> + <tabstop>editAlarmTime</tabstop> + <tabstop>editAlarmVolume</tabstop> + <tabstop>checkboxAlarmDaily</tabstop> + <tabstop>checkboxAlarmEnable</tabstop> + <tabstop>comboStationSelection</tabstop> +</tabstops> +<includes> + <include location="global" impldecl="in implementation">kiconloader.h</include> +</includes> +<pixmapfunction>SmallIcon</pixmapfunction> +<layoutdefaults spacing="6" margin="0"/> +<includehints> + <includehint>klistbox.h</includehint> +</includehints> +</UI> diff --git a/kradio3/plugins/timecontrol/timecontrol-configuration.cpp b/kradio3/plugins/timecontrol/timecontrol-configuration.cpp new file mode 100644 index 0000000..4ea6bce --- /dev/null +++ b/kradio3/plugins/timecontrol/timecontrol-configuration.cpp @@ -0,0 +1,425 @@ +/*************************************************************************** + timecontrol-configuration.cpp - description + ------------------- + begin : Sam Aug 2 2003 + copyright : (C) 2003 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 <math.h> +#include <algorithm> +using std::sort; + +#include <qdatetime.h> +#include <qlistbox.h> +#include <qcombobox.h> +#include <qdatetimeedit.h> +#include <qlabel.h> +#include <qspinbox.h> +#include <qcheckbox.h> +#include <qpushbutton.h> + +#include <klistbox.h> +#include <klocale.h> + +#include "../../src/include/stationlist.h" +#include "../../src/include/alarm.h" +#include "../../src/include/errorlog-interfaces.h" +#include "../../src/include/radiostation.h" + +#include "timecontrol-configuration.h" + +class DateTimeCmp +{ +public: + bool operator() (const Alarm &a, const Alarm &b) { + return a.nextAlarm(true) < b.nextAlarm(true); + } + +}; + +TimeControlConfiguration::TimeControlConfiguration (QWidget *parent) + : TimeControlConfigurationUI(parent), + ITimeControlClient(), + IRadioClient(), + ignoreChanges(false), + m_dirty(false) +{ + + QObject::connect(checkboxAlarmDaily, SIGNAL(toggled(bool)), this, SLOT(slotDailyChanged(bool))); + QObject::connect(listWeekdays, SIGNAL(highlighted(int)), this, SLOT(slotWeekdaysChanged())); + QObject::connect(checkboxAlarmEnable, SIGNAL(toggled(bool)), this, SLOT(slotEnabledChanged(bool))); + QObject::connect(comboStationSelection, SIGNAL(highlighted(int)), this, SLOT(slotStationChanged(int))); + QObject::connect(listAlarms, SIGNAL(highlighted(int)), this, SLOT(slotAlarmSelectChanged(int))); + QObject::connect(editAlarmDate, SIGNAL(valueChanged(const QDate &)), this, SLOT(slotDateChanged(const QDate &))); + QObject::connect(editAlarmTime, SIGNAL(valueChanged(const QTime &)), this, SLOT(slotTimeChanged(const QTime &))); + QObject::connect(editAlarmVolume, SIGNAL(valueChanged(int)), this, SLOT(slotVolumeChanged(int))); + QObject::connect(buttonAlarmNew, SIGNAL(clicked()), this, SLOT(slotNewAlarm())); + QObject::connect(buttonDeleteAlarm, SIGNAL(clicked()), this, SLOT(slotDeleteAlarm())); + QObject::connect(comboAlarmType, SIGNAL(highlighted(int)), this, SLOT(slotAlarmTypeChanged(int))); + + QObject::connect(checkboxAlarmDaily, SIGNAL(toggled(bool)), this, SLOT(slotSetDirty())); + QObject::connect(listWeekdays, SIGNAL(selectionChanged()), this, SLOT(slotSetDirty())); + QObject::connect(checkboxAlarmEnable, SIGNAL(toggled(bool)), this, SLOT(slotSetDirty())); + QObject::connect(comboStationSelection, SIGNAL(activated(int)), this, SLOT(slotSetDirty())); + QObject::connect(editAlarmDate, SIGNAL(valueChanged(const QDate &)), this, SLOT(slotSetDirty())); + QObject::connect(editAlarmTime, SIGNAL(valueChanged(const QTime &)), this, SLOT(slotSetDirty())); + QObject::connect(editAlarmVolume, SIGNAL(valueChanged(int)), this, SLOT(slotSetDirty())); + QObject::connect(buttonAlarmNew, SIGNAL(clicked()), this, SLOT(slotSetDirty())); + QObject::connect(buttonDeleteAlarm, SIGNAL(clicked()), this, SLOT(slotSetDirty())); + QObject::connect(comboAlarmType, SIGNAL(activated(int)), this, SLOT(slotSetDirty())); + QObject::connect(editSleep, SIGNAL(valueChanged(int)), this, SLOT(slotSetDirty())); +} + +TimeControlConfiguration::~TimeControlConfiguration () +{ +} + +bool TimeControlConfiguration::connectI (Interface *i) +{ + bool a = ITimeControlClient::connectI(i); + bool b = IRadioClient::connectI(i); + return a || b; +} + + +bool TimeControlConfiguration::disconnectI (Interface *i) +{ + bool a = ITimeControlClient::disconnectI(i); + bool b = IRadioClient::disconnectI(i); + return a || b; +} + + +// ITimeControlClient + +bool TimeControlConfiguration::noticeAlarmsChanged(const AlarmVector &sl) +{ + int idx = listAlarms->currentItem(); + int currentID = (idx >= 0 && (unsigned)idx < alarms.size()) ? alarms[idx].ID() : -1; + + alarms = sl; + sort(alarms.begin(), alarms.end(), DateTimeCmp()); + + bool oldBlock = listAlarms->signalsBlocked(); + listAlarms->blockSignals(true); + + listAlarms->clear(); + idx = -1; + int k = 0; + for (ciAlarmVector i = alarms.begin(); i != alarms.end(); ++i, ++k) { + listAlarms->insertItem(i->nextAlarm(true).toString()); + if (i->ID() == currentID) + idx = k; + } + listAlarms->setCurrentItem(idx); + + listAlarms->blockSignals(oldBlock); + + slotAlarmSelectChanged(idx); + return true; +} + +bool TimeControlConfiguration::noticeAlarm(const Alarm &) +{ + return false; +} + +bool TimeControlConfiguration::noticeNextAlarmChanged(const Alarm *) +{ + noticeAlarmsChanged(alarms); + return true; +} + +bool TimeControlConfiguration::noticeCountdownStarted(const QDateTime &/*end*/) +{ + return false; +} + +bool TimeControlConfiguration::noticeCountdownStopped() +{ + return false; +} + +bool TimeControlConfiguration::noticeCountdownZero() +{ + return false; +} + +bool TimeControlConfiguration::noticeCountdownSecondsChanged(int n) +{ + editSleep->setValue((int)rint(n / 60)); + return false; +} + + +// IRadioClient + +bool TimeControlConfiguration::noticePowerChanged(bool /*on*/) +{ + return false; +} + +bool TimeControlConfiguration::noticeStationChanged (const RadioStation &, int /*idx*/) +{ + return false; +} + +bool TimeControlConfiguration::noticeStationsChanged(const StationList &sl) +{ + comboStationSelection->clear(); + stationIDs.clear(); + comboStationSelection->insertItem(i18n("<don't change>")); + stationIDs.push_back(QString::null); + + for (RawStationList::Iterator i(sl.all()); i.current(); ++i) { + comboStationSelection->insertItem(i.current()->iconName(), + i.current()->longName()); + stationIDs.push_back(i.current()->stationID()); + } + return true; +} + + +// Slots + + +void TimeControlConfiguration::slotDateChanged( const QDate &d ) +{ + if (ignoreChanges) return; + + int idx = listAlarms->currentItem(); + if (idx >= 0 && (unsigned)idx < alarms.size()) { + Alarm &a = alarms[idx]; + a.setDate(d); + + ignoreChanges = true; + bool oldBlock = listAlarms->signalsBlocked(); + listAlarms->blockSignals(true); + noticeAlarmsChanged(alarms); + listAlarms->blockSignals(oldBlock); + ignoreChanges = false; + } +} + + +void TimeControlConfiguration::slotTimeChanged(const QTime &t) +{ + if (ignoreChanges) return; + + int idx = listAlarms->currentItem(); + if (idx >= 0 && (unsigned)idx < alarms.size()) { + Alarm &a = alarms[idx]; + a.setTime(t); + + ignoreChanges = true; + bool oldBlock = listAlarms->signalsBlocked(); + listAlarms->blockSignals(true); + noticeAlarmsChanged(alarms); + listAlarms->blockSignals(oldBlock); + ignoreChanges = false; + } +} + + +void TimeControlConfiguration::slotDailyChanged (bool b) +{ + if (ignoreChanges) return; + + int idx = listAlarms->currentItem(); + if (idx >= 0 && (unsigned)idx < alarms.size()) { + Alarm &a = alarms[idx]; + a.setDaily(b); + + ignoreChanges = true; + bool oldBlock = listAlarms->signalsBlocked(); + listAlarms->blockSignals(true); + noticeAlarmsChanged(alarms); + listAlarms->blockSignals(oldBlock); + ignoreChanges = false; + + editAlarmDate ->setDisabled(b); + labelAlarmDate->setDisabled(b); + listWeekdays ->setDisabled(!b); + } +} + + +void TimeControlConfiguration::slotWeekdaysChanged () +{ + if (ignoreChanges) return; + + int mask = 0; + for (int i = 0; i < 7; ++i) { + if (listWeekdays->isSelected(i)) { + mask |= (1 << i); + } + } + + int idx = listAlarms->currentItem(); + if (idx >= 0 && (unsigned)idx < alarms.size()) { + Alarm &a = alarms[idx]; + a.setWeekdayMask(mask); + + ignoreChanges = true; + bool oldBlock = listAlarms->signalsBlocked(); + listAlarms->blockSignals(true); + noticeAlarmsChanged(alarms); + listAlarms->blockSignals(oldBlock); + ignoreChanges = false; + } +} + + +void TimeControlConfiguration::slotEnabledChanged( bool b) +{ + int idx = listAlarms->currentItem(); + if (idx >= 0 && (unsigned)idx < alarms.size()) { + alarms[idx].setEnabled(b); + } +} + + +void TimeControlConfiguration::slotStationChanged( int i ) +{ + int idx = listAlarms->currentItem(); + if ( idx >= 0 && (unsigned)idx < alarms.size() + && i >= 0 && (unsigned)i < stationIDs.size()) + { + alarms[idx].setStationID( stationIDs[i] ); + } +} + + +void TimeControlConfiguration::slotVolumeChanged( int v ) +{ + int idx = listAlarms->currentItem(); + if (idx >= 0 && (unsigned)idx < alarms.size()) { + alarms[idx].setVolumePreset(0.01 * (float)v); + } +} + + +void TimeControlConfiguration::slotAlarmTypeChanged(int t) +{ + int idx = listAlarms->currentItem(); + if (idx >= 0 && (unsigned)idx < alarms.size()) { + alarms[idx].setAlarmType((Alarm::AlarmType)t); + } +} + + +void TimeControlConfiguration::slotAlarmSelectChanged(int idx) +{ + if (ignoreChanges) return; + ignoreChanges = true; + + Alarm a; + bool valid = false; + + if (idx >= 0 && (unsigned)idx < alarms.size()) { + + a = alarms[idx]; + valid = true; + + } + + editAlarmDate ->setDisabled(!valid || a.isDaily()); + labelAlarmDate ->setDisabled(!valid || a.isDaily()); + listWeekdays ->setDisabled(!valid ||!a.isDaily()); + editAlarmTime ->setDisabled(!valid); + labelAlarmTime ->setDisabled(!valid); + labelAlarmVolume ->setDisabled(!valid); + editAlarmVolume ->setDisabled(!valid); + checkboxAlarmDaily ->setDisabled(!valid); + checkboxAlarmEnable ->setDisabled(!valid); + comboStationSelection->setDisabled(!valid); + labelStationSelection->setDisabled(!valid); + buttonDeleteAlarm ->setDisabled(!valid); + comboAlarmType ->setDisabled(!valid); + + editAlarmDate ->setDate(a.alarmTime().date()); + editAlarmTime ->setTime(a.alarmTime().time()); + checkboxAlarmDaily ->setChecked(a.isDaily()); + checkboxAlarmEnable ->setChecked(a.isEnabled()); + editAlarmVolume ->setValue((int)rint(a.volumePreset() * 100)); + comboAlarmType ->setCurrentItem(a.alarmType()); + + int k = 0; + const QString &sID = a.stationID(); + for (int i = 0; !k && i < (int)stationIDs.size(); ++i) + if (stationIDs[i] == sID) k = i; + comboStationSelection->setCurrentItem(k); + + int m = a.weekdayMask(); + for (int i = 0; i < 7; ++i) { + listWeekdays->setSelected(i, m & (1 << i)); + } + + ignoreChanges = false; +} + + +void TimeControlConfiguration::slotNewAlarm() +{ + QDateTime dt(QDateTime::currentDateTime()); + Alarm a(dt, false, false); + alarms.push_back(a); + listAlarms->insertItem(a.alarmTime().toString()); + listAlarms->setSelected(listAlarms->count() - 1, true); + noticeAlarmsChanged(alarms); +} + + +void TimeControlConfiguration::slotDeleteAlarm() +{ + int idx = listAlarms->currentItem(); + + if (idx >= 0 && (unsigned)idx < alarms.size()) { + // unfortunately a function vector<>::erase(idx) does not exist + iAlarmVector i = alarms.begin(); + for (int k = 0; k < idx; ++k) + ++i; + if (i != alarms.end()) + alarms.erase(i); + listAlarms->removeItem(idx); + } +} + + +void TimeControlConfiguration::slotOK() +{ + if (m_dirty) { + sendAlarms(alarms); + sendCountdownSeconds(editSleep->value() * 60); + m_dirty = false; + } +} + +void TimeControlConfiguration::slotCancel() +{ + if (m_dirty) { + noticeAlarmsChanged(queryAlarms()); + noticeCountdownSecondsChanged(queryCountdownSeconds()); + m_dirty = false; + } +} + +void TimeControlConfiguration::slotSetDirty() +{ + if (!ignoreChanges) { + m_dirty = true; + } +} + + +#include "timecontrol-configuration.moc" diff --git a/kradio3/plugins/timecontrol/timecontrol-configuration.h b/kradio3/plugins/timecontrol/timecontrol-configuration.h new file mode 100644 index 0000000..ac4570f --- /dev/null +++ b/kradio3/plugins/timecontrol/timecontrol-configuration.h @@ -0,0 +1,90 @@ +/*************************************************************************** + timecontro-configuration.h - description + ------------------- + begin : Sam Aug 2 2003 + copyright : (C) 2003 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_TIMECONTROL_CONFIGURATION_H +#define KRADIO_TIMECONTROL_CONFIGURATION_H + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "../../src/include/radio_interfaces.h" +#include "../../src/include/timecontrol_interfaces.h" +#include "timecontrol-configuration-ui.h" + +class TimeControl; +class QWidget; + +class TimeControlConfiguration : public TimeControlConfigurationUI, + public ITimeControlClient, + public IRadioClient +{ +Q_OBJECT +public : + TimeControlConfiguration (QWidget *parent); + ~TimeControlConfiguration (); + + bool connectI (Interface *i); + bool disconnectI (Interface *i); + +// ITimeControlClient + + bool noticeAlarmsChanged(const AlarmVector &sl); + bool noticeAlarm(const Alarm &); + bool noticeNextAlarmChanged(const Alarm *); + bool noticeCountdownStarted(const QDateTime &end); + bool noticeCountdownStopped(); + bool noticeCountdownZero(); + bool noticeCountdownSecondsChanged(int n); + +// IRadioClient + + bool noticePowerChanged(bool on); + bool noticeStationChanged (const RadioStation &, int idx); + bool noticeStationsChanged(const StationList &sl); + bool noticePresetFileChanged(const QString &/*f*/) { return false; } + + bool noticeCurrentSoundStreamIDChanged(SoundStreamID /*id*/) { return false; } + +protected slots: + + void slotDailyChanged (bool daily); + void slotWeekdaysChanged (); + void slotEnabledChanged (bool enable); + void slotStationChanged (int idx); + void slotAlarmSelectChanged(int idx); + void slotDateChanged(const QDate &d); + void slotTimeChanged(const QTime &d); + void slotVolumeChanged(int v); + void slotAlarmTypeChanged(int idx); + + void slotNewAlarm(); + void slotDeleteAlarm(); + + void slotOK(); + void slotCancel(); + void slotSetDirty(); + +protected: + + AlarmVector alarms; + vector<QString> stationIDs; + + bool ignoreChanges; + bool m_dirty; +}; + +#endif diff --git a/kradio3/plugins/timecontrol/timecontrol.cpp b/kradio3/plugins/timecontrol/timecontrol.cpp new file mode 100644 index 0000000..42441ac --- /dev/null +++ b/kradio3/plugins/timecontrol/timecontrol.cpp @@ -0,0 +1,301 @@ +/*************************************************************************** + timecontrol.cpp - description + ------------------- + begin : Son Jan 12 2003 + copyright : (C) 2003 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 <kaboutdata.h> +#include <kconfig.h> + +#include "timecontrol.h" +#include "timecontrol-configuration.h" +#include "../../src/include/pluginmanager.h" +#include "../../src/include/aboutwidget.h" + +//const char *AlarmListElement = "alarmlist"; +//const char *AlarmElement = "alarm"; +const char *AlarmDateElement = "date"; +const char *AlarmTimeElement = "time"; +const char *AlarmDailyElement = "daily"; +const char *AlarmWeekdayMaskElement = "weekdayMask"; +const char *AlarmEnabledElement = "enabled"; +const char *AlarmStationIDElement = "stationID"; +//const char *AlarmFrequencyElement = "frequency"; +const char *AlarmVolumeElement = "volume"; +const char *AlarmTypeElement = "type"; + + +/////////////////////////////////////////////////////////////////////// +//// plugin library functions + +PLUGIN_LIBRARY_FUNCTIONS(TimeControl, "kradio-timecontrol", i18n("Time Control and Alarm Functions")); + +/////////////////////////////////////////////////////////////////////// + + +TimeControl::TimeControl (const QString &n) + : PluginBase(n, i18n("TimeControl Plugin")), + m_waitingFor(NULL), + m_countdownSeconds(0), + m_alarmTimer(this), + m_countdownTimer(this) +{ + QObject::connect(&m_alarmTimer, SIGNAL(timeout()), this, SLOT(slotQTimerAlarmTimeout())); + QObject::connect(&m_countdownTimer, SIGNAL(timeout()), this, SLOT(slotQTimerCountdownTimeout())); +} + + +TimeControl::~TimeControl () +{ + m_waitingFor = NULL; +} + +bool TimeControl::connectI (Interface *i) +{ + bool a = ITimeControl::connectI(i); + bool b = PluginBase::connectI(i); + return a || b; +} + +bool TimeControl::disconnectI (Interface *i) +{ + bool a = ITimeControl::disconnectI(i); + bool b = PluginBase::disconnectI(i); + return a || b; +} + +bool TimeControl::setAlarms (const AlarmVector &al) +{ + if (m_alarms != al) { + m_waitingFor = NULL; + + m_alarms = al; + + slotQTimerAlarmTimeout(); + + notifyAlarmsChanged(m_alarms); + } + return true; +} + + +bool TimeControl::setCountdownSeconds(int n) +{ + int old = m_countdownSeconds; + m_countdownSeconds = n; + if (old != n) + notifyCountdownSecondsChanged(n); + return true; +} + + +bool TimeControl::startCountdown() +{ + m_countdownEnd = QDateTime::currentDateTime().addSecs(m_countdownSeconds); + m_countdownTimer.start(m_countdownSeconds * 1000, true); + + notifyCountdownStarted(getCountdownEnd()); + + return true; +} + + +bool TimeControl::stopCountdown() +{ + m_countdownTimer.stop(); + m_countdownEnd = QDateTime(); + + notifyCountdownStopped(); + + return true; +} + + +QDateTime TimeControl::getNextAlarmTime() const +{ + const Alarm *a = getNextAlarm(); + if (a) + return a->nextAlarm(); + else + return QDateTime(); +} + + +const Alarm *TimeControl::getNextAlarm () const +{ + QDateTime now = QDateTime::currentDateTime(), + next; + + const Alarm *retval = NULL; + + for (ciAlarmVector i = m_alarms.begin(); i != m_alarms.end(); ++i) { + QDateTime n = i->nextAlarm(); + if (n.isValid() && n > now && ( ! next.isValid() || n < next)) { + next = n; + retval = &(*i); + } + } + + QDateTime old = m_nextAlarm_tmp; + m_nextAlarm_tmp = next; + if (old != m_nextAlarm_tmp) { + notifyNextAlarmChanged(retval); + } + + return retval; +} + + +QDateTime TimeControl::getCountdownEnd () const +{ + if (m_countdownTimer.isActive()) + return m_countdownEnd; + else + return QDateTime(); +} + + +void TimeControl::slotQTimerCountdownTimeout() +{ + stopCountdown(); + + notifyCountdownZero(); +} + + +void TimeControl::slotQTimerAlarmTimeout() +{ + if (m_waitingFor) { + notifyAlarm(*m_waitingFor); + } + + QDateTime now = QDateTime::currentDateTime(); + Alarm const *n = getNextAlarm(); + QDateTime na = getNextAlarmTime(); + + m_waitingFor = NULL; + + if (na.isValid()) { + + int days = now.daysTo(na); + int msecs = now.time().msecsTo(na.time()); + + if (days > 1) { + m_alarmTimer.start(24 * 3600 * 1000, true); + + } else if (days >= 0) { + + if (days > 0) + msecs += days * 24 * 3600 * 1000; + + if (msecs > 0) { + m_waitingFor = n; + m_alarmTimer.start(msecs, true); + } + } + } +} + + +void TimeControl::restoreState (KConfig *config) +{ + AlarmVector al; + + config->setGroup(QString("timecontrol-") + name()); + + int nAlarms = config->readNumEntry ("nAlarms", 0); + for (int idx = 1; idx <= nAlarms; ++idx) { + + QString num = QString().setNum(idx); + QDateTime d = config->readDateTimeEntry(AlarmTimeElement + num); + bool enable = config->readBoolEntry(AlarmEnabledElement + num, false); + bool daily = config->readBoolEntry(AlarmDailyElement + num, false); + int weekdayMask = config->readNumEntry(AlarmWeekdayMaskElement + num, 0x7F); + float vol = config->readDoubleNumEntry(AlarmVolumeElement + num, 1); + QString sid = config->readEntry(AlarmStationIDElement + num, QString::null); + int type = config->readNumEntry(AlarmTypeElement + num, 0); + + enable &= d.isValid(); + + Alarm a ( d, daily, enable); + a.setVolumePreset(vol); + a.setWeekdayMask(weekdayMask); + a.setStationID(sid); + a.setAlarmType((Alarm::AlarmType)type); + al.push_back(a); + } + + setAlarms(al); + setCountdownSeconds(config->readNumEntry("countdownSeconds", 30*60)); +} + + +void TimeControl::saveState (KConfig *config) const +{ + config->setGroup(QString("timecontrol-") + name()); + + config->writeEntry("nAlarms", m_alarms.size()); + int idx = 1; + ciAlarmVector end = m_alarms.end(); + for (ciAlarmVector i = m_alarms.begin(); i != end; ++i, ++idx) { + QString num = QString().setNum(idx); + config->writeEntry (AlarmTimeElement + num, i->alarmTime()); + config->writeEntry (AlarmEnabledElement + num, i->isEnabled()); + config->writeEntry (AlarmDailyElement + num, i->isDaily()); + config->writeEntry (AlarmWeekdayMaskElement + num, i->weekdayMask()); + config->writeEntry (AlarmVolumeElement + num, i->volumePreset()); + config->writeEntry (AlarmStationIDElement + num, i->stationID()); + config->writeEntry (AlarmTypeElement + num, i->alarmType()); + } + + config->writeEntry("countdownSeconds", m_countdownSeconds); +} + + +ConfigPageInfo TimeControl::createConfigurationPage() +{ + TimeControlConfiguration *conf = new TimeControlConfiguration(NULL); + connectI(conf); + return ConfigPageInfo (conf, i18n("Alarms"), i18n("Setup Alarms"), "kradio_kalarm"); +} + + +AboutPageInfo TimeControl::createAboutPage() +{ +/* KAboutData aboutData("kradio", + NULL, + NULL, + I18N_NOOP("Time Control Plugin for KRadio." + "<P>" + "Provides Alarms and Sleep Countdown" + "<P>"), + KAboutData::License_GPL, + "(c) 2002-2005 Martin Witte, Klas Kalass", + 0, + "http://sourceforge.net/projects/kradio", + 0); + aboutData.addAuthor("Martin Witte", "", "witte@kawo1.rwth-aachen.de"); + aboutData.addAuthor("Klas Kalass", "", "klas.kalass@gmx.de"); + + return AboutPageInfo( + new KRadioAboutWidget(aboutData, KRadioAboutWidget::AbtTabbed), + i18n("Alarms"), + i18n("Time Control Plugin"), + "kradio_kalarm" + );*/ + return AboutPageInfo(); +} + + +#include "timecontrol.moc" diff --git a/kradio3/plugins/timecontrol/timecontrol.h b/kradio3/plugins/timecontrol/timecontrol.h new file mode 100644 index 0000000..f38bae9 --- /dev/null +++ b/kradio3/plugins/timecontrol/timecontrol.h @@ -0,0 +1,95 @@ +/*************************************************************************** + timecontrol.h - description + ------------------- + begin : Son Jan 12 2003 + copyright : (C) 2003 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_TIMECONTROL_H +#define KRADIO_TIMECONTROL_H + +#include <qobject.h> +#include <qtimer.h> + +#include "../../src/include/alarm.h" +#include "../../src/include/plugins.h" +#include "../../src/include/timecontrol_interfaces.h" + +// well, it has to be a QObject :( , but only for +// receiving QTimer - timeouts + +class TimeControl : public QObject, + public PluginBase, + public ITimeControl +{ +Q_OBJECT +protected: + AlarmVector m_alarms; + Alarm const * m_waitingFor; // m_alarmTimer is exactly for this date/time + + int m_countdownSeconds; // in seconds + QDateTime m_countdownEnd; + + QTimer m_alarmTimer; + QTimer m_countdownTimer; + + mutable QDateTime m_nextAlarm_tmp; // used to recognize nextAlarm changes + +public: + TimeControl (const QString &name); + ~TimeControl(); + + virtual QString pluginClassName() const { return "TimeControl"; } + + virtual const QString &name() const { return PluginBase::name(); } + virtual QString &name() { return PluginBase::name(); } + + virtual bool connectI (Interface *i); + virtual bool disconnectI (Interface *i); + + // PluginBase + +public: + virtual void saveState (KConfig *) const; + virtual void restoreState (KConfig *); + + virtual ConfigPageInfo createConfigurationPage(); + virtual AboutPageInfo createAboutPage(); + + + // ITimeControl Interface methods + +RECEIVERS: + bool setAlarms(const AlarmVector &sl); + bool setCountdownSeconds(int n); + bool startCountdown(); + bool stopCountdown(); + +ANSWERS: + QDateTime getNextAlarmTime () const; + const Alarm* getNextAlarm () const; + const AlarmVector & getAlarms () const { return m_alarms; } + int getCountdownSeconds () const { return m_countdownSeconds; } + QDateTime getCountdownEnd () const; + + + // slots for receiving timeout messages of timers + +protected slots: + virtual void slotQTimerAlarmTimeout(); + virtual void slotQTimerCountdownTimeout(); + +}; + + +#endif diff --git a/kradio3/plugins/timeshifter/Makefile.am b/kradio3/plugins/timeshifter/Makefile.am new file mode 100644 index 0000000..23da794 --- /dev/null +++ b/kradio3/plugins/timeshifter/Makefile.am @@ -0,0 +1,18 @@ +SUBDIRS = po icons . + +INCLUDES = $(all_includes) +METASOURCES = AUTO + +libkradio_LTLIBRARIES = libtimeshifter.la +libtimeshifter_la_SOURCES = timeshifter.cpp timeshifter-configuration-ui.ui \ + timeshifter-configuration.cpp +libtimeshifter_la_LDFLAGS = -module -avoid-version $(KDE_RPATH) $(all_libraries) + +noinst_HEADERS = timeshifter.h timeshifter-configuration.h + +#messages: rc.cpp +# $(XGETTEXT) *.cpp *.h -o po/kradio-timeshifter.pot + +messages: rc.cpp + $(EXTRACTRC) *.rc *.ui >> rc.cpp + $(XGETTEXT) rc.cpp *.h *.cpp -o po/kradio-timeshifter.pot diff --git a/kradio3/plugins/timeshifter/icons/Makefile.am b/kradio3/plugins/timeshifter/icons/Makefile.am new file mode 100644 index 0000000..b3f2583 --- /dev/null +++ b/kradio3/plugins/timeshifter/icons/Makefile.am @@ -0,0 +1,2 @@ +icons_ICON = AUTO +iconsdir = $(kde_datadir)/kradio/icons diff --git a/kradio3/plugins/timeshifter/icons/hi16-action-kradio_pause.png b/kradio3/plugins/timeshifter/icons/hi16-action-kradio_pause.png Binary files differnew file mode 100644 index 0000000..a5f47a7 --- /dev/null +++ b/kradio3/plugins/timeshifter/icons/hi16-action-kradio_pause.png diff --git a/kradio3/plugins/timeshifter/icons/hi16-app-kradio_plus_pause.png b/kradio3/plugins/timeshifter/icons/hi16-app-kradio_plus_pause.png Binary files differnew file mode 100644 index 0000000..320ba48 --- /dev/null +++ b/kradio3/plugins/timeshifter/icons/hi16-app-kradio_plus_pause.png diff --git a/kradio3/plugins/timeshifter/icons/hi22-action-kradio_pause.png b/kradio3/plugins/timeshifter/icons/hi22-action-kradio_pause.png Binary files differnew file mode 100644 index 0000000..69dfb9e --- /dev/null +++ b/kradio3/plugins/timeshifter/icons/hi22-action-kradio_pause.png diff --git a/kradio3/plugins/timeshifter/icons/hi22-app-kradio_plus_pause.png b/kradio3/plugins/timeshifter/icons/hi22-app-kradio_plus_pause.png Binary files differnew file mode 100644 index 0000000..31a25ac --- /dev/null +++ b/kradio3/plugins/timeshifter/icons/hi22-app-kradio_plus_pause.png diff --git a/kradio3/plugins/timeshifter/icons/hi32-action-kradio_pause.png b/kradio3/plugins/timeshifter/icons/hi32-action-kradio_pause.png Binary files differnew file mode 100644 index 0000000..8425c1c --- /dev/null +++ b/kradio3/plugins/timeshifter/icons/hi32-action-kradio_pause.png diff --git a/kradio3/plugins/timeshifter/icons/hi32-app-kradio_plus_pause.png b/kradio3/plugins/timeshifter/icons/hi32-app-kradio_plus_pause.png Binary files differnew file mode 100644 index 0000000..9b42662 --- /dev/null +++ b/kradio3/plugins/timeshifter/icons/hi32-app-kradio_plus_pause.png diff --git a/kradio3/plugins/timeshifter/icons/hi48-app-kradio_plus_pause.png b/kradio3/plugins/timeshifter/icons/hi48-app-kradio_plus_pause.png Binary files differnew file mode 100644 index 0000000..efaa1e1 --- /dev/null +++ b/kradio3/plugins/timeshifter/icons/hi48-app-kradio_plus_pause.png diff --git a/kradio3/plugins/timeshifter/icons/hi64-app-kradio_plus_pause.png b/kradio3/plugins/timeshifter/icons/hi64-app-kradio_plus_pause.png Binary files differnew file mode 100644 index 0000000..fdd0aaf --- /dev/null +++ b/kradio3/plugins/timeshifter/icons/hi64-app-kradio_plus_pause.png diff --git a/kradio3/plugins/timeshifter/po/Makefile.am b/kradio3/plugins/timeshifter/po/Makefile.am new file mode 100644 index 0000000..276fe4b --- /dev/null +++ b/kradio3/plugins/timeshifter/po/Makefile.am @@ -0,0 +1,3 @@ + +PACKAGE = kradio-timeshifter +POFILES = AUTO diff --git a/kradio3/plugins/timeshifter/po/de.po b/kradio3/plugins/timeshifter/po/de.po new file mode 100644 index 0000000..66806f9 --- /dev/null +++ b/kradio3/plugins/timeshifter/po/de.po @@ -0,0 +1,91 @@ +# translation of de.po to +# translation of kradio-timeshifter.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: 2006-11-12 18:41+0100\n" +"PO-Revision-Date: 2006-11-12 18:24+0100\n" +"Last-Translator: Ernst Martin Witte <emw@nocabal.de>\n" +"Language-Team: <de@li.org>\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: KBabel 1.11.4\n" + +#. i18n: file timeshifter-configuration-ui.ui line 16 +#: rc.cpp:3 rc.cpp:22 timeshifter-configuration-ui.cpp:118 +#, no-c-format +msgid "SetupDialogGeneral" +msgstr "SetupDialogGeneral" + +#. i18n: file timeshifter-configuration-ui.ui line 72 +#: rc.cpp:6 rc.cpp:25 timeshifter-configuration-ui.cpp:119 +#, no-c-format +msgid " MB" +msgstr " MB" + +#. i18n: file timeshifter-configuration-ui.ui line 92 +#: rc.cpp:9 rc.cpp:28 timeshifter-configuration-ui.cpp:120 +#, no-c-format +msgid "Maximum File Size" +msgstr "maximale Dateigröße" + +#. i18n: file timeshifter-configuration-ui.ui line 100 +#: rc.cpp:12 rc.cpp:31 timeshifter-configuration-ui.cpp:121 +#, no-c-format +msgid "Playback Mixer Device" +msgstr "Wiedergabemixer" + +#. i18n: file timeshifter-configuration-ui.ui line 108 +#: rc.cpp:15 rc.cpp:34 timeshifter-configuration-ui.cpp:122 +#, no-c-format +msgid "Temporary File" +msgstr "Temporäre Datei" + +#. i18n: file timeshifter-configuration-ui.ui line 121 +#: rc.cpp:18 rc.cpp:37 timeshifter-configuration-ui.cpp:123 +#, no-c-format +msgid "Playback Mixer Channel" +msgstr "Wiedergabemixerkanal" + +#: timeshifter-configuration.cpp:138 +msgid "any ( * )" +msgstr "alle ( * )" + +#: timeshifter-configuration.cpp:140 +msgid "TimeShifter Temporary File Selection" +msgstr "Auswahl der temporären Datei für die zeitversetzte Wiedergabe" + +#: timeshifter-configuration.cpp:143 +msgid "Select TimeShifter Temporary File" +msgstr "Auswahl der temporären Datei für die zeitversetzte Wiedergabe" + +#: timeshifter.cpp:31 +msgid "TimeShift Support" +msgstr "Unterstützung für die Zeitversetzte Wiedergabe" + +#: timeshifter.cpp:36 +msgid "TimeShifter Plugin" +msgstr "Plugin für die zeitversetzte Wiedergabe" + +#: timeshifter.cpp:121 +msgid "Timeshifter" +msgstr "Zeitversetzte Wiedergabe" + +#: timeshifter.cpp:122 +msgid "Timeshifter Options" +msgstr "Optionen für die zeitversetzte Wiedergabe" + +#: timeshifter.cpp:355 +msgid "TimeShifter::notifySoundStreamData: clients skipped %1 bytes. Data Lost" +msgstr "" +"TimeShifter::notifySoundStreamData: %1 bytes der Sounddaten wurden ignoriert " +"und sind verloren" + +#: timeshifter.cpp:412 +msgid "internal stream, not stored" +msgstr "interner, nicht aufgezeichneter Datenstrom" diff --git a/kradio3/plugins/timeshifter/po/ru.po b/kradio3/plugins/timeshifter/po/ru.po new file mode 100644 index 0000000..1f692e3 --- /dev/null +++ b/kradio3/plugins/timeshifter/po/ru.po @@ -0,0 +1,91 @@ +# translation of ru.po to +# translation of kradio-timeshifter.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: 2006-11-12 18:20+0100\n" +"PO-Revision-Date: 2006-11-08 12:19+0300\n" +"Last-Translator: Алексей Кузнецов <Alexey.Kouznetsov@GMail.com>\n" +"Language-Team: <ru@li.org>\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" + +#. i18n: file timeshifter-configuration-ui.ui line 16 +#: rc.cpp:3 rc.cpp:22 timeshifter-configuration-ui.cpp:118 +#, no-c-format +msgid "SetupDialogGeneral" +msgstr "SetupDialogGeneral" + +#. i18n: file timeshifter-configuration-ui.ui line 72 +#: rc.cpp:6 rc.cpp:25 timeshifter-configuration-ui.cpp:119 +#, no-c-format +msgid " MB" +msgstr " Мб" + +#. i18n: file timeshifter-configuration-ui.ui line 92 +#: rc.cpp:9 rc.cpp:28 timeshifter-configuration-ui.cpp:120 +#, no-c-format +msgid "Maximum File Size" +msgstr "Размер файла, не более" + +#. i18n: file timeshifter-configuration-ui.ui line 100 +#: rc.cpp:12 rc.cpp:31 timeshifter-configuration-ui.cpp:121 +#, no-c-format +msgid "Playback Mixer Device" +msgstr "Устройство воспроизведения" + +#. i18n: file timeshifter-configuration-ui.ui line 108 +#: rc.cpp:15 rc.cpp:34 timeshifter-configuration-ui.cpp:122 +#, no-c-format +msgid "Temporary File" +msgstr "Временный файл" + +#. i18n: file timeshifter-configuration-ui.ui line 121 +#: rc.cpp:18 rc.cpp:37 timeshifter-configuration-ui.cpp:123 +#, no-c-format +msgid "Playback Mixer Channel" +msgstr "Канал воспроизведения" + +#: timeshifter-configuration.cpp:138 +msgid "any ( * )" +msgstr "Все ( * )" + +#: timeshifter-configuration.cpp:140 +msgid "TimeShifter Temporary File Selection" +msgstr "Выбор временного файла для реализации приостановки вещания" + +#: timeshifter-configuration.cpp:143 +msgid "Select TimeShifter Temporary File" +msgstr "Выберите временный файл" + +#: timeshifter.cpp:31 +msgid "TimeShift Support" +msgstr "Поддержка приостановки вещания" + +#: timeshifter.cpp:36 +msgid "TimeShifter Plugin" +msgstr "Модуль приостановки вещания" + +#: timeshifter.cpp:121 +msgid "Timeshifter" +msgstr "Приостановка" + +#: timeshifter.cpp:122 +msgid "Timeshifter Options" +msgstr "Параметры приостановки вещания" + +#: timeshifter.cpp:355 +msgid "TimeShifter::notifySoundStreamData: clients skipped %1 bytes. Data Lost" +msgstr "" +"TimeShifter::notifySoundStreamData: клиенты пропустили %1 байт. Данные " +"утеряны." + +#: timeshifter.cpp:412 +msgid "internal stream, not stored" +msgstr "" diff --git a/kradio3/plugins/timeshifter/timeshifter-configuration-ui.ui b/kradio3/plugins/timeshifter/timeshifter-configuration-ui.ui new file mode 100644 index 0000000..3e3f4e4 --- /dev/null +++ b/kradio3/plugins/timeshifter/timeshifter-configuration-ui.ui @@ -0,0 +1,225 @@ +<!DOCTYPE UI><UI version="3.2" stdsetdef="1"> +<class>TimeShifterConfigurationUI</class> +<widget class="QWidget"> + <property name="name"> + <cstring>TimeShifterConfigurationUI</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>299</width> + <height>134</height> + </rect> + </property> + <property name="caption"> + <string>SetupDialogGeneral</string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <widget class="QLayoutWidget" row="0" column="0"> + <property name="name"> + <cstring>layout10</cstring> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <spacer row="1" column="3"> + <property name="name"> + <cstring>spacer18_3_2</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Preferred</enum> + </property> + <property name="sizeHint"> + <size> + <width>30</width> + <height>21</height> + </size> + </property> + </spacer> + <spacer row="1" column="1"> + <property name="name"> + <cstring>spacer18_3_2_2</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Preferred</enum> + </property> + <property name="sizeHint"> + <size> + <width>104</width> + <height>21</height> + </size> + </property> + </spacer> + <widget class="QSpinBox" row="1" column="2"> + <property name="name"> + <cstring>editTempFileSize</cstring> + </property> + <property name="suffix"> + <string> MB</string> + </property> + <property name="maxValue"> + <number>10000</number> + </property> + <property name="minValue"> + <number>10</number> + </property> + <property name="lineStep"> + <number>10</number> + </property> + <property name="value"> + <number>100</number> + </property> + </widget> + <widget class="QLabel" row="1" column="0"> + <property name="name"> + <cstring>labelTempFileSize</cstring> + </property> + <property name="text"> + <string>Maximum File Size</string> + </property> + </widget> + <widget class="QLabel" row="2" column="0"> + <property name="name"> + <cstring>labelPlaybackMixerDevice</cstring> + </property> + <property name="text"> + <string>Playback Mixer Device</string> + </property> + </widget> + <widget class="QLabel" row="0" column="0"> + <property name="name"> + <cstring>labelTempFile</cstring> + </property> + <property name="text"> + <string>Temporary File</string> + </property> + </widget> + <widget class="QLineEdit" row="0" column="1" rowspan="1" colspan="2"> + <property name="name"> + <cstring>editTempFile</cstring> + </property> + </widget> + <widget class="QLabel" row="3" column="0"> + <property name="name"> + <cstring>labelPlaybackMixerChannel</cstring> + </property> + <property name="text"> + <string>Playback Mixer Channel</string> + </property> + </widget> + <widget class="QPushButton" row="0" column="3"> + <property name="name"> + <cstring>buttonSelectTempFile</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>0</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>26</width> + <height>26</height> + </size> + </property> + <property name="text"> + <string></string> + </property> + <property name="iconSet"> + <iconset>"fileopen"</iconset> + </property> + </widget> + <widget class="QComboBox" row="2" column="1" rowspan="1" colspan="2"> + <property name="name"> + <cstring>comboPlaybackMixerDevice</cstring> + </property> + </widget> + <widget class="QComboBox" row="3" column="1" rowspan="1" colspan="2"> + <property name="name"> + <cstring>comboPlaybackMixerChannel</cstring> + </property> + </widget> + <spacer row="3" column="3"> + <property name="name"> + <cstring>spacer18_3</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Preferred</enum> + </property> + <property name="sizeHint"> + <size> + <width>30</width> + <height>21</height> + </size> + </property> + </spacer> + <spacer row="2" column="3"> + <property name="name"> + <cstring>spacer18_3_4</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Preferred</enum> + </property> + <property name="sizeHint"> + <size> + <width>30</width> + <height>21</height> + </size> + </property> + </spacer> + </grid> + </widget> + <spacer row="1" column="0"> + <property name="name"> + <cstring>spacer16</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>61</height> + </size> + </property> + </spacer> + </grid> +</widget> +<tabstops> + <tabstop>editTempFile</tabstop> + <tabstop>buttonSelectTempFile</tabstop> + <tabstop>comboPlaybackMixerChannel</tabstop> +</tabstops> +<includes> + <include location="global" impldecl="in implementation">kiconloader.h</include> + <include location="global" impldecl="in implementation">knuminput.h</include> +</includes> +<pixmapfunction>SmallIconSet</pixmapfunction> +<layoutdefaults spacing="6" margin="0"/> +</UI> diff --git a/kradio3/plugins/timeshifter/timeshifter-configuration.cpp b/kradio3/plugins/timeshifter/timeshifter-configuration.cpp new file mode 100644 index 0000000..828cc33 --- /dev/null +++ b/kradio3/plugins/timeshifter/timeshifter-configuration.cpp @@ -0,0 +1,203 @@ +/*************************************************************************** + v4lradio-configuration.cpp - description + ------------------- + begin : Fre Jun 20 2003 + copyright : (C) 2003 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 <sys/ioctl.h> +#include <fcntl.h> +#include <unistd.h> +#include <linux/soundcard.h> + +#include <qspinbox.h> +#include <qlineedit.h> +#include <qcombobox.h> +#include <qlabel.h> +#include <qfile.h> +#include <qpushbutton.h> + +#include <kfiledialog.h> +#include <knuminput.h> +#include <klocale.h> + +#include "../../src/include/utils.h" +#include "../../src/include/gui_list_helper.h" +#include "timeshifter-configuration.h" +#include "timeshifter.h" + +TimeShifterConfiguration::TimeShifterConfiguration (QWidget *parent, TimeShifter *shifter) + : TimeShifterConfigurationUI(parent), + m_ignoreGUIChanges(false), + m_myControlChange(0), + m_PlaybackMixerHelper(comboPlaybackMixerDevice, StringListHelper::SORT_BY_DESCR), + m_PlaybackChannelHelper(comboPlaybackMixerChannel), + m_Shifter(shifter), + m_dirty(true) +{ + QObject::connect(buttonSelectTempFile, SIGNAL(clicked()), + this, SLOT(selectTempFile())); + QObject::connect(comboPlaybackMixerDevice, SIGNAL(activated(int)), + this, SLOT(slotComboPlaybackMixerSelected(int))); + + connect(editTempFile, SIGNAL(textChanged(const QString&)), this, SLOT(slotSetDirty())); + connect(editTempFileSize, SIGNAL(valueChanged(int)), this, SLOT(slotSetDirty())); + connect(comboPlaybackMixerChannel, SIGNAL(activated( int )), this, SLOT(slotSetDirty())); + connect(comboPlaybackMixerDevice, SIGNAL(activated( int )), this, SLOT(slotSetDirty())); + slotCancel(); +} + + +TimeShifterConfiguration::~TimeShifterConfiguration () +{ +} + + +bool TimeShifterConfiguration::connectI (Interface *i) +{ + bool a = ISoundStreamClient::connectI(i); + return a; +} + + +bool TimeShifterConfiguration::disconnectI (Interface *i) +{ + bool a = ISoundStreamClient::disconnectI(i); + return a; +} + +void TimeShifterConfiguration::noticeConnectedI (ISoundStreamServer *s, bool pointer_valid) +{ + ISoundStreamClient::noticeConnectedI(s, pointer_valid); + if (s && pointer_valid) { + s->register4_notifyPlaybackChannelsChanged(this); + } +} + +void TimeShifterConfiguration::noticeConnectedSoundClient(ISoundStreamClient::thisInterface *i, bool pointer_valid) +{ + if (i && pointer_valid && i->supportsPlayback() && m_Shifter) { + const QString &org_mid = m_Shifter->getPlaybackMixer(); + bool org_present = m_PlaybackMixerHelper.contains(org_mid); + const QString &mid = org_present ? m_PlaybackMixerHelper.getCurrentItem() : org_mid; + const QString &org_ch = m_Shifter->getPlaybackMixerChannel(); + const QString &ch = org_present ? m_PlaybackChannelHelper.getCurrentText() : org_ch; + setPlaybackMixer(mid, ch); + } +} + + +void TimeShifterConfiguration::noticeDisconnectedSoundClient(ISoundStreamClient::thisInterface *i, bool pointer_valid) +{ + if (i && pointer_valid && i->supportsPlayback()) { + setPlaybackMixer(m_Shifter->getPlaybackMixer(), m_Shifter->getPlaybackMixerChannel()); + } +} + + + +bool TimeShifterConfiguration::setPlaybackMixer(const QString &_mixer_id, const QString &Channel) +{ + QString mixer_id = _mixer_id; + bool old = m_ignoreGUIChanges; + m_ignoreGUIChanges = true; + + m_PlaybackMixerHelper.setData(getPlaybackClientDescriptions()); + m_PlaybackMixerHelper.setCurrentItem(mixer_id); + mixer_id = m_PlaybackMixerHelper.getCurrentItem(); + + ISoundStreamClient *mixer = getSoundStreamClientWithID(mixer_id); + if (mixer) { + m_PlaybackChannelHelper.setData(mixer->getPlaybackChannels()); + m_PlaybackChannelHelper.setCurrentText(m_PlaybackChannelHelper.contains(Channel) ? Channel : m_Shifter->getPlaybackMixerChannel()); + } + labelPlaybackMixerChannel->setEnabled(mixer != NULL); + comboPlaybackMixerChannel->setEnabled(mixer != NULL); + + m_ignoreGUIChanges = old; + return true; +} + + +// GUI Slots + + +void TimeShifterConfiguration::selectTempFile() +{ + KFileDialog fd("/tmp/", + i18n("any ( * )").ascii(), + this, + i18n("TimeShifter Temporary File Selection").ascii(), + TRUE); + fd.setMode(KFile::File); + fd.setCaption (i18n("Select TimeShifter Temporary File")); + + if (fd.exec() == QDialog::Accepted) { + editTempFile->setText(fd.selectedFile()); + } +} + + +void TimeShifterConfiguration::slotComboPlaybackMixerSelected(int /*idx*/) +{ + if (m_ignoreGUIChanges) return; + setPlaybackMixer(m_PlaybackMixerHelper.getCurrentItem(), m_PlaybackChannelHelper.getCurrentText()); +} + + +void TimeShifterConfiguration::slotOK() +{ + if (m_Shifter && m_dirty) { + m_Shifter->setTempFile(editTempFile->text(), editTempFileSize->value() * (Q_UINT64)(1024 * 1024)); + m_Shifter->setPlaybackMixer(m_PlaybackMixerHelper.getCurrentItem(), + m_PlaybackChannelHelper.getCurrentText()); + m_dirty = false; + } +} + + +void TimeShifterConfiguration::slotCancel() +{ + if (m_Shifter && m_dirty) { + editTempFile->setText(m_Shifter->getTempFileName()); + editTempFileSize->setValue(m_Shifter->getTempFileMaxSize() / 1024 / 1024); + + setPlaybackMixer(m_Shifter->getPlaybackMixer(), m_Shifter->getPlaybackMixerChannel()); + m_dirty = false; + } +} + + +bool TimeShifterConfiguration::noticePlaybackChannelsChanged(const QString & client_id, const QStringList &/*channels*/) +{ + if (m_PlaybackMixerHelper.getCurrentItem() == client_id) { + setPlaybackMixer(client_id, m_PlaybackChannelHelper.getCurrentText()); + } + return true; +} + + +void TimeShifterConfiguration::slotSetDirty() +{ + if (!m_ignoreGUIChanges) { + m_dirty = true; + } +} + +void TimeShifterConfiguration::slotUpdateConfig() +{ + slotSetDirty(); + slotCancel(); +} + +#include "timeshifter-configuration.moc" diff --git a/kradio3/plugins/timeshifter/timeshifter-configuration.h b/kradio3/plugins/timeshifter/timeshifter-configuration.h new file mode 100644 index 0000000..7d34c3d --- /dev/null +++ b/kradio3/plugins/timeshifter/timeshifter-configuration.h @@ -0,0 +1,83 @@ +/*************************************************************************** + v4lradio-configuration.h - description + ------------------- + begin : Fre Jun 20 2003 + copyright : (C) 2003 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_TIMESHIFTER_CONFIGURATION_H +#define KRADIO_TIMESHIFTER_CONFIGURATION_H + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "../../src/include/soundstreamclient_interfaces.h" +#include "../../src/include/gui_list_helper.h" + +#include "timeshifter-configuration-ui.h" + +class QWidget; +class TimeShifter; + +class TimeShifterConfiguration : public TimeShifterConfigurationUI, + public ISoundStreamClient +{ +Q_OBJECT +public : + TimeShifterConfiguration (QWidget *parent, TimeShifter *shifter); + ~TimeShifterConfiguration (); + + bool connectI (Interface *i); + bool disconnectI (Interface *i); + + void noticeConnectedSoundClient(ISoundStreamClient::thisInterface *i, bool pointer_valid); + void noticeDisconnectedSoundClient(ISoundStreamClient::thisInterface *i, bool pointer_valid); + +// ISoundStreamClient + +RECEIVERS: + void noticeConnectedI (ISoundStreamServer *s, bool pointer_valid); + bool noticePlaybackChannelsChanged(const QString & /*client_id*/, const QStringList &/*channels*/); + +protected: + + bool setPlaybackMixer(const QString &_mixer_id, const QString &Channel); + + +protected slots: + + void selectTempFile(); + void slotComboPlaybackMixerSelected(int idx); + + void slotOK(); + void slotCancel(); + void slotSetDirty(); + void slotUpdateConfig(); + +protected: + + bool m_ignoreGUIChanges; + int m_myControlChange; + + typedef GUIListHelper<QComboBox, QString> StringListHelper; + typedef GUISimpleListHelper<QComboBox> ChannelListHelper; + + StringListHelper m_PlaybackMixerHelper; + ChannelListHelper m_PlaybackChannelHelper; + + TimeShifter *m_Shifter; + bool m_dirty; +}; + +#endif diff --git a/kradio3/plugins/timeshifter/timeshifter.cpp b/kradio3/plugins/timeshifter/timeshifter.cpp new file mode 100644 index 0000000..bff1851 --- /dev/null +++ b/kradio3/plugins/timeshifter/timeshifter.cpp @@ -0,0 +1,455 @@ +/*************************************************************************** + timeshifter.cpp - description + ------------------- + begin : Mon May 16 13:39:31 CEST 2005 + copyright : (C) 2005 by Ernst 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. * + * * + ***************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <klocale.h> +#include <linux/soundcard.h> + +#include "../../src/include/utils.h" +#include "timeshifter.h" +#include "timeshifter-configuration.h" + +/////////////////////////////////////////////////////////////////////// + +PLUGIN_LIBRARY_FUNCTIONS(TimeShifter, "kradio-timeshifter", i18n("TimeShift Support")); + +/////////////////////////////////////////////////////////////////////// + +TimeShifter::TimeShifter (const QString &name) + : PluginBase(name, i18n("TimeShifter Plugin")), + m_TempFileName("/tmp/kradio-timeshifter-tempfile"), + m_TempFileMaxSize(256*1024*1024), + m_PlaybackMixerID(QString::null), + m_PlaybackMixerChannel("PCM"), + m_orgVolume(0.0), + m_PlaybackMetaData(0,0,0), + m_PlaybackDataLeftInBuffer(0), + m_RingBuffer(m_TempFileName, m_TempFileMaxSize) +{ +} + + +TimeShifter::~TimeShifter () +{ +} + + +bool TimeShifter::connectI (Interface *i) +{ + bool a = PluginBase::connectI(i); + bool b = ISoundStreamClient::connectI(i); + return a || b; +} + + +bool TimeShifter::disconnectI (Interface *i) +{ + bool a = PluginBase::disconnectI(i); + bool b = ISoundStreamClient::disconnectI(i); + return a || b; +} + + +void TimeShifter::noticeConnectedI (ISoundStreamServer *s, bool pointer_valid) +{ + ISoundStreamClient::noticeConnectedI(s, pointer_valid); + if (s && pointer_valid) { + s->register4_notifySoundStreamClosed(this); + s->register4_sendStartPlayback(this); + s->register4_sendStopPlayback(this); + s->register4_sendPausePlayback(this); + s->register4_notifySoundStreamData(this); + s->register4_notifyReadyForPlaybackData(this); + s->register4_querySoundStreamDescription(this); + s->register4_sendStartCaptureWithFormat(this); + s->register4_sendStopCapture(this); + } +} + + +void TimeShifter::saveState (KConfig *config) const +{ + config->setGroup(QString("timeshifter-") + name()); + + config->writeEntry("temp-file-name", m_TempFileName); + config->writeEntry("max-file-size", m_TempFileMaxSize / 1024 / 1024); + + config->writeEntry("PlaybackMixerID", m_PlaybackMixerID); + config->writeEntry("PlaybackMixerChannel", m_PlaybackMixerChannel); +} + + +void TimeShifter::restoreState (KConfig *config) +{ + config->setGroup(QString("timeshifter-") + name()); + + QString fname = config->readEntry("temp-file-name", "/tmp/kradio-timeshifter-tempfile"); + Q_UINT64 fsize = 1024 * 1024 * config->readNumEntry("max-file-size", 256); + + QString mixerID = config->readEntry ("PlaybackMixerID", QString::null); + QString channel = config->readEntry ("PlaybackMixerChannel", "PCM"); + + setPlaybackMixer(mixerID, channel); + setTempFile(fname, fsize); + + emit sigUpdateConfig(); +} + + +ConfigPageInfo TimeShifter::createConfigurationPage() +{ + TimeShifterConfiguration *conf = new TimeShifterConfiguration(NULL, this); + QObject::connect(this, SIGNAL(sigUpdateConfig()), conf, SLOT(slotUpdateConfig())); + return ConfigPageInfo (conf, + i18n("Timeshifter"), + i18n("Timeshifter Options"), + "kradio_pause"); +} + +AboutPageInfo TimeShifter::createAboutPage() +{ + return AboutPageInfo(); +} + + +bool TimeShifter::noticeSoundStreamClosed(SoundStreamID id) +{ + return stopPlayback(id); +} + +bool TimeShifter::startPlayback(SoundStreamID id) +{ + if (id == m_OrgStreamID) { + m_StreamPaused = false; + return true; + } + return false; +} + +bool TimeShifter::stopPlayback(SoundStreamID id) +{ + if (id == m_NewStreamID) { + + return sendStopPlayback(m_OrgStreamID); + + } else if (id == m_OrgStreamID) { + + SoundStreamID tmp_newID = m_NewStreamID; + SoundStreamID tmp_orgID = m_OrgStreamID; + + m_OrgStreamID.invalidate(); + m_NewStreamID.invalidate(); + + sendStopCapture(tmp_newID); + closeSoundStream(tmp_newID); + stopPlayback(tmp_newID); + m_RingBuffer.clear(); + m_PlaybackMetaData = SoundMetaData(0,0,0); + m_PlaybackDataLeftInBuffer = 0; + return true; + } + return false; +} + + +bool TimeShifter::pausePlayback(SoundStreamID id) +{ + if (!m_OrgStreamID.isValid()) { + SoundStreamID orgid = id; + SoundStreamID newid = createNewSoundStream(orgid, false); + m_OrgStreamID = orgid; + m_NewStreamID = newid; + notifySoundStreamCreated(newid); + notifySoundStreamRedirected(orgid, newid); + queryPlaybackVolume(newid, m_orgVolume); + sendMute(newid); + sendPlaybackVolume(newid, 0); + + m_NewStreamID.invalidate(); + sendStopPlayback(newid); + m_NewStreamID = newid; + + m_StreamPaused = true; + + m_RingBuffer.clear(); + m_PlaybackMetaData = SoundMetaData(0,0,0); + m_PlaybackDataLeftInBuffer = 0; + + sendStartCaptureWithFormat(m_NewStreamID, m_SoundFormat, m_realSoundFormat); + + ISoundStreamClient *playback_mixer = searchPlaybackMixer(); + if (playback_mixer) { + playback_mixer->preparePlayback(m_OrgStreamID, m_PlaybackMixerChannel, /*active*/true, /*startimmediately*/ true); + m_PlaybackMixerID = playback_mixer->getSoundStreamClientID(); + } + + return true; + + } else if (id == m_OrgStreamID) { + m_StreamPaused = !m_StreamPaused; + if (!m_StreamPaused) { +// sendStartPlayback(m_OrgStreamID); + sendUnmute(m_OrgStreamID); + sendPlaybackVolume(m_OrgStreamID, m_orgVolume); + } else { + queryPlaybackVolume(m_OrgStreamID, m_orgVolume); + } + return true; + } + return false; +} + + +size_t TimeShifter::writeMetaDataToBuffer(const SoundMetaData &md, char *buffer, size_t buffer_size) +{ + Q_UINT64 pos = md.position(); + time_t abs = md.absoluteTimestamp(); + time_t rel = md.relativeTimestamp(); + size_t url_len = md.url().url().length() + 1; + size_t req_size = sizeof(req_size) + sizeof(pos) + sizeof(abs) + sizeof(rel) + sizeof(url_len) + url_len; + if (req_size <= buffer_size) { + *(size_t*)buffer = req_size; + buffer += sizeof(req_size); + *(Q_UINT64*)buffer = pos; + buffer += sizeof(pos); + *(time_t*)buffer = abs; + buffer += sizeof(abs); + *(time_t*)buffer = rel; + buffer += sizeof(rel); + *(size_t*)buffer = url_len; + buffer += sizeof(url_len); + memcpy(buffer, md.url().url().ascii(), url_len); + buffer += url_len; + return req_size; + } else if (buffer_size >= sizeof(req_size)) { + *(size_t*)buffer = sizeof(req_size); + return sizeof(req_size); + } else { + return 0; + } +} + +size_t TimeShifter::readMetaDataFromBuffer(SoundMetaData &md, const char *buffer, size_t buffer_size) +{ + size_t req_size = 0; + Q_UINT64 pos = 0; + time_t abs = 0; + time_t rel = 0; + size_t url_len = 0; + KURL url; + if (buffer_size >= sizeof(req_size)) { + req_size = *(size_t*)buffer; + buffer += sizeof(req_size); + if (req_size > sizeof(req_size)) { + pos = *(Q_UINT64*)buffer; + buffer += sizeof(Q_UINT64); + abs = *(time_t*)buffer; + buffer += sizeof(abs); + rel = *(time_t*)buffer; + buffer += sizeof(rel); + url_len = *(size_t*)buffer; + buffer += sizeof(url_len); + url = buffer; + buffer += url_len; + } + } + md = SoundMetaData(pos, rel, abs, url); + return req_size; +} + + +bool TimeShifter::noticeSoundStreamData(SoundStreamID id, const SoundFormat &/*sf*/, const char *data, size_t size, size_t &consumed_size, const SoundMetaData &md) +{ + if (id == m_NewStreamID) { + char buffer_meta[1024]; + size_t meta_buffer_size = writeMetaDataToBuffer(md, buffer_meta, 1024); + size_t packet_size = meta_buffer_size + sizeof(size) + size; + if (packet_size > m_RingBuffer.getMaxSize()) + return false; + Q_INT64 diff = m_RingBuffer.getFreeSize() - packet_size; + while (diff < 0) { + skipPacketInRingBuffer(); + diff = m_RingBuffer.getFreeSize() - packet_size; + } + m_RingBuffer.addData(buffer_meta, meta_buffer_size); + m_RingBuffer.addData((const char*)&size, sizeof(size)); + m_RingBuffer.addData(data, size); + consumed_size = (consumed_size == SIZE_T_DONT_CARE) ? size : min(consumed_size, size); + return true; + } + return false; +} + + +void TimeShifter::skipPacketInRingBuffer() +{ + if (m_PlaybackDataLeftInBuffer > 0) { + m_RingBuffer.removeData(m_PlaybackDataLeftInBuffer); + } else { + size_t meta_size = 0; + m_RingBuffer.takeData((char*)&meta_size, sizeof(meta_size)); + m_RingBuffer.removeData(meta_size - sizeof(meta_size)); + size_t packet_size = 0; + m_RingBuffer.takeData((char*)&packet_size, sizeof(packet_size)); + m_RingBuffer.removeData(packet_size - sizeof(packet_size)); + } +} + + +bool TimeShifter::noticeReadyForPlaybackData(SoundStreamID id, size_t free_size) +{ + if (id == m_OrgStreamID && !m_StreamPaused) { + + while (!m_RingBuffer.error() && m_RingBuffer.getFillSize() > 0 && free_size > 0) { + if (m_PlaybackDataLeftInBuffer == 0) { + char meta_buffer[1024]; + size_t &meta_size = *(size_t*)meta_buffer; + meta_size = 0; + m_RingBuffer.takeData(meta_buffer, sizeof(meta_size)); + if (meta_size && meta_size <= 1024) { + m_RingBuffer.takeData(meta_buffer + sizeof(meta_size), meta_size - sizeof(meta_size)); + readMetaDataFromBuffer(m_PlaybackMetaData, meta_buffer, meta_size); + } else { + m_RingBuffer.removeData(meta_size - sizeof(meta_size)); + } + + m_PlaybackDataLeftInBuffer = 0; + m_RingBuffer.takeData((char*)&m_PlaybackDataLeftInBuffer, sizeof(m_PlaybackDataLeftInBuffer)); + } + + const size_t buffer_size = 65536; + char buffer[buffer_size]; + + while (!m_RingBuffer.error() && m_PlaybackDataLeftInBuffer > 0 && free_size > 0) { + size_t s = m_PlaybackDataLeftInBuffer < free_size ? m_PlaybackDataLeftInBuffer : free_size; + + if (s > buffer_size) + s = buffer_size; + s = m_RingBuffer.takeData(buffer, s); + + size_t consumed_size = SIZE_T_DONT_CARE; + notifySoundStreamData(m_OrgStreamID, m_realSoundFormat, buffer, s, consumed_size, m_PlaybackMetaData); + if (consumed_size == SIZE_T_DONT_CARE) + consumed_size = s; + + free_size -= consumed_size; + m_PlaybackDataLeftInBuffer -= consumed_size; + if (consumed_size < s) { + logError(i18n("TimeShifter::notifySoundStreamData: clients skipped %1 bytes. Data Lost").arg(s - consumed_size)); + free_size = 0; // break condition for outer loop + break; + } + } + } + return true; + } + return false; +} + + + +ISoundStreamClient *TimeShifter::searchPlaybackMixer() +{ + ISoundStreamClient *playback_mixer = getSoundStreamClientWithID(m_PlaybackMixerID); + + // some simple sort of autodetection if one mixer isn't present any more + if (!playback_mixer) { + QPtrList<ISoundStreamClient> playback_mixers = queryPlaybackMixers(); + if (!playback_mixers.isEmpty()) + playback_mixer = playback_mixers.first(); + } + return playback_mixer; +} + + +bool TimeShifter::setPlaybackMixer(const QString &soundStreamClientID, const QString &ch) +{ + m_PlaybackMixerID = soundStreamClientID; + m_PlaybackMixerChannel = ch; + + ISoundStreamClient *playback_mixer = searchPlaybackMixer(); + + float oldVolume; + if (m_OrgStreamID.isValid()) { + queryPlaybackVolume(m_OrgStreamID, oldVolume); + sendStopPlayback(m_OrgStreamID); + sendReleasePlayback(m_OrgStreamID); + } + + if (playback_mixer) + playback_mixer->preparePlayback(m_OrgStreamID, m_PlaybackMixerChannel, /*active*/true, /*start_imm*/false); + + if (m_OrgStreamID.isValid()) { + sendStartPlayback(m_OrgStreamID); + sendPlaybackVolume(m_OrgStreamID, oldVolume); + } + + return true; +} + + +void TimeShifter::setTempFile(const QString &filename, Q_UINT64 s) +{ + m_RingBuffer.clear(); + m_RingBuffer.resize(m_TempFileName = filename, m_TempFileMaxSize = s); + m_PlaybackMetaData = SoundMetaData(0,0,0, i18n("internal stream, not stored")); + m_PlaybackDataLeftInBuffer = 0; +} + +bool TimeShifter::getSoundStreamDescription(SoundStreamID id, QString &descr) const +{ + if (id == m_NewStreamID) { + descr = name(); + return true; + } + else { + return false; + } +} + +bool TimeShifter::startCaptureWithFormat( + SoundStreamID id, + const SoundFormat &proposed_format, + SoundFormat &real_format, + bool force_format +) +{ + if (id == m_OrgStreamID) { + if (force_format && m_realSoundFormat != proposed_format) { + sendStopCapture(m_NewStreamID); + sendStartCaptureWithFormat(m_NewStreamID, proposed_format, m_realSoundFormat); + } + real_format = m_realSoundFormat; + return true; + } else { + return false; + } +} + +bool TimeShifter::stopCapture(SoundStreamID id) +{ + if (id == m_OrgStreamID) { + return true; + } else { + return false; + } +} + +#include "timeshifter.moc" diff --git a/kradio3/plugins/timeshifter/timeshifter.h b/kradio3/plugins/timeshifter/timeshifter.h new file mode 100644 index 0000000..32c3837 --- /dev/null +++ b/kradio3/plugins/timeshifter/timeshifter.h @@ -0,0 +1,120 @@ +/*************************************************************************** + timeshifter.h - description + ------------------- + begin : May 16 2005 + copyright : (C) 2005 Ernst 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_TIMESHIFTER_H +#define KRADIO_TIMESHIFTER_H + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "../../src/include/plugins.h" +#include "../../src/include/soundstreamclient_interfaces.h" +#include "../../src/include/fileringbuffer.h" + + +class TimeShifter : public QObject, + public PluginBase, + public ISoundStreamClient +{ +Q_OBJECT +public: + TimeShifter (const QString &name); + virtual ~TimeShifter (); + + virtual bool connectI (Interface *); + virtual bool disconnectI (Interface *); + + virtual QString pluginClassName() const { return "TimeShifter"; } + + virtual const QString &name() const { return PluginBase::name(); } + virtual QString &name() { return PluginBase::name(); } + + // config + + const QString &getPlaybackMixer() const { return m_PlaybackMixerID; } + const QString &getPlaybackMixerChannel() const { return m_PlaybackMixerChannel; } + const QString &getTempFileName() const { return m_TempFileName; } + Q_UINT64 getTempFileMaxSize() const { return m_TempFileMaxSize; } + + void setTempFile(const QString &filename, Q_UINT64 s); + bool setPlaybackMixer(const QString &soundStreamClientID, const QString &ch); + + // PluginBase + +public: + virtual void saveState (KConfig *) const; + virtual void restoreState (KConfig *); + + virtual ConfigPageInfo createConfigurationPage(); + virtual AboutPageInfo createAboutPage(); + +protected: + + ISoundStreamClient *searchPlaybackMixer(); + + size_t writeMetaDataToBuffer(const SoundMetaData &md, char *buffer, size_t buffer_size); + size_t readMetaDataFromBuffer(SoundMetaData &md, const char *buffer, size_t buffer_size); + void skipPacketInRingBuffer(); + + // SoundStreamClient + void noticeConnectedI (ISoundStreamServer *s, bool pointer_valid); + + bool startCaptureWithFormat(SoundStreamID id, + const SoundFormat &proposed_format, + SoundFormat &real_format, + bool force_format); + bool stopCapture(SoundStreamID id); + bool noticeSoundStreamClosed(SoundStreamID id); + bool startPlayback(SoundStreamID id); + bool stopPlayback(SoundStreamID id); + bool pausePlayback(SoundStreamID id); + bool noticeSoundStreamData(SoundStreamID id, const SoundFormat &sf, const char *data, size_t size, size_t &consumed_size, const SoundMetaData &md); + bool noticeReadyForPlaybackData(SoundStreamID id, size_t size); + + bool getSoundStreamDescription(SoundStreamID id, QString &descr) const; + + // FIXME: react on redirect request + +signals: + + void sigUpdateConfig(); + +protected: + + QString m_TempFileName; + size_t m_TempFileMaxSize; + SoundFormat m_SoundFormat; + SoundFormat m_realSoundFormat; + + QString m_PlaybackMixerID; + QString m_PlaybackMixerChannel; + + QString m_StreamFile; + bool m_StreamPaused; + SoundStreamID m_OrgStreamID; + SoundStreamID m_NewStreamID; + SoundFormat m_RealSoundFormat; + float m_orgVolume; + + SoundMetaData m_PlaybackMetaData; + size_t m_PlaybackDataLeftInBuffer; + + FileRingBuffer m_RingBuffer; +}; + +#endif diff --git a/kradio3/plugins/v4lradio/Makefile.am b/kradio3/plugins/v4lradio/Makefile.am new file mode 100644 index 0000000..093d346 --- /dev/null +++ b/kradio3/plugins/v4lradio/Makefile.am @@ -0,0 +1,18 @@ +SUBDIRS = po . + +INCLUDES = $(all_includes) +METASOURCES = AUTO + +libkradio_LTLIBRARIES = libv4lradio.la +libv4lradio_la_SOURCES = v4lcfg_interfaces.cpp v4lradio-configuration.cpp \ + v4lradio-configuration-ui.ui v4lradio.cpp +libv4lradio_la_LDFLAGS = -module -avoid-version $(KDE_RPATH) $(all_libraries) + +noinst_HEADERS = v4lcfg_interfaces.h v4lradio-configuration.h v4lradio.h + +#messages: rc.cpp +# $(XGETTEXT) *.cpp *.h -o po/kradio-v4lradio.pot + +messages: rc.cpp + $(EXTRACTRC) *.rc *.ui >> rc.cpp + $(XGETTEXT) rc.cpp *.h *.cpp -o po/kradio-v4lradio.pot diff --git a/kradio3/plugins/v4lradio/linux/videodev.h b/kradio3/plugins/v4lradio/linux/videodev.h new file mode 100644 index 0000000..e16a8a8 --- /dev/null +++ b/kradio3/plugins/v4lradio/linux/videodev.h @@ -0,0 +1,432 @@ +#ifndef __LINUX_VIDEODEV_H +#define __LINUX_VIDEODEV_H + +#include <linux/types.h> +#include <linux/version.h> +//#include <linux/device.h> + +//#define HAVE_V4L2 1 +//#include <linux/videodev2.h> + +#ifdef __KERNEL__ + +#include <linux/poll.h> +#include <linux/mm.h> + +struct video_device +{ + /* device info */ + struct device *dev; + char name[32]; + int type; /* v4l1 */ + int type2; /* v4l2 */ + int hardware; + int minor; + + /* device ops + callbacks */ + struct file_operations *fops; + void (*release)(struct video_device *vfd); + + +#if 1 /* to be removed in 2.7.x */ + /* obsolete -- fops->owner is used instead */ + struct module *owner; + /* dev->driver_data will be used instead some day. + * Use the video_{get|set}_drvdata() helper functions, + * so the switch over will be transparent for you. + * Or use {pci|usb}_{get|set}_drvdata() directly. */ + void *priv; +#endif + + /* for videodev.c intenal usage -- please don't touch */ + int users; /* video_exclusive_{open|close} ... */ + struct semaphore lock; /* ... helper function uses these */ + char devfs_name[64]; /* devfs */ + struct class_device class_dev; /* sysfs */ +}; + +#define VIDEO_MAJOR 81 + +#define VFL_TYPE_GRABBER 0 +#define VFL_TYPE_VBI 1 +#define VFL_TYPE_RADIO 2 +#define VFL_TYPE_VTX 3 + +extern int video_register_device(struct video_device *, int type, int nr); +extern void video_unregister_device(struct video_device *); +extern struct video_device* video_devdata(struct file*); + +#define to_video_device(cd) container_of(cd, struct video_device, class_dev) +static inline void +video_device_create_file(struct video_device *vfd, + struct class_device_attribute *attr) +{ + class_device_create_file(&vfd->class_dev, attr); +} + +/* helper functions to alloc / release struct video_device, the + later can be used for video_device->release() */ +struct video_device *video_device_alloc(void); +void video_device_release(struct video_device *vfd); + +/* helper functions to access driver private data. */ +static inline void *video_get_drvdata(struct video_device *dev) +{ + return dev->priv; +} + +static inline void video_set_drvdata(struct video_device *dev, void *data) +{ + dev->priv = data; +} + +extern int video_exclusive_open(struct inode *inode, struct file *file); +extern int video_exclusive_release(struct inode *inode, struct file *file); +extern int video_usercopy(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg, + int (*func)(struct inode *inode, struct file *file, + unsigned int cmd, void *arg)); +#endif /* __KERNEL__ */ + +#define VID_TYPE_CAPTURE 1 /* Can capture */ +#define VID_TYPE_TUNER 2 /* Can tune */ +#define VID_TYPE_TELETEXT 4 /* Does teletext */ +#define VID_TYPE_OVERLAY 8 /* Overlay onto frame buffer */ +#define VID_TYPE_CHROMAKEY 16 /* Overlay by chromakey */ +#define VID_TYPE_CLIPPING 32 /* Can clip */ +#define VID_TYPE_FRAMERAM 64 /* Uses the frame buffer memory */ +#define VID_TYPE_SCALES 128 /* Scalable */ +#define VID_TYPE_MONOCHROME 256 /* Monochrome only */ +#define VID_TYPE_SUBCAPTURE 512 /* Can capture subareas of the image */ +#define VID_TYPE_MPEG_DECODER 1024 /* Can decode MPEG streams */ +#define VID_TYPE_MPEG_ENCODER 2048 /* Can encode MPEG streams */ +#define VID_TYPE_MJPEG_DECODER 4096 /* Can decode MJPEG streams */ +#define VID_TYPE_MJPEG_ENCODER 8192 /* Can encode MJPEG streams */ + +struct video_capability +{ + char name[32]; + int type; + int channels; /* Num channels */ + int audios; /* Num audio devices */ + int maxwidth; /* Supported width */ + int maxheight; /* And height */ + int minwidth; /* Supported width */ + int minheight; /* And height */ +}; + + +struct video_channel +{ + int channel; + char name[32]; + int tuners; + __u32 flags; +#define VIDEO_VC_TUNER 1 /* Channel has a tuner */ +#define VIDEO_VC_AUDIO 2 /* Channel has audio */ + __u16 type; +#define VIDEO_TYPE_TV 1 +#define VIDEO_TYPE_CAMERA 2 + __u16 norm; /* Norm set by channel */ +}; + +struct video_tuner +{ + int tuner; + char name[32]; + unsigned long rangelow, rangehigh; /* Tuner range */ + __u32 flags; +#define VIDEO_TUNER_PAL 1 +#define VIDEO_TUNER_NTSC 2 +#define VIDEO_TUNER_SECAM 4 +#define VIDEO_TUNER_LOW 8 /* Uses KHz not MHz */ +#define VIDEO_TUNER_NORM 16 /* Tuner can set norm */ +#define VIDEO_TUNER_STEREO_ON 128 /* Tuner is seeing stereo */ +#define VIDEO_TUNER_RDS_ON 256 /* Tuner is seeing an RDS datastream */ +#define VIDEO_TUNER_MBS_ON 512 /* Tuner is seeing an MBS datastream */ + __u16 mode; /* PAL/NTSC/SECAM/OTHER */ +#define VIDEO_MODE_PAL 0 +#define VIDEO_MODE_NTSC 1 +#define VIDEO_MODE_SECAM 2 +#define VIDEO_MODE_AUTO 3 + __u16 signal; /* Signal strength 16bit scale */ +}; + +struct video_picture +{ + __u16 brightness; + __u16 hue; + __u16 colour; + __u16 contrast; + __u16 whiteness; /* Black and white only */ + __u16 depth; /* Capture depth */ + __u16 palette; /* Palette in use */ +#define VIDEO_PALETTE_GREY 1 /* Linear greyscale */ +#define VIDEO_PALETTE_HI240 2 /* High 240 cube (BT848) */ +#define VIDEO_PALETTE_RGB565 3 /* 565 16 bit RGB */ +#define VIDEO_PALETTE_RGB24 4 /* 24bit RGB */ +#define VIDEO_PALETTE_RGB32 5 /* 32bit RGB */ +#define VIDEO_PALETTE_RGB555 6 /* 555 15bit RGB */ +#define VIDEO_PALETTE_YUV422 7 /* YUV422 capture */ +#define VIDEO_PALETTE_YUYV 8 +#define VIDEO_PALETTE_UYVY 9 /* The great thing about standards is ... */ +#define VIDEO_PALETTE_YUV420 10 +#define VIDEO_PALETTE_YUV411 11 /* YUV411 capture */ +#define VIDEO_PALETTE_RAW 12 /* RAW capture (BT848) */ +#define VIDEO_PALETTE_YUV422P 13 /* YUV 4:2:2 Planar */ +#define VIDEO_PALETTE_YUV411P 14 /* YUV 4:1:1 Planar */ +#define VIDEO_PALETTE_YUV420P 15 /* YUV 4:2:0 Planar */ +#define VIDEO_PALETTE_YUV410P 16 /* YUV 4:1:0 Planar */ +#define VIDEO_PALETTE_PLANAR 13 /* start of planar entries */ +#define VIDEO_PALETTE_COMPONENT 7 /* start of component entries */ +}; + +struct video_audio +{ + int audio; /* Audio channel */ + __u16 volume; /* If settable */ + __u16 bass, treble; + __u32 flags; +#define VIDEO_AUDIO_MUTE 1 +#define VIDEO_AUDIO_MUTABLE 2 +#define VIDEO_AUDIO_VOLUME 4 +#define VIDEO_AUDIO_BASS 8 +#define VIDEO_AUDIO_TREBLE 16 +#define VIDEO_AUDIO_BALANCE 32 + char name[16]; +#define VIDEO_SOUND_MONO 1 +#define VIDEO_SOUND_STEREO 2 +#define VIDEO_SOUND_LANG1 4 +#define VIDEO_SOUND_LANG2 8 + __u16 mode; + __u16 balance; /* Stereo balance */ + __u16 step; /* Step actual volume uses */ +}; + +struct video_clip +{ + __s32 x,y; + __s32 width, height; + struct video_clip *next; /* For user use/driver use only */ +}; + +struct video_window +{ + __u32 x,y; /* Position of window */ + __u32 width,height; /* Its size */ + __u32 chromakey; + __u32 flags; + struct video_clip *clips; /* Set only */ + int clipcount; +#define VIDEO_WINDOW_INTERLACE 1 +#define VIDEO_WINDOW_CHROMAKEY 16 /* Overlay by chromakey */ +#define VIDEO_CLIP_BITMAP -1 +/* bitmap is 1024x625, a '1' bit represents a clipped pixel */ +#define VIDEO_CLIPMAP_SIZE (128 * 625) +}; + +struct video_capture +{ + __u32 x,y; /* Offsets into image */ + __u32 width, height; /* Area to capture */ + __u16 decimation; /* Decimation divider */ + __u16 flags; /* Flags for capture */ +#define VIDEO_CAPTURE_ODD 0 /* Temporal */ +#define VIDEO_CAPTURE_EVEN 1 +}; + +struct video_buffer +{ + void *base; + int height,width; + int depth; + int bytesperline; +}; + +struct video_mmap +{ + unsigned int frame; /* Frame (0 - n) for double buffer */ + int height,width; + unsigned int format; /* should be VIDEO_PALETTE_* */ +}; + +struct video_key +{ + __u8 key[8]; + __u32 flags; +}; + + +#define VIDEO_MAX_FRAME 32 + +struct video_mbuf +{ + int size; /* Total memory to map */ + int frames; /* Frames */ + int offsets[VIDEO_MAX_FRAME]; +}; + + +#define VIDEO_NO_UNIT (-1) + + +struct video_unit +{ + int video; /* Video minor */ + int vbi; /* VBI minor */ + int radio; /* Radio minor */ + int audio; /* Audio minor */ + int teletext; /* Teletext minor */ +}; + +struct vbi_format { + __u32 sampling_rate; /* in Hz */ + __u32 samples_per_line; + __u32 sample_format; /* VIDEO_PALETTE_RAW only (1 byte) */ + __s32 start[2]; /* starting line for each frame */ + __u32 count[2]; /* count of lines for each frame */ + __u32 flags; +#define VBI_UNSYNC 1 /* can distingues between top/bottom field */ +#define VBI_INTERLACED 2 /* lines are interlaced */ +}; + +/* video_info is biased towards hardware mpeg encode/decode */ +/* but it could apply generically to any hardware compressor/decompressor */ +struct video_info +{ + __u32 frame_count; /* frames output since decode/encode began */ + __u32 h_size; /* current unscaled horizontal size */ + __u32 v_size; /* current unscaled veritcal size */ + __u32 smpte_timecode; /* current SMPTE timecode (for current GOP) */ + __u32 picture_type; /* current picture type */ + __u32 temporal_reference; /* current temporal reference */ + __u8 user_data[256]; /* user data last found in compressed stream */ + /* user_data[0] contains user data flags, user_data[1] has count */ +}; + +/* generic structure for setting playback modes */ +struct video_play_mode +{ + int mode; + int p1; + int p2; +}; + +/* for loading microcode / fpga programming */ +struct video_code +{ + char loadwhat[16]; /* name or tag of file being passed */ + int datasize; + __u8 *data; +}; + +#define VIDIOCGCAP _IOR('v',1,struct video_capability) /* Get capabilities */ +#define VIDIOCGCHAN _IOWR('v',2,struct video_channel) /* Get channel info (sources) */ +#define VIDIOCSCHAN _IOW('v',3,struct video_channel) /* Set channel */ +#define VIDIOCGTUNER _IOWR('v',4,struct video_tuner) /* Get tuner abilities */ +#define VIDIOCSTUNER _IOW('v',5,struct video_tuner) /* Tune the tuner for the current channel */ +#define VIDIOCGPICT _IOR('v',6,struct video_picture) /* Get picture properties */ +#define VIDIOCSPICT _IOW('v',7,struct video_picture) /* Set picture properties */ +#define VIDIOCCAPTURE _IOW('v',8,int) /* Start, end capture */ +#define VIDIOCGWIN _IOR('v',9, struct video_window) /* Get the video overlay window */ +#define VIDIOCSWIN _IOW('v',10, struct video_window) /* Set the video overlay window - passes clip list for hardware smarts , chromakey etc */ +#define VIDIOCGFBUF _IOR('v',11, struct video_buffer) /* Get frame buffer */ +#define VIDIOCSFBUF _IOW('v',12, struct video_buffer) /* Set frame buffer - root only */ +#define VIDIOCKEY _IOR('v',13, struct video_key) /* Video key event - to dev 255 is to all - cuts capture on all DMA windows with this key (0xFFFFFFFF == all) */ +#define VIDIOCGFREQ _IOR('v',14, unsigned long) /* Set tuner */ +#define VIDIOCSFREQ _IOW('v',15, unsigned long) /* Set tuner */ +#define VIDIOCGAUDIO _IOR('v',16, struct video_audio) /* Get audio info */ +#define VIDIOCSAUDIO _IOW('v',17, struct video_audio) /* Audio source, mute etc */ +#define VIDIOCSYNC _IOW('v',18, int) /* Sync with mmap grabbing */ +#define VIDIOCMCAPTURE _IOW('v',19, struct video_mmap) /* Grab frames */ +#define VIDIOCGMBUF _IOR('v',20, struct video_mbuf) /* Memory map buffer info */ +#define VIDIOCGUNIT _IOR('v',21, struct video_unit) /* Get attached units */ +#define VIDIOCGCAPTURE _IOR('v',22, struct video_capture) /* Get subcapture */ +#define VIDIOCSCAPTURE _IOW('v',23, struct video_capture) /* Set subcapture */ +#define VIDIOCSPLAYMODE _IOW('v',24, struct video_play_mode) /* Set output video mode/feature */ +#define VIDIOCSWRITEMODE _IOW('v',25, int) /* Set write mode */ +#define VIDIOCGPLAYINFO _IOR('v',26, struct video_info) /* Get current playback info from hardware */ +#define VIDIOCSMICROCODE _IOW('v',27, struct video_code) /* Load microcode into hardware */ +#define VIDIOCGVBIFMT _IOR('v',28, struct vbi_format) /* Get VBI information */ +#define VIDIOCSVBIFMT _IOW('v',29, struct vbi_format) /* Set VBI information */ + + +#define BASE_VIDIOCPRIVATE 192 /* 192-255 are private */ + +/* VIDIOCSWRITEMODE */ +#define VID_WRITE_MPEG_AUD 0 +#define VID_WRITE_MPEG_VID 1 +#define VID_WRITE_OSD 2 +#define VID_WRITE_TTX 3 +#define VID_WRITE_CC 4 +#define VID_WRITE_MJPEG 5 + +/* VIDIOCSPLAYMODE */ +#define VID_PLAY_VID_OUT_MODE 0 + /* p1: = VIDEO_MODE_PAL, VIDEO_MODE_NTSC, etc ... */ +#define VID_PLAY_GENLOCK 1 + /* p1: 0 = OFF, 1 = ON */ + /* p2: GENLOCK FINE DELAY value */ +#define VID_PLAY_NORMAL 2 +#define VID_PLAY_PAUSE 3 +#define VID_PLAY_SINGLE_FRAME 4 +#define VID_PLAY_FAST_FORWARD 5 +#define VID_PLAY_SLOW_MOTION 6 +#define VID_PLAY_IMMEDIATE_NORMAL 7 +#define VID_PLAY_SWITCH_CHANNELS 8 +#define VID_PLAY_FREEZE_FRAME 9 +#define VID_PLAY_STILL_MODE 10 +#define VID_PLAY_MASTER_MODE 11 + /* p1: see below */ +#define VID_PLAY_MASTER_NONE 1 +#define VID_PLAY_MASTER_VIDEO 2 +#define VID_PLAY_MASTER_AUDIO 3 +#define VID_PLAY_ACTIVE_SCANLINES 12 + /* p1 = first active; p2 = last active */ +#define VID_PLAY_RESET 13 +#define VID_PLAY_END_MARK 14 + + + +#define VID_HARDWARE_BT848 1 +#define VID_HARDWARE_QCAM_BW 2 +#define VID_HARDWARE_PMS 3 +#define VID_HARDWARE_QCAM_C 4 +#define VID_HARDWARE_PSEUDO 5 +#define VID_HARDWARE_SAA5249 6 +#define VID_HARDWARE_AZTECH 7 +#define VID_HARDWARE_SF16MI 8 +#define VID_HARDWARE_RTRACK 9 +#define VID_HARDWARE_ZOLTRIX 10 +#define VID_HARDWARE_SAA7146 11 +#define VID_HARDWARE_VIDEUM 12 /* Reserved for Winnov videum */ +#define VID_HARDWARE_RTRACK2 13 +#define VID_HARDWARE_PERMEDIA2 14 /* Reserved for Permedia2 */ +#define VID_HARDWARE_RIVA128 15 /* Reserved for RIVA 128 */ +#define VID_HARDWARE_PLANB 16 /* PowerMac motherboard video-in */ +#define VID_HARDWARE_BROADWAY 17 /* Broadway project */ +#define VID_HARDWARE_GEMTEK 18 +#define VID_HARDWARE_TYPHOON 19 +#define VID_HARDWARE_VINO 20 /* SGI Indy Vino */ +#define VID_HARDWARE_CADET 21 /* Cadet radio */ +#define VID_HARDWARE_TRUST 22 /* Trust FM Radio */ +#define VID_HARDWARE_TERRATEC 23 /* TerraTec ActiveRadio */ +#define VID_HARDWARE_CPIA 24 +#define VID_HARDWARE_ZR36120 25 /* Zoran ZR36120/ZR36125 */ +#define VID_HARDWARE_ZR36067 26 /* Zoran ZR36067/36060 */ +#define VID_HARDWARE_OV511 27 +#define VID_HARDWARE_ZR356700 28 /* Zoran 36700 series */ +#define VID_HARDWARE_W9966 29 +#define VID_HARDWARE_SE401 30 /* SE401 USB webcams */ +#define VID_HARDWARE_PWC 31 /* Philips webcams */ +#define VID_HARDWARE_MEYE 32 /* Sony Vaio MotionEye cameras */ +#define VID_HARDWARE_CPIA2 33 +#define VID_HARDWARE_VICAM 34 +#define VID_HARDWARE_SF16FMR2 35 +#endif /* __LINUX_VIDEODEV_H */ + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ diff --git a/kradio3/plugins/v4lradio/linux/videodev2.h b/kradio3/plugins/v4lradio/linux/videodev2.h new file mode 100644 index 0000000..c41831a --- /dev/null +++ b/kradio3/plugins/v4lradio/linux/videodev2.h @@ -0,0 +1,940 @@ +#ifndef __LINUX_VIDEODEV2_H +#define __LINUX_VIDEODEV2_H +/* + * Video for Linux Two + * + * Header file for v4l or V4L2 drivers and applications, for + * Linux kernels 2.2.x or 2.4.x. + * + * See http://bytesex.org/v4l/ for API specs and other + * v4l2 documentation. + * + * Author: Bill Dirks <bdirks@pacbell.net> + * Justin Schoeman + * et al. + */ + +#include <asm/types.h> +#ifdef __KERNEL__ +#include <linux/time.h> /* need struct timeval */ +#endif + +/* + * M I S C E L L A N E O U S + */ + +/* Four-character-code (FOURCC) */ +#define v4l2_fourcc(a,b,c,d)\ + (((__u32)(a)<<0)|((__u32)(b)<<8)|((__u32)(c)<<16)|((__u32)(d)<<24)) + +/* + * E N U M S + */ +enum v4l2_field { + V4L2_FIELD_ANY = 0, /* driver can choose from none, + top, bottom, interlaced + depending on whatever it thinks + is approximate ... */ + V4L2_FIELD_NONE = 1, /* this device has no fields ... */ + V4L2_FIELD_TOP = 2, /* top field only */ + V4L2_FIELD_BOTTOM = 3, /* bottom field only */ + V4L2_FIELD_INTERLACED = 4, /* both fields interlaced */ + V4L2_FIELD_SEQ_TB = 5, /* both fields sequential into one + buffer, top-bottom order */ + V4L2_FIELD_SEQ_BT = 6, /* same as above + bottom-top order */ + V4L2_FIELD_ALTERNATE = 7 /* both fields alternating into + separate buffers */ +}; +#define V4L2_FIELD_HAS_TOP(field) \ + ((field) == V4L2_FIELD_TOP ||\ + (field) == V4L2_FIELD_INTERLACED ||\ + (field) == V4L2_FIELD_SEQ_TB ||\ + (field) == V4L2_FIELD_SEQ_BT) +#define V4L2_FIELD_HAS_BOTTOM(field) \ + ((field) == V4L2_FIELD_BOTTOM ||\ + (field) == V4L2_FIELD_INTERLACED ||\ + (field) == V4L2_FIELD_SEQ_TB ||\ + (field) == V4L2_FIELD_SEQ_BT) +#define V4L2_FIELD_HAS_BOTH(field) \ + ((field) == V4L2_FIELD_INTERLACED ||\ + (field) == V4L2_FIELD_SEQ_TB ||\ + (field) == V4L2_FIELD_SEQ_BT) + +enum v4l2_buf_type { + V4L2_BUF_TYPE_VIDEO_CAPTURE = 1, + V4L2_BUF_TYPE_VIDEO_OUTPUT = 2, + V4L2_BUF_TYPE_VIDEO_OVERLAY = 3, + V4L2_BUF_TYPE_VBI_CAPTURE = 4, + V4L2_BUF_TYPE_VBI_OUTPUT = 5, + V4L2_BUF_TYPE_PRIVATE = 0x80 +}; + +enum v4l2_ctrl_type { + V4L2_CTRL_TYPE_INTEGER = 1, + V4L2_CTRL_TYPE_BOOLEAN = 2, + V4L2_CTRL_TYPE_MENU = 3, + V4L2_CTRL_TYPE_BUTTON = 4 +}; + +enum v4l2_tuner_type { + V4L2_TUNER_RADIO = 1, + V4L2_TUNER_ANALOG_TV = 2 +}; + +enum v4l2_memory { + V4L2_MEMORY_MMAP = 1, + V4L2_MEMORY_USERPTR = 2, + V4L2_MEMORY_OVERLAY = 3 +}; + +/* see also http://vektor.theorem.ca/graphics/ycbcr/ */ +enum v4l2_colorspace { + /* ITU-R 601 -- broadcast NTSC/PAL */ + V4L2_COLORSPACE_SMPTE170M = 1, + + /* 1125-Line (US) HDTV */ + V4L2_COLORSPACE_SMPTE240M = 2, + + /* HD and modern captures. */ + V4L2_COLORSPACE_REC709 = 3, + + /* broken BT878 extents (601, luma range 16-253 instead of 16-235) */ + V4L2_COLORSPACE_BT878 = 4, + + /* These should be useful. Assume 601 extents. */ + V4L2_COLORSPACE_470_SYSTEM_M = 5, + V4L2_COLORSPACE_470_SYSTEM_BG = 6, + + /* I know there will be cameras that send this. So, this is + * unspecified chromaticities and full 0-255 on each of the + * Y'CbCr components + */ + V4L2_COLORSPACE_JPEG = 7, + + /* For RGB colourspaces, this is probably a good start. */ + V4L2_COLORSPACE_SRGB = 8 +}; + +enum v4l2_priority { + V4L2_PRIORITY_UNSET = 0, /* not initialized */ + V4L2_PRIORITY_BACKGROUND = 1, + V4L2_PRIORITY_INTERACTIVE = 2, + V4L2_PRIORITY_RECORD = 3, + V4L2_PRIORITY_DEFAULT = V4L2_PRIORITY_INTERACTIVE +}; + +struct v4l2_rect { + __s32 left; + __s32 top; + __s32 width; + __s32 height; +}; + +struct v4l2_fract { + __u32 numerator; + __u32 denominator; +}; + +/* + * D R I V E R C A P A B I L I T I E S + */ +struct v4l2_capability +{ + __u8 driver[16]; /* i.e. "bttv" */ + __u8 card[32]; /* i.e. "Hauppauge WinTV" */ + __u8 bus_info[32]; /* "PCI:" + pci_name(pci_dev) */ + __u32 version; /* should use KERNEL_VERSION() */ + __u32 capabilities; /* Device capabilities */ + __u32 reserved[4]; +}; + +/* Values for 'capabilities' field */ +#define V4L2_CAP_VIDEO_CAPTURE 0x00000001 /* Is a video capture device */ +#define V4L2_CAP_VIDEO_OUTPUT 0x00000002 /* Is a video output device */ +#define V4L2_CAP_VIDEO_OVERLAY 0x00000004 /* Can do video overlay */ +#define V4L2_CAP_VBI_CAPTURE 0x00000010 /* Is a VBI capture device */ +#define V4L2_CAP_VBI_OUTPUT 0x00000020 /* Is a VBI output device */ +#define V4L2_CAP_RDS_CAPTURE 0x00000100 /* RDS data capture */ + +#define V4L2_CAP_TUNER 0x00010000 /* has a tuner */ +#define V4L2_CAP_AUDIO 0x00020000 /* has audio support */ +#define V4L2_CAP_RADIO 0x00040000 /* is a radio device */ + +#define V4L2_CAP_READWRITE 0x01000000 /* read/write systemcalls */ +#define V4L2_CAP_ASYNCIO 0x02000000 /* async I/O */ +#define V4L2_CAP_STREAMING 0x04000000 /* streaming I/O ioctls */ + +/* + * V I D E O I M A G E F O R M A T + */ + +struct v4l2_pix_format +{ + __u32 width; + __u32 height; + __u32 pixelformat; + enum v4l2_field field; + __u32 bytesperline; /* for padding, zero if unused */ + __u32 sizeimage; + enum v4l2_colorspace colorspace; + __u32 priv; /* private data, depends on pixelformat */ +}; + +/* Pixel format FOURCC depth Description */ +#define V4L2_PIX_FMT_RGB332 v4l2_fourcc('R','G','B','1') /* 8 RGB-3-3-2 */ +#define V4L2_PIX_FMT_RGB555 v4l2_fourcc('R','G','B','O') /* 16 RGB-5-5-5 */ +#define V4L2_PIX_FMT_RGB565 v4l2_fourcc('R','G','B','P') /* 16 RGB-5-6-5 */ +#define V4L2_PIX_FMT_RGB555X v4l2_fourcc('R','G','B','Q') /* 16 RGB-5-5-5 BE */ +#define V4L2_PIX_FMT_RGB565X v4l2_fourcc('R','G','B','R') /* 16 RGB-5-6-5 BE */ +#define V4L2_PIX_FMT_BGR24 v4l2_fourcc('B','G','R','3') /* 24 BGR-8-8-8 */ +#define V4L2_PIX_FMT_RGB24 v4l2_fourcc('R','G','B','3') /* 24 RGB-8-8-8 */ +#define V4L2_PIX_FMT_BGR32 v4l2_fourcc('B','G','R','4') /* 32 BGR-8-8-8-8 */ +#define V4L2_PIX_FMT_RGB32 v4l2_fourcc('R','G','B','4') /* 32 RGB-8-8-8-8 */ +#define V4L2_PIX_FMT_GREY v4l2_fourcc('G','R','E','Y') /* 8 Greyscale */ +#define V4L2_PIX_FMT_YVU410 v4l2_fourcc('Y','V','U','9') /* 9 YVU 4:1:0 */ +#define V4L2_PIX_FMT_YVU420 v4l2_fourcc('Y','V','1','2') /* 12 YVU 4:2:0 */ +#define V4L2_PIX_FMT_YUYV v4l2_fourcc('Y','U','Y','V') /* 16 YUV 4:2:2 */ +#define V4L2_PIX_FMT_UYVY v4l2_fourcc('U','Y','V','Y') /* 16 YUV 4:2:2 */ +#define V4L2_PIX_FMT_YUV422P v4l2_fourcc('4','2','2','P') /* 16 YVU422 planar */ +#define V4L2_PIX_FMT_YUV411P v4l2_fourcc('4','1','1','P') /* 16 YVU411 planar */ +#define V4L2_PIX_FMT_Y41P v4l2_fourcc('Y','4','1','P') /* 12 YUV 4:1:1 */ + +/* two planes -- one Y, one Cr + Cb interleaved */ +#define V4L2_PIX_FMT_NV12 v4l2_fourcc('N','V','1','2') /* 12 Y/CbCr 4:2:0 */ +#define V4L2_PIX_FMT_NV21 v4l2_fourcc('N','V','2','1') /* 12 Y/CrCb 4:2:0 */ + +/* The following formats are not defined in the V4L2 specification */ +#define V4L2_PIX_FMT_YUV410 v4l2_fourcc('Y','U','V','9') /* 9 YUV 4:1:0 */ +#define V4L2_PIX_FMT_YUV420 v4l2_fourcc('Y','U','1','2') /* 12 YUV 4:2:0 */ +#define V4L2_PIX_FMT_YYUV v4l2_fourcc('Y','Y','U','V') /* 16 YUV 4:2:2 */ +#define V4L2_PIX_FMT_HI240 v4l2_fourcc('H','I','2','4') /* 8 8-bit color */ + +/* compressed formats */ +#define V4L2_PIX_FMT_MJPEG v4l2_fourcc('M','J','P','G') /* Motion-JPEG */ +#define V4L2_PIX_FMT_JPEG v4l2_fourcc('J','P','E','G') /* JFIF JPEG */ +#define V4L2_PIX_FMT_DV v4l2_fourcc('d','v','s','d') /* 1394 */ +#define V4L2_PIX_FMT_MPEG v4l2_fourcc('M','P','E','G') /* MPEG */ + +/* Vendor-specific formats */ +#define V4L2_PIX_FMT_WNVA v4l2_fourcc('W','N','V','A') /* Winnov hw compress */ + +/* + * F O R M A T E N U M E R A T I O N + */ +struct v4l2_fmtdesc +{ + __u32 index; /* Format number */ + enum v4l2_buf_type type; /* buffer type */ + __u32 flags; + __u8 description[32]; /* Description string */ + __u32 pixelformat; /* Format fourcc */ + __u32 reserved[4]; +}; + +#define V4L2_FMT_FLAG_COMPRESSED 0x0001 + + +/* + * T I M E C O D E + */ +struct v4l2_timecode +{ + __u32 type; + __u32 flags; + __u8 frames; + __u8 seconds; + __u8 minutes; + __u8 hours; + __u8 userbits[4]; +}; + +/* Type */ +#define V4L2_TC_TYPE_24FPS 1 +#define V4L2_TC_TYPE_25FPS 2 +#define V4L2_TC_TYPE_30FPS 3 +#define V4L2_TC_TYPE_50FPS 4 +#define V4L2_TC_TYPE_60FPS 5 + +/* Flags */ +#define V4L2_TC_FLAG_DROPFRAME 0x0001 /* "drop-frame" mode */ +#define V4L2_TC_FLAG_COLORFRAME 0x0002 +#define V4L2_TC_USERBITS_field 0x000C +#define V4L2_TC_USERBITS_USERDEFINED 0x0000 +#define V4L2_TC_USERBITS_8BITCHARS 0x0008 +/* The above is based on SMPTE timecodes */ + + +/* + * C O M P R E S S I O N P A R A M E T E R S + */ +#if 0 +/* ### generic compression settings don't work, there is too much + * ### codec-specific stuff. Maybe reuse that for MPEG codec settings + * ### later ... */ +struct v4l2_compression +{ + __u32 quality; + __u32 keyframerate; + __u32 pframerate; + __u32 reserved[5]; + +/* what we'll need for MPEG, extracted from some postings on + the v4l list (Gert Vervoort, PlasmaJohn). + +system stream: + - type: elementary stream(ES), packatised elementary stream(s) (PES) + program stream(PS), transport stream(TS) + - system bitrate + - PS packet size (DVD: 2048 bytes, VCD: 2324 bytes) + - TS video PID + - TS audio PID + - TS PCR PID + - TS system information tables (PAT, PMT, CAT, NIT and SIT) + - (MPEG-1 systems stream vs. MPEG-2 program stream (TS not supported + by MPEG-1 systems) + +audio: + - type: MPEG (+Layer I,II,III), AC-3, LPCM + - bitrate + - sampling frequency (DVD: 48 Khz, VCD: 44.1 KHz, 32 kHz) + - Trick Modes? (ff, rew) + - Copyright + - Inverse Telecine + +video: + - picturesize (SIF, 1/2 D1, 2/3 D1, D1) and PAL/NTSC norm can be set + through excisting V4L2 controls + - noise reduction, parameters encoder specific? + - MPEG video version: MPEG-1, MPEG-2 + - GOP (Group Of Pictures) definition: + - N: number of frames per GOP + - M: distance between reference (I,P) frames + - open/closed GOP + - quantiser matrix: inter Q matrix (64 bytes) and intra Q matrix (64 bytes) + - quantiser scale: linear or logarithmic + - scanning: alternate or zigzag + - bitrate mode: CBR (constant bitrate) or VBR (variable bitrate). + - target video bitrate for CBR + - target video bitrate for VBR + - maximum video bitrate for VBR - min. quantiser value for VBR + - max. quantiser value for VBR + - adaptive quantisation value + - return the number of bytes per GOP or bitrate for bitrate monitoring + +*/ +}; +#endif + +struct v4l2_jpegcompression +{ + int quality; + + int APPn; /* Number of APP segment to be written, + * must be 0..15 */ + int APP_len; /* Length of data in JPEG APPn segment */ + char APP_data[60]; /* Data in the JPEG APPn segment. */ + + int COM_len; /* Length of data in JPEG COM segment */ + char COM_data[60]; /* Data in JPEG COM segment */ + + __u32 jpeg_markers; /* Which markers should go into the JPEG + * output. Unless you exactly know what + * you do, leave them untouched. + * Inluding less markers will make the + * resulting code smaller, but there will + * be fewer aplications which can read it. + * The presence of the APP and COM marker + * is influenced by APP_len and COM_len + * ONLY, not by this property! */ + +#define V4L2_JPEG_MARKER_DHT (1<<3) /* Define Huffman Tables */ +#define V4L2_JPEG_MARKER_DQT (1<<4) /* Define Quantization Tables */ +#define V4L2_JPEG_MARKER_DRI (1<<5) /* Define Restart Interval */ +#define V4L2_JPEG_MARKER_COM (1<<6) /* Comment segment */ +#define V4L2_JPEG_MARKER_APP (1<<7) /* App segment, driver will + * allways use APP0 */ +}; + + +/* + * M E M O R Y - M A P P I N G B U F F E R S + */ +struct v4l2_requestbuffers +{ + __u32 count; + enum v4l2_buf_type type; + enum v4l2_memory memory; + __u32 reserved[2]; +}; + +struct v4l2_buffer +{ + __u32 index; + enum v4l2_buf_type type; + __u32 bytesused; + __u32 flags; + enum v4l2_field field; + struct timeval timestamp; + struct v4l2_timecode timecode; + __u32 sequence; + + /* memory location */ + enum v4l2_memory memory; + union { + __u32 offset; + unsigned long userptr; + } m; + __u32 length; + + __u32 reserved[2]; +}; + +/* Flags for 'flags' field */ +#define V4L2_BUF_FLAG_MAPPED 0x0001 /* Buffer is mapped (flag) */ +#define V4L2_BUF_FLAG_QUEUED 0x0002 /* Buffer is queued for processing */ +#define V4L2_BUF_FLAG_DONE 0x0004 /* Buffer is ready */ +#define V4L2_BUF_FLAG_KEYFRAME 0x0008 /* Image is a keyframe (I-frame) */ +#define V4L2_BUF_FLAG_PFRAME 0x0010 /* Image is a P-frame */ +#define V4L2_BUF_FLAG_BFRAME 0x0020 /* Image is a B-frame */ +#define V4L2_BUF_FLAG_TIMECODE 0x0100 /* timecode field is valid */ + +/* + * O V E R L A Y P R E V I E W + */ +struct v4l2_framebuffer +{ + __u32 capability; + __u32 flags; +/* FIXME: in theory we should pass something like PCI device + memory + * region + offset instead of some physical address */ + void* base; + struct v4l2_pix_format fmt; +}; +/* Flags for the 'capability' field. Read only */ +#define V4L2_FBUF_CAP_EXTERNOVERLAY 0x0001 +#define V4L2_FBUF_CAP_CHROMAKEY 0x0002 +#define V4L2_FBUF_CAP_LIST_CLIPPING 0x0004 +#define V4L2_FBUF_CAP_BITMAP_CLIPPING 0x0008 +/* Flags for the 'flags' field. */ +#define V4L2_FBUF_FLAG_PRIMARY 0x0001 +#define V4L2_FBUF_FLAG_OVERLAY 0x0002 +#define V4L2_FBUF_FLAG_CHROMAKEY 0x0004 + +struct v4l2_clip +{ + struct v4l2_rect c; + struct v4l2_clip *next; +}; + +struct v4l2_window +{ + struct v4l2_rect w; + enum v4l2_field field; + __u32 chromakey; + struct v4l2_clip *clips; + __u32 clipcount; + void *bitmap; +}; + + +/* + * C A P T U R E P A R A M E T E R S + */ +struct v4l2_captureparm +{ + __u32 capability; /* Supported modes */ + __u32 capturemode; /* Current mode */ + struct v4l2_fract timeperframe; /* Time per frame in .1us units */ + __u32 extendedmode; /* Driver-specific extensions */ + __u32 readbuffers; /* # of buffers for read */ + __u32 reserved[4]; +}; +/* Flags for 'capability' and 'capturemode' fields */ +#define V4L2_MODE_HIGHQUALITY 0x0001 /* High quality imaging mode */ +#define V4L2_CAP_TIMEPERFRAME 0x1000 /* timeperframe field is supported */ + +struct v4l2_outputparm +{ + __u32 capability; /* Supported modes */ + __u32 outputmode; /* Current mode */ + struct v4l2_fract timeperframe; /* Time per frame in seconds */ + __u32 extendedmode; /* Driver-specific extensions */ + __u32 writebuffers; /* # of buffers for write */ + __u32 reserved[4]; +}; + +/* + * I N P U T I M A G E C R O P P I N G + */ + +struct v4l2_cropcap { + enum v4l2_buf_type type; + struct v4l2_rect bounds; + struct v4l2_rect defrect; + struct v4l2_fract pixelaspect; +}; + +struct v4l2_crop { + enum v4l2_buf_type type; + struct v4l2_rect c; +}; + +/* + * A N A L O G V I D E O S T A N D A R D + */ + +typedef unsigned long long v4l2_std_id; + +/* one bit for each */ +#define V4L2_STD_PAL_B ((v4l2_std_id)0x00000001) +#define V4L2_STD_PAL_B1 ((v4l2_std_id)0x00000002) +#define V4L2_STD_PAL_G ((v4l2_std_id)0x00000004) +#define V4L2_STD_PAL_H ((v4l2_std_id)0x00000008) +#define V4L2_STD_PAL_I ((v4l2_std_id)0x00000010) +#define V4L2_STD_PAL_D ((v4l2_std_id)0x00000020) +#define V4L2_STD_PAL_D1 ((v4l2_std_id)0x00000040) +#define V4L2_STD_PAL_K ((v4l2_std_id)0x00000080) + +#define V4L2_STD_PAL_M ((v4l2_std_id)0x00000100) +#define V4L2_STD_PAL_N ((v4l2_std_id)0x00000200) +#define V4L2_STD_PAL_Nc ((v4l2_std_id)0x00000400) +#define V4L2_STD_PAL_60 ((v4l2_std_id)0x00000800) + +#define V4L2_STD_NTSC_M ((v4l2_std_id)0x00001000) +#define V4L2_STD_NTSC_M_JP ((v4l2_std_id)0x00002000) + +#define V4L2_STD_SECAM_B ((v4l2_std_id)0x00010000) +#define V4L2_STD_SECAM_D ((v4l2_std_id)0x00020000) +#define V4L2_STD_SECAM_G ((v4l2_std_id)0x00040000) +#define V4L2_STD_SECAM_H ((v4l2_std_id)0x00080000) +#define V4L2_STD_SECAM_K ((v4l2_std_id)0x00100000) +#define V4L2_STD_SECAM_K1 ((v4l2_std_id)0x00200000) +#define V4L2_STD_SECAM_L ((v4l2_std_id)0x00400000) + +/* ATSC/HDTV */ +#define V4L2_STD_ATSC_8_VSB ((v4l2_std_id)0x01000000) +#define V4L2_STD_ATSC_16_VSB ((v4l2_std_id)0x02000000) + +/* some common needed stuff */ +#define V4L2_STD_PAL_BG (V4L2_STD_PAL_B |\ + V4L2_STD_PAL_B1 |\ + V4L2_STD_PAL_G) +#define V4L2_STD_PAL_DK (V4L2_STD_PAL_D |\ + V4L2_STD_PAL_D1 |\ + V4L2_STD_PAL_K) +#define V4L2_STD_PAL (V4L2_STD_PAL_BG |\ + V4L2_STD_PAL_DK |\ + V4L2_STD_PAL_H |\ + V4L2_STD_PAL_I) +#define V4L2_STD_NTSC (V4L2_STD_NTSC_M |\ + V4L2_STD_NTSC_M_JP) +#define V4L2_STD_SECAM (V4L2_STD_SECAM_B |\ + V4L2_STD_SECAM_D |\ + V4L2_STD_SECAM_G |\ + V4L2_STD_SECAM_H |\ + V4L2_STD_SECAM_K |\ + V4L2_STD_SECAM_K1 |\ + V4L2_STD_SECAM_L) + +#define V4L2_STD_525_60 (V4L2_STD_PAL_M |\ + V4L2_STD_PAL_60 |\ + V4L2_STD_NTSC) +#define V4L2_STD_625_50 (V4L2_STD_PAL |\ + V4L2_STD_PAL_N |\ + V4L2_STD_PAL_Nc |\ + V4L2_STD_SECAM) + +#define V4L2_STD_UNKNOWN 0 +#define V4L2_STD_ALL (V4L2_STD_525_60 |\ + V4L2_STD_625_50) + +struct v4l2_standard +{ + __u32 index; + v4l2_std_id id; + __u8 name[24]; + struct v4l2_fract frameperiod; /* Frames, not fields */ + __u32 framelines; + __u32 reserved[4]; +}; + + +/* + * V I D E O I N P U T S + */ +struct v4l2_input +{ + __u32 index; /* Which input */ + __u8 name[32]; /* Label */ + __u32 type; /* Type of input */ + __u32 audioset; /* Associated audios (bitfield) */ + __u32 tuner; /* Associated tuner */ + v4l2_std_id std; + __u32 status; + __u32 reserved[4]; +}; +/* Values for the 'type' field */ +#define V4L2_INPUT_TYPE_TUNER 1 +#define V4L2_INPUT_TYPE_CAMERA 2 + +/* field 'status' - general */ +#define V4L2_IN_ST_NO_POWER 0x00000001 /* Attached device is off */ +#define V4L2_IN_ST_NO_SIGNAL 0x00000002 +#define V4L2_IN_ST_NO_COLOR 0x00000004 + +/* field 'status' - analog */ +#define V4L2_IN_ST_NO_H_LOCK 0x00000100 /* No horizontal sync lock */ +#define V4L2_IN_ST_COLOR_KILL 0x00000200 /* Color killer is active */ + +/* field 'status' - digital */ +#define V4L2_IN_ST_NO_SYNC 0x00010000 /* No synchronization lock */ +#define V4L2_IN_ST_NO_EQU 0x00020000 /* No equalizer lock */ +#define V4L2_IN_ST_NO_CARRIER 0x00040000 /* Carrier recovery failed */ + +/* field 'status' - VCR and set-top box */ +#define V4L2_IN_ST_MACROVISION 0x01000000 /* Macrovision detected */ +#define V4L2_IN_ST_NO_ACCESS 0x02000000 /* Conditional access denied */ +#define V4L2_IN_ST_VTR 0x04000000 /* VTR time constant */ + +/* + * V I D E O O U T P U T S + */ +struct v4l2_output +{ + __u32 index; /* Which output */ + __u8 name[32]; /* Label */ + __u32 type; /* Type of output */ + __u32 audioset; /* Associated audios (bitfield) */ + __u32 modulator; /* Associated modulator */ + v4l2_std_id std; + __u32 reserved[4]; +}; +/* Values for the 'type' field */ +#define V4L2_OUTPUT_TYPE_MODULATOR 1 +#define V4L2_OUTPUT_TYPE_ANALOG 2 +#define V4L2_OUTPUT_TYPE_ANALOGVGAOVERLAY 3 + +/* + * C O N T R O L S + */ +struct v4l2_control +{ + __u32 id; + __s32 value; +}; + +/* Used in the VIDIOC_QUERYCTRL ioctl for querying controls */ +struct v4l2_queryctrl +{ + __u32 id; + enum v4l2_ctrl_type type; + __u8 name[32]; /* Whatever */ + __s32 minimum; /* Note signedness */ + __s32 maximum; + __s32 step; + __s32 default_value; + __u32 flags; + __u32 reserved[2]; +}; + +/* Used in the VIDIOC_QUERYMENU ioctl for querying menu items */ +struct v4l2_querymenu +{ + __u32 id; + __u32 index; + __u8 name[32]; /* Whatever */ + __u32 reserved; +}; + +/* Control flags */ +#define V4L2_CTRL_FLAG_DISABLED 0x0001 +#define V4L2_CTRL_FLAG_GRABBED 0x0002 + +/* Control IDs defined by V4L2 */ +#define V4L2_CID_BASE 0x00980900 +/* IDs reserved for driver specific controls */ +#define V4L2_CID_PRIVATE_BASE 0x08000000 + +#define V4L2_CID_BRIGHTNESS (V4L2_CID_BASE+0) +#define V4L2_CID_CONTRAST (V4L2_CID_BASE+1) +#define V4L2_CID_SATURATION (V4L2_CID_BASE+2) +#define V4L2_CID_HUE (V4L2_CID_BASE+3) +#define V4L2_CID_AUDIO_VOLUME (V4L2_CID_BASE+5) +#define V4L2_CID_AUDIO_BALANCE (V4L2_CID_BASE+6) +#define V4L2_CID_AUDIO_BASS (V4L2_CID_BASE+7) +#define V4L2_CID_AUDIO_TREBLE (V4L2_CID_BASE+8) +#define V4L2_CID_AUDIO_MUTE (V4L2_CID_BASE+9) +#define V4L2_CID_AUDIO_LOUDNESS (V4L2_CID_BASE+10) +#define V4L2_CID_BLACK_LEVEL (V4L2_CID_BASE+11) +#define V4L2_CID_AUTO_WHITE_BALANCE (V4L2_CID_BASE+12) +#define V4L2_CID_DO_WHITE_BALANCE (V4L2_CID_BASE+13) +#define V4L2_CID_RED_BALANCE (V4L2_CID_BASE+14) +#define V4L2_CID_BLUE_BALANCE (V4L2_CID_BASE+15) +#define V4L2_CID_GAMMA (V4L2_CID_BASE+16) +#define V4L2_CID_WHITENESS (V4L2_CID_GAMMA) /* ? Not sure */ +#define V4L2_CID_EXPOSURE (V4L2_CID_BASE+17) +#define V4L2_CID_AUTOGAIN (V4L2_CID_BASE+18) +#define V4L2_CID_GAIN (V4L2_CID_BASE+19) +#define V4L2_CID_HFLIP (V4L2_CID_BASE+20) +#define V4L2_CID_VFLIP (V4L2_CID_BASE+21) +#define V4L2_CID_HCENTER (V4L2_CID_BASE+22) +#define V4L2_CID_VCENTER (V4L2_CID_BASE+23) +#define V4L2_CID_LASTP1 (V4L2_CID_BASE+24) /* last CID + 1 */ + +/* + * T U N I N G + */ +struct v4l2_tuner +{ + __u32 index; + __u8 name[32]; + enum v4l2_tuner_type type; + __u32 capability; + __u32 rangelow; + __u32 rangehigh; + __u32 rxsubchans; + __u32 audmode; + __s32 signal; + __s32 afc; + __u32 reserved[4]; +}; + +struct v4l2_modulator +{ + __u32 index; + __u8 name[32]; + __u32 capability; + __u32 rangelow; + __u32 rangehigh; + __u32 txsubchans; + __u32 reserved[4]; +}; + +/* Flags for the 'capability' field */ +#define V4L2_TUNER_CAP_LOW 0x0001 +#define V4L2_TUNER_CAP_NORM 0x0002 +#define V4L2_TUNER_CAP_STEREO 0x0010 +#define V4L2_TUNER_CAP_LANG2 0x0020 +#define V4L2_TUNER_CAP_SAP 0x0020 +#define V4L2_TUNER_CAP_LANG1 0x0040 + +/* Flags for the 'rxsubchans' field */ +#define V4L2_TUNER_SUB_MONO 0x0001 +#define V4L2_TUNER_SUB_STEREO 0x0002 +#define V4L2_TUNER_SUB_LANG2 0x0004 +#define V4L2_TUNER_SUB_SAP 0x0004 +#define V4L2_TUNER_SUB_LANG1 0x0008 + +/* Values for the 'audmode' field */ +#define V4L2_TUNER_MODE_MONO 0x0000 +#define V4L2_TUNER_MODE_STEREO 0x0001 +#define V4L2_TUNER_MODE_LANG2 0x0002 +#define V4L2_TUNER_MODE_SAP 0x0002 +#define V4L2_TUNER_MODE_LANG1 0x0003 + +struct v4l2_frequency +{ + __u32 tuner; + enum v4l2_tuner_type type; + __u32 frequency; + __u32 reserved[8]; +}; + +/* + * A U D I O + */ +struct v4l2_audio +{ + __u32 index; + __u8 name[32]; + __u32 capability; + __u32 mode; + __u32 reserved[2]; +}; +/* Flags for the 'capability' field */ +#define V4L2_AUDCAP_STEREO 0x00001 +#define V4L2_AUDCAP_AVL 0x00002 + +/* Flags for the 'mode' field */ +#define V4L2_AUDMODE_AVL 0x00001 + +struct v4l2_audioout +{ + __u32 index; + __u8 name[32]; + __u32 capability; + __u32 mode; + __u32 reserved[2]; +}; + +/* + * D A T A S E R V I C E S ( V B I ) + * + * Data services API by Michael Schimek + */ + +struct v4l2_vbi_format +{ + __u32 sampling_rate; /* in 1 Hz */ + __u32 offset; + __u32 samples_per_line; + __u32 sample_format; /* V4L2_PIX_FMT_* */ + __s32 start[2]; + __u32 count[2]; + __u32 flags; /* V4L2_VBI_* */ + __u32 reserved[2]; /* must be zero */ +}; + +/* VBI flags */ +#define V4L2_VBI_UNSYNC (1<< 0) +#define V4L2_VBI_INTERLACED (1<< 1) + + +/* + * A G G R E G A T E S T R U C T U R E S + */ + +/* Stream data format + */ +struct v4l2_format +{ + enum v4l2_buf_type type; + union + { + struct v4l2_pix_format pix; // V4L2_BUF_TYPE_VIDEO_CAPTURE + struct v4l2_window win; // V4L2_BUF_TYPE_VIDEO_OVERLAY + struct v4l2_vbi_format vbi; // V4L2_BUF_TYPE_VBI_CAPTURE + __u8 raw_data[200]; // user-defined + } fmt; +}; + + +/* Stream type-dependent parameters + */ +struct v4l2_streamparm +{ + enum v4l2_buf_type type; + union + { + struct v4l2_captureparm capture; + struct v4l2_outputparm output; + __u8 raw_data[200]; /* user-defined */ + } parm; +}; + + + +/* + * I O C T L C O D E S F O R V I D E O D E V I C E S + * + */ +#define VIDIOC_QUERYCAP _IOR ('V', 0, struct v4l2_capability) +#define VIDIOC_RESERVED _IO ('V', 1) +#define VIDIOC_ENUM_FMT _IOWR ('V', 2, struct v4l2_fmtdesc) +#define VIDIOC_G_FMT _IOWR ('V', 4, struct v4l2_format) +#define VIDIOC_S_FMT _IOWR ('V', 5, struct v4l2_format) +#if 0 +#define VIDIOC_G_COMP _IOR ('V', 6, struct v4l2_compression) +#define VIDIOC_S_COMP _IOW ('V', 7, struct v4l2_compression) +#endif +#define VIDIOC_REQBUFS _IOWR ('V', 8, struct v4l2_requestbuffers) +#define VIDIOC_QUERYBUF _IOWR ('V', 9, struct v4l2_buffer) +#define VIDIOC_G_FBUF _IOR ('V', 10, struct v4l2_framebuffer) +#define VIDIOC_S_FBUF _IOW ('V', 11, struct v4l2_framebuffer) +#define VIDIOC_OVERLAY _IOW ('V', 14, int) +#define VIDIOC_QBUF _IOWR ('V', 15, struct v4l2_buffer) +#define VIDIOC_DQBUF _IOWR ('V', 17, struct v4l2_buffer) +#define VIDIOC_STREAMON _IOW ('V', 18, int) +#define VIDIOC_STREAMOFF _IOW ('V', 19, int) +#define VIDIOC_G_PARM _IOWR ('V', 21, struct v4l2_streamparm) +#define VIDIOC_S_PARM _IOWR ('V', 22, struct v4l2_streamparm) +#define VIDIOC_G_STD _IOR ('V', 23, v4l2_std_id) +#define VIDIOC_S_STD _IOW ('V', 24, v4l2_std_id) +#define VIDIOC_ENUMSTD _IOWR ('V', 25, struct v4l2_standard) +#define VIDIOC_ENUMINPUT _IOWR ('V', 26, struct v4l2_input) +#define VIDIOC_G_CTRL _IOWR ('V', 27, struct v4l2_control) +#define VIDIOC_S_CTRL _IOWR ('V', 28, struct v4l2_control) +#define VIDIOC_G_TUNER _IOWR ('V', 29, struct v4l2_tuner) +#define VIDIOC_S_TUNER _IOW ('V', 30, struct v4l2_tuner) +#define VIDIOC_G_AUDIO _IOR ('V', 33, struct v4l2_audio) +#define VIDIOC_S_AUDIO _IOW ('V', 34, struct v4l2_audio) +#define VIDIOC_QUERYCTRL _IOWR ('V', 36, struct v4l2_queryctrl) +#define VIDIOC_QUERYMENU _IOWR ('V', 37, struct v4l2_querymenu) +#define VIDIOC_G_INPUT _IOR ('V', 38, int) +#define VIDIOC_S_INPUT _IOWR ('V', 39, int) +#define VIDIOC_G_OUTPUT _IOR ('V', 46, int) +#define VIDIOC_S_OUTPUT _IOWR ('V', 47, int) +#define VIDIOC_ENUMOUTPUT _IOWR ('V', 48, struct v4l2_output) +#define VIDIOC_G_AUDOUT _IOR ('V', 49, struct v4l2_audioout) +#define VIDIOC_S_AUDOUT _IOW ('V', 50, struct v4l2_audioout) +#define VIDIOC_G_MODULATOR _IOWR ('V', 54, struct v4l2_modulator) +#define VIDIOC_S_MODULATOR _IOW ('V', 55, struct v4l2_modulator) +#define VIDIOC_G_FREQUENCY _IOWR ('V', 56, struct v4l2_frequency) +#define VIDIOC_S_FREQUENCY _IOW ('V', 57, struct v4l2_frequency) +#define VIDIOC_CROPCAP _IOR ('V', 58, struct v4l2_cropcap) +#define VIDIOC_G_CROP _IOWR ('V', 59, struct v4l2_crop) +#define VIDIOC_S_CROP _IOW ('V', 60, struct v4l2_crop) +#define VIDIOC_G_JPEGCOMP _IOR ('V', 61, struct v4l2_jpegcompression) +#define VIDIOC_S_JPEGCOMP _IOW ('V', 62, struct v4l2_jpegcompression) +#define VIDIOC_QUERYSTD _IOR ('V', 63, v4l2_std_id) +#define VIDIOC_TRY_FMT _IOWR ('V', 64, struct v4l2_format) +#define VIDIOC_ENUMAUDIO _IOWR ('V', 65, struct v4l2_audio) +#define VIDIOC_ENUMAUDOUT _IOWR ('V', 66, struct v4l2_audioout) +#define VIDIOC_G_PRIORITY _IOR ('V', 67, enum v4l2_priority) +#define VIDIOC_S_PRIORITY _IOW ('V', 68, enum v4l2_priority) + +/* for compatibility, will go away some day */ +#define VIDIOC_OVERLAY_OLD _IOWR ('V', 14, int) +#define VIDIOC_S_PARM_OLD _IOW ('V', 22, struct v4l2_streamparm) +#define VIDIOC_S_CTRL_OLD _IOW ('V', 28, struct v4l2_control) +#define VIDIOC_G_AUDIO_OLD _IOWR ('V', 33, struct v4l2_audio) +#define VIDIOC_G_AUDOUT_OLD _IOWR ('V', 49, struct v4l2_audioout) + +#define BASE_VIDIOC_PRIVATE 192 /* 192-255 are private */ + + +#ifdef __KERNEL__ +/* + * + * V 4 L 2 D R I V E R H E L P E R A P I + * + * Some commonly needed functions for drivers (v4l2-common.o module) + */ +#include <linux/fs.h> + +/* Video standard functions */ +extern unsigned int v4l2_video_std_fps(struct v4l2_standard *vs); +extern int v4l2_video_std_construct(struct v4l2_standard *vs, + int id, char *name); + +/* prority handling */ +struct v4l2_prio_state { + atomic_t prios[4]; +}; +int v4l2_prio_init(struct v4l2_prio_state *global); +int v4l2_prio_change(struct v4l2_prio_state *global, enum v4l2_priority *local, + enum v4l2_priority new); +int v4l2_prio_open(struct v4l2_prio_state *global, enum v4l2_priority *local); +int v4l2_prio_close(struct v4l2_prio_state *global, enum v4l2_priority *local); +enum v4l2_priority v4l2_prio_max(struct v4l2_prio_state *global); +int v4l2_prio_check(struct v4l2_prio_state *global, enum v4l2_priority *local); + +/* names for fancy debug output */ +extern char *v4l2_field_names[]; +extern char *v4l2_type_names[]; +extern char *v4l2_ioctl_names[]; + +/* Compatibility layer interface -- v4l1-compat module */ +typedef int (*v4l2_kioctl)(struct inode *inode, struct file *file, + unsigned int cmd, void *arg); +int v4l_compat_translate_ioctl(struct inode *inode, struct file *file, + int cmd, void *arg, v4l2_kioctl driver_ioctl); + +#endif /* __KERNEL__ */ +#endif /* __LINUX_VIDEODEV2_H */ + +/* + * Local variables: + * c-basic-offset: 8 + * End: + */ diff --git a/kradio3/plugins/v4lradio/po/Makefile.am b/kradio3/plugins/v4lradio/po/Makefile.am new file mode 100644 index 0000000..6f04af2 --- /dev/null +++ b/kradio3/plugins/v4lradio/po/Makefile.am @@ -0,0 +1,3 @@ + +PACKAGE = kradio-v4lradio +POFILES = AUTO diff --git a/kradio3/plugins/v4lradio/po/de.po b/kradio3/plugins/v4lradio/po/de.po new file mode 100644 index 0000000..718cb19 --- /dev/null +++ b/kradio3/plugins/v4lradio/po/de.po @@ -0,0 +1,362 @@ +# translation of de.po to +# translation of kradio-v4lradio.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: 2006-11-11 18:43+0100\n" +"PO-Revision-Date: 2006-11-06 00:24+0100\n" +"Last-Translator: Ernst Martin Witte <emw@nocabal.de>\n" +"Language-Team: <de@li.org>\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: KBabel 1.11.4\n" + +#. i18n: file v4lradio-configuration-ui.ui line 16 +#: rc.cpp:3 rc.cpp:90 v4lradio-configuration-ui.cpp:328 +#, no-c-format +msgid "SetupDialogGeneral" +msgstr "SetupDialogGeneral" + +#. i18n: file v4lradio-configuration-ui.ui line 37 +#: rc.cpp:6 rc.cpp:93 v4lradio-configuration-ui.cpp:344 +#, no-c-format +msgid "Devices" +msgstr "Geräte" + +#. i18n: file v4lradio-configuration-ui.ui line 68 +#: rc.cpp:9 rc.cpp:96 v4lradio-configuration-ui.cpp:329 +#, no-c-format +msgid "Playback Mixer Device" +msgstr "Wiedergabe Mixer" + +#. i18n: file v4lradio-configuration-ui.ui line 76 +#: rc.cpp:12 rc.cpp:99 v4lradio-configuration-ui.cpp:330 +#, no-c-format +msgid "Playback Mixer Channel" +msgstr "Wiedergabe Mixerkanal" + +#. i18n: file v4lradio-configuration-ui.ui line 169 +#: rc.cpp:15 rc.cpp:102 v4lradio-configuration-ui.cpp:331 +#, no-c-format +msgid "Radio Device" +msgstr "Radio Gerät" + +#. i18n: file v4lradio-configuration-ui.ui line 196 +#: rc.cpp:19 rc.cpp:106 v4lradio-configuration-ui.cpp:333 +#, no-c-format +msgid "Capture Mixer Device" +msgstr "Aufnahme Mixer" + +#. i18n: file v4lradio-configuration-ui.ui line 217 +#: rc.cpp:22 rc.cpp:109 v4lradio-configuration-ui.cpp:334 +#, no-c-format +msgid "Capture Mixer Channel" +msgstr "Aufnahme Mixerkanal" + +#. i18n: file v4lradio-configuration-ui.ui line 249 +#: rc.cpp:25 rc.cpp:112 v4lradio-configuration-ui.cpp:336 +#, no-c-format +msgid "test" +msgstr "test" + +#. i18n: file v4lradio-configuration-ui.ui line 269 +#: rc.cpp:28 rc.cpp:115 v4lradio-configuration-ui.cpp:337 +#, no-c-format +msgid "unknown v4l device" +msgstr "Unbekanntes V4L-Gerät" + +#. i18n: file v4lradio-configuration-ui.ui line 315 +#: rc.cpp:31 rc.cpp:118 v4lradio-configuration-ui.cpp:338 +#, no-c-format +msgid "Use active pla&yback by capturing" +msgstr "Aktive &Wiedergabe verwenden (Aufgenommenes abspielen)" + +#. i18n: file v4lradio-configuration-ui.ui line 318 +#: rc.cpp:34 rc.cpp:121 v4lradio-configuration-ui.cpp:339 +#, no-c-format +msgid "Alt+Y" +msgstr "Alt+Y" + +#. i18n: file v4lradio-configuration-ui.ui line 334 +#: rc.cpp:37 rc.cpp:124 v4lradio-configuration-ui.cpp:340 +#, no-c-format +msgid "Mute Play&back Channel on Power Off" +msgstr "Wiedergabekanal beim Abschalten des Radios stummschalten" + +#. i18n: file v4lradio-configuration-ui.ui line 337 +#: rc.cpp:40 rc.cpp:127 v4lradio-configuration-ui.cpp:341 +#, no-c-format +msgid "Alt+B" +msgstr "Alt+B" + +#. i18n: file v4lradio-configuration-ui.ui line 353 +#: rc.cpp:43 rc.cpp:130 v4lradio-configuration-ui.cpp:342 +#, no-c-format +msgid "Set Playback Channel Volume to &Zero on Power Off" +msgstr "Wiedergabelautstärke beim Abschalten des Radios auf 0 setzen" + +#. i18n: file v4lradio-configuration-ui.ui line 356 +#: rc.cpp:46 rc.cpp:133 v4lradio-configuration-ui.cpp:343 +#, no-c-format +msgid "Alt+Z" +msgstr "Alt+Z" + +#. i18n: file v4lradio-configuration-ui.ui line 394 +#: rc.cpp:52 rc.cpp:139 v4lradio-configuration-ui.cpp:345 +#, no-c-format +msgid "to" +msgstr "bis" + +#. i18n: file v4lradio-configuration-ui.ui line 413 +#. i18n: file v4lradio-configuration-ui.ui line 443 +#. i18n: file v4lradio-configuration-ui.ui line 479 +#. i18n: file v4lradio-configuration-ui.ui line 413 +#. i18n: file v4lradio-configuration-ui.ui line 443 +#. i18n: file v4lradio-configuration-ui.ui line 479 +#: rc.cpp:55 rc.cpp:58 rc.cpp:64 rc.cpp:142 rc.cpp:145 rc.cpp:151 +#: v4lradio-configuration-ui.cpp:346 v4lradio-configuration-ui.cpp:347 +#: v4lradio-configuration-ui.cpp:349 +#, no-c-format +msgid " kHz" +msgstr " kHz" + +#. i18n: file v4lradio-configuration-ui.ui line 460 +#: rc.cpp:61 rc.cpp:148 v4lradio-configuration-ui.cpp:348 +#, no-c-format +msgid "minimum signal quality" +msgstr "Mindest-Signalpegel" + +#. i18n: file v4lradio-configuration-ui.ui line 499 +#: rc.cpp:67 rc.cpp:154 v4lradio-configuration-ui.cpp:350 +#, no-c-format +msgid "station scan step" +msgstr "Sendersuchschrittweite" + +#. i18n: file v4lradio-configuration-ui.ui line 507 +#: rc.cpp:70 rc.cpp:157 v4lradio-configuration-ui.cpp:351 +#, no-c-format +msgid "allowed frequency range" +msgstr "erlaubter Frequenzbereich" + +#. i18n: file v4lradio-configuration-ui.ui line 566 +#: rc.cpp:75 rc.cpp:162 v4lradio-configuration-ui.cpp:359 +#, no-c-format +msgid "V4L Mixer Controls" +msgstr "V4L Mixersteuerung" + +#. i18n: file v4lradio-configuration-ui.ui line 594 +#: rc.cpp:78 rc.cpp:165 v4lradio-configuration-ui.cpp:355 +#, no-c-format +msgid "volume" +msgstr "Lautstärke" + +#. i18n: file v4lradio-configuration-ui.ui line 684 +#: rc.cpp:81 rc.cpp:168 v4lradio-configuration-ui.cpp:356 +#, no-c-format +msgid "treble" +msgstr "Höhen" + +#. i18n: file v4lradio-configuration-ui.ui line 774 +#: rc.cpp:84 rc.cpp:171 v4lradio-configuration-ui.cpp:357 +#, no-c-format +msgid "bass" +msgstr "Tiefen" + +#. i18n: file v4lradio-configuration-ui.ui line 861 +#: rc.cpp:87 rc.cpp:174 v4lradio-configuration-ui.cpp:358 +#, no-c-format +msgid "balance" +msgstr "Balance" + +#: _translatorinfo.cpp:1 +msgid "" +"_: NAME OF TRANSLATORS\n" +"Your names" +msgstr "Ernst Martin Witte" + +#: _translatorinfo.cpp:3 +msgid "" +"_: EMAIL OF TRANSLATORS\n" +"Your emails" +msgstr "emw@nocabal.de" + +#: v4lradio-configuration.cpp:443 +msgid "any ( * )" +msgstr "Alle ( * )" + +#: v4lradio-configuration.cpp:445 +msgid "Radio Device Selection" +msgstr "Auswahl der Radio-Gerätedatei" + +#: v4lradio-configuration.cpp:448 +msgid "Select Radio Device" +msgstr "Wählen Sie die Radio-Gerätedatei aus" + +#: v4lradio.cpp:56 +msgid "Support for V4L(2) Radio Devices" +msgstr "Unterstützung für V4L(2)-Radiogeräte" + +#: v4lradio.cpp:61 +msgid "Video For Linux Plugin" +msgstr "Video für Linux (V4L) Plugin" + +#: v4lradio.cpp:659 +msgid "invalid frequency %1" +msgstr "ungültige Frequenz: %1" + +#: v4lradio.cpp:680 v4lradio.cpp:1358 v4lradio.cpp:1507 +msgid "don't known how to handle V4L-version %1" +msgstr "Keine Ahnung, wie die V4L-Version %1 behandelt werden soll" + +#: v4lradio.cpp:686 +msgid "error setting frequency to %1 (%2)" +msgstr "Fehler (%2) beim Einstellen der Frequenz auf %1." + +#: v4lradio.cpp:1004 +msgid "" +"Device %1 does exist but is not readable/writable. Please check device " +"permissions." +msgstr "" +"Das Gerät %1 existiert, ist aber nicht lesbar/schreibbar. Bitte überprüfen " +"Sie die Einstellung der Zugriffsrechte für das Gerät." + +#: v4lradio.cpp:1014 +msgid "Could not find an accessible v4l(2) radio device." +msgstr "Kann kein verwendbares V4L(2)-Radiogerät finden." + +#: v4lradio.cpp:1077 +msgid "V4L Radio" +msgstr "V4L Radio" + +#: v4lradio.cpp:1078 +msgid "V4L Radio Options" +msgstr "Optionen des V4L-Radios" + +#: v4lradio.cpp:1088 +msgid "" +"V4L/V4L2 Plugin for KRadio.<P>Provides Support for V4L/V4L2 based Radio " +"Cards<P>" +msgstr "" +"V4L/V4L2-Plugin für KRadio.<P>Dieses Plugin bindet vom V4L/V4L2-Treiber " +"unterstützte Radio-Karten in KRadio ein.<P>" + +#: v4lradio.cpp:1103 +msgid "V4L/V4L2" +msgstr "V4L/V4L2" + +#: v4lradio.cpp:1104 +msgid "V4L/V4L2 Plugin" +msgstr "V4L/V4L2-Plugin" + +#: v4lradio.cpp:1135 +msgid "Cannot open radio device %1" +msgstr "Die Radiogerätedatei %1 kann nicht geöffnet werden" + +#: v4lradio.cpp:1186 +msgid "cannot open %1" +msgstr "%1 kann nicht geöffnet werden" + +#: v4lradio.cpp:1210 +msgid "audio caps = %1" +msgstr "Audio-Fähigkeiten: %1" + +#: v4lradio.cpp:1224 +msgid "error reading V4L1 caps" +msgstr "Fehler beim Lesen der V4L1-Fähigkeiten" + +#: v4lradio.cpp:1233 +msgid "V4L2 - Version: %1" +msgstr "V4L2 - Version: %1" + +#: v4lradio.cpp:1253 +msgid "V4L2: Querying mute control failed" +msgstr "V4L2: Die Abfrage des Stummschaltungs-Reglers schlug fehl" + +#: v4lradio.cpp:1260 +msgid "V4L2: Querying volume control failed" +msgstr "V4L2: Die Abfrage des Lautstärke-Reglers schlug fehl" + +#: v4lradio.cpp:1268 +msgid "V4L2: Querying treble control failed" +msgstr "V4L2: Die Abfrage des Höhen-Reglers schlug fehl" + +#: v4lradio.cpp:1276 +msgid "V4L2: Querying bass control failed" +msgstr "V4L2: Die Abfrage des Bass-Reglers schlug fehl" + +#: v4lradio.cpp:1284 +msgid "V4L2: Querying balance control failed" +msgstr "V4L2: Die Abfrage des Balance-Reglers schlug fehl" + +#: v4lradio.cpp:1288 +msgid "V4LRadio::readV4LCaps: Reading V4L2 caps failed" +msgstr "V4LRadio::readV4LCaps: Das Lesen der V4L2-Fähigkeiten schlug fehl" + +#: v4lradio.cpp:1292 +msgid "V4L %1 detected" +msgstr "V4L %1 wurde gefunden" + +#: v4lradio.cpp:1294 +msgid "V4L not detected" +msgstr "Das Radiogerät unterstützt V4L nicht" + +#: v4lradio.cpp:1297 +msgid "Radio is mutable" +msgstr "Das Radio kann stummgeschaltet werden" + +#: v4lradio.cpp:1297 +msgid "Radio is not mutable" +msgstr "Das Radio kann nicht stummgeschaltet werden" + +#: v4lradio.cpp:1298 +msgid "Radio has Volume Control" +msgstr "Das Radio hat einen Lautstärkeregler" + +#: v4lradio.cpp:1298 +msgid "Radio has no Volume Control" +msgstr "Das Radio hat keinen Lautstärkeregler" + +#: v4lradio.cpp:1299 +msgid "Radio has Bass Control" +msgstr "Das Radio hat einen Bass-Regler" + +#: v4lradio.cpp:1299 +msgid "Radio has no Bass Control" +msgstr "Das Radio hat keinen Bass-Regler" + +#: v4lradio.cpp:1300 +msgid "Radio has Treble Control" +msgstr "Das Radio hat einen Höhen-Regler" + +#: v4lradio.cpp:1300 +msgid "Radio has no Treble Control" +msgstr "Das Radio hat keinen Bass-Regler" + +#: v4lradio.cpp:1365 +msgid "cannot get tuner info (error %1)" +msgstr "Tuner-Informationen können nicht gelesen werden (Fehler %1)" + +#: v4lradio.cpp:1409 +msgid "error setting %1: %2" +msgstr "Fehler %2 beim Setzen von %1" + +#: v4lradio.cpp:1417 +msgid "error reading %1: %2" +msgstr "Fehler %2 beim Lesen von %1" + +#: v4lradio.cpp:1513 +msgid "error updating radio audio info (%1): %2" +msgstr "Fehler %2 beim Updaten der Audio-Informationen (%1)" + +#: v4lradio.cpp:1514 +msgid "write" +msgstr "Schreiben" + +#: v4lradio.cpp:1514 +msgid "read" +msgstr "Lesen" diff --git a/kradio3/plugins/v4lradio/po/ru.po b/kradio3/plugins/v4lradio/po/ru.po new file mode 100644 index 0000000..dc57522 --- /dev/null +++ b/kradio3/plugins/v4lradio/po/ru.po @@ -0,0 +1,362 @@ +# translation of ru.po to +# translation of kradio-v4lradio.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: 2006-11-11 18:43+0100\n" +"PO-Revision-Date: 2006-11-08 11:59+0300\n" +"Last-Translator: Алексей Кузнецов <Alexey.Kouznetsov@GMail.com>\n" +"Language-Team: <ru@li.org>\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" + +#. i18n: file v4lradio-configuration-ui.ui line 16 +#: rc.cpp:3 rc.cpp:90 v4lradio-configuration-ui.cpp:328 +#, no-c-format +msgid "SetupDialogGeneral" +msgstr "SetupDialogGeneral" + +#. i18n: file v4lradio-configuration-ui.ui line 37 +#: rc.cpp:6 rc.cpp:93 v4lradio-configuration-ui.cpp:344 +#, no-c-format +msgid "Devices" +msgstr "Устройства" + +#. i18n: file v4lradio-configuration-ui.ui line 68 +#: rc.cpp:9 rc.cpp:96 v4lradio-configuration-ui.cpp:329 +#, no-c-format +msgid "Playback Mixer Device" +msgstr "Устройство воспроизведения" + +#. i18n: file v4lradio-configuration-ui.ui line 76 +#: rc.cpp:12 rc.cpp:99 v4lradio-configuration-ui.cpp:330 +#, no-c-format +msgid "Playback Mixer Channel" +msgstr "Канал воспроизведения" + +#. i18n: file v4lradio-configuration-ui.ui line 169 +#: rc.cpp:15 rc.cpp:102 v4lradio-configuration-ui.cpp:331 +#, no-c-format +msgid "Radio Device" +msgstr "Устройство радио" + +#. i18n: file v4lradio-configuration-ui.ui line 196 +#: rc.cpp:19 rc.cpp:106 v4lradio-configuration-ui.cpp:333 +#, no-c-format +msgid "Capture Mixer Device" +msgstr "Устройство записи" + +#. i18n: file v4lradio-configuration-ui.ui line 217 +#: rc.cpp:22 rc.cpp:109 v4lradio-configuration-ui.cpp:334 +#, no-c-format +msgid "Capture Mixer Channel" +msgstr "Канал записи" + +#. i18n: file v4lradio-configuration-ui.ui line 249 +#: rc.cpp:25 rc.cpp:112 v4lradio-configuration-ui.cpp:336 +#, no-c-format +msgid "test" +msgstr "проверка" + +#. i18n: file v4lradio-configuration-ui.ui line 269 +#: rc.cpp:28 rc.cpp:115 v4lradio-configuration-ui.cpp:337 +#, no-c-format +msgid "unknown v4l device" +msgstr "неизвестно" + +#. i18n: file v4lradio-configuration-ui.ui line 315 +#: rc.cpp:31 rc.cpp:118 v4lradio-configuration-ui.cpp:338 +#, no-c-format +msgid "Use active pla&yback by capturing" +msgstr "Захватывать звук и затем проигрывать его" + +#. i18n: file v4lradio-configuration-ui.ui line 318 +#: rc.cpp:34 rc.cpp:121 v4lradio-configuration-ui.cpp:339 +#, no-c-format +msgid "Alt+Y" +msgstr "Alt+Y" + +#. i18n: file v4lradio-configuration-ui.ui line 334 +#: rc.cpp:37 rc.cpp:124 v4lradio-configuration-ui.cpp:340 +#, no-c-format +msgid "Mute Play&back Channel on Power Off" +msgstr "Выключать звук на канале воспроизведения при выходе" + +#. i18n: file v4lradio-configuration-ui.ui line 337 +#: rc.cpp:40 rc.cpp:127 v4lradio-configuration-ui.cpp:341 +#, no-c-format +msgid "Alt+B" +msgstr "Alt+B" + +#. i18n: file v4lradio-configuration-ui.ui line 353 +#: rc.cpp:43 rc.cpp:130 v4lradio-configuration-ui.cpp:342 +#, no-c-format +msgid "Set Playback Channel Volume to &Zero on Power Off" +msgstr "Устанавливать &нулевую громкость воспроизведения при выходе" + +#. i18n: file v4lradio-configuration-ui.ui line 356 +#: rc.cpp:46 rc.cpp:133 v4lradio-configuration-ui.cpp:343 +#, no-c-format +msgid "Alt+Z" +msgstr "Alt+Z" + +#. i18n: file v4lradio-configuration-ui.ui line 394 +#: rc.cpp:52 rc.cpp:139 v4lradio-configuration-ui.cpp:345 +#, no-c-format +msgid "to" +msgstr "до" + +#. i18n: file v4lradio-configuration-ui.ui line 413 +#. i18n: file v4lradio-configuration-ui.ui line 443 +#. i18n: file v4lradio-configuration-ui.ui line 479 +#. i18n: file v4lradio-configuration-ui.ui line 413 +#. i18n: file v4lradio-configuration-ui.ui line 443 +#. i18n: file v4lradio-configuration-ui.ui line 479 +#: rc.cpp:55 rc.cpp:58 rc.cpp:64 rc.cpp:142 rc.cpp:145 rc.cpp:151 +#: v4lradio-configuration-ui.cpp:346 v4lradio-configuration-ui.cpp:347 +#: v4lradio-configuration-ui.cpp:349 +#, no-c-format +msgid " kHz" +msgstr " кГц" + +#. i18n: file v4lradio-configuration-ui.ui line 460 +#: rc.cpp:61 rc.cpp:148 v4lradio-configuration-ui.cpp:348 +#, no-c-format +msgid "minimum signal quality" +msgstr "Минимальный уровень сигнала" + +#. i18n: file v4lradio-configuration-ui.ui line 499 +#: rc.cpp:67 rc.cpp:154 v4lradio-configuration-ui.cpp:350 +#, no-c-format +msgid "station scan step" +msgstr "Шаг изменения частоты при поиске" + +#. i18n: file v4lradio-configuration-ui.ui line 507 +#: rc.cpp:70 rc.cpp:157 v4lradio-configuration-ui.cpp:351 +#, no-c-format +msgid "allowed frequency range" +msgstr "Допустимый частотный диапазон:\tот" + +#. i18n: file v4lradio-configuration-ui.ui line 566 +#: rc.cpp:75 rc.cpp:162 v4lradio-configuration-ui.cpp:359 +#, no-c-format +msgid "V4L Mixer Controls" +msgstr "Аппаратные регуляторы V4l" + +#. i18n: file v4lradio-configuration-ui.ui line 594 +#: rc.cpp:78 rc.cpp:165 v4lradio-configuration-ui.cpp:355 +#, no-c-format +msgid "volume" +msgstr "Громкость" + +#. i18n: file v4lradio-configuration-ui.ui line 684 +#: rc.cpp:81 rc.cpp:168 v4lradio-configuration-ui.cpp:356 +#, no-c-format +msgid "treble" +msgstr "ВЧ" + +#. i18n: file v4lradio-configuration-ui.ui line 774 +#: rc.cpp:84 rc.cpp:171 v4lradio-configuration-ui.cpp:357 +#, no-c-format +msgid "bass" +msgstr "НЧ" + +#. i18n: file v4lradio-configuration-ui.ui line 861 +#: rc.cpp:87 rc.cpp:174 v4lradio-configuration-ui.cpp:358 +#, no-c-format +msgid "balance" +msgstr "Стереобаланс" + +#: _translatorinfo.cpp:1 +msgid "" +"_: NAME OF TRANSLATORS\n" +"Your names" +msgstr "Алексей Кузнецов" + +#: _translatorinfo.cpp:3 +msgid "" +"_: EMAIL OF TRANSLATORS\n" +"Your emails" +msgstr "Alexey.Kouznetsov@GMail.com" + +#: v4lradio-configuration.cpp:443 +msgid "any ( * )" +msgstr "Все ( * )" + +#: v4lradio-configuration.cpp:445 +msgid "Radio Device Selection" +msgstr "Выбор устройства радио" + +#: v4lradio-configuration.cpp:448 +msgid "Select Radio Device" +msgstr "Выберите устройство радиоприёмника" + +#: v4lradio.cpp:56 +msgid "Support for V4L(2) Radio Devices" +msgstr "Поддержка устройств V4l(2)" + +#: v4lradio.cpp:61 +msgid "Video For Linux Plugin" +msgstr "Модуль \"Видео для linux\"" + +#: v4lradio.cpp:659 +msgid "invalid frequency %1" +msgstr "Неправильная частота %1" + +#: v4lradio.cpp:680 v4lradio.cpp:1358 v4lradio.cpp:1507 +msgid "don't known how to handle V4L-version %1" +msgstr "Не знаю что делать с версией V4l \"%1\"" + +#: v4lradio.cpp:686 +msgid "error setting frequency to %1 (%2)" +msgstr "Ошибка установки частоты %1 (%2)" + +#: v4lradio.cpp:1004 +msgid "" +"Device %1 does exist but is not readable/writable. Please check device " +"permissions." +msgstr "" +"Устройство %1 недоступно для чтения/записи. Проверьте права на устройство, а " +"также не использует ли его другая программа." + +#: v4lradio.cpp:1014 +msgid "Could not find an accessible v4l(2) radio device." +msgstr "Не найти доступное устройство V4l(2)." + +#: v4lradio.cpp:1077 +msgid "V4L Radio" +msgstr "Радио V4l" + +#: v4lradio.cpp:1078 +msgid "V4L Radio Options" +msgstr "Параметры устройства V4l" + +#: v4lradio.cpp:1088 +msgid "" +"V4L/V4L2 Plugin for KRadio.<P>Provides Support for V4L/V4L2 based Radio " +"Cards<P>" +msgstr "" +"Модуль V4l/V4l2 для KRadio. <P> Предоставляет поддержку плат радио, " +"совместимых с V4l/V4l2<P>" + +#: v4lradio.cpp:1103 +msgid "V4L/V4L2" +msgstr "V4L/V4LV2" + +#: v4lradio.cpp:1104 +msgid "V4L/V4L2 Plugin" +msgstr "Модуль V4L/V4L2" + +#: v4lradio.cpp:1135 +msgid "Cannot open radio device %1" +msgstr "Не могу открыть устройство радио: %1" + +#: v4lradio.cpp:1186 +msgid "cannot open %1" +msgstr "Не могу открыть %1" + +#: v4lradio.cpp:1210 +msgid "audio caps = %1" +msgstr "возможности звука = %1" + +#: v4lradio.cpp:1224 +msgid "error reading V4L1 caps" +msgstr "Ошибка чтения возможностей V4l1" + +#: v4lradio.cpp:1233 +msgid "V4L2 - Version: %1" +msgstr "Версия V4l2: %1" + +#: v4lradio.cpp:1253 +msgid "V4L2: Querying mute control failed" +msgstr "V4L2: Не могу обратиться к выключателю звука платы" + +#: v4lradio.cpp:1260 +msgid "V4L2: Querying volume control failed" +msgstr "V4L2: Не могу обратиться к регулятору громкости" + +#: v4lradio.cpp:1268 +msgid "V4L2: Querying treble control failed" +msgstr "V4L2: Не могу обратиться к регулятору верхних частот" + +#: v4lradio.cpp:1276 +msgid "V4L2: Querying bass control failed" +msgstr "V4L2: Не могу обратиться к регулятору нижних частот" + +#: v4lradio.cpp:1284 +msgid "V4L2: Querying balance control failed" +msgstr "V4L2: Не могу обратиться к регулятору стереобаланса" + +#: v4lradio.cpp:1288 +msgid "V4LRadio::readV4LCaps: Reading V4L2 caps failed" +msgstr "V4LRadio::readV4LCaps:Не могу узнать возможности устройства" + +#: v4lradio.cpp:1292 +msgid "V4L %1 detected" +msgstr "Найдено устройство V4L: %1" + +#: v4lradio.cpp:1294 +msgid "V4L not detected" +msgstr "Устройств V4L не обнаружено" + +#: v4lradio.cpp:1297 +msgid "Radio is mutable" +msgstr "Радио не поддерживает выключения звука" + +#: v4lradio.cpp:1297 +msgid "Radio is not mutable" +msgstr "Радио поддерживает выключение звука" + +#: v4lradio.cpp:1298 +msgid "Radio has Volume Control" +msgstr "Есть регулировка громкости" + +#: v4lradio.cpp:1298 +msgid "Radio has no Volume Control" +msgstr "Регулировки громкости нет" + +#: v4lradio.cpp:1299 +msgid "Radio has Bass Control" +msgstr "Есть регулировка НЧ" + +#: v4lradio.cpp:1299 +msgid "Radio has no Bass Control" +msgstr "Регулировки НЧ нет" + +#: v4lradio.cpp:1300 +msgid "Radio has Treble Control" +msgstr "Есть регулировка ВЧ" + +#: v4lradio.cpp:1300 +msgid "Radio has no Treble Control" +msgstr "Регулировки ВЧ нет" + +#: v4lradio.cpp:1365 +msgid "cannot get tuner info (error %1)" +msgstr "Не могу получить информацию о тюнере (код ошибки %1)" + +#: v4lradio.cpp:1409 +msgid "error setting %1: %2" +msgstr "Ошибка установки %1: %2" + +#: v4lradio.cpp:1417 +msgid "error reading %1: %2" +msgstr "Ошибка чтения %1: %2" + +#: v4lradio.cpp:1513 +msgid "error updating radio audio info (%1): %2" +msgstr "Ошибка %1: %2" + +#: v4lradio.cpp:1514 +msgid "write" +msgstr "запись" + +#: v4lradio.cpp:1514 +msgid "read" +msgstr "чтение" diff --git a/kradio3/plugins/v4lradio/v4lcfg_interfaces.cpp b/kradio3/plugins/v4lradio/v4lcfg_interfaces.cpp new file mode 100644 index 0000000..c679c76 --- /dev/null +++ b/kradio3/plugins/v4lradio/v4lcfg_interfaces.cpp @@ -0,0 +1,193 @@ +/*************************************************************************** + v4lradio_interfaces.cpp - description + ------------------- + begin : Sam Jun 21 2003 + copyright : (C) 2003 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 <linux/soundcard.h> +#include "v4lcfg_interfaces.h" + +/////////////////////////////////////////////////////////////////////// + +V4LCaps::V4LCaps() + : version(0), + description(QString::null), + hasMute(false), + hasVolume(false), + minVolume(0), + maxVolume(65535), + hasTreble(false), + minTreble(0), + maxTreble(65535), + hasBass(false), + minBass(0), + maxBass(65535), + hasBalance(false), + minBalance(0), + maxBalance(65535) +{ +} + + +V4LCaps::V4LCaps(const V4LCaps &c) + : version(c.version), + description(c.description), + hasMute(c.hasMute), + hasVolume(c.hasVolume), + minVolume(c.minVolume), + maxVolume(c.maxVolume), + hasTreble(c.hasTreble), + minTreble(c.minTreble), + maxTreble(c.maxTreble), + hasBass(c.hasBass), + minBass(c.minBass), + maxBass(c.maxBass), + hasBalance(c.hasBalance), + minBalance(c.minBalance), + maxBalance(c.maxBalance) +{ +} + + +// IV4LCfg + +IF_IMPL_SENDER ( IV4LCfg::notifyRadioDeviceChanged(const QString &s), + noticeRadioDeviceChanged(s) + ) +IF_IMPL_SENDER ( IV4LCfg::notifyPlaybackMixerChanged(const QString &s, const QString &Channel), + noticePlaybackMixerChanged(s, Channel) + ) +IF_IMPL_SENDER ( IV4LCfg::notifyCaptureMixerChanged(const QString &s, const QString &Channel), + noticeCaptureMixerChanged(s, Channel) + ) +IF_IMPL_SENDER ( IV4LCfg::notifyDeviceVolumeChanged(float v), + noticeDeviceVolumeChanged(v) + ) +IF_IMPL_SENDER ( IV4LCfg::notifyCapabilitiesChanged(const V4LCaps &c), + noticeCapabilitiesChanged(c) + ) + +IF_IMPL_SENDER ( IV4LCfg::notifyActivePlaybackChanged(bool a), + noticeActivePlaybackChanged(a) + ) + +IF_IMPL_SENDER ( IV4LCfg::notifyMuteOnPowerOffChanged(bool a), + noticeMuteOnPowerOffChanged(a) + ) + +IF_IMPL_SENDER ( IV4LCfg::notifyVolumeZeroOnPowerOffChanged(bool a), + noticeVolumeZeroOnPowerOffChanged(a) + ) +// IV4LCfgClient + +IF_IMPL_SENDER ( IV4LCfgClient::sendRadioDevice (const QString &s), + setRadioDevice(s) + ) +IF_IMPL_SENDER ( IV4LCfgClient::sendPlaybackMixer(const QString &s, const QString &ch), + setPlaybackMixer(s, ch) + ) +IF_IMPL_SENDER ( IV4LCfgClient::sendCaptureMixer(const QString &s, const QString &ch), + setCaptureMixer(s, ch) + ) +IF_IMPL_SENDER ( IV4LCfgClient::sendDeviceVolume(float v), + setDeviceVolume(v) + ) + +IF_IMPL_SENDER ( IV4LCfgClient::sendActivePlayback(bool a), + setActivePlayback(a) + ) + +IF_IMPL_SENDER ( IV4LCfgClient::sendMuteOnPowerOff(bool a), + setMuteOnPowerOff(a) + ) + +IF_IMPL_SENDER ( IV4LCfgClient::sendVolumeZeroOnPowerOff(bool a), + setVolumeZeroOnPowerOff(a) + ) + +static QString defaultRDev("/dev/radio"); +// static QString defaultMDev("/dev/mixer"); + +IF_IMPL_QUERY ( const QString &IV4LCfgClient::queryRadioDevice (), + getRadioDevice(), + defaultRDev + ) +IF_IMPL_QUERY ( const QString &IV4LCfgClient::queryPlaybackMixerID (), + getPlaybackMixerID(), + QString::null + ) +IF_IMPL_QUERY ( const QString &IV4LCfgClient::queryCaptureMixerID (), + getCaptureMixerID(), + QString::null + ) + +static const QString channel_line("Line"); +IF_IMPL_QUERY ( const QString &IV4LCfgClient::queryPlaybackMixerChannel(), + getPlaybackMixerChannel(), + channel_line + ) +IF_IMPL_QUERY ( const QString &IV4LCfgClient::queryCaptureMixerChannel(), + getCaptureMixerChannel(), + channel_line + ) +IF_IMPL_QUERY ( float IV4LCfgClient::queryDeviceVolume (), + getDeviceVolume(), + 0.0 + ) +IF_IMPL_QUERY ( V4LCaps IV4LCfgClient::queryCapabilities(QString dev), + getCapabilities(dev), + V4LCaps() + ) + +IF_IMPL_QUERY ( bool IV4LCfgClient::queryActivePlayback(), + getActivePlayback(), + false + ) + +IF_IMPL_QUERY ( bool IV4LCfgClient::queryMuteOnPowerOff(), + getMuteOnPowerOff(), + false + ) + +IF_IMPL_QUERY ( bool IV4LCfgClient::queryVolumeZeroOnPowerOff(), + getVolumeZeroOnPowerOff(), + false + ) + +void IV4LCfgClient::noticeConnectedI (cmplInterface *, bool /*pointer_valid*/) +{ + noticeRadioDeviceChanged(queryRadioDevice()); + noticePlaybackMixerChanged(queryPlaybackMixerID(), queryPlaybackMixerChannel()); + noticeCaptureMixerChanged (queryCaptureMixerID(), queryCaptureMixerChannel()); + noticeDeviceVolumeChanged(queryDeviceVolume()); + noticeCapabilitiesChanged(queryCapabilities()); + noticeActivePlaybackChanged(queryActivePlayback()); + noticeMuteOnPowerOffChanged(queryMuteOnPowerOff()); + noticeVolumeZeroOnPowerOffChanged(queryVolumeZeroOnPowerOff()); +} + + +void IV4LCfgClient::noticeDisconnectedI (cmplInterface *, bool /*pointer_valid*/) +{ + noticeRadioDeviceChanged(queryRadioDevice()); + noticePlaybackMixerChanged(queryPlaybackMixerID(), queryPlaybackMixerChannel()); + noticeCaptureMixerChanged (queryCaptureMixerID(), queryCaptureMixerChannel()); + noticeDeviceVolumeChanged(queryDeviceVolume()); + noticeCapabilitiesChanged(queryCapabilities()); + noticeActivePlaybackChanged(queryActivePlayback()); + noticeMuteOnPowerOffChanged(queryMuteOnPowerOff()); + noticeVolumeZeroOnPowerOffChanged(queryVolumeZeroOnPowerOff()); +} + + diff --git a/kradio3/plugins/v4lradio/v4lcfg_interfaces.h b/kradio3/plugins/v4lradio/v4lcfg_interfaces.h new file mode 100644 index 0000000..f2e1032 --- /dev/null +++ b/kradio3/plugins/v4lradio/v4lcfg_interfaces.h @@ -0,0 +1,151 @@ +/*************************************************************************** + v4lradio_interfaces.h - description + ------------------- + begin : Sam Jun 21 2003 + copyright : (C) 2003 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_V4LCFG_INTERFACES_H +#define KRADIO_V4LCFG_INTERFACES_H + +#include "../../src/include/interfaces.h" +#include "math.h" + +struct V4LCaps +{ + int version; + QString description; + + bool hasMute; + + bool hasVolume; + int minVolume, maxVolume; + bool hasTreble; + int minTreble, maxTreble; + bool hasBass; + int minBass, maxBass; + bool hasBalance; + int minBalance, maxBalance; + + V4LCaps(); + V4LCaps(const V4LCaps &); + + float volumeStep() const { return 1.0 / (float)(maxVolume - minVolume); } + float trebleStep() const { return 1.0 / (float)(maxTreble - minTreble); } + float bassStep() const { return 1.0 / (float)(maxBass - minBass); } + float balanceStep() const { return 1.0 / (float)(maxBalance - minBalance); } + + void setVolume (int min, int max) { hasVolume = true; minVolume = min; maxVolume = max; } + void setTreble (int min, int max) { hasTreble = true; minTreble = min; maxTreble = max; } + void setBass (int min, int max) { hasBass = true; minBass = min; maxBass = max; } + void setBalance(int min, int max) { hasBalance = true; minBalance = min; maxBalance = max; } + + void unsetVolume () { hasVolume = false; minVolume = 0; maxVolume = 65535; } + void unsetTreble () { hasTreble = false; minTreble = 0; maxTreble = 65535; } + void unsetBass () { hasBass = false; minBass = 0; maxBass = 65535; } + void unsetBalance() { hasBalance = false; minBalance = 0; maxBalance = 65535; } + + int intGetVolume (float f) const { return (int)rint(minVolume + (maxVolume - minVolume ) * f); } + int intGetTreble (float f) const { return (int)rint(minTreble + (maxTreble - minTreble ) * f); } + int intGetBass (float f) const { return (int)rint(minBass + (maxBass - minBass ) * f); } + int intGetBalance(float f) const { return (int)rint(minBalance + (maxBalance - minBalance) / 2.0 * (1.0 + f)); } + + float floatGetVolume (int i) const { return (float)(i - minVolume) * volumeStep(); } + float floatGetTreble (int i) const { return (float)(i - minTreble) * trebleStep(); } + float floatGetBass (int i) const { return (float)(i - minBass ) * bassStep(); } + float floatGetBalance(int i) const { return (float)(i - minBalance) * balanceStep() * 2.0 - 1.0; } +}; + + + +INTERFACE(IV4LCfg, IV4LCfgClient) +{ +public: + IF_CON_DESTRUCTOR(IV4LCfg, -1) + +RECEIVERS: + IF_RECEIVER( setRadioDevice (const QString &s) ) + IF_RECEIVER( setPlaybackMixer(const QString &soundStreamClientID, const QString &ch) ) + IF_RECEIVER( setCaptureMixer (const QString &soundStreamClientID, const QString &ch) ) + IF_RECEIVER( setDeviceVolume(float v) ) + IF_RECEIVER( setActivePlayback(bool a) ) + IF_RECEIVER( setMuteOnPowerOff(bool m) ) + IF_RECEIVER( setVolumeZeroOnPowerOff(bool m) ) + +SENDERS: + IF_SENDER ( notifyRadioDeviceChanged (const QString &s) ) + IF_SENDER ( notifyPlaybackMixerChanged(const QString &soundStreamClientID, const QString &Channel) ) + IF_SENDER ( notifyCaptureMixerChanged (const QString &soundStreamClientID, const QString &Channel) ) + IF_SENDER ( notifyDeviceVolumeChanged (float v) ) + IF_SENDER ( notifyCapabilitiesChanged (const V4LCaps &) ) + IF_SENDER ( notifyActivePlaybackChanged (bool a) ) + IF_SENDER ( notifyMuteOnPowerOffChanged (bool a) ) + IF_SENDER ( notifyVolumeZeroOnPowerOffChanged (bool a) ) + +ANSWERS: + IF_ANSWER ( const QString &getRadioDevice () const ) + IF_ANSWER ( const QString &getPlaybackMixerID () const ) + IF_ANSWER ( const QString &getCaptureMixerID () const ) + IF_ANSWER ( const QString &getPlaybackMixerChannel() const ) + IF_ANSWER ( const QString &getCaptureMixerChannel() const ) + IF_ANSWER ( float getDeviceVolume() const ) + IF_ANSWER ( V4LCaps getCapabilities(QString dev = QString::null) const ) + IF_ANSWER ( bool getActivePlayback() const ) + IF_ANSWER ( bool getMuteOnPowerOff() const ) + IF_ANSWER ( bool getVolumeZeroOnPowerOff() const ) +}; + + + +INTERFACE(IV4LCfgClient, IV4LCfg) +{ +public: + IF_CON_DESTRUCTOR(IV4LCfgClient, 1) + +SENDERS: + IF_SENDER ( sendRadioDevice (const QString &s) ) + IF_SENDER ( sendPlaybackMixer(const QString &soundStreamClientID, const QString &ch) ) + IF_SENDER ( sendCaptureMixer (const QString &soundStreamClientID, const QString &ch) ) + IF_SENDER ( sendDeviceVolume(float v) ) + IF_SENDER ( sendActivePlayback(bool a) ) + IF_SENDER ( sendMuteOnPowerOff(bool a) ) + IF_SENDER ( sendVolumeZeroOnPowerOff(bool a) ) + +RECEIVERS: + IF_RECEIVER( noticeRadioDeviceChanged(const QString &s) ) + IF_RECEIVER( noticePlaybackMixerChanged(const QString &soundStreamClientID, const QString &Channel) ) + IF_RECEIVER( noticeCaptureMixerChanged (const QString &soundStreamClientID, const QString &Channel) ) + IF_RECEIVER( noticeDeviceVolumeChanged(float v) ) + IF_RECEIVER( noticeCapabilitiesChanged(const V4LCaps &) ) + IF_RECEIVER( noticeActivePlaybackChanged(bool a) ) + IF_RECEIVER( noticeMuteOnPowerOffChanged(bool a) ) + IF_RECEIVER( noticeVolumeZeroOnPowerOffChanged(bool a) ) + +QUERIES: + IF_QUERY ( const QString &queryRadioDevice () ) + IF_QUERY ( const QString &queryPlaybackMixerID () ) + IF_QUERY ( const QString &queryCaptureMixerID () ) + IF_QUERY ( const QString &queryPlaybackMixerChannel() ) + IF_QUERY ( const QString &queryCaptureMixerChannel() ) + IF_QUERY ( float queryDeviceVolume() ) + IF_QUERY ( V4LCaps queryCapabilities(QString dev = QString::null) ) + IF_QUERY ( bool queryActivePlayback() ) + IF_QUERY ( bool queryMuteOnPowerOff() ) + IF_QUERY ( bool queryVolumeZeroOnPowerOff() ) + +RECEIVERS: + virtual void noticeConnectedI (cmplInterface *, bool /*pointer_valid*/); + virtual void noticeDisconnectedI (cmplInterface *, bool /*pointer_valid*/); +}; + +#endif diff --git a/kradio3/plugins/v4lradio/v4lradio-configuration-ui.ui b/kradio3/plugins/v4lradio/v4lradio-configuration-ui.ui new file mode 100644 index 0000000..2cc4cfd --- /dev/null +++ b/kradio3/plugins/v4lradio/v4lradio-configuration-ui.ui @@ -0,0 +1,966 @@ +<!DOCTYPE UI><UI version="3.3" stdsetdef="1"> +<class>V4LRadioConfigurationUI</class> +<widget class="QWidget"> + <property name="name"> + <cstring>V4LRadioConfigurationUI</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>512</width> + <height>357</height> + </rect> + </property> + <property name="caption"> + <string>SetupDialogGeneral</string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <widget class="QTabWidget" row="0" column="0"> + <property name="name"> + <cstring>kTabWidget1</cstring> + </property> + <property name="currentPage"> + <number>0</number> + </property> + <widget class="QWidget"> + <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="2"> + <property name="name"> + <cstring>spacer18_3_2</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Preferred</enum> + </property> + <property name="sizeHint"> + <size> + <width>40</width> + <height>21</height> + </size> + </property> + </spacer> + <widget class="QLabel" row="2" column="0"> + <property name="name"> + <cstring>labelPlaybackMixerDevice</cstring> + </property> + <property name="text"> + <string>Playback Mixer Device</string> + </property> + </widget> + <widget class="QLabel" row="3" column="0"> + <property name="name"> + <cstring>labelPlaybackMixerChannel</cstring> + </property> + <property name="text"> + <string>Playback Mixer Channel</string> + </property> + </widget> + <spacer row="2" column="2"> + <property name="name"> + <cstring>spacer18_3_4</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Preferred</enum> + </property> + <property name="sizeHint"> + <size> + <width>40</width> + <height>21</height> + </size> + </property> + </spacer> + <spacer row="3" column="2"> + <property name="name"> + <cstring>spacer18_3</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Preferred</enum> + </property> + <property name="sizeHint"> + <size> + <width>40</width> + <height>21</height> + </size> + </property> + </spacer> + <spacer row="4" column="2"> + <property name="name"> + <cstring>spacer18_3_4_2</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Preferred</enum> + </property> + <property name="sizeHint"> + <size> + <width>40</width> + <height>21</height> + </size> + </property> + </spacer> + <spacer row="5" column="2"> + <property name="name"> + <cstring>spacer18_3_5</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Preferred</enum> + </property> + <property name="sizeHint"> + <size> + <width>40</width> + <height>21</height> + </size> + </property> + </spacer> + <spacer row="1" column="0"> + <property name="name"> + <cstring>spacer18_3_3</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Preferred</enum> + </property> + <property name="sizeHint"> + <size> + <width>152</width> + <height>21</height> + </size> + </property> + </spacer> + <widget class="QLabel" row="0" column="0"> + <property name="name"> + <cstring>labelRadioDevice</cstring> + </property> + <property name="text"> + <string>Radio Device</string> + </property> + </widget> + <widget class="QPushButton" row="0" column="2"> + <property name="name"> + <cstring>buttonSelectRadioDevice</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>5</hsizetype> + <vsizetype>5</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string></string> + </property> + <property name="iconSet"> + <iconset>"fileopen"</iconset> + </property> + </widget> + <widget class="QLabel" row="4" column="0"> + <property name="name"> + <cstring>labelCaptureMixerDevice</cstring> + </property> + <property name="text"> + <string>Capture Mixer Device</string> + </property> + </widget> + <widget class="QComboBox" row="5" column="1"> + <property name="name"> + <cstring>comboCaptureMixerChannel</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>1</hsizetype> + <vsizetype>5</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + </widget> + <widget class="QLabel" row="5" column="0"> + <property name="name"> + <cstring>labelCaptureMixerChannel</cstring> + </property> + <property name="text"> + <string>Capture Mixer Channel</string> + </property> + </widget> + <widget class="QComboBox" row="4" column="1"> + <property name="name"> + <cstring>comboCaptureMixerDevice</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>1</hsizetype> + <vsizetype>5</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + </widget> + <widget class="QComboBox" row="3" column="1"> + <property name="name"> + <cstring>comboPlaybackMixerChannel</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>1</hsizetype> + <vsizetype>5</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + </widget> + <widget class="QComboBox" row="2" column="1"> + <item> + <property name="text"> + <string>test</string> + </property> + </item> + <property name="name"> + <cstring>comboPlaybackMixerDevice</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>1</hsizetype> + <vsizetype>5</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + </widget> + <widget class="QLabel" row="1" column="1"> + <property name="name"> + <cstring>labelDescription</cstring> + </property> + <property name="text"> + <string>unknown v4l device</string> + </property> + </widget> + <widget class="QLineEdit" row="0" column="1"> + <property name="name"> + <cstring>editRadioDevice</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>7</hsizetype> + <vsizetype>5</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + </widget> + <spacer row="9" column="1"> + <property name="name"> + <cstring>spacer15</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>5</width> + <height>5</height> + </size> + </property> + </spacer> + <widget class="QCheckBox" row="6" column="0" rowspan="1" colspan="3"> + <property name="name"> + <cstring>m_checkboxActivePlayback</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>1</hsizetype> + <vsizetype>5</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>Use active pla&yback by capturing</string> + </property> + <property name="accel"> + <string>Alt+Y</string> + </property> + </widget> + <widget class="QCheckBox" row="7" column="0" rowspan="1" colspan="3"> + <property name="name"> + <cstring>m_checkboxMuteOnPowerOff</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>1</hsizetype> + <vsizetype>5</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>Mute Play&back Channel on Power Off</string> + </property> + <property name="accel"> + <string>Alt+B</string> + </property> + </widget> + <widget class="QCheckBox" row="8" column="0" rowspan="1" colspan="3"> + <property name="name"> + <cstring>m_checkboxVolumeZeroOnPowerOff</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>1</hsizetype> + <vsizetype>5</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>Set Playback Channel Volume to &Zero on Power Off</string> + </property> + <property name="accel"> + <string>Alt+Z</string> + </property> + </widget> + </grid> + </widget> + <widget class="QWidget"> + <property name="name"> + <cstring>TabPage</cstring> + </property> + <attribute name="title"> + <string>Options</string> + </attribute> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>11</number> + </property> + <widget class="QLayoutWidget" row="0" column="2"> + <property name="name"> + <cstring>layout37</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>labelFrequencyRange</cstring> + </property> + <property name="enabled"> + <bool>true</bool> + </property> + <property name="text"> + <string>to</string> + </property> + </widget> + <widget class="QSpinBox"> + <property name="name"> + <cstring>editMaxFrequency</cstring> + </property> + <property name="enabled"> + <bool>true</bool> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>1</hsizetype> + <vsizetype>5</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="suffix"> + <string> kHz</string> + </property> + <property name="maxValue"> + <number>300000</number> + </property> + <property name="minValue"> + <number>1</number> + </property> + <property name="lineStep"> + <number>1000</number> + </property> + <property name="value"> + <number>300000</number> + </property> + </widget> + </hbox> + </widget> + <widget class="QSpinBox" row="1" column="1"> + <property name="name"> + <cstring>editScanStep</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>1</hsizetype> + <vsizetype>5</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="suffix"> + <string> kHz</string> + </property> + <property name="maxValue"> + <number>500</number> + </property> + <property name="minValue"> + <number>1</number> + </property> + <property name="value"> + <number>50</number> + </property> + </widget> + <widget class="QLabel" row="2" column="0"> + <property name="name"> + <cstring>labelSignalMinQuality</cstring> + </property> + <property name="text"> + <string>minimum signal quality</string> + </property> + </widget> + <widget class="QSpinBox" row="0" column="1"> + <property name="name"> + <cstring>editMinFrequency</cstring> + </property> + <property name="enabled"> + <bool>true</bool> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>1</hsizetype> + <vsizetype>5</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="suffix"> + <string> kHz</string> + </property> + <property name="maxValue"> + <number>2999999</number> + </property> + <property name="minValue"> + <number>0</number> + </property> + <property name="lineStep"> + <number>1000</number> + </property> + <property name="value"> + <number>0</number> + </property> + </widget> + <widget class="QLabel" row="1" column="0"> + <property name="name"> + <cstring>labelScanStep</cstring> + </property> + <property name="text"> + <string>station scan step</string> + </property> + </widget> + <widget class="QLabel" row="0" column="0"> + <property name="name"> + <cstring>labelMinMaxFrequency</cstring> + </property> + <property name="text"> + <string>allowed frequency range</string> + </property> + </widget> + <widget class="QLabel" row="1" column="2"> + <property name="name"> + <cstring>textLabel1_3</cstring> + </property> + <property name="text"> + <string></string> + </property> + </widget> + <widget class="QSpinBox" row="2" column="1"> + <property name="name"> + <cstring>editSignalMinQuality</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>1</hsizetype> + <vsizetype>5</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="value"> + <number>75</number> + </property> + </widget> + <widget class="QLabel" row="2" column="2"> + <property name="name"> + <cstring>textLabel1_4_2</cstring> + </property> + <property name="text"> + <string></string> + </property> + </widget> + <spacer row="3" column="1"> + <property name="name"> + <cstring>spacer16</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> + </grid> + </widget> + <widget class="QWidget"> + <property name="name"> + <cstring>TabPage</cstring> + </property> + <attribute name="title"> + <string>V4L Mixer Controls</string> + </attribute> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>11</number> + </property> + <widget class="QLayoutWidget" row="0" column="0"> + <property name="name"> + <cstring>layout35</cstring> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <property name="spacing"> + <number>3</number> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>labelDeviceVolume</cstring> + </property> + <property name="text"> + <string>volume</string> + </property> + <property name="alignment"> + <set>AlignCenter</set> + </property> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout34</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <spacer> + <property name="name"> + <cstring>spacer42</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> + <widget class="QSlider"> + <property name="name"> + <cstring>sliderDeviceVolume</cstring> + </property> + <property name="maxValue"> + <number>100</number> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + </widget> + <spacer> + <property name="name"> + <cstring>spacer43</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="KDoubleNumInput"> + <property name="name"> + <cstring>editDeviceVolume</cstring> + </property> + <property name="maxValue"> + <number>1</number> + </property> + </widget> + </vbox> + </widget> + <widget class="QLayoutWidget" row="0" column="1"> + <property name="name"> + <cstring>layout35_2</cstring> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <property name="spacing"> + <number>3</number> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>labelTreble</cstring> + </property> + <property name="text"> + <string>treble</string> + </property> + <property name="alignment"> + <set>AlignCenter</set> + </property> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout34_2</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <spacer> + <property name="name"> + <cstring>spacer42_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> + <widget class="QSlider"> + <property name="name"> + <cstring>sliderTreble</cstring> + </property> + <property name="maxValue"> + <number>100</number> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + </widget> + <spacer> + <property name="name"> + <cstring>spacer43_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="KDoubleNumInput"> + <property name="name"> + <cstring>editTreble</cstring> + </property> + <property name="maxValue"> + <number>1</number> + </property> + </widget> + </vbox> + </widget> + <widget class="QLayoutWidget" row="0" column="2"> + <property name="name"> + <cstring>layout35_2_2</cstring> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <property name="spacing"> + <number>3</number> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>labelBass</cstring> + </property> + <property name="text"> + <string>bass</string> + </property> + <property name="alignment"> + <set>AlignCenter</set> + </property> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout34_2_3</cstring> + </property> + <hbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <spacer> + <property name="name"> + <cstring>spacer42_2_3</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> + <widget class="QSlider"> + <property name="name"> + <cstring>sliderBass</cstring> + </property> + <property name="maxValue"> + <number>100</number> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + </widget> + <spacer> + <property name="name"> + <cstring>spacer43_2_3</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="KDoubleNumInput"> + <property name="name"> + <cstring>editBass</cstring> + </property> + <property name="maxValue"> + <number>1</number> + </property> + </widget> + </vbox> + </widget> + <widget class="QLayoutWidget" row="0" column="3"> + <property name="name"> + <cstring>layout51</cstring> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="spacing"> + <number>3</number> + </property> + <widget class="QLabel"> + <property name="name"> + <cstring>labelBalance</cstring> + </property> + <property name="text"> + <string>balance</string> + </property> + <property name="alignment"> + <set>AlignCenter</set> + </property> + </widget> + <spacer> + <property name="name"> + <cstring>spacer40</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>33</height> + </size> + </property> + </spacer> + <widget class="QSlider"> + <property name="name"> + <cstring>sliderBalance</cstring> + </property> + <property name="minValue"> + <number>0</number> + </property> + <property name="maxValue"> + <number>65535</number> + </property> + <property name="pageStep"> + <number>1</number> + </property> + <property name="value"> + <number>0</number> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + </widget> + <spacer> + <property name="name"> + <cstring>spacer41</cstring> + </property> + <property name="orientation"> + <enum>Vertical</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>20</width> + <height>33</height> + </size> + </property> + </spacer> + <widget class="KDoubleNumInput"> + <property name="name"> + <cstring>editBalance</cstring> + </property> + <property name="minValue"> + <number>-1</number> + </property> + <property name="maxValue"> + <number>1</number> + </property> + </widget> + </vbox> + </widget> + </grid> + </widget> + </widget> + </grid> +</widget> +<customwidgets> +</customwidgets> +<tabstops> + <tabstop>editRadioDevice</tabstop> + <tabstop>buttonSelectRadioDevice</tabstop> + <tabstop>comboPlaybackMixerChannel</tabstop> + <tabstop>editMinFrequency</tabstop> + <tabstop>editMaxFrequency</tabstop> + <tabstop>editSignalMinQuality</tabstop> +</tabstops> +<includes> + <include location="global" impldecl="in implementation">kiconloader.h</include> + <include location="global" impldecl="in implementation">knuminput.h</include> +</includes> +<pixmapfunction>SmallIconSet</pixmapfunction> +<layoutdefaults spacing="6" margin="0"/> +<includehints> + <includehint>ktabwidget.h</includehint> + <includehint>knuminput.h</includehint> + <includehint>knuminput.h</includehint> + <includehint>knuminput.h</includehint> + <includehint>knuminput.h</includehint> + <includehint>knuminput.h</includehint> + <includehint>knuminput.h</includehint> + <includehint>knuminput.h</includehint> + <includehint>knuminput.h</includehint> +</includehints> +</UI> diff --git a/kradio3/plugins/v4lradio/v4lradio-configuration.cpp b/kradio3/plugins/v4lradio/v4lradio-configuration.cpp new file mode 100644 index 0000000..f7472fc --- /dev/null +++ b/kradio3/plugins/v4lradio/v4lradio-configuration.cpp @@ -0,0 +1,648 @@ +/*************************************************************************** + v4lradio-configuration.cpp - description + ------------------- + begin : Fre Jun 20 2003 + copyright : (C) 2003 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 <sys/ioctl.h> +#include <fcntl.h> +#include <unistd.h> +#include <linux/soundcard.h> + +#include <qspinbox.h> +#include <qlineedit.h> +#include <qcombobox.h> +#include <qlabel.h> +#include <qfile.h> +#include <qpushbutton.h> +#include <qslider.h> +#include <qcheckbox.h> + +#include <kfiledialog.h> +#include <knuminput.h> +#include <klocale.h> +#include <ktabwidget.h> + +#include "../../src/include/utils.h" +#include "../../src/include/gui_list_helper.h" +#include "v4lradio-configuration.h" +#include "v4lradio.h" + +V4LRadioConfiguration::V4LRadioConfiguration (QWidget *parent, SoundStreamID ssid) + : V4LRadioConfigurationUI(parent), + m_SoundStreamID(ssid), + m_ignoreGUIChanges(false), + m_myControlChange(0), + m_orgTreble(-1), + m_orgBass(-1), + m_orgBalance(-2), + m_orgDeviceVolume(-1), + m_PlaybackMixerHelper(comboPlaybackMixerDevice, StringListHelper::SORT_BY_DESCR), + m_CaptureMixerHelper (comboCaptureMixerDevice, StringListHelper::SORT_BY_DESCR), + m_PlaybackChannelHelper(comboPlaybackMixerChannel), + m_CaptureChannelHelper (comboCaptureMixerChannel) +{ + QObject::connect(buttonSelectRadioDevice, SIGNAL(clicked()), + this, SLOT(selectRadioDevice())); + editRadioDevice->installEventFilter(this); + QObject::connect(editMinFrequency, SIGNAL(valueChanged(int)), + this, SLOT(guiMinFrequencyChanged(int))); + QObject::connect(editMaxFrequency, SIGNAL(valueChanged(int)), + this, SLOT(guiMaxFrequencyChanged(int))); + + QObject::connect(editDeviceVolume, SIGNAL(valueChanged(double)), + this, SLOT(slotDeviceVolumeChanged(double))); + QObject::connect(editTreble, SIGNAL(valueChanged(double)), + this, SLOT(slotTrebleChanged(double))); + QObject::connect(editBass, SIGNAL(valueChanged(double)), + this, SLOT(slotBassChanged(double))); + QObject::connect(editBalance, SIGNAL(valueChanged(double)), + this, SLOT(slotBalanceChanged(double))); + + QObject::connect(sliderDeviceVolume, SIGNAL(valueChanged(int)), + this, SLOT(slotDeviceVolumeChanged(int))); + QObject::connect(sliderTreble, SIGNAL(valueChanged(int)), + this, SLOT(slotTrebleChanged(int))); + QObject::connect(sliderBass, SIGNAL(valueChanged(int)), + this, SLOT(slotBassChanged(int))); + QObject::connect(sliderBalance, SIGNAL(valueChanged(int)), + this, SLOT(slotBalanceChanged(int))); + + QObject::connect(comboPlaybackMixerDevice, SIGNAL(activated(int)), + this, SLOT(slotComboPlaybackMixerSelected(int))); + QObject::connect(comboCaptureMixerDevice, SIGNAL(activated(int)), + this, SLOT(slotComboCaptureMixerSelected(int))); + + sliderBalance->installEventFilter(this); +} + + +V4LRadioConfiguration::~V4LRadioConfiguration () +{ +} + + +bool V4LRadioConfiguration::connectI (Interface *i) +{ + bool a = IV4LCfgClient::connectI(i); + bool b = IFrequencyRadioClient::connectI(i); + bool c = IRadioDeviceClient::connectI(i); + bool d = ISoundStreamClient::connectI(i); + return a || b || c || d; +} + + +bool V4LRadioConfiguration::disconnectI (Interface *i) +{ + bool a = IV4LCfgClient::disconnectI(i); + bool b = IFrequencyRadioClient::disconnectI(i); + bool c = IRadioDeviceClient::disconnectI(i); + bool d = ISoundStreamClient::disconnectI(i); + return a || b || c || d; +} + +void V4LRadioConfiguration::noticeConnectedI (ISoundStreamServer *s, bool pointer_valid) +{ + ISoundStreamClient::noticeConnectedI(s, pointer_valid); + if (s && pointer_valid) { + s->register4_notifyTrebleChanged(this); + s->register4_notifyBassChanged(this); + s->register4_notifyBalanceChanged(this); + s->register4_notifySignalMinQualityChanged(this); + + s->register4_notifyPlaybackChannelsChanged(this); + s->register4_notifyCaptureChannelsChanged(this); + s->register4_notifySoundStreamCreated(this); + } +} + +void V4LRadioConfiguration::noticeConnectedSoundClient(ISoundStreamClient::thisInterface *i, bool pointer_valid) +{ + if (i && pointer_valid && i->supportsPlayback()) { + const QString &org_mid = queryPlaybackMixerID(); + bool org_present = m_PlaybackMixerHelper.contains(org_mid); + const QString &mid = org_present ? m_PlaybackMixerHelper.getCurrentItem() : org_mid; + const QString &org_ch = queryPlaybackMixerChannel(); + const QString &ch = org_present ? m_PlaybackChannelHelper.getCurrentText() : org_ch; + noticePlaybackMixerChanged(mid, ch); + } + if (i && pointer_valid && i->supportsCapture()) { + const QString &org_mid = queryCaptureMixerID(); + bool org_present = m_CaptureMixerHelper.contains(org_mid); + const QString &mid = org_present ? m_CaptureMixerHelper.getCurrentItem() : org_mid; + const QString &org_ch = queryCaptureMixerChannel(); + const QString &ch = org_present ? m_CaptureChannelHelper.getCurrentText() : org_ch; + noticeCaptureMixerChanged(mid, ch); + } +} + + +void V4LRadioConfiguration::noticeDisconnectedSoundClient(ISoundStreamClient::thisInterface *i, bool pointer_valid) +{ + if (i && pointer_valid && i->supportsPlayback()) { + noticePlaybackMixerChanged(queryPlaybackMixerID(), queryPlaybackMixerChannel()); + } + if (i && pointer_valid && i->supportsCapture()) { + noticeCaptureMixerChanged (queryCaptureMixerID(), queryCaptureMixerChannel()); + } +} + +// IV4LCfgClient + +bool V4LRadioConfiguration::noticeRadioDeviceChanged(const QString &s) +{ + bool old = m_ignoreGUIChanges; + m_ignoreGUIChanges = true; + + editRadioDevice->setText(s); + + m_ignoreGUIChanges = old; + return true; +} + + +bool V4LRadioConfiguration::noticePlaybackMixerChanged(const QString &_mixer_id, const QString &Channel) +{ + QString mixer_id = _mixer_id; + bool old = m_ignoreGUIChanges; + m_ignoreGUIChanges = true; + + m_PlaybackMixerHelper.setData(getPlaybackClientDescriptions()); + m_PlaybackMixerHelper.setCurrentItem(mixer_id); + mixer_id = m_PlaybackMixerHelper.getCurrentItem(); + + ISoundStreamClient *mixer = getSoundStreamClientWithID(mixer_id); + if (mixer) { + m_PlaybackChannelHelper.setData(mixer->getPlaybackChannels()); + m_PlaybackChannelHelper.setCurrentText(m_PlaybackChannelHelper.contains(Channel) ? Channel : queryPlaybackMixerChannel()); + } + labelPlaybackMixerChannel->setEnabled(mixer != NULL); + comboPlaybackMixerChannel->setEnabled(mixer != NULL); + + m_ignoreGUIChanges = old; + return true; +} + + +bool V4LRadioConfiguration::noticeCaptureMixerChanged(const QString &_mixer_id, const QString &Channel) +{ + QString mixer_id = _mixer_id; + bool old = m_ignoreGUIChanges; + m_ignoreGUIChanges = true; + + m_CaptureMixerHelper.setData(getCaptureClientDescriptions()); + m_CaptureMixerHelper.setCurrentItem(mixer_id); + mixer_id = m_CaptureMixerHelper.getCurrentItem(); + + ISoundStreamClient *mixer = getSoundStreamClientWithID(mixer_id); + if (mixer) { + m_CaptureChannelHelper.setData(mixer->getCaptureChannels()); + m_CaptureChannelHelper.setCurrentText(m_CaptureChannelHelper.contains(Channel) ? Channel : queryCaptureMixerChannel()); + } + labelCaptureMixerChannel->setEnabled(mixer != NULL); + comboCaptureMixerChannel->setEnabled(mixer != NULL); + + m_ignoreGUIChanges = old; + return true; +} + + +bool V4LRadioConfiguration::noticeDeviceVolumeChanged(float v) +{ + bool old = m_ignoreGUIChanges; + m_ignoreGUIChanges = true; + v = v > 1 ? 1 : v; + v = v < 0 ? 0 : v; + + if (!m_myControlChange) + m_orgDeviceVolume = v; + + editDeviceVolume ->setValue(v); + sliderDeviceVolume->setValue(m_caps.maxVolume - m_caps.intGetVolume(v)); + m_ignoreGUIChanges = old; + return true; +} + + +bool V4LRadioConfiguration::noticeCapabilitiesChanged(const V4LCaps &c) +{ + bool old = m_ignoreGUIChanges; + m_ignoreGUIChanges = true; + + labelDeviceVolume ->setEnabled(c.hasVolume); + editDeviceVolume ->setEnabled(c.hasVolume); + editDeviceVolume ->setRange(0, 1, c.volumeStep(), false); + sliderDeviceVolume->setMinValue(0); + sliderDeviceVolume->setMaxValue(c.maxVolume - c.minVolume); + sliderDeviceVolume->setEnabled(c.hasVolume); + + labelTreble ->setEnabled(c.hasTreble); + editTreble ->setEnabled(c.hasTreble); + editTreble ->setRange(0, 1, c.trebleStep(), false); + sliderTreble->setMinValue(0); + sliderTreble->setMaxValue(c.maxTreble - c.minTreble); + sliderTreble->setEnabled(c.hasTreble); + + labelBass ->setEnabled(c.hasBass); + editBass ->setEnabled(c.hasBass); + editBass ->setRange(0, 1, c.bassStep(), false); + sliderBass->setMinValue(0); + sliderBass->setMaxValue(c.maxBass - c.minBass); + sliderBass->setEnabled(c.hasBass); + + labelBalance ->setEnabled(c.hasBalance); + editBalance ->setEnabled(c.hasBalance); + editBalance ->setRange(-1, 1, c.balanceStep(), false); + sliderBalance->setMinValue(0); + sliderBalance->setMaxValue(c.maxBalance - c.minBalance); + sliderBalance->setEnabled(c.hasBalance); + + m_caps = c; + + float tmp = 0; + noticeDeviceVolumeChanged(queryDeviceVolume()); + + queryTreble(m_SoundStreamID, tmp); + noticeTrebleChanged(m_SoundStreamID, tmp); + + queryBass(m_SoundStreamID, tmp); + noticeBassChanged(m_SoundStreamID, tmp); + + queryBalance(m_SoundStreamID, tmp); + noticeBalanceChanged(m_SoundStreamID, tmp); + + m_ignoreGUIChanges = old; + return true; +} + +bool V4LRadioConfiguration::noticeActivePlaybackChanged(bool a) +{ + bool old = m_ignoreGUIChanges; + m_ignoreGUIChanges = true; + m_checkboxActivePlayback->setChecked(a); + m_ignoreGUIChanges = old; + return true; +} + +bool V4LRadioConfiguration::noticeMuteOnPowerOffChanged(bool a) +{ + bool old = m_ignoreGUIChanges; + m_ignoreGUIChanges = true; + m_checkboxMuteOnPowerOff->setChecked(a); + m_ignoreGUIChanges = old; + return true; +} + +bool V4LRadioConfiguration::noticeVolumeZeroOnPowerOffChanged(bool a) +{ + bool old = m_ignoreGUIChanges; + m_ignoreGUIChanges = true; + m_checkboxVolumeZeroOnPowerOff->setChecked(a); + m_ignoreGUIChanges = old; + return true; +} + +// IRadioDeviceClient + +bool V4LRadioConfiguration::noticeDescriptionChanged (const QString &s, const IRadioDevice */*sender*/) +{ + labelDescription->setText(s); + return true; +} + + +// IFrequencyRadioClient + +bool V4LRadioConfiguration::noticeFrequencyChanged(float /*f*/, const RadioStation */*s*/) +{ + return false; // we don't care +} + + +bool V4LRadioConfiguration::noticeMinMaxFrequencyChanged(float min, float max) +{ + editMinFrequency->setValue((int)rint(min*1000)); + editMaxFrequency->setValue((int)rint(max*1000)); + return true; +} + + +bool V4LRadioConfiguration::noticeDeviceMinMaxFrequencyChanged(float min, float max) +{ + editMinFrequency->setMinValue((int)rint(min*1000)); + editMaxFrequency->setMaxValue((int)rint(max*1000)); + return true; +} + + +bool V4LRadioConfiguration::noticeScanStepChanged(float s) +{ + editScanStep->setValue((int)rint(s * 1000)); + return true; +} + + +// IRadioSoundClient + +bool V4LRadioConfiguration::noticeTrebleChanged(SoundStreamID id, float t) +{ + if (id != m_SoundStreamID) + return false; + + bool old = m_ignoreGUIChanges; + m_ignoreGUIChanges = true; + t = t > 1 ? 1 : t; + t = t < 0 ? 0 : t; + + if (!m_myControlChange) + m_orgTreble = t; + + editTreble ->setValue (t); + sliderTreble->setValue(m_caps.maxTreble - m_caps.intGetTreble(t)); + m_ignoreGUIChanges = old; + return true; +} + + +bool V4LRadioConfiguration::noticeBassChanged(SoundStreamID id, float b) +{ + if (id != m_SoundStreamID) + return false; + + bool old = m_ignoreGUIChanges; + m_ignoreGUIChanges = true; + b = b > 1 ? 1 : b; + b = b < 0 ? 0 : b; + + if (!m_myControlChange) + m_orgBass = b; + + editBass ->setValue(b); + sliderBass->setValue(m_caps.maxBass - m_caps.intGetBass(b)); + m_ignoreGUIChanges = old; + return true; +} + + +bool V4LRadioConfiguration::noticeBalanceChanged(SoundStreamID id, float b) +{ + if (id != m_SoundStreamID) + return false; + + bool old = m_ignoreGUIChanges; + m_ignoreGUIChanges = true; + b = b > 1 ? 1 : b; + b = b < -1 ? -1 : b; + + if (!m_myControlChange) + m_orgBalance = b; + + editBalance ->setValue(b); + sliderBalance->setValue(m_caps.intGetBalance(b)); + m_ignoreGUIChanges = old; + return true; +} + + +bool V4LRadioConfiguration::noticeSignalMinQualityChanged(SoundStreamID id, float q) +{ + if (id != m_SoundStreamID) + return false; + + editSignalMinQuality->setValue((int)rint(q * 100)); + return true; +} + + +bool V4LRadioConfiguration::noticeSoundStreamCreated(SoundStreamID id) +{ + if (id.HasSamePhysicalID(m_SoundStreamID)) { + m_SoundStreamID = id; + } + return true; +} + + +// GUI Slots + + +void V4LRadioConfiguration::selectRadioDevice() +{ + KFileDialog fd("/dev/", + i18n("any ( * )").ascii(), + this, + i18n("Radio Device Selection").ascii(), + TRUE); + fd.setMode(KFile::File | KFile::ExistingOnly); + fd.setCaption (i18n("Select Radio Device")); + + if (fd.exec() == QDialog::Accepted) { + editRadioDevice->setText(fd.selectedFile()); + } +} + + +bool V4LRadioConfiguration::eventFilter(QObject *o, QEvent *e) +{ + if (e->type() == QEvent::FocusOut && o == editRadioDevice) { + slotEditRadioDeviceChanged(); + } + if (e->type() == QEvent::MouseButtonDblClick && o == sliderBalance) { + slotBalanceCenter(); + } + return false; +} + + +void V4LRadioConfiguration::slotEditRadioDeviceChanged() +{ + if (m_ignoreGUIChanges) return; + const QString &s = editRadioDevice->text(); + if (s != queryRadioDevice() || !queryIsPowerOn()) { + V4LCaps c = queryCapabilities(s); + noticeDescriptionChanged(c.description); + } else { + noticeDescriptionChanged(queryDescription()); + } +} + + +void V4LRadioConfiguration::slotComboPlaybackMixerSelected(int /*idx*/) +{ + if (m_ignoreGUIChanges) return; + QString id = m_PlaybackMixerHelper.getCurrentItem(); + noticePlaybackMixerChanged(id, queryPlaybackMixerChannel()); +} + + +void V4LRadioConfiguration::slotComboCaptureMixerSelected(int /*idx*/) +{ + if (m_ignoreGUIChanges) return; + QString id = m_CaptureMixerHelper.getCurrentItem(); + noticeCaptureMixerChanged(id, queryCaptureMixerChannel()); +} + + +void V4LRadioConfiguration::slotOK() +{ + sendMinFrequency(((float)editMinFrequency->value()) / 1000.0); + sendMaxFrequency(((float)editMaxFrequency->value()) / 1000.0); + sendSignalMinQuality(m_SoundStreamID, editSignalMinQuality->value() * 0.01); + sendRadioDevice(editRadioDevice->text()); + sendScanStep(((float)editScanStep->value()) / 1000.0); + + sendCaptureMixer (m_CaptureMixerHelper.getCurrentItem(), + m_CaptureChannelHelper.getCurrentText()); + sendPlaybackMixer(m_PlaybackMixerHelper.getCurrentItem(), + m_PlaybackChannelHelper.getCurrentText()); + + sendActivePlayback(m_checkboxActivePlayback->isChecked()); + sendMuteOnPowerOff(m_checkboxMuteOnPowerOff->isChecked()); + sendVolumeZeroOnPowerOff(m_checkboxVolumeZeroOnPowerOff->isChecked()); + + queryTreble (m_SoundStreamID, m_orgTreble); + queryBass (m_SoundStreamID, m_orgBass); + queryBalance(m_SoundStreamID, m_orgBalance); + m_orgDeviceVolume = queryDeviceVolume(); +} + + +void V4LRadioConfiguration::slotCancel() +{ + noticeRadioDeviceChanged(queryRadioDevice()); + noticePlaybackMixerChanged(queryPlaybackMixerID(), queryPlaybackMixerChannel()); + noticeCaptureMixerChanged (queryCaptureMixerID(), queryCaptureMixerChannel()); + noticeMinMaxFrequencyChanged(queryMinFrequency(), queryMaxFrequency()); + noticeActivePlaybackChanged(queryActivePlayback()); + noticeMuteOnPowerOffChanged(queryMuteOnPowerOff()); + noticeVolumeZeroOnPowerOffChanged(queryVolumeZeroOnPowerOff()); + + float q = 0; + querySignalMinQuality(m_SoundStreamID, q); + noticeSignalMinQualityChanged(m_SoundStreamID, q); + noticeScanStepChanged(queryScanStep()); + + sendTreble (m_SoundStreamID, m_orgTreble); + sendBass (m_SoundStreamID, m_orgBass); + sendBalance (m_SoundStreamID, m_orgBalance); + sendDeviceVolume(m_orgDeviceVolume); +} + + +void V4LRadioConfiguration::guiMinFrequencyChanged(int v) +{ + editMaxFrequency->setMinValue(v); +} + + +void V4LRadioConfiguration::guiMaxFrequencyChanged(int v) +{ + editMinFrequency->setMaxValue(v); +} + +void V4LRadioConfiguration::slotDeviceVolumeChanged (double v) // for KDoubleNumInput, 0.0..1.0 +{ + if (m_ignoreGUIChanges) return; + ++m_myControlChange; + sendDeviceVolume(v); + --m_myControlChange; +} + +void V4LRadioConfiguration::slotTrebleChanged (double t) // for KDoubleNumInput, 0.0..1.0 +{ + if (m_ignoreGUIChanges) return; + ++m_myControlChange; + sendTreble(m_SoundStreamID, t); + --m_myControlChange; +} + +void V4LRadioConfiguration::slotBassChanged (double b) // for KDoubleNumInput, 0.0..1.0 +{ + if (m_ignoreGUIChanges) return; + ++m_myControlChange; + sendBass(m_SoundStreamID, b); + --m_myControlChange; +} + +void V4LRadioConfiguration::slotBalanceChanged(double b) // for KDoubleNumInput, -1.0..1.0 +{ + if (m_ignoreGUIChanges) return; + ++m_myControlChange; + sendBalance(m_SoundStreamID, b); + --m_myControlChange; +} + + +void V4LRadioConfiguration::slotDeviceVolumeChanged (int v) +{ + if (m_ignoreGUIChanges) return; + ++m_myControlChange; + sendDeviceVolume(m_caps.floatGetVolume(m_caps.maxVolume - v)); + --m_myControlChange; +} + +void V4LRadioConfiguration::slotTrebleChanged (int t) +{ + if (m_ignoreGUIChanges) return; + ++m_myControlChange; + sendTreble(m_SoundStreamID, m_caps.floatGetTreble(m_caps.maxTreble - t)); + --m_myControlChange; +} + +void V4LRadioConfiguration::slotBassChanged (int b) +{ + if (m_ignoreGUIChanges) return; + ++m_myControlChange; + sendBass(m_SoundStreamID, m_caps.floatGetBass(m_caps.maxBass - b)); + --m_myControlChange; +} + +void V4LRadioConfiguration::slotBalanceChanged(int b) +{ + if (m_ignoreGUIChanges) return; + ++m_myControlChange; + sendBalance(m_SoundStreamID, m_caps.floatGetBalance(b)); + --m_myControlChange; +} + + +void V4LRadioConfiguration::slotBalanceCenter() +{ + if (m_ignoreGUIChanges) return; + ++m_myControlChange; + sendBalance(m_SoundStreamID, 0); + --m_myControlChange; +} + + +bool V4LRadioConfiguration::noticePlaybackChannelsChanged(const QString & client_id, const QStringList &/*channels*/) +{ + if (m_PlaybackMixerHelper.getCurrentItem() == client_id) { + noticePlaybackMixerChanged(client_id, m_PlaybackChannelHelper.getCurrentText()); + } + return true; +} + + +bool V4LRadioConfiguration::noticeCaptureChannelsChanged (const QString & client_id, const QStringList &/*channels*/) +{ + if (m_CaptureMixerHelper.getCurrentItem() == client_id) { + noticeCaptureMixerChanged(client_id, m_CaptureChannelHelper.getCurrentText()); + } + return true; +} + + + +#include "v4lradio-configuration.moc" diff --git a/kradio3/plugins/v4lradio/v4lradio-configuration.h b/kradio3/plugins/v4lradio/v4lradio-configuration.h new file mode 100644 index 0000000..bf41b54 --- /dev/null +++ b/kradio3/plugins/v4lradio/v4lradio-configuration.h @@ -0,0 +1,147 @@ +/*************************************************************************** + v4lradio-configuration.h - description + ------------------- + begin : Fre Jun 20 2003 + copyright : (C) 2003 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_V4LRADIO_CONFIGURATION_H +#define KRADIO_V4LRADIO_CONFIGURATION_H + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "../../src/include/radiodevice_interfaces.h" +#include "../../src/include/soundstreamclient_interfaces.h" +#include "../../src/include/gui_list_helper.h" + +#include "v4lradio-configuration-ui.h" +#include "v4lcfg_interfaces.h" + +class V4LRadio; +class QWidget; + +class V4LRadioConfiguration : public V4LRadioConfigurationUI, + public IV4LCfgClient, + public IFrequencyRadioClient, + public ISoundStreamClient, + public IRadioDeviceClient +{ +Q_OBJECT +public : + V4LRadioConfiguration (QWidget *parent, SoundStreamID id); + ~V4LRadioConfiguration (); + + bool connectI (Interface *i); + bool disconnectI (Interface *i); + + void noticeConnectedSoundClient(ISoundStreamClient::thisInterface *i, bool pointer_valid); + void noticeDisconnectedSoundClient(ISoundStreamClient::thisInterface *i, bool pointer_valid); + +// IV4LCfgClient + +RECEIVERS: + bool noticeRadioDeviceChanged(const QString &s); + bool noticePlaybackMixerChanged(const QString &soundStreamClientID, const QString &Channel); + bool noticeCaptureMixerChanged (const QString &soundStreamClientID, const QString &Channel); + bool noticeDeviceVolumeChanged(float v); + bool noticeCapabilitiesChanged(const V4LCaps &c); + bool noticeActivePlaybackChanged(bool a); + bool noticeMuteOnPowerOffChanged(bool a); + bool noticeVolumeZeroOnPowerOffChanged(bool a); + +// IRadioDeviceClient + +RECEIVERS: + bool noticePowerChanged (bool /*on*/, const IRadioDevice */*sender = NULL*/) { return false; } + bool noticeStationChanged (const RadioStation &, const IRadioDevice */*sender = NULL*/) { return false; } + bool noticeDescriptionChanged (const QString &, const IRadioDevice *sender = NULL); + + bool noticeCurrentSoundStreamIDChanged(SoundStreamID /*id*/, const IRadioDevice */*sender*/) { return false; } + +// IFrequencyRadioClient + +RECEIVERS: + bool noticeFrequencyChanged(float f, const RadioStation *s); + bool noticeMinMaxFrequencyChanged(float min, float max); + bool noticeDeviceMinMaxFrequencyChanged(float min, float max); + bool noticeScanStepChanged(float s); + +// ISoundStreamClient + +RECEIVERS: + void noticeConnectedI (ISoundStreamServer *s, bool pointer_valid); + + bool noticeTrebleChanged(SoundStreamID id, float t); + bool noticeBassChanged(SoundStreamID id, float b); + bool noticeBalanceChanged(SoundStreamID id, float b); + bool noticeSignalMinQualityChanged(SoundStreamID id, float q); + + bool noticePlaybackChannelsChanged(const QString & /*client_id*/, const QStringList &/*channels*/); + bool noticeCaptureChannelsChanged (const QString & /*client_id*/, const QStringList &/*channels*/); + bool noticeSoundStreamCreated(SoundStreamID /*id*/); + + +protected: + + bool eventFilter(QObject *o, QEvent *e); + +protected slots: + + void selectRadioDevice(); + void slotEditRadioDeviceChanged(); + void slotComboPlaybackMixerSelected(int idx); + void slotComboCaptureMixerSelected(int idx); + + void slotOK(); + void slotCancel(); + + void guiMinFrequencyChanged(int v); + void guiMaxFrequencyChanged(int v); + + void slotDeviceVolumeChanged (double v); // for KDoubleNumInput, 0.0..1.0 + void slotTrebleChanged (double t); // for KDoubleNumInput, 0.0..1.0 + void slotBassChanged (double b); // for KDoubleNumInput, 0.0..1.0 + void slotBalanceChanged(double b); // for KDoubleNumInput, -1.0..1.0 + + void slotDeviceVolumeChanged (int v); // for slider, 0..65535 + void slotTrebleChanged (int t); // for slider, 0..65535 + void slotBassChanged (int b); // for slider, 0..65535 + void slotBalanceChanged(int b); // for slider, 0..65535 + void slotBalanceCenter (); + +protected: + + SoundStreamID m_SoundStreamID; + + bool m_ignoreGUIChanges; + + int m_myControlChange; + float m_orgTreble, + m_orgBass, + m_orgBalance, + m_orgDeviceVolume; + + V4LCaps m_caps; + + typedef GUIListHelper<QComboBox, QString> StringListHelper; + typedef GUISimpleListHelper<QComboBox> ChannelListHelper; + + StringListHelper m_PlaybackMixerHelper, + m_CaptureMixerHelper; + ChannelListHelper m_PlaybackChannelHelper, + m_CaptureChannelHelper; +}; + +#endif diff --git a/kradio3/plugins/v4lradio/v4lradio.cpp b/kradio3/plugins/v4lradio/v4lradio.cpp new file mode 100644 index 0000000..fb1ee9f --- /dev/null +++ b/kradio3/plugins/v4lradio/v4lradio.cpp @@ -0,0 +1,1621 @@ +/*************************************************************************** + v4lradio.cpp - description + ------------------- + begin : Don Mr 8 21:57:17 CET 2001 + copyright : (C) 2002-2005 by Ernst 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. * + * * + ***************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <fcntl.h> +#include <sys/ioctl.h> +#include <unistd.h> + +#ifdef HAVE_V4L2 +#include "linux/videodev2.h" +#endif +#include "linux/videodev.h" +#include <linux/soundcard.h> + +#include <string.h> // memcpy needed + +#include <qlayout.h> +#include <qfile.h> +#include <qfileinfo.h> +#include <qvaluelist.h> + +#include <kconfig.h> +#include <kiconloader.h> +#include <kdialogbase.h> +#include <kaboutdata.h> +#include <klocale.h> + +#include "../../src/include/aboutwidget.h" +#include "../../src/include/utils.h" +#include "v4lradio.h" +#include "v4lradio-configuration.h" + +#include "../../src/include/debug-profiler.h" + +struct _lrvol { unsigned char l, r; short dummy; }; + +/////////////////////////////////////////////////////////////////////// + +PLUGIN_LIBRARY_FUNCTIONS(V4LRadio, "kradio-v4lradio", i18n("Support for V4L(2) Radio Devices")); + +/////////////////////////////////////////////////////////////////////// + +V4LRadio::V4LRadio(const QString &name) + : PluginBase(name, i18n("Video For Linux Plugin")), + m_treble(0.5), + m_bass(0.5), + m_balance(0), + m_deviceVolume(0.9), + m_muted(false), + m_signalQuality(0), + m_stereo(false), + m_minQuality(0.75), + m_minFrequency(87.0), + m_maxFrequency(108.0), + m_lastMinDevFrequency(87.0), + m_lastMaxDevFrequency(108.0), + + m_defaultPlaybackVolume(0.5), + + m_scanStep(0.05), + + m_radioDev("/dev/radio0"), + m_radio_fd(-1), + m_useOldV4L2Calls(true), + m_pollTimer(this), + + m_blockReadTuner(false), + m_blockReadAudio(false), + + m_SoundStreamID(createNewSoundStream(false)), + m_PlaybackMixerID(QString::null), + m_CaptureMixerID(QString::null), + m_PlaybackMixerChannel(QString::null), + m_CaptureMixerChannel(QString::null), + m_ActivePlayback(false), + m_MuteOnPowerOff(false), + m_VolumeZeroOnPowerOff(false), + m_restorePowerOn(false) +{ + QObject::connect (&m_pollTimer, SIGNAL(timeout()), this, SLOT(poll())); + m_pollTimer.start(333); + + m_audio = new video_audio; + bzero(m_audio, sizeof(video_audio)); + m_tuner = new video_tuner; + bzero(m_tuner, sizeof(video_tuner)); +#ifdef HAVE_V4L2 + m_tuner2 = new v4l2_tuner; + bzero(m_tuner2, sizeof(v4l2_tuner)); +#endif + m_caps.version = 0; + + m_seekHelper = new FrequencySeekHelper(*this); + m_seekHelper->connectI(this); +} + + +V4LRadio::~V4LRadio() +{ + setPower(false); + + if (m_seekHelper) + delete m_seekHelper; + + if (m_audio) delete m_audio; + if (m_tuner) delete m_tuner; +#ifdef HAVE_V4L2 + if (m_tuner2) delete m_tuner2; +#endif +} + + +bool V4LRadio::connectI (Interface *i) +{ + bool a = IRadioDevice::connectI(i); + bool b = ISeekRadio::connectI(i); + bool c = IFrequencyRadio::connectI(i); + bool d = IV4LCfg::connectI(i); + bool e = PluginBase::connectI(i); + bool f = ISoundStreamClient::connectI(i); + return a || b || c || d || e || f; +} + + +bool V4LRadio::disconnectI (Interface *i) +{ + bool a = IRadioDevice::disconnectI(i); + bool b = ISeekRadio::disconnectI(i); + bool c = IFrequencyRadio::disconnectI(i); + bool d = IV4LCfg::disconnectI(i); + bool e = PluginBase::disconnectI(i); + bool f = ISoundStreamClient::disconnectI(i); + m_seekHelper->disconnectI(i); + return a || b || c || d || e || f; +} + + +void V4LRadio::noticeConnectedI (ISoundStreamServer *s, bool pointer_valid) +{ + ISoundStreamClient::noticeConnectedI(s, pointer_valid); + if (s && pointer_valid) { + m_seekHelper->connectI(s); + + s->register4_queryPlaybackVolume(this); + s->register4_sendTreble(this); + s->register4_sendBass(this); + s->register4_sendBalance(this); + s->register4_sendMute(this); + s->register4_sendUnmute(this); + s->register4_sendSignalMinQuality(this); + s->register4_sendStereo(this); + + s->register4_queryTreble(this); + s->register4_queryBass(this); + s->register4_queryBalance(this); + s->register4_querySignalQuality(this); + s->register4_querySignalMinQuality(this); + s->register4_queryHasGoodQuality(this); + s->register4_queryIsStereo(this); + s->register4_queryIsMuted(this); + + + s->register4_sendPlaybackVolume(this); + s->register4_sendCaptureVolume(this); + + s->register4_sendStopCapture(this); + + s->register4_querySoundStreamDescription(this); + s->register4_querySoundStreamRadioStation(this); + s->register4_queryEnumerateSoundStreams(this); + + notifySoundStreamCreated(m_SoundStreamID); + } +} + +void V4LRadio::noticeConnectedSoundClient(ISoundStreamClient::thisInterface *i, bool pointer_valid) +{ + if (i && pointer_valid && i->getSoundStreamClientID() == m_PlaybackMixerID) { + setPlaybackMixer(m_PlaybackMixerID, m_PlaybackMixerChannel); + } + if (i && pointer_valid && i->getSoundStreamClientID() == m_CaptureMixerID) { + setCaptureMixer(m_CaptureMixerID, m_CaptureMixerChannel); + } +} + +// IRadioDevice methods + +bool V4LRadio::setPower (bool on) +{ + return on ? powerOn() : powerOff(); +} + +void V4LRadio::searchMixers(ISoundStreamClient **playback_mixer, ISoundStreamClient **capture_mixer) +{ + if (playback_mixer) { + *playback_mixer = getSoundStreamClientWithID(m_PlaybackMixerID); + if (!*playback_mixer) { + QPtrList<ISoundStreamClient> playback_mixers = queryPlaybackMixers(); + if (!playback_mixers.isEmpty()) + *playback_mixer = playback_mixers.first(); + } + } + if (capture_mixer) { + *capture_mixer = getSoundStreamClientWithID(m_CaptureMixerID); + if (!*capture_mixer) { + QPtrList<ISoundStreamClient> capture_mixers = queryCaptureMixers(); + if (!capture_mixers.isEmpty()) + *capture_mixer = capture_mixers.first(); + } + } +} + + +bool V4LRadio::powerOn () +{ + if (isPowerOn()) + return true; + + radio_init(); + + if (isPowerOn()) { + ISoundStreamClient *playback_mixer = NULL, + *capture_mixer = NULL; + + searchMixers(&playback_mixer, &capture_mixer); + + if (playback_mixer) + playback_mixer->preparePlayback(m_SoundStreamID, m_PlaybackMixerChannel, m_ActivePlayback, false); + if (capture_mixer) + capture_mixer->prepareCapture(m_SoundStreamID, m_CaptureMixerChannel); + + sendStartPlayback(m_SoundStreamID); + float tmp_vol = 0; + queryPlaybackVolume(m_SoundStreamID, tmp_vol); + if (tmp_vol < 0.005) + sendPlaybackVolume(m_SoundStreamID, m_defaultPlaybackVolume); + + if (m_ActivePlayback) { + SoundFormat sf; + sendStartCaptureWithFormat(m_SoundStreamID, sf, sf); + } + + unmute(m_SoundStreamID); + notifyPowerChanged(true); + } + + return true; +} + + +bool V4LRadio::powerOff () +{ + if (! isPowerOn()) + return true; + + queryPlaybackVolume(m_SoundStreamID, m_defaultPlaybackVolume); + if (m_MuteOnPowerOff) + sendMute(m_SoundStreamID, true); + if (m_VolumeZeroOnPowerOff) + sendPlaybackVolume(m_SoundStreamID, 0.0); + mute(m_SoundStreamID); + radio_done(); + + sendStopPlayback(m_SoundStreamID); + sendStopCapture(m_SoundStreamID); + closeSoundStream(m_SoundStreamID); + m_SoundStreamID = createNewSoundStream(m_SoundStreamID, false); + notifySoundStreamCreated(m_SoundStreamID); + + if (isPowerOff()) { + notifyPowerChanged(false); + } + + return true; +} + + +bool V4LRadio::activateStation(const RadioStation &rs) +{ + const FrequencyRadioStation *frs = dynamic_cast<const FrequencyRadioStation*>(&rs); + if (frs == NULL) + return false; + + if (setFrequency(frs->frequency())) { + m_currentStation = *frs; + + if (frs->initialVolume() > 0) + setPlaybackVolume(m_SoundStreamID, frs->initialVolume()); + + return true; + } + + return false; +} + + + +bool V4LRadio::isPowerOn() const +{ + return m_radio_fd >= 0; +} + + +bool V4LRadio::isPowerOff() const +{ + return m_radio_fd < 0; +} + + +SoundStreamID V4LRadio::getSoundStreamID() const +{ + return m_SoundStreamID; +} + + +const RadioStation &V4LRadio::getCurrentStation() const +{ + return m_currentStation; +} + + +const QString &V4LRadio::getDescription() const +{ + return m_caps.description; +} + + +SoundStreamID V4LRadio::getCurrentSoundStreamID() const +{ + return m_SoundStreamID; +} + + + + +bool V4LRadio::setTreble (SoundStreamID id, float t) +{ + if (id != m_SoundStreamID) + return false; + + if (t > 1.0) t = 1.0; + if (t < 0) t = 0.0; + if ((int)rint(m_treble*65535) != (int)rint(t*65535)) { + m_treble = t; + writeAudioInfo(); + notifyTrebleChanged(id, t); + } + return true; +} + + +bool V4LRadio::setBass (SoundStreamID id, float b) +{ + if (id != m_SoundStreamID) + return false; + + if (b > 1.0) b = 1.0; + if (b < 0) b = 0.0; + if ((int)rint(m_bass*65535) != (int)rint(b*65535)) { + m_bass = b; + writeAudioInfo(); + notifyBassChanged(id, b); + } + + return true; +} + + +bool V4LRadio::setBalance (SoundStreamID id, float b) +{ + if (id != m_SoundStreamID) + return false; + + if (b > +1.0) b = +1.0; + if (b < -1.0) b = -1.0; + if ((int)rint(m_balance*32767) != (int)rint(b*32767)) { + m_balance = b; + writeAudioInfo(); + notifyBalanceChanged(id, b); + } + return true; +} + + +bool V4LRadio::setDeviceVolume (float v) +{ + if (v > 1.0) v = 1.0; + if (v < 0) v = 0; + if ((int)rint(m_deviceVolume*65535) != (int)rint(v*65535)) { + m_deviceVolume = v; + writeAudioInfo(); + notifyDeviceVolumeChanged(v); + } + return true; +} + + +bool V4LRadio::mute (SoundStreamID id, bool mute) +{ + if (id != m_SoundStreamID) + return false; + + if (m_muted != mute) { + m_muted = mute; + bool r = writeAudioInfo(); + if (r) + notifyMuted(id, m_muted); + return r; + } + return false; +} + + +bool V4LRadio::unmute (SoundStreamID id, bool unmute) +{ + return mute(id, !unmute); +} + + +bool V4LRadio::setSignalMinQuality (SoundStreamID id, float mq) +{ + if (id != m_SoundStreamID) + return false; + if (rint(mq*100) == rint(m_minQuality*100)) + return true; + + m_minQuality = mq; + notifySignalMinQualityChanged(id, m_minQuality); + return true; +} + + +bool V4LRadio::setStereo(SoundStreamID /*id*/, bool /*b*/) +{ + // FIXME if possible + return false; // we can't do that currently, not even switch stereo to mono +} + + + + +bool V4LRadio::getTreble (SoundStreamID id, float &t) const +{ + if (id != m_SoundStreamID) + return false; + + readAudioInfo(); + t = m_treble; + return true; +} + + +bool V4LRadio::getBass (SoundStreamID id, float &b) const +{ + if (id != m_SoundStreamID) + return false; + + readAudioInfo(); + b = m_bass; + return true; +} + + +bool V4LRadio::getBalance (SoundStreamID id, float &b) const +{ + if (id != m_SoundStreamID) + return false; + + readAudioInfo(); + b = m_balance; + return true; +} + + +float V4LRadio::getDeviceVolume () const +{ + readAudioInfo(); + return m_deviceVolume; +} + + + +bool V4LRadio::getSignalMinQuality(SoundStreamID id, float &q) const +{ + if (id != m_SoundStreamID) + return false; + + q = m_minQuality; + return true; +} + + +bool V4LRadio::getSignalQuality(SoundStreamID id, float &q) const +{ + if (id != m_SoundStreamID) + return false; + + readTunerInfo(); + q = m_signalQuality; + return true; +} + + +bool V4LRadio::hasGoodQuality(SoundStreamID id, bool &good) const +{ + if (id != m_SoundStreamID) + return false; + + float q = 0; + if (getSignalQuality(id, q)) + good = q >= m_minQuality; + return true; +} + + +bool V4LRadio::isStereo(SoundStreamID id, bool &s) const +{ + if (id != m_SoundStreamID) + return false; + + readAudioInfo(); + s = m_stereo; + return true; +} + + +bool V4LRadio::isMuted(SoundStreamID id, bool &m) const +{ + if (id != m_SoundStreamID) + return false; + + readAudioInfo(); + m = m_muted; + return true; +} + + +// ISeekRadio + +bool V4LRadio::toBeginning() +{ + setFrequency(getMinFrequency()); + return true; +} + +bool V4LRadio::toEnd() +{ + setFrequency(getMaxFrequency()); + return true; +} + +bool V4LRadio::startSeekUp() +{ + return startSeek(true); +} + +bool V4LRadio::startSeekDown() +{ + return startSeek(false); +} + +bool V4LRadio::startSeek(bool up) +{ + if (isPowerOn() && m_seekHelper) { + m_seekHelper->start(m_SoundStreamID, up ? SeekHelper::up : SeekHelper::down); + return true; + } else { + return false; + } +} + +bool V4LRadio::stopSeek() +{ + if (m_seekHelper) m_seekHelper->stop(); + return true; +} + +bool V4LRadio::isSeekRunning() const +{ + if (m_seekHelper) + return m_seekHelper->isRunning(); + else + return false; +} + + +bool V4LRadio::isSeekUpRunning() const +{ + if (m_seekHelper) + return m_seekHelper->isRunningUp(); + else + return false; +} + + +bool V4LRadio::isSeekDownRunning() const +{ + if (m_seekHelper) + return m_seekHelper->isRunningDown(); + else + return false; +} + +float V4LRadio::getProgress () const +{ + float min = getMinFrequency(); + float max = getMaxFrequency(); + + return (getFrequency() - min) / (max - min); +} + + +// IFrequencyRadio + +bool V4LRadio::setFrequency(float freq) +{ +// if (isSeekRunning()) +// stopSeek(); + + if (m_currentStation.frequency() == freq) { + return true; + } + + float minf = getMinFrequency(); + float maxf = getMaxFrequency(); + + if (isPowerOn()) { + + bool oldMute = false; + isMuted(m_SoundStreamID, oldMute); + if (!oldMute && !m_ActivePlayback) + mute(m_SoundStreamID); + + + if (!m_tunercache.valid) readTunerInfo(); + float df = m_tunercache.deltaF; + + unsigned long lfreq = (unsigned long) rint(freq / df); + + if (freq > maxf || freq < minf) { + logError("V4LRadio::setFrequency: " + + i18n("invalid frequency %1").arg(QString().setNum(freq))); + if (!oldMute && !m_ActivePlayback) + unmute(m_SoundStreamID); + return false; + } + + int r = -1; + if (m_caps.version == 1) { + r = ioctl(m_radio_fd, VIDIOCSFREQ, &lfreq); + } +#ifdef HAVE_V4L2 + else if (m_caps.version == 2) { + v4l2_frequency tmp; + tmp.tuner = 0; + tmp.type = V4L2_TUNER_RADIO; + tmp.frequency = lfreq; + r = ioctl(m_radio_fd, VIDIOC_S_FREQUENCY, &tmp); + } +#endif + else { + logError("V4LRadio::setFrequency: " + + i18n("don't known how to handle V4L-version %1") + .arg(m_caps.version)); + } + + if (r) { + logError("V4LRadio::setFrequency: " + + i18n("error setting frequency to %1 (%2)") + .arg(QString().setNum(freq)) + .arg(QString().setNum(r))); + // unmute the old radio with the old radio station + if (!oldMute && !m_ActivePlayback) + unmute(m_SoundStreamID); + return false; + } + + // unmute this radio device, because we now have the current + // radio station + if (!oldMute && !m_ActivePlayback) + unmute(m_SoundStreamID); + } + + m_currentStation.setFrequency(freq); + notifyFrequencyChanged(freq, &m_currentStation); + notifyStationChanged(m_currentStation); + notifyProgress((freq - minf) / (maxf - minf)); + notifySoundStreamChanged(m_SoundStreamID); + return true; +} + + +bool V4LRadio::setMinFrequency (float minF) +{ + float oldm = getMinFrequency(); + m_minFrequency = minF; + + float newm = getMinFrequency(); + if (oldm != newm) + notifyMinMaxFrequencyChanged(newm, getMaxFrequency()); + + return true; +} + + +bool V4LRadio::setMaxFrequency (float maxF) +{ + float oldm = getMaxFrequency(); + m_maxFrequency = maxF; + + float newm = getMaxFrequency(); + if (oldm != newm) + notifyMinMaxFrequencyChanged(getMinFrequency(), newm); + + return true; +} + + +bool V4LRadio::setScanStep(float s) +{ + float old = m_scanStep; + m_scanStep = s; + + if (old != s) notifyScanStepChanged(m_scanStep); + return true; +} + + +float V4LRadio::getFrequency() const +{ + return m_currentStation.frequency(); +} + + +float V4LRadio::getMinFrequency() const +{ + return m_minFrequency ? m_minFrequency : getMinDeviceFrequency(); +} + + +float V4LRadio::getMaxFrequency() const +{ + return m_maxFrequency ? m_maxFrequency : getMaxDeviceFrequency(); +} + + +float V4LRadio::getMinDeviceFrequency() const +{ + if (!m_tunercache.valid) + readTunerInfo(); + + return m_tunercache.minF; +} + + +float V4LRadio::getMaxDeviceFrequency() const +{ + if (!m_tunercache.valid) + readTunerInfo(); + + return m_tunercache.maxF; +} + + +float V4LRadio::getScanStep() const +{ + return m_scanStep; +} + + + +// IV4LCfg methods + +bool V4LRadio::setRadioDevice(const QString &s) +{ + if (m_radioDev != s) { + bool p = isPowerOn(); + powerOff(); + m_radioDev = s; + + m_caps = readV4LCaps(m_radioDev); + notifyRadioDeviceChanged(m_radioDev); + notifyDescriptionChanged(m_caps.description); + notifyCapabilitiesChanged(m_caps); + setPower(p); + } + return true; +} + + +bool V4LRadio::setPlaybackMixer(const QString &soundStreamClientID, const QString &ch) +{ + bool change = m_PlaybackMixerID != soundStreamClientID || m_PlaybackMixerChannel != ch; + m_PlaybackMixerID = soundStreamClientID; + m_PlaybackMixerChannel = ch; + + + if (isPowerOn()) { + queryPlaybackVolume(m_SoundStreamID, m_defaultPlaybackVolume); + sendStopPlayback(m_SoundStreamID); + sendReleasePlayback(m_SoundStreamID); + } + + ISoundStreamClient *playback_mixer = NULL; + searchMixers(&playback_mixer, NULL); + if (playback_mixer) + playback_mixer->preparePlayback(m_SoundStreamID, m_PlaybackMixerChannel, m_ActivePlayback, false); + + if (isPowerOn()) { + sendStartPlayback(m_SoundStreamID); + sendPlaybackVolume(m_SoundStreamID, m_defaultPlaybackVolume); + if (m_ActivePlayback) { + SoundFormat sf; + sendStartCaptureWithFormat(m_SoundStreamID, sf, sf); + } + } + + if (change) + notifyPlaybackMixerChanged(soundStreamClientID, ch); + + return true; +} + + +bool V4LRadio::setCaptureMixer(const QString &soundStreamClientID, const QString &ch) +{ + bool change = m_PlaybackMixerID != soundStreamClientID || m_PlaybackMixerChannel != ch; + m_CaptureMixerID = soundStreamClientID; + m_CaptureMixerChannel = ch; + + bool r = false; + SoundFormat sf; + queryIsCaptureRunning(m_SoundStreamID, r, sf); + + float v = 0; + if (isPowerOn() && r) { + queryCaptureVolume(m_SoundStreamID, v); + sendStopCapture(m_SoundStreamID); + sendReleaseCapture(m_SoundStreamID); + } + + ISoundStreamClient *capture_mixer = NULL; + searchMixers(NULL, &capture_mixer); + if (capture_mixer) + capture_mixer->prepareCapture(m_SoundStreamID, m_CaptureMixerChannel); + + if (isPowerOn() && r) { + sendStartCaptureWithFormat(m_SoundStreamID, sf, sf); + sendCaptureVolume(m_SoundStreamID, v); + } + + if (change) + notifyCaptureMixerChanged(soundStreamClientID, ch); + + return true; +} + + +V4LCaps V4LRadio::getCapabilities(QString dev) const +{ + if (dev.isNull()) { + return m_caps; + } else { + return readV4LCaps(dev); + } +} + + +bool V4LRadio::setActivePlayback(bool a) +{ + if (a == m_ActivePlayback) + return true; + + + if (isPowerOn()) { + queryPlaybackVolume(m_SoundStreamID, m_defaultPlaybackVolume); + sendStopPlayback(m_SoundStreamID); + sendReleasePlayback(m_SoundStreamID); + if (m_ActivePlayback) { + sendStopCapture(m_SoundStreamID); + } + } + + m_ActivePlayback = a; + + ISoundStreamClient *playback_mixer = NULL; + searchMixers(&playback_mixer, NULL); + if (playback_mixer) + playback_mixer->preparePlayback(m_SoundStreamID, m_PlaybackMixerChannel, m_ActivePlayback, false); + + if (isPowerOn()) { + sendStartPlayback(m_SoundStreamID); + sendPlaybackVolume(m_SoundStreamID, m_defaultPlaybackVolume); + if (m_ActivePlayback) { + SoundFormat sf; + sendStartCaptureWithFormat(m_SoundStreamID, sf, sf); + } + } + + // FIXME: restart playback/capture + notifyActivePlaybackChanged(m_ActivePlayback); + + return true; +} + +bool V4LRadio::setMuteOnPowerOff(bool a) +{ + if (a != m_MuteOnPowerOff) { + m_MuteOnPowerOff = a; + notifyMuteOnPowerOffChanged(m_MuteOnPowerOff); + } + return true; +} + +bool V4LRadio::setVolumeZeroOnPowerOff(bool a) +{ + if (a != m_VolumeZeroOnPowerOff) { + m_VolumeZeroOnPowerOff = a; + notifyVolumeZeroOnPowerOffChanged(m_VolumeZeroOnPowerOff); + } + return true; +} + +// PluginBase methods + +void V4LRadio::saveState (KConfig *config) const +{ + config->setGroup(QString("v4lradio-") + name()); + + config->writeEntry("RadioDev", m_radioDev); + + config->writeEntry("PlaybackMixerID", m_PlaybackMixerID); + config->writeEntry("PlaybackMixerChannel", m_PlaybackMixerChannel); + config->writeEntry("CaptureMixerID", m_CaptureMixerID); + config->writeEntry("CaptureMixerChannel", m_CaptureMixerChannel); + + config->writeEntry("fMinOverride", m_minFrequency); + config->writeEntry("fMaxOverride", m_maxFrequency); + config->writeEntry("fLastDevMin", m_lastMinDevFrequency); + config->writeEntry("fLastDevMax", m_lastMaxDevFrequency); + + config->writeEntry("defaultPlaybackVolume", m_defaultPlaybackVolume); + + config->writeEntry("signalMinQuality", m_minQuality); + + config->writeEntry("scanStep", m_scanStep); + + config->writeEntry("Frequency", m_currentStation.frequency()); + config->writeEntry("Treble", m_treble); + config->writeEntry("Bass", m_bass); + config->writeEntry("Balance", m_balance); + config->writeEntry("DeviceVolume", m_deviceVolume); + + config->writeEntry("PowerOn", isPowerOn()); + config->writeEntry("UseOldV4L2Calls", m_useOldV4L2Calls); + + config->writeEntry("ActivePlayback", m_ActivePlayback); + config->writeEntry("MuteOnPowerOff", m_MuteOnPowerOff); + config->writeEntry("VolumeZeroOnPowerOff", m_VolumeZeroOnPowerOff); +} + + +void V4LRadio::restoreState (KConfig *config) +{ + BlockProfiler p("V4LRadio::restoreState"); + + config->setGroup(QString("v4lradio-") + name()); + + QString base_devname = "/dev/radio"; + + QStringList testlist (base_devname ); + for (int i = 0; i < 9; ++i) + testlist.append(base_devname + QString::number(i)); + + QString found_devname(QString::null); + for (QValueListConstIterator<QString> it = testlist.begin(); it != testlist.end(); ++it) { + QFile f(*it); + if (f.exists()) { + QFileInfo info(f); + if (info.isReadable() && info.isWritable()) { + found_devname = *it; + break; + } + else { + if (found_devname.isNull()) + found_devname = *it; + logWarning(i18n("Device %1 does exist but is not readable/writable. Please check device permissions.").arg(*it)); + } + } + } + + QString default_devname = found_devname.isNull() ? base_devname : found_devname; + + QString devname = config->readEntry ("RadioDev", default_devname); + + if (found_devname.isNull() && devname == default_devname) { + logError(i18n("Could not find an accessible v4l(2) radio device.")); + } + + setRadioDevice(devname); + + QString PlaybackMixerID = config->readEntry ("PlaybackMixerID", QString::null); + QString PlaybackMixerChannel = config->readEntry ("PlaybackMixerChannel", "Line"); + + QString CaptureMixerID = config->readEntry ("CaptureMixerID", QString::null); + QString CaptureMixerChannel = config->readEntry ("CaptureMixerChannel", "Line"); + + m_ActivePlayback = config->readBoolEntry("ActivePlayback", false); + m_MuteOnPowerOff = config->readBoolEntry("MuteOnPowerOff", false); + m_VolumeZeroOnPowerOff = config->readBoolEntry("VolumeZeroOnPowerOff", false); + + m_lastMinDevFrequency = config->readDoubleNumEntry ("fLastDevMin", 65.0); + m_lastMaxDevFrequency = config->readDoubleNumEntry ("fLastDevMax", 108.0); + m_minFrequency = config->readDoubleNumEntry ("fMinOverride", m_lastMinDevFrequency); + m_maxFrequency = config->readDoubleNumEntry ("fMaxOverride", m_lastMaxDevFrequency); + + m_minQuality = config->readDoubleNumEntry ("signalMinQuality", 0.75); + m_scanStep = config->readDoubleNumEntry ("scanStep", 0.05); + m_defaultPlaybackVolume = config->readDoubleNumEntry ("defaultPlaybackVolume", 0.5); + + setPlaybackMixer(PlaybackMixerID, PlaybackMixerChannel); + setCaptureMixer (CaptureMixerID, CaptureMixerChannel); + notifyDeviceMinMaxFrequencyChanged(m_lastMinDevFrequency, m_lastMaxDevFrequency); + notifyMinMaxFrequencyChanged(m_minFrequency, m_maxFrequency); + notifySignalMinQualityChanged(m_SoundStreamID, m_minQuality); + notifyScanStepChanged(m_scanStep); + notifyActivePlaybackChanged(m_ActivePlayback); + notifyMuteOnPowerOffChanged(m_MuteOnPowerOff); + notifyVolumeZeroOnPowerOffChanged(m_VolumeZeroOnPowerOff); + + BlockProfiler p2("V4LRadio::restoreState2"); + + setFrequency(config->readDoubleNumEntry("Frequency", 88)); + m_restorePowerOn = config->readBoolEntry ("PowerOn", false); + + BlockProfiler p3("V4LRadio::restoreState3"); + + setTreble (m_SoundStreamID, config->readDoubleNumEntry("Treble", 0.5)); + setBass (m_SoundStreamID, config->readDoubleNumEntry("Bass", 0.5)); + setBalance (m_SoundStreamID, config->readDoubleNumEntry("Balance", 0.0)); + setDeviceVolume( config->readDoubleNumEntry("DeviceVolume", 0.9)); + + m_useOldV4L2Calls = config->readBoolEntry("UseOldV4L2Calls", true); + + if (isPowerOff()) + notifyPlaybackVolumeChanged(m_SoundStreamID, m_defaultPlaybackVolume); +} + +void V4LRadio::startPlugin() +{ + PluginBase::startPlugin(); + setPower(m_restorePowerOn); +} + +ConfigPageInfo V4LRadio::createConfigurationPage() +{ + V4LRadioConfiguration *v4lconf = new V4LRadioConfiguration(NULL, m_SoundStreamID); + connectI(v4lconf); + return ConfigPageInfo (v4lconf, + i18n("V4L Radio"), + i18n("V4L Radio Options"), + "package_utilities"); +} + + +AboutPageInfo V4LRadio::createAboutPage() +{ + KAboutData aboutData("kradio", + NULL, + NULL, + I18N_NOOP("V4L/V4L2 Plugin for KRadio." + "<P>" + "Provides Support for V4L/V4L2 based Radio Cards" + "<P>"), + 0, + //KAboutData::License_GPL, + "(c) 2002-2005 Martin Witte, Klas Kalass", + 0, + "http://sourceforge.net/projects/kradio", + 0); + aboutData.addAuthor("Martin Witte", "", "witte@kawo1.rwth-aachen.de"); + aboutData.addAuthor("Klas Kalass", "", "klas.kalass@gmx.de"); + + return AboutPageInfo( + new KRadioAboutWidget(aboutData, KRadioAboutWidget::AbtTabbed), + i18n("V4L/V4L2"), + i18n("V4L/V4L2 Plugin"), + "package_utilities" + ); +} + +//////////////////////////////////////// +// anything else + +void V4LRadio::radio_init() +{ + if (isSeekRunning()) + stopSeek(); + + m_caps = readV4LCaps(m_radioDev); + notifyCapabilitiesChanged(m_caps); + notifyDescriptionChanged(m_caps.description); + +/* m_mixer_fd = open(m_mixerDev, O_RDONLY); + if (m_mixer_fd < 0) { + radio_done(); + + logError("V4LRadio::radio_init: " + + i18n("Cannot open mixer device %1").arg(m_mixerDev)); + return; + } +*/ + m_radio_fd = open(m_radioDev.ascii(), O_RDONLY); + if (m_radio_fd < 0) { + radio_done(); + + logError("V4LRadio::radio_init: " + + i18n("Cannot open radio device %1").arg(m_radioDev)); + return; + } + + readTunerInfo(); + writeAudioInfo(); // set tuner-audio config as used last time + readAudioInfo(); // reread tuner-audio and read-only flags (e.g. stereo) + + // restore frequency + float old = getFrequency(); + m_currentStation.setFrequency(0); + setFrequency(old); + + // read volume level from mixer + // FIXME: do we still need this +/* float v = 0; + getVolume(m_SoundStreamID, v) + setVolume (m_SoundStreamID, v);*/ +} + + +void V4LRadio::radio_done() +{ + if (isSeekRunning()) + stopSeek(); + + if (m_radio_fd >= 0) close (m_radio_fd); +// if (m_mixer_fd >= 0) close (m_mixer_fd); + + m_radio_fd = -1; +// m_mixer_fd = -1; +} + + + + + +#define CAPS_NAME_LEN 127 +V4LCaps V4LRadio::readV4LCaps(const QString &device) const +{ + char buffer[CAPS_NAME_LEN+1]; + int r; + int fd; + + V4LCaps c; + c.description = device; + + fd = open(device.ascii(), O_RDONLY); + + if (fd < 0) { + logError("V4LRadio::readV4LCaps: " + + i18n("cannot open %1").arg(device)); + return c; + } + + video_capability caps; + r = ioctl(fd, VIDIOCGCAP, &caps); + if (r == 0) { + c.version = 1; + + size_t l = sizeof(caps.name); + l = l < CAPS_NAME_LEN ? l : CAPS_NAME_LEN; + memcpy(buffer, caps.name, l); + buffer[l] = 0; + c.description = buffer; + + c.hasMute = false; + c.unsetVolume(); + c.unsetTreble(); + c.unsetBass(); + c.unsetBalance(); + + video_audio audiocaps; + if (0 == ioctl(fd, VIDIOCGAUDIO, &audiocaps)) { + logDebug("V4LRadio::readV4LCaps: " + + i18n("audio caps = %1").arg(QString().setNum(audiocaps.flags))); + if ((audiocaps.flags & VIDEO_AUDIO_MUTABLE) != 0) + c.hasMute = true; + if ((audiocaps.flags & VIDEO_AUDIO_VOLUME) != 0) + c.setVolume (0, 65535); + if ((audiocaps.flags & VIDEO_AUDIO_TREBLE) != 0) + c.setTreble (0, 65535); + if ((audiocaps.flags & VIDEO_AUDIO_BASS) != 0) + c.setBass (0, 65535); + // at least my driver has support for balance, but the bit is not set ... + c.setBalance(0, 65535); + } + } else { + logError("V4LRadio::readV4LCaps: " + + i18n("error reading V4L1 caps")); + } + +#ifdef HAVE_V4L2 + v4l2_capability caps2; + r = ioctl(fd, VIDIOC_QUERYCAP, &caps2); + if (r == 0) { + c.version = 2; + + logDebug(i18n("V4L2 - Version: %1").arg(QString().sprintf("%08X", caps2.version))); + + size_t l = sizeof(caps.name); + l = l < CAPS_NAME_LEN ? l : CAPS_NAME_LEN; + memcpy(buffer, caps.name, l); + buffer[l] = 0; + // c.description = buffer; + + v4l2_queryctrl ctrl; + + c.hasMute = false; + c.unsetVolume(); + c.unsetTreble(); + c.unsetBass(); + c.unsetBalance(); + + ctrl.id = V4L2_CID_AUDIO_MUTE; + if (0 == ioctl(fd, VIDIOC_QUERYCTRL, &ctrl)) + c.hasMute = !(ctrl.flags & V4L2_CTRL_FLAG_DISABLED); + else + logError(i18n("V4L2: Querying mute control failed")); + + ctrl.id = V4L2_CID_AUDIO_VOLUME; + if (0 == ioctl(fd, VIDIOC_QUERYCTRL, &ctrl)) { + if (!(ctrl.flags & V4L2_CTRL_FLAG_DISABLED)) + c.setVolume(ctrl.minimum, ctrl.maximum); + } else { + logError(i18n("V4L2: Querying volume control failed")); + } + + ctrl.id = V4L2_CID_AUDIO_TREBLE; + if (0 == ioctl(fd, VIDIOC_QUERYCTRL, &ctrl)) { + if (!(ctrl.flags & V4L2_CTRL_FLAG_DISABLED)) + c.setTreble(ctrl.minimum, ctrl.maximum); + } else { + logError(i18n("V4L2: Querying treble control failed")); + } + + ctrl.id = V4L2_CID_AUDIO_BASS; + if (0 == ioctl(fd, VIDIOC_QUERYCTRL, &ctrl)) { + if (!(ctrl.flags & V4L2_CTRL_FLAG_DISABLED)) + c.setBass(ctrl.minimum, c.maxBass = ctrl.maximum); + } else { + logError(i18n("V4L2: Querying bass control failed")); + } + + ctrl.id = V4L2_CID_AUDIO_BALANCE; + if (0 == ioctl(fd, VIDIOC_QUERYCTRL, &ctrl)) { + if (!(ctrl.flags & V4L2_CTRL_FLAG_DISABLED)) + c.setBalance(ctrl.minimum, ctrl.maximum); + } else { + logError(i18n("V4L2: Querying balance control failed")); + } + + } else { + logWarning(i18n("V4LRadio::readV4LCaps: Reading V4L2 caps failed")); + } +#endif + if (c.version > 0) { + logInfo(i18n("V4L %1 detected").arg(c.version)); + } else { + logError(i18n("V4L not detected")); + } + + logInfo(c.hasMute ? i18n("Radio is mutable") : i18n("Radio is not mutable")); + logInfo(c.hasVolume ? i18n("Radio has Volume Control") : i18n("Radio has no Volume Control")); + logInfo(c.hasBass ? i18n("Radio has Bass Control") : i18n("Radio has no Bass Control")); + logInfo(c.hasTreble ? i18n("Radio has Treble Control") : i18n("Radio has no Treble Control")); + + close(fd); + return c; +} + + +bool V4LRadio::readTunerInfo() const +{ + if (m_blockReadTuner) return true; + + float oldq = m_signalQuality; + float oldminf = m_tunercache.minF; + float oldmaxf = m_tunercache.maxF; + + if (!m_tunercache.valid) { + m_tunercache.minF = m_lastMinDevFrequency; + m_tunercache.maxF = m_lastMaxDevFrequency; + m_tunercache.deltaF = 1.0/16.0; + m_tunercache.valid = true; + } + + int r = 0; + if (isPowerOn()) { + + // v4l1 + if (m_caps.version == 1) { + + r = ioctl(m_radio_fd, VIDIOCGTUNER, m_tuner); + + if (r == 0) { + if ((m_tuner->flags & VIDEO_TUNER_LOW) != 0) + m_tunercache.deltaF = 1.0 / 16000.0; + m_tunercache.minF = float(m_tuner->rangelow) * m_tunercache.deltaF; + m_tunercache.maxF = float(m_tuner->rangehigh) * m_tunercache.deltaF; + m_tunercache.valid = true; + m_signalQuality = float(m_tuner->signal) / 32767.0; + + } + } +#ifdef HAVE_V4L2 + // v4l2 + else if (m_caps.version == 2) { + + r = ioctl(m_radio_fd, VIDIOC_G_TUNER, m_tuner2); + + if (r == 0) { + if ((m_tuner2->capability & V4L2_TUNER_CAP_LOW) != 0) + m_tunercache.deltaF = 1.0 / 16000.0; + m_tunercache.minF = float(m_tuner2->rangelow) * m_tunercache.deltaF; + m_tunercache.maxF = float(m_tuner2->rangehigh) * m_tunercache.deltaF; + m_tunercache.valid = true; + m_signalQuality = float(m_tuner2->signal) / 32767.0; + } + } +#endif + else { + logError("V4LRadio::readTunerInfo: " + + i18n("don't known how to handle V4L-version %1") + .arg(QString().setNum(m_caps.version))); + } + + if (r != 0) { + m_signalQuality = 0; + logError("V4LRadio::readTunerInfo: " + + i18n("cannot get tuner info (error %1)").arg(QString().setNum(r))); + } + } else { + m_signalQuality = 0; + } + + // prevent loops, if noticeXYZ-method is reading my state + m_blockReadTuner = true; + + if (oldminf != m_tunercache.minF || oldmaxf != m_tunercache.maxF) + notifyDeviceMinMaxFrequencyChanged(m_tunercache.minF, m_tunercache.maxF); + m_lastMinDevFrequency = m_tunercache.minF; + m_lastMaxDevFrequency = m_tunercache.maxF; + + if ( ! m_minFrequency && (oldminf != m_tunercache.minF) + || ! m_maxFrequency && (oldmaxf != m_tunercache.maxF)) + notifyMinMaxFrequencyChanged(getMinFrequency(), getMaxFrequency()); + + + if (m_signalQuality != oldq) + notifySignalQualityChanged(m_SoundStreamID, m_signalQuality); + if ( (m_signalQuality >= m_minQuality) != (oldq >= m_minQuality)) + notifySignalQualityBoolChanged(m_SoundStreamID, m_signalQuality > m_minQuality); + + m_blockReadTuner = false; + + return true; +} + + + +#define V4L2_S_CTRL(what,val) \ + { ctl.value = (val); \ + ctl.id = (what); \ + /* Problem: Current V4L2 development has changed the IOCTL-IDs for VIDIOC_S_CTRL */ \ + /* => we must du "try and error" to figure out what version we should use */ \ + r = ioctl (m_radio_fd, m_useOldV4L2Calls ? VIDIOC_S_CTRL_OLD : VIDIOC_S_CTRL, &ctl); \ + /* in case this did not work, try the other version of the call */ \ + if (r) { \ + r = ioctl (m_radio_fd, !m_useOldV4L2Calls ? VIDIOC_S_CTRL_OLD : VIDIOC_S_CTRL, &ctl); \ + if (!r) m_useOldV4L2Calls = !m_useOldV4L2Calls; \ + } \ + x = x ? x : r; \ + if (r) \ + logError(i18n("error setting %1: %2").arg(#what).arg(QString().setNum(r))); \ + } + +#define V4L2_G_CTRL(what) \ + { ctl.id = (what); \ + r = ioctl (m_radio_fd, VIDIOC_G_CTRL, &ctl); \ + x = x ? x : r; \ + if (r) \ + logError(i18n("error reading %1: %2").arg(#what).arg(QString().setNum(r))); \ + } + + +bool V4LRadio::updateAudioInfo(bool write) const +{ + if (m_blockReadAudio && !write) + return true; + + bool oldStereo = m_stereo; + bool oldMute = m_muted; + int iOldDeviceVolume = m_caps.intGetVolume (m_deviceVolume); + int iOldTreble = m_caps.intGetTreble (m_treble); + int iOldBass = m_caps.intGetBass (m_bass); + int iOldBalance = m_caps.intGetBalance(m_balance); + + if (isPowerOn()) { + int r = 0; + if (m_caps.version == 1) { + m_audio->audio = 0; + if (m_muted) m_audio->flags |= VIDEO_AUDIO_MUTE; + else m_audio->flags &= ~VIDEO_AUDIO_MUTE; + + m_audio->volume = m_caps.intGetVolume (m_deviceVolume); + m_audio->treble = m_caps.intGetTreble (m_treble); + m_audio->bass = m_caps.intGetBass (m_bass); + m_audio->balance = m_caps.intGetBalance(m_balance); + + r = ioctl(m_radio_fd, write ? VIDIOCSAUDIO : VIDIOCGAUDIO, m_audio); + + m_stereo = (r == 0) && ((m_audio->mode & VIDEO_SOUND_STEREO) != 0); + + m_muted = m_caps.hasMute && + ((r != 0) || ((m_audio->flags & VIDEO_AUDIO_MUTE) != 0)); + + /* Some drivers seem to set volumes to zero if they are muted. + Thus we do not reload them if radio is muted */ + if (!m_muted && !write) { + m_deviceVolume = m_caps.hasVolume && !r ? m_caps.floatGetVolume (m_audio->volume) : 1; + m_treble = m_caps.hasTreble && !r ? m_caps.floatGetTreble (m_audio->treble) : 1; + m_bass = m_caps.hasBass && !r ? m_caps.floatGetBass (m_audio->bass) : 1; + m_balance = m_caps.hasBalance && !r ? m_caps.floatGetBalance(m_audio->balance) : 0; + } + } +#ifdef HAVE_V4L2 + else if (m_caps.version == 2) { + v4l2_control ctl; + int x = 0; // x stores first ioctl error + if (write) { + if (m_caps.hasMute) + V4L2_S_CTRL(V4L2_CID_AUDIO_MUTE, m_muted); + if (m_caps.hasTreble) + V4L2_S_CTRL(V4L2_CID_AUDIO_TREBLE, m_caps.intGetTreble(m_treble)); + if (m_caps.hasBass) + V4L2_S_CTRL(V4L2_CID_AUDIO_BASS, m_caps.intGetBass(m_bass)); + if (m_caps.hasBalance) + V4L2_S_CTRL(V4L2_CID_AUDIO_BALANCE, m_caps.intGetBalance(m_balance)); + if (m_caps.hasVolume) + V4L2_S_CTRL(V4L2_CID_AUDIO_VOLUME, m_caps.intGetVolume(m_deviceVolume)); + } else { + if (m_caps.hasMute) + V4L2_G_CTRL(V4L2_CID_AUDIO_MUTE); + m_muted = m_caps.hasMute && ((r != 0) || ctl.value); + + /* Some drivers seem to set volumes to zero if they are muted. + Thus we do not reload them if radio is muted */ + if (!m_muted) { + if (m_caps.hasVolume) + V4L2_G_CTRL(V4L2_CID_AUDIO_VOLUME); + m_deviceVolume = m_caps.hasVolume && !r ? m_caps.floatGetVolume (ctl.value) : 1; + if (m_caps.hasTreble) + V4L2_G_CTRL(V4L2_CID_AUDIO_TREBLE); + m_treble = m_caps.hasTreble && !r ? m_caps.floatGetTreble (ctl.value) : 1; + if (m_caps.hasBass) + V4L2_G_CTRL(V4L2_CID_AUDIO_BASS); + m_bass = m_caps.hasBass && !r ? m_caps.floatGetBass (ctl.value) : 1; + if (m_caps.hasBalance) + V4L2_G_CTRL(V4L2_CID_AUDIO_BALANCE); + m_balance = m_caps.hasBalance&& !r ? m_caps.floatGetBalance(ctl.value) : 0; + } + + r = ioctl (m_radio_fd, VIDIOC_G_TUNER, m_tuner2); + m_stereo = (r == 0) && ((m_tuner2->rxsubchans & V4L2_TUNER_SUB_STEREO) != 0); + x = x ? x : r; + } + r = x; // store first error back to r, used below for error message + } +#endif + else { + logError("V4LRadio::updateAudioInfo: " + + i18n("don't known how to handle V4L-version %1") + .arg(QString().setNum(m_caps.version))); + } + + if (r) { + logError("V4LRadio::updateAudioInfo: " + + i18n("error updating radio audio info (%1): %2") + .arg(write ? i18n("write") : i18n("read")) + .arg(QString().setNum(r))); + return false; + } + } + + // prevent loops, if noticeXYZ-method is reading my state + bool oldBlock = m_blockReadAudio; + m_blockReadAudio = true; + + // send notifications + + if (oldStereo != m_stereo) + notifyStereoChanged(m_SoundStreamID, m_stereo); + if (oldMute != m_muted) + notifyMuted(m_SoundStreamID, m_muted); + if (iOldDeviceVolume != m_caps.intGetVolume(m_deviceVolume)) + notifyDeviceVolumeChanged(m_deviceVolume); + if (iOldTreble != m_caps.intGetTreble(m_treble)) + notifyTrebleChanged(m_SoundStreamID, m_treble); + if (iOldBass != m_caps.intGetBass(m_bass)) + notifyBassChanged(m_SoundStreamID, m_bass); + if (iOldBalance != m_caps.intGetBalance(m_balance)) + notifyBalanceChanged(m_SoundStreamID, m_balance); + + m_blockReadAudio = oldBlock; + + return isPowerOn(); +} + + + + +void V4LRadio::poll() +{ + readTunerInfo(); + readAudioInfo(); +} + + +bool V4LRadio::setPlaybackVolume(SoundStreamID id, float volume) +{ + if (isPowerOff() && id == m_SoundStreamID) { + m_defaultPlaybackVolume = min(max(volume, 0.0), 1.0); + return true; + } else { + return false; + } +} + +bool V4LRadio::getPlaybackVolume(SoundStreamID id, float &volume) const +{ + if (isPowerOff() && id == m_SoundStreamID) { + volume = m_defaultPlaybackVolume; + return true; + } else { + return false; + } +} + + + +bool V4LRadio::getSoundStreamDescription(SoundStreamID id, QString &descr) const +{ + if (id == m_SoundStreamID) { + descr = name() + " - " + m_currentStation.name(); + return true; + } + else { + return false; + } +} + + +bool V4LRadio::getSoundStreamRadioStation(SoundStreamID id, const RadioStation *&rs) const +{ + if (id == m_SoundStreamID) { + rs = &m_currentStation; + return true; + } + else { + return false; + } +} + + +bool V4LRadio::enumerateSoundStreams(QMap<QString, SoundStreamID> &list) const +{ + if (m_SoundStreamID.isValid()) { + QString tmp = QString::null; + getSoundStreamDescription(m_SoundStreamID, tmp); + list[tmp] = m_SoundStreamID; + return true; + } + return false; +} + + +// bool V4LRadio::stopCapture(SoundStreamID id) +// { +// if (id.isValid() && id == m_SoundStreamID && m_ActivePlayback) { +// sendStopPlayback(id); +// return true; +// } +// return false; +// } + +#include "v4lradio.moc" diff --git a/kradio3/plugins/v4lradio/v4lradio.h b/kradio3/plugins/v4lradio/v4lradio.h new file mode 100644 index 0000000..4b86cb5 --- /dev/null +++ b/kradio3/plugins/v4lradio/v4lradio.h @@ -0,0 +1,265 @@ +/*************************************************************************** + v4lradio.h - description + ------------------- + begin : Jan 2002 + copyright : (C) 2002-2005 Ernst Martin Witte, Klas Kalass + email : witte@kawo1.rwth-aachen.de, klas@kde.org + ***************************************************************************/ + +/*************************************************************************** + * * + * 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_V4LRADIO_H +#define KRADIO_V4LRADIO_H + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <qtimer.h> + +#include "../../src/include/radiodevice_interfaces.h" +#include "../../src/include/plugins.h" +#include "../../src/include/frequencyradiostation.h" +#include "../../src/include/frequencyseekhelper.h" +#include "../../src/include/soundstreamclient_interfaces.h" +#include "v4lcfg_interfaces.h" + + +struct video_tuner; +struct video_audio; +#ifdef HAVE_V4L2 +struct v4l2_tuner; +#endif + +class V4LRadio : public QObject, + public PluginBase, + public IRadioDevice, +// public IRadioSound, + public ISeekRadio, + public IFrequencyRadio, + public ISoundStreamClient, + public IV4LCfg +{ +Q_OBJECT +public: + V4LRadio (const QString &name); + virtual ~V4LRadio (); + + virtual bool connectI (Interface *); + virtual bool disconnectI (Interface *); + + virtual QString pluginClassName() const { return "V4LRadio"; } + + virtual const QString &name() const { return PluginBase::name(); } + virtual QString &name() { return PluginBase::name(); } + + // PluginBase + +public: + virtual void saveState (KConfig *) const; + virtual void restoreState (KConfig *); + virtual void startPlugin(); + + virtual ConfigPageInfo createConfigurationPage(); + virtual AboutPageInfo createAboutPage(); + + // IRadioDevice methods + +RECEIVERS: + virtual bool setPower(bool p); + virtual bool powerOn(); + virtual bool powerOff(); + virtual bool activateStation(const RadioStation &rs); + +ANSWERS: + virtual bool isPowerOn() const; + virtual bool isPowerOff() const; + virtual SoundStreamID getSoundStreamID() const; + virtual const RadioStation & getCurrentStation() const; + virtual const QString & getDescription() const; + virtual SoundStreamID getCurrentSoundStreamID() const; + + + // ISeekRadio + +RECEIVERS: + virtual bool toBeginning(); + virtual bool toEnd(); + virtual bool startSeek (bool up); + virtual bool startSeekUp(); + virtual bool startSeekDown(); + virtual bool stopSeek(); + +ANSWERS: + virtual bool isSeekRunning() const; + virtual bool isSeekUpRunning() const; + virtual bool isSeekDownRunning() const; + virtual float getProgress () const; + + + // IFrequencyRadio + +RECEIVERS: + virtual bool setFrequency(float f); + virtual bool setMinFrequency(float mf); + virtual bool setMaxFrequency(float mf); + virtual bool setScanStep(float s); + +ANSWERS: + virtual float getFrequency() const; + virtual float getMinFrequency() const; + virtual float getMinDeviceFrequency() const; + virtual float getMaxFrequency() const; + virtual float getMaxDeviceFrequency() const; + virtual float getScanStep() const; + + + // ISoundStreamClient: mixer functions + + +RECEIVERS: + void noticeConnectedI (ISoundStreamServer *s, bool pointer_valid); + void noticeConnectedSoundClient(ISoundStreamClient::thisInterface *i, bool pointer_valid); + + bool setTreble (SoundStreamID, float v); + bool setBass (SoundStreamID, float v); + bool setBalance (SoundStreamID, float v); + bool mute (SoundStreamID, bool mute = true); + bool unmute (SoundStreamID, bool unmute = true); + bool setSignalMinQuality(SoundStreamID, float q); + bool setStereo(SoundStreamID, bool s); + + bool getTreble(SoundStreamID, float &v) const; + bool getBass (SoundStreamID, float &v) const; + bool getBalance (SoundStreamID, float &b) const; + bool getSignalQuality(SoundStreamID, float &q) const; + bool getSignalMinQuality(SoundStreamID, float &q) const; + bool hasGoodQuality(SoundStreamID, bool &) const; + bool isStereo(SoundStreamID, bool &s) const; + bool isMuted(SoundStreamID, bool &m) const; + + // ISoundStreamClient: generic stream handling (broadcasts) + +RECEIVERS: + + bool getSoundStreamDescription(SoundStreamID id, QString &descr) const; + bool getSoundStreamRadioStation(SoundStreamID id, const RadioStation *&rs) const; + bool enumerateSoundStreams(QMap<QString, SoundStreamID> &list) const; + +// bool stopCapture(SoundStreamID id); // if active playback also call stopPlayback + + + // IV4LCfg +RECEIVERS: + bool setRadioDevice (const QString &s); + bool setPlaybackMixer(const QString &soundStreamClientID, const QString &ch); + bool setCaptureMixer (const QString &soundStreamClientID, const QString &ch); + bool setDeviceVolume (float v); + bool setActivePlayback(bool a); + bool setMuteOnPowerOff(bool a); + bool setVolumeZeroOnPowerOff(bool a); + + // if the radio is powered off, we will handle the volume by changing m_defaultPlaybackVolume + bool setPlaybackVolume(SoundStreamID id, float volume); + bool getPlaybackVolume(SoundStreamID id, float &volume) const; + +ANSWERS: + const QString &getRadioDevice () const { return m_radioDev; } + const QString &getPlaybackMixerID () const { return m_PlaybackMixerID; } + const QString &getCaptureMixerID () const { return m_CaptureMixerID; } + const QString &getPlaybackMixerChannel() const { return m_PlaybackMixerChannel; } + const QString &getCaptureMixerChannel () const { return m_CaptureMixerChannel; } + float getDeviceVolume () const; + V4LCaps getCapabilities(QString dev = QString::null) const; + + bool getActivePlayback() const { return m_ActivePlayback; } + bool getMuteOnPowerOff() const { return m_MuteOnPowerOff; } + bool getVolumeZeroOnPowerOff() const { return m_VolumeZeroOnPowerOff; } + + // anything else + +protected slots: + void poll(); + +protected: + V4LCaps readV4LCaps(const QString &device) const; + void radio_init(); + void radio_done(); + + bool readTunerInfo() const; + bool updateAudioInfo(bool write) const; + bool readAudioInfo() const { return updateAudioInfo(false); } + bool writeAudioInfo() const { return updateAudioInfo(true); } + + void searchMixers(ISoundStreamClient **playback_mixer, ISoundStreamClient **capture_mixer); + +protected: + + FrequencyRadioStation m_currentStation; + mutable float m_treble; + mutable float m_bass; + mutable float m_balance; + mutable float m_deviceVolume; + mutable bool m_muted; + mutable float m_signalQuality; + mutable bool m_stereo; + + float m_minQuality; + float m_minFrequency; + float m_maxFrequency; + mutable float m_lastMinDevFrequency; + mutable float m_lastMaxDevFrequency; + + float m_defaultPlaybackVolume; + + FrequencySeekHelper *m_seekHelper; + float m_scanStep; + + V4LCaps m_caps; + QString m_radioDev; + int m_radio_fd; + + mutable bool m_useOldV4L2Calls; + + + mutable struct video_audio *m_audio; + mutable struct video_tuner *m_tuner; +#ifdef HAVE_V4L2 + mutable struct v4l2_tuner *m_tuner2; +#endif + + QTimer m_pollTimer; + + struct TunerCache { + bool valid; + float deltaF; + float minF, maxF; + TunerCache() { valid = false; deltaF = minF = maxF = 0; } + }; + mutable struct TunerCache m_tunercache; + + + mutable bool m_blockReadTuner, + m_blockReadAudio; + + SoundStreamID m_SoundStreamID; + QString m_PlaybackMixerID; + QString m_CaptureMixerID; + QString m_PlaybackMixerChannel; + QString m_CaptureMixerChannel; + + bool m_ActivePlayback; + bool m_MuteOnPowerOff; + bool m_VolumeZeroOnPowerOff; + + bool m_restorePowerOn; +}; + +#endif |