aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/qmmp/Output/CMakeLists.txt12
-rw-r--r--lib/qmmp/Output/oss/CMakeLists.txt61
-rw-r--r--lib/qmmp/Output/oss/outputoss.cpp486
-rw-r--r--lib/qmmp/Output/oss/outputoss.h78
-rw-r--r--lib/qmmp/Output/oss/outputossfactory.cpp58
-rw-r--r--lib/qmmp/Output/oss/outputossfactory.h48
6 files changed, 741 insertions, 2 deletions
diff --git a/lib/qmmp/Output/CMakeLists.txt b/lib/qmmp/Output/CMakeLists.txt
index 85d236d39..864d945c1 100644
--- a/lib/qmmp/Output/CMakeLists.txt
+++ b/lib/qmmp/Output/CMakeLists.txt
@@ -1,16 +1,24 @@
SET(USE_ALSA TRUE CACHE BOOL "enable/disable alsa plugin")
SET(USE_JACK TRUE CACHE BOOL "enable/disable jack plugin")
+SET(USE_OSS TRUE CACHE BOOL "enable/disable oss plugin")
IF(USE_ALSA)
MESSAGE( STATUS "ALSA ON")
add_subdirectory(alsa)
-ELSE(USE_MAD)
+ELSE(USE_ALSA)
MESSAGE( STATUS "ALSA OFF")
ENDIF(USE_ALSA)
IF(USE_JACK)
MESSAGE( STATUS "JACK ON")
add_subdirectory(jack)
-ELSE(USE_FLAC)
+ELSE(USE_JACK)
MESSAGE( STATUS "JACK OFF")
ENDIF(USE_JACK)
+
+IF(USE_OSS)
+MESSAGE( STATUS "OSS ON")
+add_subdirectory(oss)
+ELSE(USE_OSS)
+MESSAGE( STATUS "OSS OFF")
+ENDIF(USE_OSS) \ No newline at end of file
diff --git a/lib/qmmp/Output/oss/CMakeLists.txt b/lib/qmmp/Output/oss/CMakeLists.txt
new file mode 100644
index 000000000..639e1cd94
--- /dev/null
+++ b/lib/qmmp/Output/oss/CMakeLists.txt
@@ -0,0 +1,61 @@
+project(liboss)
+
+cmake_minimum_required(VERSION 2.4.0)
+
+
+INCLUDE(UsePkgConfig)
+INCLUDE(FindQt4)
+
+find_package(Qt4 REQUIRED) # find and setup Qt4 for this project
+include(${QT_USE_FILE})
+
+# qt plugin
+ADD_DEFINITIONS( -Wall )
+ADD_DEFINITIONS(${QT_DEFINITIONS})
+ADD_DEFINITIONS(-DQT_PLUGIN)
+ADD_DEFINITIONS(-DQT_NO_DEBUG)
+ADD_DEFINITIONS(-DQT_SHARED)
+ADD_DEFINITIONS(-DQT_THREAD)
+
+include_directories(${CMAKE_CURRENT_BINARY_DIR})
+
+SET(QT_INCLUDES
+ ${QT_INCLUDES}
+ ${CMAKE_CURRENT_BINARY_DIR}/../../../
+)
+
+# libqmmp
+include_directories(${CMAKE_CURRENT_BINARY_DIR}/../../../)
+link_directories(${CMAKE_CURRENT_BINARY_DIR}/../../../)
+
+
+
+include_directories(${JACK_INCLUDE_DIR} ${JACK_INCLUDE_DIR})
+link_directories(${SAMPLERATE_LINK_DIR} ${SAMPLERATE_LINK_DIR})
+
+ADD_DEFINITIONS(${JACK_CFLAGS})
+ADD_DEFINITIONS(${SAMPLERATE_CFLAGS})
+
+
+SET(liboss_SRCS
+ outputossfactory.cpp
+ outputoss.cpp
+)
+
+SET(liboss_MOC_HDRS
+ outputossfactory.h
+ outputoss.h
+)
+
+#SET(libjack_RCCS translations/translations.qrc)
+
+QT4_ADD_RESOURCES(libjack_RCC_SRCS ${libjack_RCCS})
+
+QT4_WRAP_CPP(liboss_MOC_SRCS ${liboss_MOC_HDRS})
+
+
+
+ADD_LIBRARY(oss SHARED ${liboss_SRCS} ${liboss_MOC_SRCS})
+target_link_libraries(oss ${QT_LIBRARIES} -lqmmp )
+install(TARGETS oss DESTINATION lib/qmmp/Output)
+
diff --git a/lib/qmmp/Output/oss/outputoss.cpp b/lib/qmmp/Output/oss/outputoss.cpp
new file mode 100644
index 000000000..ccc5eace4
--- /dev/null
+++ b/lib/qmmp/Output/oss/outputoss.cpp
@@ -0,0 +1,486 @@
+/***************************************************************************
+ * Copyright (C) 2007 by Uriy Zhuravlev stalkerg@gmail.com *
+ * *
+ * Copyright (c) 2000-2001 Brad Hughes bhughes@trolltech.com *
+ * *
+ * 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., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+
+
+#include <qobject.h>
+#include <qapplication.h>
+
+#include "outputoss.h"
+#include "constants.h"
+#include "buffer.h"
+#include "visualization.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <QtGlobal>
+
+#include <iostream>
+
+//extern Q_EXPORT QApplication* qApp;
+
+
+void OutputOSS::stop()
+{
+ m_userStop = TRUE;
+}
+
+void OutputOSS::status()
+{
+ long ct = (m_totalWritten - latency()) / m_bps;
+
+ if (ct < 0)
+ ct = 0;
+
+ if (ct > m_currentSeconds)
+ {
+ m_currentSeconds = ct;
+ dispatch(m_currentSeconds, m_totalWritten, m_rate,
+ m_frequency, m_precision, m_channels);
+ }
+}
+
+long OutputOSS::written()
+{
+ return m_totalWritten;
+}
+
+void OutputOSS::seek(long pos)
+{
+ recycler()->mutex()->lock();
+ recycler()->clear();
+ recycler()->mutex()->unlock();
+
+ m_totalWritten = (pos * m_bps);
+ m_currentSeconds = -1;
+}
+
+//#if defined(_OS_UNIX_) || defined(Q_OS_UNIX)
+
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <sys/time.h>
+
+#if defined(__FreeBSD__)
+# include <machine/soundcard.h>
+#elif defined(__linux__)
+# include <linux/soundcard.h>
+#elif defined(__bsdi__)
+# include <sys/soundcard.h>
+#endif
+
+
+OutputOSS::OutputOSS(QObject * parent)
+ : Output(parent, Output::Custom), m_inited(FALSE), m_pause(FALSE), m_play(FALSE),
+ m_userStop(FALSE),
+ m_totalWritten(0), m_currentSeconds(-1),
+ m_bps(1), m_frequency(-1), m_channels(-1), m_precision(-1),
+ do_select(TRUE),
+ m_audio_fd(-1), m_mixer_fd(-1)
+{
+m_master = true;
+openMixer();
+}
+
+OutputOSS::~OutputOSS()
+{
+ if (m_audio_fd > 0)
+ {
+ close(m_audio_fd);
+ m_audio_fd = -1;
+ }
+ if (m_mixer_fd > 0)
+ {
+ close(m_mixer_fd);
+ m_mixer_fd = -1;
+ }
+}
+
+void OutputOSS::configure(long freq, int chan, int prec, int rate)
+{
+ // we need to configure
+ if (freq != m_frequency || chan != m_channels || prec != m_precision) {
+ // we have already configured, but are changing settings...
+ // reset the device
+ resetDSP();
+
+ m_frequency = freq;
+ m_channels = chan;
+ m_precision = prec;
+
+ m_bps = freq * chan * (prec / 8);
+
+ int p;
+ switch(prec) {
+ default:
+ case 16:
+#if defined(AFMT_S16_NE)
+ p = AFMT_S16_NE;
+#else
+ p = AFMT_S16_LE;
+#endif
+ break;
+
+ case 8:
+ p = AFMT_S8;
+ break;
+
+ }
+
+ ioctl(m_audio_fd, SNDCTL_DSP_SETFMT, &p);
+ ioctl(m_audio_fd, SNDCTL_DSP_SAMPLESIZE, &prec);
+ int stereo = (chan > 1) ? 1 : 0;
+ ioctl(m_audio_fd, SNDCTL_DSP_STEREO, &stereo);
+ ioctl(m_audio_fd, SNDCTL_DSP_SPEED, &freq);
+ }
+
+ m_rate = rate;
+
+ prepareVisuals();
+}
+
+
+void OutputOSS::reset()
+{
+ if (m_audio_fd > 0)
+ {
+ close(m_audio_fd);
+ m_audio_fd = -1;
+ }
+
+ m_audio_fd = open(m_audio_device.toAscii(), O_WRONLY, 0);
+
+ if (m_audio_fd < 0)
+ {
+ error(QString("OSSOutput: failed to open output device '%1'").
+ arg(m_audio_device));
+ return;
+ }
+
+ int flags;
+ if ((flags = fcntl(m_audio_fd, F_GETFL, 0)) > 0)
+ {
+ flags &= O_NDELAY;
+ fcntl(m_audio_fd, F_SETFL, flags);
+ }
+
+ fd_set afd;
+ FD_ZERO(&afd);
+ FD_SET(m_audio_fd, &afd);
+ struct timeval tv;
+ tv.tv_sec = 0l;
+ tv.tv_usec = 50000l;
+ do_select = (select(m_audio_fd + 1, 0, &afd, 0, &tv) > 0);
+
+ if (m_audio_fd > 0)
+ {
+ close(m_mixer_fd);
+ m_mixer_fd = -1;
+ }
+ openMixer();
+}
+
+void OutputOSS::openMixer()
+{
+ if (m_mixer_fd != -1)
+ return;
+
+ if ((m_mixer_fd = open(m_mixer_device.toAscii(), O_RDWR)) == -1)
+ {
+ return;
+ }
+ if (m_audio_fd < 0)
+ {
+ error(QString("OSSOutput: failed to open mixer device '%1'").
+ arg(m_mixer_device));
+ return;
+ }
+}
+
+void OutputOSS::pause()
+{
+ m_pause = (m_pause) ? FALSE : TRUE;
+}
+
+void OutputOSS::post()
+{
+ if (m_audio_fd < 1)
+ return;
+
+ int unused;
+ ioctl(m_audio_fd, SNDCTL_DSP_POST, &unused);
+}
+
+void OutputOSS::sync()
+{
+ if (m_audio_fd < 1)
+ return;
+
+ int unused;
+ ioctl(m_audio_fd, SNDCTL_DSP_SYNC, &unused);
+}
+
+
+void OutputOSS::resetDSP()
+{
+ if (m_audio_fd < 1)
+ return;
+
+ int unused;
+ ioctl(m_audio_fd, SNDCTL_DSP_RESET, &unused);
+}
+
+
+bool OutputOSS::initialize()
+{
+ m_inited = m_pause = m_play = m_userStop = FALSE;
+ m_audio_device = "/dev/dsp";
+ m_mixer_device = "/dev/mixer";
+ /*if (!audio_device) {
+ error(QString("AudioOutput: cannot initialize, no device name"));
+
+ return FALSE;
+ }*/
+
+ reset();
+ if (m_audio_fd < 0)
+ return FALSE;
+ if (m_mixer_fd < 0)
+ return FALSE;
+
+
+ m_currentSeconds = -1;
+ m_totalWritten = 0;
+ stat = OutputState::Stopped;
+
+ m_inited = TRUE;
+ return TRUE;
+}
+
+void OutputOSS::uninitialize()
+{
+ if (!m_inited)
+ return;
+ m_inited = FALSE;
+ m_pause = FALSE;
+ m_play = FALSE;
+ m_userStop = FALSE;
+ m_totalWritten = 0;
+ m_currentSeconds = -1;
+ m_bps = -1;
+ m_frequency = -1;
+ m_channels = -1;
+ m_precision = -1;
+ resetDSP();
+ if (m_audio_fd > 0)
+ {
+ close(m_audio_fd);
+ m_audio_fd = -1;
+ }
+ if (m_audio_fd > 0)
+ {
+ close(m_mixer_fd);
+ m_mixer_fd = -1;
+ }
+
+ qDebug("OutputOSS: uninitialize");
+ dispatch(OutputState::Stopped);
+}
+
+long OutputOSS::latency()
+{
+ ulong used = 0;
+
+ if (! m_pause)
+ {
+ if (ioctl(m_audio_fd, SNDCTL_DSP_GETODELAY, &used) == -1)
+ used = 0;
+ }
+
+ return used;
+}
+
+void OutputOSS::run()
+{
+ mutex()->lock();
+
+ if (! m_inited)
+ {
+ mutex()->unlock();
+
+ return;
+ }
+
+ m_play = TRUE;
+
+ mutex()->unlock();
+
+ fd_set afd;
+ struct timeval tv;
+ Buffer *b = 0;
+ bool done = FALSE;
+ unsigned long n = 0, m = 0, l = 0;
+
+ dispatch(OutputState::Playing);
+
+ FD_ZERO(&afd);
+
+ while (! done) {
+ mutex()->lock();
+
+ recycler()->mutex()->lock();
+
+ done = m_userStop;
+
+ while (! done && (recycler()->empty() || m_pause)) {
+ post();
+
+ mutex()->unlock();
+
+ {
+ stat = m_pause ? OutputState::Paused : OutputState::Buffering;
+ OutputState e((OutputState::Type) stat);
+ dispatch(e);
+ }
+
+ recycler()->cond()->wakeOne();
+ recycler()->cond()->wait(recycler()->mutex());
+
+ mutex()->lock();
+ done = m_userStop;
+ status();
+ }
+
+ if (! b) {
+ b = recycler()->next();
+ if (b->rate)
+ m_rate = b->rate;
+ }
+
+ recycler()->cond()->wakeOne();
+ recycler()->mutex()->unlock();
+
+ FD_ZERO(&afd);
+ FD_SET(m_audio_fd, &afd);
+ // nice long poll timeout
+ tv.tv_sec = 5l;
+ tv.tv_usec = 0l;
+
+ if (b &&
+ (! do_select || (select(m_audio_fd + 1, 0, &afd, 0, &tv) > 0 &&
+ FD_ISSET(m_audio_fd, &afd)))) {
+ l = qMin(int(2048), int(b->nbytes - n));
+ if (l > 0) {
+ m = write(m_audio_fd, b->data + n, l);
+ n += m;
+
+ status();
+ dispatchVisual(b, m_totalWritten, m_channels, m_precision);
+ } else {
+ // force buffer change
+ n = b->nbytes;
+ m = 0;
+ }
+ }
+
+ m_totalWritten += m;
+
+ if (n == b->nbytes) {
+ recycler()->mutex()->lock();
+ recycler()->done();
+ recycler()->mutex()->unlock();
+
+ b = 0;
+ n = 0;
+ }
+
+ mutex()->unlock();
+ }
+
+ mutex()->lock();
+
+ if (! m_userStop)
+ sync();
+ resetDSP();
+
+ m_play = FALSE;
+
+ dispatch(OutputState::Stopped);
+ mutex()->unlock();
+}
+
+
+void OutputOSS::setVolume(int l, int r)
+{
+
+ int v, devs;
+ long cmd;
+
+ ioctl(m_mixer_fd, SOUND_MIXER_READ_DEVMASK, &devs);
+ if ((devs & SOUND_MASK_PCM) && (m_master == false))
+ cmd = SOUND_MIXER_WRITE_PCM;
+ else if ((devs & SOUND_MASK_VOLUME) && (m_master == true))
+ cmd = SOUND_MIXER_WRITE_VOLUME;
+ else
+ {
+ //close(mifd);
+ return;
+ }
+ v = (r << 8) | l;
+ ioctl(m_mixer_fd, cmd, &v);
+}
+
+void OutputOSS::checkVolume()
+{
+ long ll = 0, lr = 0, cmd;
+ int v, devs;
+
+ /*
+ * We dont show any errors if this fails, as this is called
+ * rather often
+ */
+// if (!open_mixer_device()) {
+ ioctl(m_mixer_fd, SOUND_MIXER_READ_DEVMASK, &devs);
+ if ((devs & SOUND_MASK_PCM) && (m_master == 0))
+ cmd = SOUND_MIXER_READ_PCM;
+ else if ((devs & SOUND_MASK_VOLUME) && (m_master == 1))
+ cmd = SOUND_MIXER_READ_VOLUME;
+ else
+ return;
+
+ ioctl(m_mixer_fd, cmd, &v);
+ ll = (v & 0xFF00) >> 8;
+ lr = (v & 0x00FF);
+
+ ll = (ll > 100) ? 100 : ll;
+ lr = (lr > 100) ? 100 : lr;
+ ll = (ll < 0) ? 0 : ll;
+ lr = (lr < 0) ? 0 : lr;
+ if (bl!=ll || br!=lr)
+ {
+ bl = ll;
+ br = lr;
+ dispatchVolume(ll,lr);
+ }
+// }
+}
+
+
diff --git a/lib/qmmp/Output/oss/outputoss.h b/lib/qmmp/Output/oss/outputoss.h
new file mode 100644
index 000000000..f24d69df7
--- /dev/null
+++ b/lib/qmmp/Output/oss/outputoss.h
@@ -0,0 +1,78 @@
+// Copyright (c) 2000-2001 Brad Hughes <bhughes@trolltech.com>
+//
+// Use, modification and distribution is allowed without limitation,
+// warranty, or liability of any kind.
+//
+
+#ifndef OUTPUTOSS_H
+#define OUTPUTOSS_H
+
+class OutputOSS;
+
+#include <output.h>
+#include <QObject>
+/*
+#if defined( Q_OS_WIN32 )
+#include <dsound.h>
+#include "constants.h"
+#endif
+*/
+
+class OutputOSS : public Output
+{
+public:
+ OutputOSS(QObject * parent = 0);
+ virtual ~OutputOSS();
+
+ bool isInitialized() const { return m_inited; }
+ bool initialize();
+ void uninitialize();
+ void configure(long, int, int, int);
+ void stop();
+ void pause();
+ long written();
+ long latency();
+ void seek(long);
+ void setVolume(int l, int r);
+ void checkVolume();
+
+private:
+ // thread run function
+ void run();
+
+ // helper functions
+ void reset();
+ void resetDSP();
+ void status();
+ void post();
+ void sync();
+ void openMixer();
+
+ QString m_audio_device, m_mixer_device;
+
+ bool m_inited, m_pause, m_play, m_userStop, m_master;
+ long m_totalWritten, m_currentSeconds, m_bps;
+ int stat;
+ int m_rate, m_frequency, m_channels, m_precision;
+//#if defined(_OS_UNIX_) || defined(Q_OS_UNIX)
+ bool do_select;
+ int m_audio_fd, m_mixer_fd;
+ long bl, br;
+
+/*#elif defined( _OS_WIN32_ ) || defined( Q_OS_WIN32 )
+ LPDIRECTSOUND lpds;
+ LPDIRECTSOUNDBUFFER lpdsb;
+ LPDIRECTSOUNDNOTIFY lpdsn;
+ PCMWAVEFORMAT pcmwf;
+ Qt::HANDLE hNotifyEvent;
+ DSBPOSITIONNOTIFY notifies[ BUFFERBLOCKS ];
+ DWORD currentLatency;
+// Not sure we need this
+// DSCAPS dsCaps;
+//
+//#endif
+*/
+};
+
+
+#endif // __audiooutout_h
diff --git a/lib/qmmp/Output/oss/outputossfactory.cpp b/lib/qmmp/Output/oss/outputossfactory.cpp
new file mode 100644
index 000000000..11454b173
--- /dev/null
+++ b/lib/qmmp/Output/oss/outputossfactory.cpp
@@ -0,0 +1,58 @@
+/***************************************************************************
+ * Copyright (C) 2007 by Zhuravlev Uriy *
+ * stalkerg@gmail.com *
+ * *
+ * 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., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+
+#include <QtGui>
+
+#include "outputoss.h"
+#include "outputossfactory.h"
+
+
+const QString& OutputOSSFactory::name() const
+{
+ static QString name(tr("OSS Plugin"));
+ return name;
+}
+
+Output* OutputOSSFactory::create(QObject* parent)
+{
+ return new OutputOSS(parent);
+}
+
+void OutputOSSFactory::showSettings(QWidget*)
+{
+}
+
+void OutputOSSFactory::showAbout(QWidget *parent)
+{
+QMessageBox::about (parent, tr("About OSS Output Plugin"),
+ tr("Qmmp OSS Output Plugin")+"\n"+
+ tr("Writen by: Yuriy Zhuravlev <slalkerg@gmail.com>")+"\n"+
+ tr("Based on code by:Brad Hughes <bhughes@trolltech.com>"));
+}
+
+QTranslator *OutputOSSFactory::createTranslator(QObject *parent)
+{
+ QTranslator *translator = new QTranslator(parent);
+ QString locale = QLocale::system().name();
+ translator->load(QString(":/oss_plugin_") + locale);
+ return translator;
+}
+
+Q_EXPORT_PLUGIN(OutputOSSFactory)
diff --git a/lib/qmmp/Output/oss/outputossfactory.h b/lib/qmmp/Output/oss/outputossfactory.h
new file mode 100644
index 000000000..0c5864a7c
--- /dev/null
+++ b/lib/qmmp/Output/oss/outputossfactory.h
@@ -0,0 +1,48 @@
+/***************************************************************************
+ * Copyright (C) 2006 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., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#ifndef OUTPUTOSSFACTORY_H
+#define OUTPUTOSSFACTORY_H
+
+
+#include <QObject>
+#include <QString>
+#include <QIODevice>
+#include <QWidget>
+
+#include <output.h>
+#include <outputfactory.h>
+
+
+class OutputOSSFactory : public QObject,
+ OutputFactory
+{
+Q_OBJECT
+Q_INTERFACES(OutputFactory);
+
+public:
+ const QString& name() const;
+ Output* create(QObject* parent);
+ void showSettings(QWidget* parent);
+ void showAbout(QWidget *parent);
+ QTranslator *createTranslator(QObject *parent);
+
+};
+
+#endif