/***************************************************************************
oss - sound . cpp - description
- - - - - - - - - - - - - - - - - - -
begin : Sun Mar 21 2004
copyright : ( C ) 2004 by Martin Witte
email : witte @ kawo1 . rwth - aachen . de
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/***************************************************************************
* *
* This program is free software ; you can redistribute it and / or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation ; either version 2 of the License , or *
* ( at your option ) any later version . *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# include "oss-sound.h"
# include "../../src/include/aboutwidget.h"
# include <klocale.h>
# include <kaboutdata.h>
# include <sys/types.h>
# include <sys/stat.h>
# include <sys/soundcard.h>
# include <sys/ioctl.h>
# include <fcntl.h>
# include <unistd.h>
# include <math.h>
# include <errno.h>
# include "oss-sound-configuration.h"
# include "../../src/include/utils.h"
///////////////////////////////////////////////////////////////////////
//// plugin library functions
PLUGIN_LIBRARY_FUNCTIONS ( OSSSoundDevice , " kradio-oss-sound " , i18n ( " Open Sound System (OSS) Support " ) ) ;
/////////////////////////////////////////////////////////////////////////////
struct _lrvol { unsigned char l , r ; short dummy ; } ;
OSSSoundDevice : : OSSSoundDevice ( const TQString & name )
: TQObject ( NULL , NULL ) ,
PluginBase ( name , i18n ( " KRadio OSS Sound Plugin " ) ) ,
m_DSPDeviceName ( " " ) ,
m_MixerDeviceName ( " " ) ,
m_DSP_fd ( - 1 ) ,
m_Mixer_fd ( - 1 ) ,
m_DuplexMode ( DUPLEX_UNKNOWN ) ,
m_DSPFormat ( ) ,
m_PassivePlaybackStreams ( ) ,
m_PlaybackStreamID ( ) ,
m_CaptureStreamID ( ) ,
m_BufferSize ( 65536 ) ,
m_PlaybackBuffer ( m_BufferSize ) ,
m_CaptureBuffer ( m_BufferSize ) ,
m_CaptureRequestCounter ( 0 ) ,
m_CapturePos ( 0 ) ,
m_CaptureStartTime ( 0 ) ,
//m_PlaybackSkipCount(0),
m_CaptureSkipCount ( 0 ) ,
m_EnablePlayback ( true ) ,
m_EnableCapture ( true )
{
TQObject : : connect ( & m_PollingTimer , TQT_SIGNAL ( timeout ( ) ) , this , TQT_SLOT ( slotPoll ( ) ) ) ;
}
OSSSoundDevice : : ~ OSSSoundDevice ( )
{
stopCapture ( m_CaptureStreamID ) ;
stopPlayback ( m_PlaybackStreamID ) ;
closeDSPDevice ( ) ;
closeMixerDevice ( ) ;
}
bool OSSSoundDevice : : connectI ( Interface * i )
{
bool a = PluginBase : : connectI ( i ) ;
bool b = ISoundStreamClient : : connectI ( i ) ;
return a | | b ;
}
bool OSSSoundDevice : : disconnectI ( Interface * i )
{
bool a = PluginBase : : disconnectI ( i ) ;
bool b = ISoundStreamClient : : disconnectI ( i ) ;
return a | | b ;
}
void OSSSoundDevice : : noticeConnectedI ( ISoundStreamServer * s , bool pointer_valid )
{
ISoundStreamClient : : noticeConnectedI ( s , pointer_valid ) ;
if ( s & & pointer_valid ) {
s - > register4_sendReleasePlayback ( this ) ;
s - > register4_sendReleaseCapture ( this ) ;
s - > register4_sendPlaybackVolume ( this ) ;
s - > register4_sendCaptureVolume ( this ) ;
s - > register4_queryPlaybackVolume ( this ) ;
s - > register4_queryCaptureVolume ( this ) ;
s - > register4_sendStartPlayback ( this ) ;
s - > register4_sendPausePlayback ( this ) ;
s - > register4_sendStopPlayback ( this ) ;
s - > register4_queryIsPlaybackRunning ( this ) ;
s - > register4_sendStartCaptureWithFormat ( this ) ;
s - > register4_sendStopCapture ( this ) ;
s - > register4_queryIsCaptureRunning ( this ) ;
s - > register4_notifySoundStreamClosed ( this ) ;
s - > register4_notifySoundStreamRedirected ( this ) ;
s - > register4_notifySoundStreamData ( this ) ;
}
}
// PluginBase
void OSSSoundDevice : : saveState ( KConfig * c ) const
{
c - > setGroup ( TQString ( " oss-sound- " ) + PluginBase : : name ( ) ) ;
c - > writeEntry ( " dsp-device " , m_DSPDeviceName ) ;
c - > writeEntry ( " mixer-device " , m_MixerDeviceName ) ;
c - > writeEntry ( " enable-playback " , m_EnablePlayback ) ;
c - > writeEntry ( " enable-capture " , m_EnableCapture ) ;
c - > writeEntry ( " buffer-size " , m_BufferSize ) ;
c - > writeEntry ( " soundstreamclient-id " , m_SoundStreamClientID ) ;
}
void OSSSoundDevice : : restoreState ( KConfig * c )
{
c - > setGroup ( TQString ( " oss-sound- " ) + PluginBase : : name ( ) ) ;
m_EnablePlayback = c - > readBoolEntry ( " enable-playback " , true ) ;
m_EnableCapture = c - > readBoolEntry ( " enable-capture " , true ) ;
m_BufferSize = c - > readNumEntry ( " buffer-size " , 65536 ) ;
setDSPDeviceName ( c - > readEntry ( " dsp-device " , " /dev/dsp " ) ) ;
setMixerDeviceName ( c - > readEntry ( " mixer-device " , " /dev/mixer " ) ) ;
m_PlaybackBuffer . resize ( m_BufferSize ) ;
m_CaptureBuffer . resize ( m_BufferSize ) ;
setSoundStreamClientID ( c - > readEntry ( " soundstreamclient-id " , getSoundStreamClientID ( ) ) ) ;
emit sigUpdateConfig ( ) ;
}
void OSSSoundDevice : : setMixerDeviceName ( const TQString & dev_name )
{
if ( m_MixerDeviceName ! = dev_name ) {
m_MixerDeviceName = dev_name ;
if ( m_Mixer_fd > = 0 )
openMixerDevice ( true ) ;
getMixerChannels ( SOUND_MIXER_DEVMASK , m_PlaybackChannels , m_revPlaybackChannels ) ;
getMixerChannels ( SOUND_MIXER_RECMASK , m_CaptureChannels , m_revCaptureChannels ) ;
notifyPlaybackChannelsChanged ( m_SoundStreamClientID , m_PlaybackChannels ) ;
notifyCaptureChannelsChanged ( m_SoundStreamClientID , m_CaptureChannels ) ;
}
}
ConfigPageInfo OSSSoundDevice : : createConfigurationPage ( )
{
OSSSoundConfiguration * conf = new OSSSoundConfiguration ( NULL , this ) ;
TQObject : : connect ( this , TQT_SIGNAL ( sigUpdateConfig ( ) ) , conf , TQT_SLOT ( slotUpdateConfig ( ) ) ) ;
return ConfigPageInfo ( conf ,
i18n ( " OSS Sound " ) ,
i18n ( " OSS Sound Device Options " ) ,
" kradio_oss " ) ;
}
AboutPageInfo OSSSoundDevice : : createAboutPage ( )
{
/* KAboutData aboutData("kradio",
NULL ,
NULL ,
I18N_NOOP ( " OSS Sound Plugin for KRadio " ) ,
KAboutData : : License_GPL ,
" (c) 2004 Martin Witte " ,
0 ,
" http://sourceforge.net/projects/kradio " ,
0 ) ;
aboutData . addAuthor ( " Martin Witte " , " " , " witte@kawo1.rwth-aachen.de " ) ;
return AboutPageInfo (
new KRadioAboutWidget ( aboutData , KRadioAboutWidget : : AbtTabbed ) ,
i18n ( " OSS Sound " ) ,
i18n ( " OSS Sound " ) ,
" kradio_oss_sound "
) ;
*/
return AboutPageInfo ( ) ;
}
bool OSSSoundDevice : : preparePlayback ( SoundStreamID id , const TQString & channel , bool active_mode , bool start_immediately )
{
if ( id . isValid ( ) & & m_revPlaybackChannels . contains ( channel ) ) {
m_PlaybackStreams . insert ( id , SoundStreamConfig ( m_revPlaybackChannels [ channel ] , active_mode ) ) ;
if ( start_immediately )
startPlayback ( id ) ;
return true ;
// FIXME: what to do if stream is already playing?
}
return false ;
}
bool OSSSoundDevice : : prepareCapture ( SoundStreamID id , const TQString & channel )
{
if ( id . isValid ( ) & & m_revCaptureChannels . contains ( channel ) ) {
m_CaptureStreams . insert ( id , SoundStreamConfig ( m_revCaptureChannels [ channel ] ) ) ;
return true ;
// FIXME: what to do if stream is already playing?
}
return false ;
}
bool OSSSoundDevice : : releasePlayback ( SoundStreamID id )
{
if ( id . isValid ( ) & & m_PlaybackStreams . contains ( id ) ) {
if ( m_PlaybackStreamID = = id | | m_PassivePlaybackStreams . contains ( id ) ) {
stopPlayback ( id ) ;
}
m_PlaybackStreams . remove ( id ) ;
return true ;
}
return false ;
}
bool OSSSoundDevice : : releaseCapture ( SoundStreamID id )
{
if ( id . isValid ( ) & & m_CaptureStreams . contains ( id ) ) {
if ( m_CaptureStreamID = = id ) {
stopCapture ( id ) ;
}
m_CaptureStreams . remove ( id ) ;
return true ;
}
return false ;
}
bool OSSSoundDevice : : supportsPlayback ( ) const
{
return m_EnablePlayback ;
}
bool OSSSoundDevice : : supportsCapture ( ) const
{
return m_EnableCapture ;
}
bool OSSSoundDevice : : startPlayback ( SoundStreamID id )
{
if ( id . isValid ( ) & & m_PlaybackStreams . contains ( id ) & & m_EnablePlayback ) {
SoundStreamConfig & cfg = m_PlaybackStreams [ id ] ;
bool ok = false ;
if ( cfg . m_ActiveMode ) {
if ( ! m_PlaybackStreamID . isValid ( ) ) {
m_PlaybackStreamID = id ;
ok = true ;
}
} else {
if ( ! m_PassivePlaybackStreams . contains ( id ) )
m_PassivePlaybackStreams . append ( id ) ;
ok = true ;
}
if ( ok ) {
openMixerDevice ( ) ;
if ( cfg . m_Volume > = 0 )
writeMixerVolume ( cfg . m_Channel , cfg . m_Volume ) ;
}
// error handling?
return true ;
} else {
return false ;
}
}
bool OSSSoundDevice : : pausePlayback ( SoundStreamID /*id*/ )
{
//return stopPlayback(id);
return false ;
}
bool OSSSoundDevice : : stopPlayback ( SoundStreamID id )
{
if ( id . isValid ( ) & & m_PlaybackStreams . contains ( id ) ) {
SoundStreamConfig & cfg = m_PlaybackStreams [ id ] ;
if ( ! cfg . m_ActiveMode ) {
if ( m_PassivePlaybackStreams . contains ( id ) ) {
// writeMixerVolume(cfg.m_Channel, 0);
m_PassivePlaybackStreams . remove ( id ) ;
}
} else if ( m_PlaybackStreamID = = id ) {
m_PlaybackStreamID = SoundStreamID : : InvalidID ;
m_PlaybackBuffer . clear ( ) ;
closeDSPDevice ( ) ;
}
closeMixerDevice ( ) ;
return true ;
} else {
return false ;
}
}
bool OSSSoundDevice : : isPlaybackRunning ( SoundStreamID id , bool & b ) const
{
if ( id . isValid ( ) & & m_PlaybackStreams . contains ( id ) ) {
b = true ;
return true ;
} else {
return false ;
}
}
bool OSSSoundDevice : : startCaptureWithFormat ( SoundStreamID id ,
const SoundFormat & proposed_format ,
SoundFormat & real_format ,
bool force_format )
{
if ( m_CaptureStreams . contains ( id ) & & m_EnableCapture ) {
if ( m_CaptureStreamID ! = id ) {
m_CapturePos = 0 ;
m_CaptureStartTime = time ( NULL ) ;
}
if ( m_CaptureStreamID ! = id | | force_format ) {
m_CaptureStreamID = id ;
SoundStreamConfig & cfg = m_CaptureStreams [ id ] ;
openMixerDevice ( ) ;
selectCaptureChannel ( cfg . m_Channel ) ;
if ( cfg . m_Volume > = 0 )
writeMixerVolume ( cfg . m_Channel , cfg . m_Volume ) ;
openDSPDevice ( proposed_format ) ;
// FIXME: error handling?
}
real_format = m_DSPFormat ;
m_CaptureRequestCounter + + ;
return true ;
} else {
return false ;
}
}
bool OSSSoundDevice : : stopCapture ( SoundStreamID id )
{
if ( id . isValid ( ) & & m_CaptureStreamID = = id ) {
if ( - - m_CaptureRequestCounter = = 0 ) {
m_CaptureStreamID = SoundStreamID : : InvalidID ;
m_CaptureBuffer . clear ( ) ;
closeMixerDevice ( ) ;
closeDSPDevice ( ) ;
}
return true ;
} else {
return false ;
}
}
bool OSSSoundDevice : : isCaptureRunning ( SoundStreamID id , bool & b , SoundFormat & sf ) const
{
if ( id . isValid ( ) & & m_CaptureStreamID = = id ) {
b = true ;
sf = m_DSPFormat ;
return true ;
} else {
return false ;
}
}
bool OSSSoundDevice : : noticeSoundStreamClosed ( SoundStreamID id )
{
bool found = false ;
if ( m_PlaybackStreamID = = id | | m_PassivePlaybackStreams . contains ( id ) ) {
stopPlayback ( id ) ;
found = true ;
}
if ( m_CaptureStreamID = = id ) {
stopCapture ( id ) ;
found = true ;
}
m_PlaybackStreams . remove ( id ) ;
m_CaptureStreams . remove ( id ) ;
return found ;
}
bool OSSSoundDevice : : noticeSoundStreamRedirected ( SoundStreamID oldID , SoundStreamID newID )
{
bool found = false ;
if ( m_PlaybackStreams . contains ( oldID ) ) {
m_PlaybackStreams . insert ( newID , m_PlaybackStreams [ oldID ] ) ;
if ( newID ! = oldID )
m_PlaybackStreams . remove ( oldID ) ;
found = true ;
}
if ( m_CaptureStreams . contains ( oldID ) ) {
m_CaptureStreams . insert ( newID , m_CaptureStreams [ oldID ] ) ;
if ( newID ! = oldID )
m_CaptureStreams . remove ( oldID ) ;
found = true ;
}
if ( m_PlaybackStreamID = = oldID )
m_PlaybackStreamID = newID ;
if ( m_CaptureStreamID = = oldID )
m_CaptureStreamID = newID ;
if ( m_PassivePlaybackStreams . contains ( oldID ) ) {
m_PassivePlaybackStreams . remove ( oldID ) ;
m_PassivePlaybackStreams . append ( newID ) ;
}
return found ;
}
bool OSSSoundDevice : : noticeSoundStreamData ( SoundStreamID id ,
const SoundFormat & format ,
const char * data , size_t size , size_t & consumed_size ,
const SoundMetaData & /*md*/
)
{
if ( ! id . isValid ( ) | | id ! = m_PlaybackStreamID )
return false ;
if ( m_DSP_fd < 0 ) {
openDSPDevice ( format ) ;
} else if ( format ! = m_DSPFormat ) {
if ( m_CaptureStreamID . isValid ( ) )
return false ;
// flush playback buffer
size_t buffersize = 0 ;
char * buffer = m_PlaybackBuffer . getData ( buffersize ) ;
write ( m_DSP_fd , buffer , buffersize ) ;
// if not all could be written, it must be discarded
m_PlaybackBuffer . clear ( ) ;
closeDSPDevice ( ) ;
openDSPDevice ( format ) ;
// error handling ?
}
size_t n = m_PlaybackBuffer . addData ( data , size ) ;
consumed_size = ( consumed_size = = SIZE_T_DONT_CARE ) ? n : min ( consumed_size , n ) ;
// if (n < size) {
// m_PlaybackSkipCount += size - n;
// } else if (m_PlaybackSkipCount > 0) {
// logWarning(i18n("%1: Playback buffer overflow. Skipped %1 bytes").tqarg(m_DSPDeviceName).tqarg(TQString::number(m_PlaybackSkipCount)));
// m_PlaybackSkipCount = 0;
// }
return true ; //m_PlaybackSkipCount == 0;
}
void OSSSoundDevice : : slotPoll ( )
{
int err = 0 ;
if ( m_CaptureStreamID . isValid ( ) & & m_DSP_fd > = 0 ) {
size_t bufferSize = 0 ;
char * buffer = m_CaptureBuffer . getFreeSpace ( bufferSize ) ;
int bytesRead = read ( m_DSP_fd , buffer , bufferSize ) ;
if ( bytesRead > 0 ) {
m_CaptureBuffer . removeFreeSpace ( bytesRead ) ;
} else if ( bytesRead < 0 & & errno = = EAGAIN ) {
bytesRead = 0 ;
} else if ( bytesRead = = 0 ) {
err = - 1 ;
logError ( i18n ( " OSS device %1: No data to record " ) . tqarg ( m_DSPDeviceName ) ) ;
} else {
err = errno ;
}
while ( m_CaptureBuffer . getFillSize ( ) > m_CaptureBuffer . getSize ( ) / 3 ) {
size_t size = 0 ;
buffer = m_CaptureBuffer . getData ( size ) ;
time_t cur_time = time ( NULL ) ;
size_t consumed_size = SIZE_T_DONT_CARE ;
notifySoundStreamData ( m_CaptureStreamID , m_DSPFormat , buffer , size , consumed_size , SoundMetaData ( m_CapturePos , cur_time - m_CaptureStartTime , cur_time , i18n ( " internal stream, not stored (%1) " ) . tqarg ( m_DSPDeviceName ) ) ) ;
if ( consumed_size = = SIZE_T_DONT_CARE )
consumed_size = size ;
m_CaptureBuffer . removeData ( consumed_size ) ;
m_CapturePos + = consumed_size ;
if ( consumed_size < size )
break ;
}
}
if ( m_PlaybackStreamID . isValid ( ) /* && m_DSP_fd >= 0*/ ) {
if ( m_PlaybackBuffer . getFillSize ( ) > 0 & & m_DSP_fd > = 0 ) {
size_t buffersize = 0 ;
char * buffer = m_PlaybackBuffer . getData ( buffersize ) ;
int bytesWritten = write ( m_DSP_fd , buffer , buffersize ) ;
if ( bytesWritten > 0 ) {
m_PlaybackBuffer . removeData ( bytesWritten ) ;
} else if ( bytesWritten < 0 & & errno = = EAGAIN ) {
bytesWritten = 0 ;
} else {
err = errno ;
}
}
if ( m_PlaybackBuffer . getFreeSize ( ) > 0 )
notifyReadyForPlaybackData ( m_PlaybackStreamID , m_PlaybackBuffer . getFreeSize ( ) ) ;
}
if ( err ) {
logError ( i18n ( " Error %1 while handling OSS device %2 " ) . tqarg ( TQString ( ) . setNum ( err ) ) . tqarg ( m_DSPDeviceName ) ) ;
}
if ( m_PlaybackStreamID . isValid ( ) )
checkMixerVolume ( m_PlaybackStreamID ) ;
if ( m_CaptureStreamID . isValid ( ) )
checkMixerVolume ( m_CaptureStreamID ) ;
TQValueListConstIterator < SoundStreamID > end = m_PassivePlaybackStreams . end ( ) ;
for ( TQValueListConstIterator < SoundStreamID > it = m_PassivePlaybackStreams . begin ( ) ; it ! = end ; + + it )
checkMixerVolume ( * it ) ;
}
bool OSSSoundDevice : : openDSPDevice ( const SoundFormat & format , bool reopen )
{
if ( m_DSP_fd > = 0 ) {
if ( reopen ) {
closeDSPDevice ( /* force = */ true ) ;
} else {
if ( format ! = m_DSPFormat )
return false ;
if ( m_DuplexMode ! = DUPLEX_FULL & & m_CaptureStreamID . isValid ( ) & & m_PlaybackStreamID . isValid ( ) )
return false ;
return true ;
}
} else {
if ( reopen )
return true ;
}
m_DSPFormat = format ;
// first testopen for CAPS
m_DSP_fd = open ( m_DSPDeviceName . ascii ( ) , O_NONBLOCK | O_RDONLY ) ;
bool err = m_DSP_fd < 0 ;
if ( err ) {
logError ( i18n ( " Cannot open DSP device %1 " ) . tqarg ( m_DSPDeviceName ) ) ;
return false ;
}
int caps = 0 ;
err | = ( ioctl ( m_DSP_fd , SNDCTL_DSP_GETCAPS , & caps ) ! = 0 ) ;
if ( err )
logError ( i18n ( " Cannot read DSP capabilities for %1 " ) . tqarg ( m_DSPDeviceName ) ) ;
m_DuplexMode = ( caps & DSP_CAP_DUPLEX ) ? DUPLEX_FULL : DUPLEX_HALF ;
close ( m_DSP_fd ) ;
m_DSP_fd = - 1 ;
// opening and seeting up the device file
int mode = O_NONBLOCK ;
if ( m_DuplexMode = = DUPLEX_FULL ) {
mode | = O_RDWR ;
} else if ( m_CaptureStreamID . isValid ( ) ) {
mode | = O_RDONLY ;
} else {
mode | = O_WRONLY ;
}
m_DSP_fd = open ( m_DSPDeviceName . ascii ( ) , mode ) ;
err = m_DSP_fd < 0 ;
if ( err ) {
logError ( i18n ( " Cannot open DSP device %1 " ) . tqarg ( m_DSPDeviceName ) ) ;
return false ;
}
int oss_format = getOSSFormat ( m_DSPFormat ) ;
err | = ( ioctl ( m_DSP_fd , SNDCTL_DSP_SETFMT , & oss_format ) ! = 0 ) ;
if ( err )
logError ( i18n ( " Cannot set DSP sample format for %1 " ) . tqarg ( m_DSPDeviceName ) ) ;
int channels = m_DSPFormat . m_Channels ;
err | = ( ioctl ( m_DSP_fd , SNDCTL_DSP_CHANNELS , & channels ) ! = 0 ) ;
if ( err )
logError ( i18n ( " Cannot set number of channels for %1 " ) . tqarg ( m_DSPDeviceName ) ) ;
int rate = m_DSPFormat . m_SampleRate ;
err | = ( ioctl ( m_DSP_fd , SNDCTL_DSP_SPEED , & rate ) ! = 0 ) ;
if ( err )
logError ( i18n ( " Cannot set sampling rate for %1 " ) . tqarg ( m_DSPDeviceName ) ) ;
if ( rate ! = ( int ) m_DSPFormat . m_SampleRate ) {
logWarning ( i18n ( " Asking for %1 Hz but %2 uses %3 Hz " ) .
arg ( TQString : : number ( m_DSPFormat . m_SampleRate ) ) .
arg ( m_DSPDeviceName ) .
arg ( TQString : : number ( rate ) ) ) ;
m_DSPFormat . m_SampleRate = rate ;
}
int stereo = m_DSPFormat . m_Channels = = 2 ;
err | = ( ioctl ( m_DSP_fd , SNDCTL_DSP_STEREO , & stereo ) ! = 0 ) ;
if ( err )
logError ( i18n ( " Cannot set stereo mode for %1 " ) . tqarg ( m_DSPDeviceName ) ) ;
unsigned sampleSize = m_DSPFormat . m_SampleBits ;
err | = ( ioctl ( m_DSP_fd , SNDCTL_DSP_SAMPLESIZE , & sampleSize ) ! = 0 ) ;
if ( err | | sampleSize ! = m_DSPFormat . m_SampleBits )
logError ( i18n ( " Cannot set sample size for %1 " ) . tqarg ( m_DSPDeviceName ) ) ;
// setup buffer, ask for 40ms latency
int tmp = ( 400 * m_DSPFormat . frameSize ( ) * m_DSPFormat . m_SampleRate ) / 1000 ;
int tqmask = - 1 ; for ( ; tmp ; tmp > > = 1 ) + + tqmask ;
if ( tqmask < 8 ) tqmask = 12 ; // default 4kB
tqmask | = 0x7FFF0000 ;
err | = ioctl ( m_DSP_fd , SNDCTL_DSP_SETFRAGMENT , & tqmask ) ;
if ( err )
logError ( i18n ( " Cannot set buffers for %1 " ) . tqarg ( m_DSPDeviceName ) ) ;
int bufferBlockSize = 0 ;
err | = ioctl ( m_DSP_fd , SNDCTL_DSP_GETBLKSIZE , & bufferBlockSize ) ;
if ( err ) {
logError ( i18n ( " Cannot read buffer size for %1 " ) . tqarg ( m_DSPDeviceName ) ) ;
} else {
logInfo ( i18n ( " %1 uses buffer blocks of %2 bytes " ) . tqarg ( m_DSPDeviceName ) . tqarg ( TQString : : number ( bufferBlockSize ) ) ) ;
size_t tmp = ( ( ( m_BufferSize - 1 ) / bufferBlockSize ) + 1 ) * bufferBlockSize ;
setBufferSize ( tmp ) ;
logInfo ( i18n ( " adjusted own buffer size to %1 bytes " ) . tqarg ( TQString : : number ( tmp ) ) ) ;
}
int trigger = ~ PCM_ENABLE_INPUT & ~ PCM_ENABLE_OUTPUT ;
ioctl ( m_DSP_fd , SNDCTL_DSP_SETTRIGGER , & trigger ) ;
trigger = PCM_ENABLE_INPUT | PCM_ENABLE_OUTPUT ;
ioctl ( m_DSP_fd , SNDCTL_DSP_SETTRIGGER , & trigger ) ;
if ( ! err ) {
m_PollingTimer . start ( 40 ) ;
} else {
closeDSPDevice ( ) ;
}
m_CaptureSkipCount = 0 ;
//m_PlaybackSkipCount = 0;
return ! err ;
}
bool OSSSoundDevice : : closeDSPDevice ( bool force )
{
if ( ( ! m_PlaybackStreamID . isValid ( ) & & ! m_CaptureStreamID . isValid ( ) ) | | force ) {
if ( m_Mixer_fd < 0 )
m_PollingTimer . stop ( ) ;
if ( m_DSP_fd > = 0 )
close ( m_DSP_fd ) ;
m_DSP_fd = - 1 ;
m_PlaybackBuffer . clear ( ) ;
m_CaptureBuffer . clear ( ) ;
}
return true ;
}
bool OSSSoundDevice : : openMixerDevice ( bool reopen )
{
if ( reopen ) {
if ( m_Mixer_fd > = 0 )
closeMixerDevice ( /* force = */ true ) ;
else
return true ;
}
if ( m_Mixer_fd < 0 )
m_Mixer_fd = open ( m_MixerDeviceName . ascii ( ) , O_RDONLY ) ;
if ( m_Mixer_fd < 0 ) {
logError ( i18n ( " Cannot open mixer device %1 " ) . tqarg ( m_MixerDeviceName ) ) ;
} else {
m_PollingTimer . start ( 40 ) ;
}
return m_Mixer_fd > = 0 ;
}
bool OSSSoundDevice : : closeMixerDevice ( bool force )
{
if ( ( ! m_PlaybackStreamID . isValid ( ) & & ! m_CaptureStreamID . isValid ( ) ) | | force ) {
if ( m_DSP_fd < 0 )
m_PollingTimer . stop ( ) ;
if ( m_Mixer_fd > = 0 )
close ( m_Mixer_fd ) ;
m_Mixer_fd = - 1 ;
}
return m_Mixer_fd < 0 ;
}
void OSSSoundDevice : : getMixerChannels ( int query , TQStringList & retval , TQMap < TQString , int > & revmap ) const
{
retval . clear ( ) ;
revmap . clear ( ) ;
int fd = m_Mixer_fd ;
if ( fd < 0 )
fd = open ( m_MixerDeviceName . ascii ( ) , O_RDONLY ) ;
if ( fd < 0 ) {
logError ( i18n ( " OSSSoundDevice::getMixerChannels: Cannot open mixer device %1 " ) . tqarg ( m_MixerDeviceName ) ) ;
}
if ( fd > = 0 ) {
int tqmask = 0 ;
if ( ioctl ( fd , MIXER_READ ( query ) , & tqmask ) = = 0 ) {
for ( int i = 0 ; i < SOUND_MIXER_NRDEVICES ; + + i ) {
if ( tqmask & ( 1 < < i ) ) {
static const char * labels [ ] = SOUND_DEVICE_LABELS ;
retval . append ( i18n ( labels [ i ] ) ) ;
revmap . insert ( i18n ( labels [ i ] ) , i ) ;
}
}
} else {
logError ( i18n ( " OSSSoundDevice::getMixerChannels: Cannot read mixer device tqmask on device %1 " ) . tqarg ( m_MixerDeviceName ) ) ;
}
}
if ( fd ! = m_Mixer_fd )
close ( fd ) ;
}
const TQStringList & OSSSoundDevice : : getPlaybackChannels ( ) const
{
return m_PlaybackChannels ;
}
const TQStringList & OSSSoundDevice : : getCaptureChannels ( ) const
{
return m_CaptureChannels ;
}
bool OSSSoundDevice : : setPlaybackVolume ( SoundStreamID id , float volume )
{
if ( id . isValid ( ) & & ( m_PlaybackStreamID = = id | | m_PassivePlaybackStreams . contains ( id ) ) ) {
SoundStreamConfig & cfg = m_PlaybackStreams [ id ] ;
if ( rint ( 100 * volume ) ! = rint ( 100 * cfg . m_Volume ) ) {
cfg . m_Volume = writeMixerVolume ( cfg . m_Channel , volume ) ;
notifyPlaybackVolumeChanged ( id , cfg . m_Volume ) ;
}
return true ;
}
return false ;
}
bool OSSSoundDevice : : setCaptureVolume ( SoundStreamID id , float volume )
{
if ( id . isValid ( ) & & m_CaptureStreamID = = id ) {
SoundStreamConfig & cfg = m_CaptureStreams [ id ] ;
if ( rint ( 100 * volume ) ! = rint ( 100 * cfg . m_Volume ) ) {
cfg . m_Volume = writeMixerVolume ( cfg . m_Channel , volume ) ;
notifyCaptureVolumeChanged ( id , cfg . m_Volume ) ;
}
return true ;
}
return false ;
}
bool OSSSoundDevice : : getPlaybackVolume ( SoundStreamID id , float & volume ) const
{
if ( id . isValid ( ) & & ( m_PlaybackStreamID = = id | | m_PassivePlaybackStreams . contains ( id ) ) ) {
const SoundStreamConfig & cfg = m_PlaybackStreams [ id ] ;
volume = cfg . m_Volume ;
return true ;
}
return false ;
}
bool OSSSoundDevice : : getCaptureVolume ( SoundStreamID id , float & volume ) const
{
if ( id . isValid ( ) & & m_CaptureStreamID = = id ) {
const SoundStreamConfig & cfg = m_CaptureStreams [ id ] ;
volume = cfg . m_Volume ;
return true ;
}
return false ;
}
void OSSSoundDevice : : checkMixerVolume ( SoundStreamID id )
{
if ( m_Mixer_fd > = 0 & & id . isValid ( ) ) {
if ( m_PassivePlaybackStreams . contains ( id ) | | m_PlaybackStreamID = = id ) {
SoundStreamConfig & cfg = m_PlaybackStreams [ id ] ;
float v = readMixerVolume ( cfg . m_Channel ) ;
if ( rint ( 100 * cfg . m_Volume ) ! = rint ( 100 * v ) ) {
cfg . m_Volume = v ;
notifyPlaybackVolumeChanged ( id , v ) ;
}
}
if ( m_CaptureStreamID = = id ) {
SoundStreamConfig & cfg = m_CaptureStreams [ id ] ;
float v = readMixerVolume ( cfg . m_Channel ) ;
if ( rint ( 100 * cfg . m_Volume ) ! = rint ( 100 * v ) ) {
cfg . m_Volume = v ;
notifyCaptureVolumeChanged ( id , v ) ;
}
}
}
}
float OSSSoundDevice : : readMixerVolume ( int channel ) const
{
_lrvol tmpvol ;
int err = ioctl ( m_Mixer_fd , MIXER_READ ( channel ) , & tmpvol ) ;
if ( err ) {
logError ( " OSSSound::readMixerVolume: " +
i18n ( " error %1 while reading volume from %2 " )
. tqarg ( TQString ( ) . setNum ( err ) )
. tqarg ( m_MixerDeviceName ) ) ;
tmpvol . l = tmpvol . r = 0 ;
}
return float ( tmpvol . l ) / 100.0 ;
}
float OSSSoundDevice : : writeMixerVolume ( int channel , float vol )
{
if ( vol > 1.0 ) vol = 1.0 ;
if ( vol < 0 ) vol = 0.0 ;
const int divs = 100 ;
vol = rint ( vol * divs ) / float ( divs ) ;
if ( m_Mixer_fd > = 0 ) {
_lrvol tmpvol ;
tmpvol . r = tmpvol . l = ( unsigned int ) ( rint ( vol * divs ) ) ;
int err = ioctl ( m_Mixer_fd , MIXER_WRITE ( channel ) , & tmpvol ) ;
if ( err ! = 0 ) {
logError ( " OSSSoundDevice::writeMixerVolume: " +
i18n ( " error %1 while setting volume to %2 on device %3 " )
. tqarg ( TQString ( ) . setNum ( err ) )
. tqarg ( TQString ( ) . setNum ( vol ) )
. tqarg ( m_MixerDeviceName ) ) ;
return - 1 ;
}
}
return vol ;
}
void OSSSoundDevice : : selectCaptureChannel ( int channel )
{
int x = 1 < < channel ;
int err = ioctl ( m_Mixer_fd , SOUND_MIXER_WRITE_RECSRC , & x ) ;
if ( err )
logError ( i18n ( " Selecting recording source on device %1 failed with error code %2 " )
. tqarg ( m_MixerDeviceName )
. tqarg ( TQString : : number ( err ) ) ) ;
_lrvol tmpvol ;
err = ioctl ( m_Mixer_fd , MIXER_READ ( SOUND_MIXER_IGAIN ) , & tmpvol ) ;
if ( err )
logError ( i18n ( " Reading igain volume on device %1 failed with error code %2 " )
. tqarg ( m_MixerDeviceName )
. tqarg ( TQString : : number ( err ) ) ) ;
if ( tmpvol . r = = 0 & & tmpvol . l = = 0 ) {
tmpvol . r = tmpvol . l = 1 ;
err = ioctl ( m_Mixer_fd , MIXER_WRITE ( SOUND_MIXER_IGAIN ) , & tmpvol ) ;
if ( err )
logError ( i18n ( " Setting igain volume on device %1 failed with error code %2 " )
. tqarg ( m_MixerDeviceName )
. tqarg ( TQString : : number ( err ) ) ) ;
}
}
int OSSSoundDevice : : getOSSFormat ( const SoundFormat & f )
{
if ( f . m_SampleBits = = 16 ) {
switch ( 2 * f . m_IsSigned + ( f . m_Endianess = = LITTLE_ENDIAN ) ) {
case 0 : return AFMT_U16_BE ;
case 1 : return AFMT_U16_LE ;
case 2 : return AFMT_S16_BE ;
case 3 : return AFMT_S16_LE ;
}
}
if ( f . m_SampleBits = = 8 ) {
switch ( f . m_IsSigned ) {
case 0 : return AFMT_U8 ;
case 1 : return AFMT_S8 ;
}
}
return 0 ;
}
void OSSSoundDevice : : setBufferSize ( int s )
{
m_BufferSize = s ;
m_PlaybackBuffer . resize ( m_BufferSize ) ;
m_CaptureBuffer . resize ( m_BufferSize ) ;
}
void OSSSoundDevice : : enablePlayback ( bool on )
{
m_EnablePlayback = on ;
}
void OSSSoundDevice : : enableCapture ( bool on )
{
m_EnableCapture = on ;
}
void OSSSoundDevice : : setDSPDeviceName ( const TQString & s )
{
m_DSPDeviceName = s ;
SoundFormat f = m_DSPFormat ;
if ( m_DSP_fd > = 0 )
openDSPDevice ( f , /* reopen = */ true ) ;
}
TQString OSSSoundDevice : : getSoundStreamClientDescription ( ) const
{
return i18n ( " OSS Sound Device %1 " ) . tqarg ( PluginBase : : name ( ) ) ;
}
# include "oss-sound.moc"