diff options
author | Timothy Pearson <kb9vqf@pearsoncomputing.net> | 2013-02-01 17:25:34 -0600 |
---|---|---|
committer | Timothy Pearson <kb9vqf@pearsoncomputing.net> | 2013-02-01 17:25:34 -0600 |
commit | 48906a623383ab5222541ae048e99dd039b62a9a (patch) | |
tree | 1c5f588e90899bb1301f79cf97b8f6ddc0b1c367 /tderadio3/plugins/streaming | |
parent | a1e6ce502c334194d31a0b78b11b77e9532da64b (diff) | |
download | tderadio-48906a623383ab5222541ae048e99dd039b62a9a.tar.gz tderadio-48906a623383ab5222541ae048e99dd039b62a9a.zip |
Fix FTBFS
Diffstat (limited to 'tderadio3/plugins/streaming')
17 files changed, 2970 insertions, 0 deletions
diff --git a/tderadio3/plugins/streaming/Makefile.am b/tderadio3/plugins/streaming/Makefile.am new file mode 100644 index 0000000..0e5ed11 --- /dev/null +++ b/tderadio3/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/tderadio3/plugins/streaming/icons/Makefile.am b/tderadio3/plugins/streaming/icons/Makefile.am new file mode 100644 index 0000000..b3f2583 --- /dev/null +++ b/tderadio3/plugins/streaming/icons/Makefile.am @@ -0,0 +1,2 @@ +icons_ICON = AUTO +iconsdir = $(kde_datadir)/kradio/icons diff --git a/tderadio3/plugins/streaming/icons/hi16-action-tderadio_streaming.png b/tderadio3/plugins/streaming/icons/hi16-action-tderadio_streaming.png Binary files differnew file mode 100644 index 0000000..b7cec00 --- /dev/null +++ b/tderadio3/plugins/streaming/icons/hi16-action-tderadio_streaming.png diff --git a/tderadio3/plugins/streaming/icons/hi22-action-tderadio_streaming.png b/tderadio3/plugins/streaming/icons/hi22-action-tderadio_streaming.png Binary files differnew file mode 100644 index 0000000..184c283 --- /dev/null +++ b/tderadio3/plugins/streaming/icons/hi22-action-tderadio_streaming.png diff --git a/tderadio3/plugins/streaming/icons/hi32-action-tderadio_streaming.png b/tderadio3/plugins/streaming/icons/hi32-action-tderadio_streaming.png Binary files differnew file mode 100644 index 0000000..0253e79 --- /dev/null +++ b/tderadio3/plugins/streaming/icons/hi32-action-tderadio_streaming.png diff --git a/tderadio3/plugins/streaming/icons/hi48-action-tderadio_streaming.png b/tderadio3/plugins/streaming/icons/hi48-action-tderadio_streaming.png Binary files differnew file mode 100644 index 0000000..e5dd54b --- /dev/null +++ b/tderadio3/plugins/streaming/icons/hi48-action-tderadio_streaming.png diff --git a/tderadio3/plugins/streaming/icons/hi64-action-tderadio_streaming.png b/tderadio3/plugins/streaming/icons/hi64-action-tderadio_streaming.png Binary files differnew file mode 100644 index 0000000..eb8d540 --- /dev/null +++ b/tderadio3/plugins/streaming/icons/hi64-action-tderadio_streaming.png diff --git a/tderadio3/plugins/streaming/po/Makefile.am b/tderadio3/plugins/streaming/po/Makefile.am new file mode 100644 index 0000000..e1b5685 --- /dev/null +++ b/tderadio3/plugins/streaming/po/Makefile.am @@ -0,0 +1,2 @@ +PACKAGE = kradio-streaming +POFILES = AUTO diff --git a/tderadio3/plugins/streaming/po/de.po b/tderadio3/plugins/streaming/po/de.po new file mode 100644 index 0000000..84459b0 --- /dev/null +++ b/tderadio3/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 "TDERadio Streaming Plugin" +msgstr "TDERadio 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/tderadio3/plugins/streaming/po/ru.po b/tderadio3/plugins/streaming/po/ru.po new file mode 100644 index 0000000..c5025f6 --- /dev/null +++ b/tderadio3/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 "TDERadio Streaming Plugin" +msgstr "Модуль сетевого вещания для TDERadio" + +#: 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/tderadio3/plugins/streaming/streaming-configuration-ui.ui b/tderadio3/plugins/streaming/streaming-configuration-ui.ui new file mode 100644 index 0000000..28f0d98 --- /dev/null +++ b/tderadio3/plugins/streaming/streaming-configuration-ui.ui @@ -0,0 +1,777 @@ +<!DOCTYPE UI><UI version="3.3" stdsetdef="1"> +<class>StreamingConfigurationUI</class> +<widget class="TQWidget"> + <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="TQLayoutWidget" row="0" column="0"> + <property name="name"> + <cstring>layout48</cstring> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="TDEListView" 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="TDEListView" 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="TQLabel" row="0" column="2"> + <property name="name"> + <cstring>textLabel1_2</cstring> + </property> + <property name="text"> + <string>Capture URLs</string> + </property> + </widget> + <widget class="TQLabel" row="0" column="0"> + <property name="name"> + <cstring>textLabel1</cstring> + </property> + <property name="text"> + <string>Playback URLs</string> + </property> + </widget> + <widget class="TQLayoutWidget" row="1" column="3"> + <property name="name"> + <cstring>layout38_2</cstring> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="TQPushButton"> + <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="TQPushButton"> + <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="TQPushButton"> + <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="TQPushButton"> + <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="TQLayoutWidget" row="1" column="1"> + <property name="name"> + <cstring>layout38</cstring> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="TQPushButton"> + <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="TQPushButton"> + <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="TQPushButton"> + <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="TQPushButton"> + <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="TQGroupBox" 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="TQLabel" row="3" column="0"> + <property name="name"> + <cstring>lableBits</cstring> + </property> + <property name="text"> + <string>Sample Bits</string> + </property> + </widget> + <widget class="TQLabel" row="5" column="0"> + <property name="name"> + <cstring>lableChannels</cstring> + </property> + <property name="text"> + <string>Channels</string> + </property> + </widget> + <widget class="TQLabel" 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="TQLabel" row="0" column="0"> + <property name="name"> + <cstring>labelRate_2</cstring> + </property> + <property name="text"> + <string>Buffer Size</string> + </property> + </widget> + <widget class="TQLabel" row="1" column="0"> + <property name="name"> + <cstring>labelRate_2_2</cstring> + </property> + <property name="text"> + <string>Format</string> + </property> + </widget> + <widget class="TQLabel" 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/tderadio3/plugins/streaming/streaming-configuration.cpp b/tderadio3/plugins/streaming/streaming-configuration.cpp new file mode 100644 index 0000000..2c519db --- /dev/null +++ b/tderadio3/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 <tqcheckbox.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 (TQWidget *parent, StreamingDevice *streamer) + : StreamingConfigurationUI(parent), + m_ignore_updates(false), + m_dirty(true), + m_StreamingDevice(streamer) +{ + connect(m_pbNewPlaybackURL, TQT_SIGNAL(clicked()), this, TQT_SLOT(slotNewPlaybackChannel())); + connect(m_pbDeletePlaybackURL, TQT_SIGNAL(clicked()), this, TQT_SLOT(slotDeletePlaybackChannel())); + connect(m_pbUpPlaybackURL, TQT_SIGNAL(clicked()), this, TQT_SLOT(slotUpPlaybackChannel())); + connect(m_pbDownPlaybackURL, TQT_SIGNAL(clicked()), this, TQT_SLOT(slotDownPlaybackChannel())); + connect(m_ListPlaybackURLs, TQT_SIGNAL(selectionChanged()), this, TQT_SLOT(slotPlaybackSelectionChanged())); + connect(m_ListPlaybackURLs, TQT_SIGNAL(itemRenamed(TQListViewItem *)), this, TQT_SLOT(slotSetDirty())); + + connect(m_pbNewCaptureURL, TQT_SIGNAL(clicked()), this, TQT_SLOT(slotNewCaptureChannel())); + connect(m_pbDeleteCaptureURL, TQT_SIGNAL(clicked()), this, TQT_SLOT(slotDeleteCaptureChannel())); + connect(m_pbUpCaptureURL, TQT_SIGNAL(clicked()), this, TQT_SLOT(slotUpCaptureChannel())); + connect(m_pbDownCaptureURL, TQT_SIGNAL(clicked()), this, TQT_SLOT(slotDownCaptureChannel())); + connect(m_ListCaptureURLs, TQT_SIGNAL(selectionChanged()), this, TQT_SLOT(slotCaptureSelectionChanged())); + connect(m_ListCaptureURLs, TQT_SIGNAL(itemRenamed(TQListViewItem *)), this, TQT_SLOT(slotSetDirty())); + + connect(m_cbBits, TQT_SIGNAL(activated(int)), this, TQT_SLOT(slotUpdateSoundFormat())); + connect(m_cbChannels, TQT_SIGNAL(activated(int)), this, TQT_SLOT(slotUpdateSoundFormat())); + connect(m_cbEndianess, TQT_SIGNAL(activated(int)), this, TQT_SLOT(slotUpdateSoundFormat())); + connect(m_cbFormat, TQT_SIGNAL(activated(int)), this, TQT_SLOT(slotUpdateSoundFormat())); + connect(m_cbRate, TQT_SIGNAL(activated(int)), this, TQT_SLOT(slotUpdateSoundFormat())); + connect(m_cbSign, TQT_SIGNAL(activated(int)), this, TQT_SLOT(slotUpdateSoundFormat())); + connect(m_sbBufferSize, TQT_SIGNAL(valueChanged(int)), this, TQT_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); + + TQListViewItem *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 TQStringList &playbackChannels = m_StreamingDevice->getPlaybackChannels(); + const TQStringList &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; + TQString url; + m_StreamingDevice->getPlaybackStreamOptions(playbackChannels[i], url, sf, buffer_size); + m_PlaybackSoundFormats.append(sf); + m_PlaybackBufferSizes.append(buffer_size); + + TQListViewItem *item = new TQListViewItem(m_ListPlaybackURLs, m_ListPlaybackURLs->lastChild()); + item->setText(0, TQString::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; + TQString url; + m_StreamingDevice->getCaptureStreamOptions(captureChannels[i], url, sf, buffer_size); + m_CaptureSoundFormats.append(sf); + m_CaptureBufferSizes.append(buffer_size); + + TQListViewItem *item = new TQListViewItem(m_ListCaptureURLs, m_ListCaptureURLs->lastChild()); + item->setText(0, TQString::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(); + TQListViewItem *item = new TQListViewItem(m_ListPlaybackURLs, m_ListPlaybackURLs->lastChild()); + item->setText(0, TQString::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(); + TQListViewItem *item = m_ListPlaybackURLs->selectedItem(); + if (item) { + int idx = 0; + TQListViewItem *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, TQString::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(); + TQListViewItem *prev = NULL; + TQListViewItem *i = m_ListPlaybackURLs->firstChild(); + TQListViewItem *item = m_ListPlaybackURLs->selectedItem(); + int idx = 0; + for (; i && i != item; i = i->nextSibling(), ++idx) { + prev = i; + } + if (prev && item) { + TQString 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(); + TQListViewItem *item = m_ListPlaybackURLs->selectedItem(); + TQListViewItem *next = item ? item->nextSibling() : NULL; + TQListViewItem *i = m_ListPlaybackURLs->firstChild(); + int idx = 0; + for (; i && i != item; i = i->nextSibling()) { + ++idx; + } + if (next && item) { + TQString 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(); + TQListViewItem *item = new TQListViewItem(m_ListCaptureURLs, m_ListCaptureURLs->lastChild()); + item->setText(0, TQString::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(); + TQListViewItem *item = m_ListCaptureURLs->selectedItem(); + if (item) { + int idx = 0; + TQListViewItem *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, TQString::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(); + TQListViewItem *prev = NULL; + TQListViewItem *i = m_ListCaptureURLs->firstChild(); + TQListViewItem *item = m_ListCaptureURLs->selectedItem(); + int idx = 0; + for (; i && i != item; i = i->nextSibling(), ++idx) { + prev = i; + } + if (prev && item) { + TQString 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(); + TQListViewItem *item = m_ListCaptureURLs->selectedItem(); + TQListViewItem *next = item ? item->nextSibling() : NULL; + TQListViewItem *i = m_ListCaptureURLs->firstChild(); + int idx = 0; + for (; i && i != item; i = i->nextSibling()) { + ++idx; + } + if (next && item) { + TQString 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() +{ + TQListViewItem *item = m_ListPlaybackURLs->selectedItem(); + bool up_possible = false; + bool down_possible = false; + if (item) { + int idx = 0; + TQListViewItem *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); + } + TQListViewItem *playback_item = m_ListPlaybackURLs->selectedItem(); + TQListViewItem *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() +{ + TQListViewItem *item = m_ListCaptureURLs->selectedItem(); + bool up_possible = false; + bool down_possible = false; + if (item) { + int idx = 0; + TQListViewItem *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); + } + TQListViewItem *playback_item = m_ListPlaybackURLs->selectedItem(); + TQListViewItem *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(); + TQListViewItem *playback_item = m_ListPlaybackURLs->selectedItem(); + TQListViewItem *capture_item = m_ListCaptureURLs->selectedItem(); + if (playback_item) { + int idx = 0; + TQListViewItem *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; + TQListViewItem *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/tderadio3/plugins/streaming/streaming-configuration.h b/tderadio3/plugins/streaming/streaming-configuration.h new file mode 100644 index 0000000..c352f6a --- /dev/null +++ b/tderadio3/plugins/streaming/streaming-configuration.h @@ -0,0 +1,98 @@ +/*************************************************************************** + 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 (TQWidget *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 ; + + + TQValueList<SoundFormat> m_PlaybackSoundFormats, m_CaptureSoundFormats; + TQValueList<int> m_PlaybackBufferSizes, m_CaptureBufferSizes; + + bool m_ignore_updates; + bool m_dirty; + StreamingDevice *m_StreamingDevice; + +}; + +#endif diff --git a/tderadio3/plugins/streaming/streaming-job.cpp b/tderadio3/plugins/streaming/streaming-job.cpp new file mode 100644 index 0000000..0d0a5f5 --- /dev/null +++ b/tderadio3/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 <tdeio/job.h> + + +StreamingJob::StreamingJob() + : TQObject(), + m_URL(TQString()), + 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 TQString &_URL, const SoundFormat &_SoundFormat, size_t _bufferSize) + : TQObject(), + 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) + : TQObject(), + 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 TQString &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 = TDEIO::put(m_URL, -1, true, false, false); + if (!m_KIO_Job) + return false; + m_KIO_Job->setAsyncDataEnabled(true); + connect (m_KIO_Job, TQT_SIGNAL(dataReq(TDEIO::Job *job, TQByteArray &data)), + this, TQT_SLOT(slotWriteData (TDEIO::Job *job, TQByteArray &data))); + connect (m_KIO_Job, TQT_SIGNAL(result(TDEIO::Job *)), + this, TQT_SLOT(slotIOJobResult(TDEIO::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 = TDEIO::get(m_URL, false, false); + if (!m_KIO_Job) + return false; + m_KIO_Job->setAsyncDataEnabled(true); + connect (m_KIO_Job, TQT_SIGNAL(data(TDEIO::Job *, const TQByteArray &)), + this, TQT_SLOT(slotReadData(TDEIO::Job *, const TQByteArray &))); + connect (m_KIO_Job, TQT_SIGNAL(result(TDEIO::Job *)), + this, TQT_SLOT(slotIOJobResult(TDEIO::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 (TDEIO::Job */*job*/, const TQByteArray &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 (TDEIO::Job */*job*/, TQByteArray &) +{ + size_t size = m_Buffer.getFillSize(); + if (size) { + char *buf = new char [size]; + size = m_Buffer.takeData(buf, size); + TQByteArray 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 (TDEIO::Job *job) +{ + if (job && job->error()) { + emit logStreamError(m_URL, job->errorString()); + } +} + +#include "streaming-job.moc" + diff --git a/tderadio3/plugins/streaming/streaming-job.h b/tderadio3/plugins/streaming/streaming-job.h new file mode 100644 index 0000000..715d71c --- /dev/null +++ b/tderadio3/plugins/streaming/streaming-job.h @@ -0,0 +1,101 @@ +/*************************************************************************** + 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 <tqobject.h> + +#include <tdeio/jobclasses.h> + +class StreamingJob : public TQObject +{ +Q_OBJECT + +public: + StreamingJob(); + StreamingJob(const TQString &_URL, const SoundFormat &_SoundFormat, size_t _bufferSize); + StreamingJob(const StreamingJob &c); + + virtual ~StreamingJob(); + + const TQString &getURL() const { return m_URL; } + const SoundFormat &getSoundFormat() const { return m_SoundFormat; } + int getBufferSize() const { return m_BufferSize; } + + void setURL(const TQString &); + 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 (TDEIO::Job *job, const TQByteArray &data); + void slotWriteData (TDEIO::Job *job, TQByteArray &data); + void slotIOJobResult (TDEIO::Job *job); + +signals: + + void logStreamError(const KURL &url, const TQString &s); + void logStreamWarning(const KURL &url, const TQString &s); + +protected: + + bool startGetJob(); + bool startPutJob(); + + + TQString m_URL; + SoundFormat m_SoundFormat; + + size_t m_BufferSize; + RingBuffer m_Buffer; + + unsigned m_OpenCounter; + TQ_UINT64 m_StreamPos; + time_t m_StartTime; + + size_t m_SkipCount; + + TDEIO::TransferJob *m_KIO_Job; + bool m_capturing; +}; + + + +#endif diff --git a/tderadio3/plugins/streaming/streaming.cpp b/tderadio3/plugins/streaming/streaming.cpp new file mode 100644 index 0000000..1d49f65 --- /dev/null +++ b/tderadio3/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 TQString &name) + : TQObject(NULL, NULL), + PluginBase(name, i18n("TDERadio 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 (TDEConfig *c) const +{ + c->setGroup(TQString("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) { + TQString 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-" + TQString::number(i), c); + c->writeEntry("playback-channel-" + TQString::number(i) + "-url", url.url()); + c->writeEntry("playback-channel-" + TQString::number(i) + "-buffer-size", buffer_size); + } + + c->writeEntry("capture-channels", m_CaptureChannelList.size()); + for (unsigned int i = 0; i < m_CaptureChannelList.size(); ++i) { + TQString 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-" + TQString::number(i), c); + c->writeEntry("capture-channel-" + TQString::number(i) + "-url", url.url()); + c->writeEntry("capture-channel-" + TQString::number(i) + "-buffer-size", buffer_size); + } +} + +void StreamingDevice::restoreState (TDEConfig *c) +{ + c->setGroup(TQString("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-" + TQString::number(i), c); + TQString url = c->readEntry("playback-channel-" + TQString::number(i) + "-url", TQString()); + size_t buffer_size = c->readNum64Entry("playback-channel-" + TQString::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-" + TQString::number(i), c); + TQString url = c->readEntry("capture-channel-" + TQString::number(i) + "-url", TQString()); + size_t buffer_size = c->readNum64Entry("capture-channel-" + TQString::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); + TQObject::connect(this, TQT_SIGNAL(sigUpdateConfig()), conf, TQT_SLOT(slotUpdateConfig())); + return ConfigPageInfo (conf, + i18n("Streaming"), + i18n("Streaming Device Options"), + "kradio_streaming"); +} + + +AboutPageInfo StreamingDevice::createAboutPage() +{ + return AboutPageInfo(); +} + + + +bool StreamingDevice::preparePlayback(SoundStreamID id, const TQString &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 TQString &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 TQStringList &StreamingDevice::getPlaybackChannels() const +{ + return m_PlaybackChannelList; +} + + +const TQStringList &StreamingDevice::getCaptureChannels() const +{ + return m_CaptureChannelList; +} + + +TQString StreamingDevice::getSoundStreamClientDescription() const +{ + return i18n("Streaming Device %1").arg(PluginBase::name()); +} + + +void StreamingDevice::logStreamError(const KURL &url, const TQString &s) +{ + logError(i18n("Streaming Device %1, %2: %3").arg(name()).arg(url.url()).arg(s)); +} + +void StreamingDevice::logStreamWarning(const KURL &url, const TQString &s) +{ + logWarning(i18n("Streaming Device %1, %2: %3").arg(name()).arg(url.url()).arg(s)); +} + + +bool StreamingDevice::getPlaybackStreamOptions(const TQString &channel, TQString &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 TQString &channel, TQString &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 TQString &url, const SoundFormat &sf, size_t buffer_size, bool notification_enabled) +{ + StreamingJob *x = new StreamingJob(url, sf, buffer_size); + connect(x, TQT_SIGNAL(logStreamError(const KURL &, const TQString &)), + this, TQT_SLOT (logStreamError(const KURL &, const TQString &))); + + m_PlaybackChannelList.append(url); + m_PlaybackChannels.insert(url, x); + if (notification_enabled) { + notifyPlaybackChannelsChanged(m_SoundStreamClientID, m_PlaybackChannelList); + } +} + + +void StreamingDevice::addCaptureStream (const TQString &url, const SoundFormat &sf, size_t buffer_size, bool notification_enabled) +{ + StreamingJob *x = new StreamingJob(url, sf, buffer_size); + connect(x, TQT_SIGNAL(logStreamError(const KURL &, const TQString &)), + this, TQT_SLOT (logStreamError(const KURL &, const TQString &))); + + m_CaptureChannelList.append(url); + m_CaptureChannels.insert(url, x); + if (notification_enabled) { + notifyCaptureChannelsChanged(m_SoundStreamClientID, m_CaptureChannelList); + } +} + + +#include "streaming.moc" diff --git a/tderadio3/plugins/streaming/streaming.h b/tderadio3/plugins/streaming/streaming.h new file mode 100644 index 0000000..df55ff8 --- /dev/null +++ b/tderadio3/plugins/streaming/streaming.h @@ -0,0 +1,146 @@ +/*************************************************************************** + 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 <tqobject.h> +#include <tqdict.h> + +class StreamingJob; + +class StreamingDevice : public TQObject, + public PluginBase, + public ISoundStreamClient +{ +Q_OBJECT + + +public: + StreamingDevice (const TQString &name); + virtual ~StreamingDevice (); + + virtual bool connectI(Interface *i); + virtual bool disconnectI(Interface *i); + + bool getPlaybackStreamOptions(const TQString &channel, TQString &url, SoundFormat &sf, size_t &buffer_size) const; + bool getCaptureStreamOptions (const TQString &channel, TQString &url, SoundFormat &sf, size_t &buffer_size) const; + + void resetPlaybackStreams(bool notification_enabled = true); + void resetCaptureStreams(bool notification_enabled = true); + void addPlaybackStream(const TQString &url, const SoundFormat &sf, size_t buffer_size, bool notification_enabled = true); + void addCaptureStream (const TQString &url, const SoundFormat &sf, size_t buffer_size, bool notification_enabled = true); + + // PluginBase + +public: + virtual void saveState (TDEConfig *) const; + virtual void restoreState (TDEConfig *); + + virtual TQString pluginClassName() const { return "StreamingDevice"; } + + virtual const TQString &name() const { return PluginBase::name(); } + virtual TQString &name() { return PluginBase::name(); } + + virtual ConfigPageInfo createConfigurationPage(); + virtual AboutPageInfo createAboutPage(); + + // ISoundStreamClient: direct device access + +RECEIVERS: + void noticeConnectedI (ISoundStreamServer *s, bool pointer_valid); + bool preparePlayback(SoundStreamID id, const TQString &channel, bool active_mode, bool start_immediately); + bool prepareCapture(SoundStreamID id, const TQString &channel); + bool releasePlayback(SoundStreamID id); + bool releaseCapture(SoundStreamID id); + +ANSWERS: + bool supportsPlayback() const; + bool supportsCapture() const; + + TQString getSoundStreamClientDescription() const; + + // ISoundStreamClient: mixer access + +protected: + +ANSWERS: + const TQStringList &getPlaybackChannels() const; + const TQStringList &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 TQString &s); + void logStreamWarning(const KURL &url, const TQString &s); + +signals: + + void sigUpdateConfig(); + +protected: + + TQStringList m_PlaybackChannelList, + m_CaptureChannelList; + + TQDict<StreamingJob> + m_PlaybackChannels, + m_CaptureChannels; + + TQMap<SoundStreamID, TQString> + m_AllPlaybackStreams, + m_AllCaptureStreams, + m_EnabledPlaybackStreams, + m_EnabledCaptureStreams; +}; + + + +#endif |