diff options
| author | stalkerg <stalkerg@90c681e8-e032-0410-971d-27865f9a5e38> | 2007-08-08 22:11:13 +0000 |
|---|---|---|
| committer | stalkerg <stalkerg@90c681e8-e032-0410-971d-27865f9a5e38> | 2007-08-08 22:11:13 +0000 |
| commit | 3ee3fee6bc965308885f80237ed65b73db8dbfec (patch) | |
| tree | da66afe614ff0293a5d9e60212299cd19de71d92 | |
| parent | 928f98c35133381cadb3e263b7de3e636277c21e (diff) | |
| download | qmmp-3ee3fee6bc965308885f80237ed65b73db8dbfec.tar.gz qmmp-3ee3fee6bc965308885f80237ed65b73db8dbfec.tar.bz2 qmmp-3ee3fee6bc965308885f80237ed65b73db8dbfec.zip | |
Add OSS output plugin and fix cmake script.
git-svn-id: http://svn.code.sf.net/p/qmmp-dev/code/trunk/qmmp@70 90c681e8-e032-0410-971d-27865f9a5e38
| -rw-r--r-- | lib/qmmp/Output/CMakeLists.txt | 12 | ||||
| -rw-r--r-- | lib/qmmp/Output/oss/CMakeLists.txt | 61 | ||||
| -rw-r--r-- | lib/qmmp/Output/oss/outputoss.cpp | 486 | ||||
| -rw-r--r-- | lib/qmmp/Output/oss/outputoss.h | 78 | ||||
| -rw-r--r-- | lib/qmmp/Output/oss/outputossfactory.cpp | 58 | ||||
| -rw-r--r-- | lib/qmmp/Output/oss/outputossfactory.h | 48 |
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 |
