diff options
| author | trialuser02 <trialuser02@90c681e8-e032-0410-971d-27865f9a5e38> | 2017-01-03 12:33:54 +0000 |
|---|---|---|
| committer | trialuser02 <trialuser02@90c681e8-e032-0410-971d-27865f9a5e38> | 2017-01-03 12:33:54 +0000 |
| commit | 28dda78e5036bae2bd317decf950ba9f6caea780 (patch) | |
| tree | ad0798e5949177d0f179ec648a2e98e20c726298 /src/plugins/Output/shout | |
| parent | 94f328c91406dfe16583f3b203a21daa0def4db9 (diff) | |
| download | qmmp-28dda78e5036bae2bd317decf950ba9f6caea780.tar.gz qmmp-28dda78e5036bae2bd317decf950ba9f6caea780.tar.bz2 qmmp-28dda78e5036bae2bd317decf950ba9f6caea780.zip | |
added icecast output plugin (#47)
git-svn-id: http://svn.code.sf.net/p/qmmp-dev/code/trunk/qmmp@6929 90c681e8-e032-0410-971d-27865f9a5e38
Diffstat (limited to 'src/plugins/Output/shout')
| -rw-r--r-- | src/plugins/Output/shout/shoutclient.cpp | 101 | ||||
| -rw-r--r-- | src/plugins/Output/shout/shoutclient.h | 51 | ||||
| -rw-r--r-- | src/plugins/Output/shout/shoutoutput.cpp | 193 | ||||
| -rw-r--r-- | src/plugins/Output/shout/shoutoutput.h | 53 |
4 files changed, 398 insertions, 0 deletions
diff --git a/src/plugins/Output/shout/shoutclient.cpp b/src/plugins/Output/shout/shoutclient.cpp new file mode 100644 index 000000000..45c5d5614 --- /dev/null +++ b/src/plugins/Output/shout/shoutclient.cpp @@ -0,0 +1,101 @@ +/*************************************************************************** + * Copyright (C) 2017 by Ilya Kotov * + * forkotov02@hotmail.ru * + * * + * 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. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + ***************************************************************************/ + +#include <QTimer> +#include "shoutclient.h" + +ShoutClient::ShoutClient(QObject *parent) : + QObject(parent) +{ + shout_init(); + m_shout_conn = shout_new(); + m_timer = new QTimer(this); + m_timer->setSingleShot(true); + m_timer->setInterval(4000); + QObject::connect(m_timer, SIGNAL(timeout()), SLOT(close())); + readSettings(); +} + +ShoutClient::~ShoutClient() +{ + close(); + shout_free(m_shout_conn); + shout_shutdown(); +} + +void ShoutClient::readSettings() +{ + shout_set_host(m_shout_conn, "127.0.0.1"); + shout_set_port(m_shout_conn, 8000); + shout_set_password(m_shout_conn, "hackme"); + shout_set_mount(m_shout_conn, "/qmmp.out"); + shout_set_name(m_shout_conn, "qmmp"); + shout_set_user(m_shout_conn, "source"); + shout_set_public(m_shout_conn, 0); + shout_set_format(m_shout_conn, SHOUT_FORMAT_OGG); + shout_set_protocol(m_shout_conn, SHOUT_PROTOCOL_HTTP); + shout_set_agent(m_shout_conn, "qmmp"); + shout_set_audio_info(m_shout_conn, SHOUT_AI_CHANNELS, "2"); + shout_set_audio_info(m_shout_conn, SHOUT_AI_QUALITY, "0.4"); + shout_set_audio_info(m_shout_conn, SHOUT_AI_SAMPLERATE, "44100"); +} + +bool ShoutClient::open() +{ + QMetaObject::invokeMethod(m_timer, "stop", Qt::QueuedConnection); + int r = shout_open(m_shout_conn); + + if(r == SHOUTERR_SUCCESS || r == SHOUTERR_CONNECTED) + { + shout_sync(m_shout_conn); + qDebug("ShoutClient: connected"); + return true; + } + + qWarning("ShoutClient: unable to connect: %s", shout_get_error(m_shout_conn)); + return false; +} + +bool ShoutClient::send(const unsigned char *data, int len) +{ + shout_sync(m_shout_conn); + if(shout_send(m_shout_conn, data, len) != SHOUTERR_SUCCESS) + { + qWarning("ShoutClient: unable to send data: %s", shout_get_error(m_shout_conn)); + return false; + } + return true; +} + +qint64 ShoutClient::latency() const +{ + return shout_delay(m_shout_conn); +} + +void ShoutClient::closeLater() +{ + QMetaObject::invokeMethod(m_timer, "start", Qt::QueuedConnection); +} + +void ShoutClient::close() +{ + qDebug("%s", Q_FUNC_INFO); + shout_close(m_shout_conn); +} diff --git a/src/plugins/Output/shout/shoutclient.h b/src/plugins/Output/shout/shoutclient.h new file mode 100644 index 000000000..6e21d7c65 --- /dev/null +++ b/src/plugins/Output/shout/shoutclient.h @@ -0,0 +1,51 @@ +/*************************************************************************** + * Copyright (C) 2017 by Ilya Kotov * + * forkotov02@hotmail.ru * + * * + * 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. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + ***************************************************************************/ + +#ifndef SHOUTCLIENT_H +#define SHOUTCLIENT_H + +#include <QObject> +#include <shout/shout.h> + +class QTimer; + +class ShoutClient : public QObject +{ + Q_OBJECT +public: + explicit ShoutClient(QObject *parent); + ~ShoutClient(); + + void readSettings(); + bool open(); + bool send(const unsigned char *data, int len); + qint64 latency() const; + void closeLater(); + +public slots: + void close(); + +private: + shout_t *m_shout_conn; + QTimer *m_timer; + +}; + +#endif // SHOUTCLIENT_H diff --git a/src/plugins/Output/shout/shoutoutput.cpp b/src/plugins/Output/shout/shoutoutput.cpp new file mode 100644 index 000000000..bb0fd2bfc --- /dev/null +++ b/src/plugins/Output/shout/shoutoutput.cpp @@ -0,0 +1,193 @@ +/*************************************************************************** + * Copyright (C) 2017 by Ilya Kotov * + * forkotov02@hotmail.ru * + * * + * 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. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + ***************************************************************************/ + +#include <QFile> +#include <unistd.h> +#include "shoutoutput.h" + +ShoutOutput::ShoutOutput(ShoutClient *m) +{ + m_client = m; + +} + +ShoutOutput::~ShoutOutput() +{ + m_client->closeLater(); + ogg_stream_clear(&m_os); + vorbis_block_clear(&m_vb); + vorbis_dsp_clear(&m_vd); + vorbis_comment_clear(&m_vc); + vorbis_info_clear(&m_vi); +} + +bool ShoutOutput::initialize(quint32 freq, ChannelMap map, Qmmp::AudioFormat) +{ + vorbis_info_init(&m_vi); + vorbis_encode_init_vbr(&m_vi,2,freq,.4); + + vorbis_comment_init(&m_vc); + //vorbis_comment_add_tag(&m_vc,"TITLE","encoder_example.c"); + + vorbis_analysis_init(&m_vd, &m_vi); + vorbis_block_init(&m_vd,&m_vb); + + qsrand(time(NULL)); + ogg_stream_init(&m_os,qrand()); + + configure(freq, map, Qmmp::PCM_FLOAT); + return m_client->open(); +} + +qint64 ShoutOutput::latency() +{ + return m_client->latency(); +} + +qint64 ShoutOutput::writeAudio(unsigned char *data, qint64 maxSize) +{ + int chan = channels(); + int frames = maxSize / chan / sizeof(float); + float **buffer = vorbis_analysis_buffer(&m_vd, frames); + + if(chan == 1) + { + memcpy(buffer[0], data, frames * sizeof(float)); + memcpy(buffer[1], data, frames * sizeof(float)); + } + else + { + for(int i = 0; i < frames; i++) + { + buffer[0][i] = *reinterpret_cast<float *>(data + (i * chan) * sizeof(float)); + buffer[1][i] = *reinterpret_cast<float *>(data + (i * chan + 1) * sizeof(float)); + } + } + + vorbis_analysis_wrote(&m_vd, frames); + + bool ok = true; + + while(ok && vorbis_analysis_blockout(&m_vd, &m_vb) == 1) + { + // analysis, assume we want to use bitrate management + vorbis_analysis(&m_vb, NULL); + vorbis_bitrate_addblock(&m_vb); + + while(ok && vorbis_bitrate_flushpacket(&m_vd, &m_op)) + { + // weld the packet into the bitstream + ogg_stream_packetin(&m_os, &m_op); + // write out pages (if any) + bool eos = false; + while(!eos) + { + if(ogg_stream_pageout(&m_os, &m_og)) + { + + if(!m_client->send(m_og.header, m_og.header_len)) + { + ok = false; + break; + } + + if(!m_client->send(m_og.body, m_og.body_len)) + { + ok = false; + break; + } + + eos = (ogg_page_eos(&m_og) != 0); + } + else + { + eos = true; + } + } + } + } + + if(!ok) + { + qWarning("ShoutOutput: trying to reconnect..."); + m_client->close(); + if(!m_client->open()) + return -1; + + qsrand(time(NULL)); + ogg_stream_reset(&m_os); + ogg_stream_init(&m_os,qrand()); + + sendHeader(); + } + + return maxSize; +} + +void ShoutOutput::drain() +{ + vorbis_analysis_wrote(&m_vd,0); +} + +void ShoutOutput::reset() +{} + +void ShoutOutput::setMetaData(const QMap<Qmmp::MetaData, QString> &metaData) +{ + vorbis_comment_clear(&m_vc); + + static const struct + { + Qmmp::MetaData key; + const char *tag; + } tag_map[] = { + { Qmmp::TITLE, "title"}, + { Qmmp::ARTIST, "artist"}, + { Qmmp::ALBUM, "album"}, + { Qmmp::COMMENT, "comment"}, + { Qmmp::GENRE, "genre"}, + { Qmmp::TRACK, "tracknumber"}, + { Qmmp::YEAR, "date"}, + { Qmmp::COMPOSER, "composer"}, + { Qmmp::DISCNUMBER, "discnumber"}, + { Qmmp::UNKNOWN, 0} + }; + + int i = 0; + while(tag_map[i].key != Qmmp::UNKNOWN) + { + if(!metaData[tag_map[i].key].isEmpty()) + vorbis_comment_add_tag(&m_vc, tag_map[i].tag, metaData[tag_map[i].key].toUtf8().constData()); + i++; + } + sendHeader(); +} + +void ShoutOutput::sendHeader() +{ + ogg_packet header; + ogg_packet header_comm; + ogg_packet header_code; + + vorbis_analysis_headerout(&m_vd, &m_vc, &header, &header_comm, &header_code); + ogg_stream_packetin(&m_os, &header); // automatically placed in its own page + ogg_stream_packetin(&m_os, &header_comm); + ogg_stream_packetin(&m_os, &header_code); +} diff --git a/src/plugins/Output/shout/shoutoutput.h b/src/plugins/Output/shout/shoutoutput.h new file mode 100644 index 000000000..69f06a443 --- /dev/null +++ b/src/plugins/Output/shout/shoutoutput.h @@ -0,0 +1,53 @@ +/*************************************************************************** + * Copyright (C) 2017 by Ilya Kotov * + * forkotov02@hotmail.ru * + * * + * 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. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + ***************************************************************************/ + +#ifndef SHOUTOUTPUT_H +#define SHOUTOUTPUT_H + +#include <vorbis/vorbisenc.h> +#include <qmmp/output.h> +#include "shoutclient.h" + +class ShoutOutput : public Output +{ +public: + ShoutOutput(ShoutClient *m); + ~ShoutOutput(); + + bool initialize(quint32 freq, ChannelMap map, Qmmp::AudioFormat); + qint64 latency(); + qint64 writeAudio(unsigned char *data, qint64 maxSize); + void drain(); + void reset(); + void setMetaData(const QMap<Qmmp::MetaData, QString> &metaData); + +private: + void sendHeader(); + ShoutClient *m_client; + ogg_stream_state m_os; //take physical pages, weld into a logical stream of packets + ogg_page m_og; //one Ogg bitstream page. Vorbis packets are inside */ + ogg_packet m_op; //one raw packet of data for decode + vorbis_info m_vi; //struct that stores all the static vorbis bitstream settings + vorbis_comment m_vc; //struct that stores all the user comments + vorbis_dsp_state m_vd; //central working state for the packet->PCM decoder + vorbis_block m_vb; //local working space for packet->PCM decode +}; + +#endif // SHOUTOUTPUT_H |
