/***************************************************************************
alsa - sound . cpp - description
- - - - - - - - - - - - - - - - - - -
begin : Thu May 26 2005
copyright : ( C ) 2005 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 <tdelocale.h>
# include <tdeaboutdata.h>
# include <sys/types.h>
# include <sys/stat.h>
# include <sys/ioctl.h>
# include <fcntl.h>
# include <unistd.h>
# include <math.h>
# include <errno.h>
# include <sys/soundcard.h>
# include <alsa/asoundlib.h>
# include "alsa-sound.h"
# include "alsa-sound-configuration.h"
// #include "capture-thread.h"
# include "../../src/include/aboutwidget.h"
# include "../../src/include/utils.h"
///////////////////////////////////////////////////////////////////////
//// plugin library functions
PLUGIN_LIBRARY_FUNCTIONS ( AlsaSoundDevice , " tderadio-alsa-sound " , i18n ( " Advanced Linux Sound Architecture (ALSA) Support " ) ) ;
/////////////////////////////////////////////////////////////////////////////
struct _lrvol { unsigned char l , r ; short dummy ; } ;
AlsaSoundDevice : : AlsaSoundDevice ( const TQString & name )
: TQObject ( NULL , NULL ) ,
PluginBase ( name , i18n ( " TDERadio ALSA Sound Plugin " ) ) ,
m_hPlayback ( NULL ) ,
m_hCapture ( NULL ) ,
m_hPlaybackMixer ( NULL ) ,
m_hCaptureMixer ( NULL ) ,
m_PlaybackFormat ( ) ,
m_CaptureFormat ( ) ,
m_PlaybackCard ( - 1 ) ,
m_PlaybackDevice ( - 1 ) ,
m_CaptureCard ( - 1 ) ,
m_CaptureDevice ( - 1 ) ,
m_PlaybackLatency ( 50 ) ,
m_CaptureLatency ( 50 ) ,
m_PassivePlaybackStreams ( ) ,
m_PlaybackStreamID ( ) ,
m_CaptureStreamID ( ) ,
m_HWBufferSize ( 2048 ) ,
m_BufferSize ( 16384 ) ,
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 ) //,
// m_captureThread(NULL)
{
TQObject : : connect ( & m_PlaybackPollingTimer , TQ_SIGNAL ( timeout ( ) ) , this , TQ_SLOT ( slotPollPlayback ( ) ) ) ;
TQObject : : connect ( & m_CapturePollingTimer , TQ_SIGNAL ( timeout ( ) ) , this , TQ_SLOT ( slotPollCapture ( ) ) ) ;
}
AlsaSoundDevice : : ~ AlsaSoundDevice ( )
{
stopCapture ( m_CaptureStreamID ) ;
stopPlayback ( m_PlaybackStreamID ) ;
closePlaybackDevice ( ) ;
closeCaptureDevice ( ) ;
closePlaybackMixerDevice ( ) ;
closeCaptureMixerDevice ( ) ;
}
bool AlsaSoundDevice : : connectI ( Interface * i )
{
bool a = PluginBase : : connectI ( i ) ;
bool b = ISoundStreamClient : : connectI ( i ) ;
return a | | b ;
}
bool AlsaSoundDevice : : disconnectI ( Interface * i )
{
bool a = PluginBase : : disconnectI ( i ) ;
bool b = ISoundStreamClient : : disconnectI ( i ) ;
return a | | b ;
}
void AlsaSoundDevice : : 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_sendMute ( this ) ;
s - > register4_sendUnmute ( 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 AlsaSoundDevice : : saveState ( TDEConfig * c ) const
{
c - > setGroup ( TQString ( " alsa-sound- " ) + PluginBase : : name ( ) ) ;
c - > writeEntry ( " playback-card " , m_PlaybackCard ) ;
c - > writeEntry ( " playback-device " , m_PlaybackDevice ) ;
c - > writeEntry ( " capture-card " , m_CaptureCard ) ;
c - > writeEntry ( " capture-device " , m_CaptureDevice ) ;
c - > writeEntry ( " enable-playback " , m_EnablePlayback ) ;
c - > writeEntry ( " enable-capture " , m_EnableCapture ) ;
c - > writeEntry ( " hwbuffer-size " , m_HWBufferSize ) ;
c - > writeEntry ( " buffer-size " , m_BufferSize ) ;
c - > writeEntry ( " soundstreamclient-id " , m_SoundStreamClientID ) ;
c - > writeEntry ( " mixer-settings " , m_CaptureMixerSettings . count ( ) ) ;
int i = 0 ;
for ( TQMapConstIterator < TQString , AlsaConfigMixerSetting > it = m_CaptureMixerSettings . begin ( ) ; it ! = m_CaptureMixerSettings . end ( ) ; + + it , + + i ) {
TQString prefix = TQString ( " mixer-setting-%1- " ) . arg ( i ) ;
( * it ) . saveState ( c , prefix ) ;
}
}
void AlsaSoundDevice : : restoreState ( TDEConfig * c )
{
c - > setGroup ( TQString ( " alsa-sound- " ) + PluginBase : : name ( ) ) ;
m_EnablePlayback = c - > readBoolEntry ( " enable-playback " , true ) ;
m_EnableCapture = c - > readBoolEntry ( " enable-capture " , true ) ;
m_HWBufferSize = c - > readNumEntry ( " hwbuffer-size " , 2048 ) ;
m_BufferSize = c - > readNumEntry ( " buffer-size " , 16384 ) ;
int card = c - > readNumEntry ( " playback-card " , 0 ) ;
int dev = c - > readNumEntry ( " playback-device " , 0 ) ;
setPlaybackDevice ( card , dev ) ;
card = c - > readNumEntry ( " capture-card " , 0 ) ;
dev = c - > readNumEntry ( " capture-device " , 0 ) ;
setCaptureDevice ( card , dev ) ;
m_PlaybackBuffer . resize ( m_BufferSize ) ;
m_CaptureBuffer . resize ( m_BufferSize ) ;
setSoundStreamClientID ( c - > readEntry ( " soundstreamclient-id " , getSoundStreamClientID ( ) ) ) ;
int n = c - > readNumEntry ( " mixer-settings " , 0 ) ;
for ( int i = 0 ; i < n ; + + i ) {
TQString prefix = TQString ( " mixer-setting-%1- " ) . arg ( i ) ;
AlsaConfigMixerSetting s ( c , prefix ) ;
m_CaptureMixerSettings . insert ( s . getIDString ( ) , s ) ;
}
emit sigUpdateConfig ( ) ;
}
ConfigPageInfo AlsaSoundDevice : : createConfigurationPage ( )
{
AlsaSoundConfiguration * conf = new AlsaSoundConfiguration ( NULL , this ) ;
TQObject : : connect ( this , TQ_SIGNAL ( sigUpdateConfig ( ) ) , conf , TQ_SLOT ( slotUpdateConfig ( ) ) ) ;
return ConfigPageInfo ( conf ,
i18n ( " ALSA Sound " ) ,
i18n ( " ALSA Sound Device Options " ) ,
" tderadio_alsa2 " ) ;
}
AboutPageInfo AlsaSoundDevice : : createAboutPage ( )
{
/* TDEAboutData aboutData("tderadio",
NULL ,
NULL ,
I18N_NOOP ( " ALSA Sound Plugin for TDERadio " ) ,
TDEAboutData : : License_GPL ,
" (c) 2005 Martin Witte " ,
0 ,
" http://sourceforge.net/projects/tderadio " ,
0 ) ;
aboutData . addAuthor ( " Martin Witte " , " " , " witte@kawo1.rwth-aachen.de " ) ;
return AboutPageInfo (
new TDERadioAboutWidget ( aboutData , TDERadioAboutWidget : : AbtTabbed ) ,
i18n ( " ALSA Sound " ) ,
i18n ( " ALSA Sound " ) ,
" tderadio_alsa_sound "
) ;
*/
return AboutPageInfo ( ) ;
}
bool AlsaSoundDevice : : preparePlayback ( SoundStreamID id , const TQString & channel , bool active_mode , bool start_immediately )
{
if ( id . isValid ( ) ) {
m_PlaybackStreams . insert ( id , SoundStreamConfig ( channel , active_mode ) ) ;
if ( start_immediately )
startPlayback ( id ) ;
return true ;
// FIXME: what to do if stream is already playing?
}
return false ;
}
bool AlsaSoundDevice : : prepareCapture ( SoundStreamID id , const TQString & channel )
{
if ( id . isValid ( ) ) {
m_CaptureStreams . insert ( id , SoundStreamConfig ( channel ) ) ;
return true ;
// FIXME: what to do if stream is already playing?
}
return false ;
}
bool AlsaSoundDevice : : 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 AlsaSoundDevice : : 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 AlsaSoundDevice : : supportsPlayback ( ) const
{
return m_EnablePlayback ;
}
bool AlsaSoundDevice : : supportsCapture ( ) const
{
return m_EnableCapture ;
}
bool AlsaSoundDevice : : 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 ) {
openPlaybackMixerDevice ( ) ;
if ( cfg . m_Volume > = 0 & & writePlaybackMixerVolume ( cfg . m_Channel , cfg . m_Volume , cfg . m_Muted ) ) {
notifyPlaybackVolumeChanged ( id , cfg . m_Volume ) ;
notifyMuted ( id , cfg . m_Volume ) ;
}
m_PlaybackPollingTimer . start ( m_PlaybackLatency ) ;
}
// error handling?
return true ;
} else {
return false ;
}
}
bool AlsaSoundDevice : : pausePlayback ( SoundStreamID /*id*/ )
{
//return stopPlayback(id);
return false ;
}
bool AlsaSoundDevice : : stopPlayback ( SoundStreamID id )
{
if ( id . isValid ( ) & & m_PlaybackStreams . contains ( id ) ) {
SoundStreamConfig & cfg = m_PlaybackStreams [ id ] ;
if ( ! cfg . m_ActiveMode ) {
if ( m_PassivePlaybackStreams . contains ( id ) ) {
/* float tmp = 0;
writePlaybackMixerVolume ( cfg . m_Channel , tmp , true ) ; */
m_PassivePlaybackStreams . remove ( id ) ;
}
} else if ( m_PlaybackStreamID = = id ) {
m_PlaybackStreamID = SoundStreamID : : InvalidID ;
m_PlaybackBuffer . clear ( ) ;
closePlaybackDevice ( ) ;
}
closePlaybackMixerDevice ( ) ;
return true ;
} else {
return false ;
}
}
bool AlsaSoundDevice : : isPlaybackRunning ( SoundStreamID id , bool & b ) const
{
if ( id . isValid ( ) & & m_PlaybackStreamID = = id | | m_PassivePlaybackStreams . contains ( id ) ) {
b = true ;
return true ;
} else {
return false ;
}
}
bool AlsaSoundDevice : : 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 & & proposed_format ! = m_CaptureFormat ) ) {
m_CaptureStreamID = id ;
SoundStreamConfig & cfg = m_CaptureStreams [ id ] ;
openCaptureMixerDevice ( ) ;
selectCaptureChannel ( cfg . m_Channel ) ;
if ( cfg . m_Volume > = 0 & & writeCaptureMixerVolume ( cfg . m_Channel , cfg . m_Volume ) ) {
notifyCaptureVolumeChanged ( m_CaptureStreamID , cfg . m_Volume ) ;
}
openCaptureDevice ( proposed_format ) ;
// FIXME: error handling?
}
real_format = m_CaptureFormat ;
m_CaptureRequestCounter + + ;
// m_captureThread = new AlsaCaptureThread(this, m_hCapture, m_CaptureFormat, 5, m_BufferSize);
// m_captureThread->start();
slotPollCapture ( ) ;
return true ;
} else {
return false ;
}
}
bool AlsaSoundDevice : : stopCapture ( SoundStreamID id )
{
if ( id . isValid ( ) & & m_CaptureStreamID = = id ) {
if ( - - m_CaptureRequestCounter = = 0 ) {
// m_captureThread->setDone();
// if (!m_captureThread->wait(4000)) { //wait at maximum 4 seconds
// logError("AlsaPlugin: capture thread did not terminate. Killing it.");
// m_captureThread->terminate();
// m_captureThread->wait();
// }
slotPollCapture ( ) ;
// if (m_captureThread->error()) {
// logError(i18n("ALSA Plugin, device plughw:%1,%2: %3").arg(m_CaptureCard)
// .arg(m_CaptureDevice)
// .arg(i18n("unknown error")));
// }
//
// delete m_captureThread;
// m_captureThread = NULL;
m_CaptureStreamID = SoundStreamID : : InvalidID ;
m_CaptureBuffer . clear ( ) ;
closeCaptureMixerDevice ( ) ;
closeCaptureDevice ( ) ;
}
return true ;
} else {
return false ;
}
}
bool AlsaSoundDevice : : isCaptureRunning ( SoundStreamID id , bool & b , SoundFormat & sf ) const
{
if ( id . isValid ( ) & & m_CaptureStreamID = = id ) {
b = true ;
sf = m_CaptureFormat ;
return true ;
} else {
return false ;
}
}
bool AlsaSoundDevice : : 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 AlsaSoundDevice : : 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 AlsaSoundDevice : : 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_hPlayback ) {
openPlaybackDevice ( format ) ;
} else if ( format ! = m_PlaybackFormat ) {
// flush playback buffer
size_t buffersize = 0 ;
char * buffer = m_PlaybackBuffer . getData ( buffersize ) ;
snd_pcm_writei ( m_hPlayback , buffer , buffersize / m_PlaybackFormat . sampleSize ( ) ) ;
// if not all could be written, it must be discarded
m_PlaybackBuffer . clear ( ) ;
closePlaybackDevice ( ) ;
openPlaybackDevice ( 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 ( " plughw:%1,%2: Playback buffer overflow. Skipped %3 bytes " ) . arg ( m_PlaybackCard ) . arg ( m_PlaybackDevice ) . arg ( TQString : : number ( m_PlaybackSkipCount ) ) ) ;
m_PlaybackSkipCount = 0 ;
}
return m_PlaybackSkipCount = = 0 ; */
return true ;
}
void AlsaSoundDevice : : slotPollPlayback ( )
{
if ( m_PlaybackStreamID . isValid ( ) ) {
if ( m_PlaybackBuffer . getFillSize ( ) > 0 & & m_hPlayback ) {
size_t buffersize = 0 ;
int frameSize = m_CaptureFormat . frameSize ( ) ;
char * buffer = m_PlaybackBuffer . getData ( buffersize ) ;
int framesWritten = snd_pcm_writei ( m_hPlayback , buffer , buffersize / frameSize ) ;
int bytesWritten = framesWritten * frameSize ;
if ( framesWritten > 0 ) {
m_PlaybackBuffer . removeData ( bytesWritten ) ;
} else if ( framesWritten = = 0 ) {
logError ( i18n ( " ALSA Plugin: cannot write data for device plughw:%1,%2 " ) . arg ( m_PlaybackCard ) . arg ( m_PlaybackDevice ) ) ;
} else if ( framesWritten = = - EAGAIN ) {
// do nothing
} else {
snd_pcm_prepare ( m_hPlayback ) ;
logWarning ( i18n ( " ALSA Plugin: buffer underrun for device plughw:%1,%2 " ) . arg ( m_PlaybackCard ) . arg ( m_PlaybackDevice ) ) ;
}
}
if ( m_PlaybackBuffer . getFreeSize ( ) > m_PlaybackBuffer . getSize ( ) / 3 ) {
notifyReadyForPlaybackData ( m_PlaybackStreamID , m_PlaybackBuffer . getFreeSize ( ) ) ;
}
checkMixerVolume ( m_PlaybackStreamID ) ;
}
TQValueListConstIterator < SoundStreamID > end = m_PassivePlaybackStreams . end ( ) ;
for ( TQValueListConstIterator < SoundStreamID > it = m_PassivePlaybackStreams . begin ( ) ; it ! = end ; + + it )
checkMixerVolume ( * it ) ;
}
void AlsaSoundDevice : : slotPollCapture ( )
{
if ( m_CaptureStreamID . isValid ( ) & & m_hCapture ) {
// while (m_captureThread && m_captureThread->getAvailableReadBuffers()) {
// TQString dev = TQString("alsa://plughw:%1,%2").arg(m_CaptureCard).arg(m_CaptureDevice);
// size_t size = 0;
// char *buffer = m_captureThread->getReadBuffer(size);
// time_t cur_time = time(NULL);
// notifySoundStreamData(m_CaptureStreamID, m_CaptureFormat, buffer, size, SoundMetaData(m_CapturePos, cur_time - m_CaptureStartTime, cur_time, dev));
// m_CapturePos += size;
// }
size_t bufferSize = 0 ;
char * buffer = m_CaptureBuffer . getFreeSpace ( bufferSize ) ;
if ( bufferSize ) {
size_t frameSize = m_CaptureFormat . frameSize ( ) ;
int framesRead = snd_pcm_readi ( m_hCapture , buffer , bufferSize / frameSize ) ;
size_t bytesRead = framesRead > 0 ? framesRead * frameSize : 0 ;
// //BEGIN DEBUG
// static unsigned int debug_val = 0;
// short *debug_buf = (short*)buffer;
// for (int i = 0; i < bytesRead / 2 / sizeof(short); ++i) {
// debug_buf[2*i] = debug_val >> 10;
// debug_buf[2*i+1] = debug_val >> 10;
// ++debug_val;
// }
// //END DEBUG
if ( framesRead > 0 ) {
m_CaptureBuffer . removeFreeSpace ( bytesRead ) ;
} else if ( framesRead = = 0 ) {
snd_pcm_prepare ( m_hCapture ) ;
logError ( i18n ( " ALSA Plugin: cannot read data from device plughw:%1,%2 " ) . arg ( m_CaptureCard ) . arg ( m_CaptureDevice ) ) ;
} else if ( framesRead = = - EAGAIN ) {
// do nothing
} else {
snd_pcm_prepare ( m_hCapture ) ;
logWarning ( i18n ( " ALSA Plugin: buffer overrun for device plughw:%1,%2 (buffersize=%3, buffer=%4) " ) . arg ( m_CaptureCard ) . arg ( m_CaptureDevice ) . arg ( bufferSize ) . arg ( ( long long unsigned ) buffer ) ) ;
}
TQString dev = TQString ( " alsa://plughw:%1,%2 " ) . arg ( m_CaptureCard ) . arg ( m_CaptureDevice ) ;
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_CaptureFormat , buffer , size , consumed_size , SoundMetaData ( m_CapturePos , cur_time - m_CaptureStartTime , cur_time , i18n ( " internal stream, not stored (%1) " ) . arg ( dev ) ) ) ;
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_CaptureStreamID . isValid ( ) )
checkMixerVolume ( m_CaptureStreamID ) ;
}
bool AlsaSoundDevice : : openPlaybackDevice ( const SoundFormat & format , bool reopen )
{
if ( m_PlaybackCard < 0 | | m_PlaybackDevice < 0 )
return false ;
if ( m_hPlayback ) {
if ( reopen ) {
closePlaybackDevice ( /* force = */ true ) ;
} else {
if ( format ! = m_PlaybackFormat )
return false ;
return true ;
}
} else {
if ( reopen ) // FIXME: emw: please check if this makes sense !?!?
return true ;
}
m_PlaybackFormat = format ;
TQString dev = TQString ( " plughw:%1,%2 " ) . arg ( m_PlaybackCard ) . arg ( m_PlaybackDevice ) ;
bool error = ! openAlsaDevice ( m_hPlayback , m_PlaybackFormat , dev . ascii ( ) , SND_PCM_STREAM_PLAYBACK , SND_PCM_NONBLOCK , m_PlaybackLatency ) ;
if ( ! error ) {
m_PlaybackPollingTimer . start ( m_PlaybackLatency ) ;
} else {
closePlaybackDevice ( ) ;
}
// m_PlaybackSkipCount = 0;
return ! error ;
}
bool AlsaSoundDevice : : openCaptureDevice ( const SoundFormat & format , bool reopen )
{
if ( m_PlaybackCard < 0 | | m_PlaybackDevice < 0 )
return false ;
if ( m_hCapture ) {
if ( reopen ) {
closeCaptureDevice ( /* force = */ true ) ;
} else {
if ( format ! = m_CaptureFormat )
return false ;
return true ;
}
} else {
if ( reopen ) // FIXME: emw: please check if this makes sense !?!?
return true ;
}
m_CaptureFormat = format ;
TQString dev = TQString ( " plughw:%1,%2 " ) . arg ( m_CaptureCard ) . arg ( m_CaptureDevice ) ;
// bool error = !openAlsaDevice(m_hCapture, m_CaptureFormat, dev.ascii(), SND_PCM_STREAM_CAPTURE, /*flags = block*/0, m_CaptureLatency);
bool error = ! openAlsaDevice ( m_hCapture , m_CaptureFormat , dev . ascii ( ) , SND_PCM_STREAM_CAPTURE , SND_PCM_NONBLOCK , m_CaptureLatency ) ;
if ( ! error ) {
m_CapturePollingTimer . start ( m_CaptureLatency ) ;
} else {
closeCaptureDevice ( ) ;
}
m_CaptureSkipCount = 0 ;
return ! error ;
}
bool AlsaSoundDevice : : openAlsaDevice ( snd_pcm_t * & alsa_handle , SoundFormat & format , const char * pcm_name , snd_pcm_stream_t stream , int flags , unsigned & latency )
{
bool error = false ;
int dir = 0 ;
snd_pcm_hw_params_t * hwparams = NULL ;
snd_pcm_hw_params_alloca ( & hwparams ) ;
/* OPEN */
if ( ! error & & snd_pcm_open ( & alsa_handle , pcm_name , stream , flags ) < 0 ) {
logError ( i18n ( " ALSA Plugin: Error opening PCM device %1 " ) . arg ( pcm_name ) ) ;
error = true ;
}
if ( ! error & & snd_pcm_hw_params_any ( alsa_handle , hwparams ) < 0 ) {
logError ( i18n ( " ALSA Plugin: Can not configure PCM device %1 " ) . arg ( pcm_name ) ) ;
error = true ;
}
/* interleaved access type */
if ( ! error & & snd_pcm_hw_params_set_access ( alsa_handle , hwparams , SND_PCM_ACCESS_RW_INTERLEAVED ) < 0 ) {
logError ( i18n ( " ALSA Plugin: Error setting access for %1 " ) . arg ( pcm_name ) ) ;
error = true ;
}
/* sample format */
snd_pcm_format_t sample_format = snd_pcm_build_linear_format ( format . m_SampleBits ,
format . m_SampleBits ,
! format . m_IsSigned ,
format . m_Endianess = = BIG_ENDIAN ) ;
if ( ! error & & snd_pcm_hw_params_set_format ( alsa_handle , hwparams , sample_format ) < 0 ) {
logError ( i18n ( " ALSA Plugin: Error setting sample format for %1 " ) . arg ( pcm_name ) ) ;
error = true ;
}
/* channels */
if ( ! error & & snd_pcm_hw_params_set_channels ( alsa_handle , hwparams , format . m_Channels ) < 0 ) {
logError ( i18n ( " ALSA Plugin: Error setting channels for %1 " ) . arg ( pcm_name ) ) ;
error = true ;
}
/* sample rate */
int rate = format . m_SampleRate ;
if ( ! error & & snd_pcm_hw_params_set_rate_near ( alsa_handle , hwparams , & format . m_SampleRate , & dir ) < 0 ) {
logError ( i18n ( " ALSA Plugin: Error setting rate for %1 " ) . arg ( pcm_name ) ) ;
error = true ;
}
if ( ! error & & format . m_SampleRate ! = format . m_SampleRate ) {
logWarning ( i18n ( " ALSA Plugin: The rate %1 Hz is not supported by your hardware %2. Using %3 Hz instead " ) . arg ( rate ) . arg ( pcm_name ) . arg ( format . m_SampleRate ) ) ;
}
snd_pcm_uframes_t period_size = m_HWBufferSize / format . frameSize ( ) ;
if ( ! error & & snd_pcm_hw_params_set_period_size_near ( alsa_handle , hwparams , & period_size , & dir ) < 0 ) {
logError ( i18n ( " ALSA Plugin: Error setting period size for %1 " ) . arg ( pcm_name ) ) ;
error = true ;
}
// size_t buffersize_frames = m_HWBufferSize / format.frameSize();
// int periods = 4;
// //int period_size = m_BufferSize / periods;
//
// /* fragments */
// if (!error && snd_pcm_hw_params_set_periods(alsa_handle, hwparams, periods, 0) < 0) {
// logError(i18n("ALSA Plugin: Error setting periods for %1").arg(pcm_name));
// error = true;
// }
// /* Set buffer size (in frames). */
//
// snd_pcm_uframes_t exact_buffersize_frames = buffersize_frames;
// if (!error && snd_pcm_hw_params_set_buffer_size_near(alsa_handle, hwparams, &exact_buffersize_frames) < 0) {
// exact_buffersize_frames = 4096;
// if (!error && snd_pcm_hw_params_set_buffer_size_near(alsa_handle, hwparams, &exact_buffersize_frames) < 0) {
// logError(i18n("ALSA Plugin: Error setting buffersize for %1").arg(pcm_name));
// error = true;
// }
// }
// size_t exact_buffersize = exact_buffersize_frames * format.frameSize();
// if (!error && m_HWBufferSize != exact_buffersize) {
// logWarning(i18n("ALSA Plugin: Hardware %1 does not support buffer size of %2. Using buffer size of %3 instead.").arg(pcm_name).arg(m_HWBufferSize).arg(exact_buffersize));
// size_t tmp = (((m_HWBufferSize - 1) / exact_buffersize) + 1) * exact_buffersize;
// setHWBufferSize(tmp);
// logInfo(i18n("ALSA Plugin: adjusted buffer size for %1 to %2 bytes").arg(pcm_name).arg(TQString::number(tmp)));
// }
/* set all params */
if ( ! error & & snd_pcm_hw_params ( alsa_handle , hwparams ) < 0 ) {
logError ( i18n ( " ALSA Plugin: Error setting HW params " ) ) ;
error = true ;
}
if ( ! error & & snd_pcm_hw_params_get_period_size ( hwparams , & period_size , & dir ) < 0 ) {
logError ( i18n ( " ALSA Plugin: Error getting period size for %1 " ) . arg ( pcm_name ) ) ;
error = true ;
}
// latency = (exact_buffersize_frames * 1000) / format.m_SampleRate / periods; /* in milli seconds */
latency = ( period_size * format . frameSize ( ) * 1000 ) / format . m_SampleRate ; /* in milli seconds */
if ( ! error ) {
snd_pcm_prepare ( alsa_handle ) ;
}
return ! error ;
}
bool AlsaSoundDevice : : closePlaybackDevice ( bool force )
{
if ( ! m_PlaybackStreamID . isValid ( ) | | force ) {
if ( ! m_hPlaybackMixer )
m_PlaybackPollingTimer . stop ( ) ;
if ( m_hPlayback ) {
snd_pcm_drop ( m_hPlayback ) ;
snd_pcm_close ( m_hPlayback ) ;
}
m_hPlayback = NULL ;
m_PlaybackBuffer . clear ( ) ;
return true ;
}
return false ;
}
bool AlsaSoundDevice : : closeCaptureDevice ( bool force )
{
if ( ! m_CaptureStreamID . isValid ( ) | | force ) {
if ( ! m_hCaptureMixer )
m_CapturePollingTimer . stop ( ) ;
if ( m_hCapture ) {
snd_pcm_drop ( m_hCapture ) ;
snd_pcm_close ( m_hCapture ) ;
}
m_hCapture = NULL ;
m_CaptureBuffer . clear ( ) ;
return true ;
}
return false ;
}
bool AlsaSoundDevice : : openPlaybackMixerDevice ( bool reopen )
{
return openMixerDevice ( m_hPlaybackMixer , m_PlaybackCard , reopen , & m_PlaybackPollingTimer , m_PlaybackLatency ) ;
}
bool AlsaSoundDevice : : openCaptureMixerDevice ( bool reopen )
{
// logDebug("AlsaSoundDevice::openCaptureMixerDevice: card == " + TQString::number(m_CaptureCard));
return openMixerDevice ( m_hCaptureMixer , m_CaptureCard , reopen , & m_CapturePollingTimer , m_CaptureLatency ) ;
}
bool AlsaSoundDevice : : closePlaybackMixerDevice ( bool force )
{
return closeMixerDevice ( m_hPlaybackMixer , m_PlaybackCard , m_PlaybackStreamID , m_hPlayback , force , & m_PlaybackPollingTimer ) ;
}
bool AlsaSoundDevice : : closeCaptureMixerDevice ( bool force )
{
return closeMixerDevice ( m_hCaptureMixer , m_CaptureCard , m_CaptureStreamID , m_hCapture , force , & m_CapturePollingTimer ) ;
}
static int mixer_dummy_callback ( snd_mixer_t * , unsigned int /*mask*/ , snd_mixer_elem_t */ * elem */ )
{
return 0 ;
}
bool AlsaSoundDevice : : openMixerDevice ( snd_mixer_t * & mixer_handle , int card , bool reopen , TQTimer * timer , int timer_latency )
{
if ( reopen ) {
if ( mixer_handle ! = NULL )
closeMixerDevice ( mixer_handle , card , SoundStreamID : : InvalidID , NULL , /* force = */ true , timer ) ;
else
return true ;
}
if ( ! mixer_handle ) {
bool error = false ;
if ( snd_mixer_open ( & mixer_handle , 0 ) < 0 ) {
staticLogError ( i18n ( " ALSA Plugin: Error opening mixer " ) ) ;
error = true ;
}
TQString cardid = " hw: " + TQString : : number ( card ) ;
bool attached = false ;
if ( ! error ) {
if ( snd_mixer_attach ( mixer_handle , cardid . ascii ( ) ) < 0 ) {
staticLogError ( i18n ( " ALSA Plugin: ERROR: snd_mixer_attach for card %1 " ) . arg ( card ) ) ;
error = true ;
} else {
attached = true ;
}
}
if ( ! error & & snd_mixer_selem_register ( mixer_handle , NULL , NULL ) < 0 ) {
staticLogError ( i18n ( " ALSA Plugin: Error: snd_mixer_selem_register for card %1 " ) . arg ( card ) ) ;
error = true ;
}
if ( ! error & & snd_mixer_load ( mixer_handle ) < 0 ) {
staticLogError ( i18n ( " ALSA Plugin: Error: snd_mixer_load for card %1 " ) . arg ( card ) ) ;
error = true ;
}
if ( mixer_handle ) {
snd_mixer_set_callback ( mixer_handle , mixer_dummy_callback ) ;
}
if ( error ) {
if ( attached ) {
snd_mixer_detach ( mixer_handle , cardid . ascii ( ) ) ;
}
snd_mixer_close ( mixer_handle ) ;
mixer_handle = NULL ;
}
}
if ( mixer_handle & & timer ) {
timer - > start ( timer_latency ) ;
}
return mixer_handle ! = NULL ;
}
bool AlsaSoundDevice : : closeMixerDevice ( snd_mixer_t * & mixer_handle , int card , SoundStreamID id , snd_pcm_t * pcm_handle , bool force , TQTimer * timer )
{
if ( ! id . isValid ( ) | | force ) {
if ( ! pcm_handle & & timer )
timer - > stop ( ) ;
if ( mixer_handle ) {
TQString cardid = " hw: " + TQString : : number ( card ) ;
snd_mixer_free ( mixer_handle ) ;
snd_mixer_detach ( mixer_handle , cardid . ascii ( ) ) ;
snd_mixer_close ( mixer_handle ) ;
}
mixer_handle = NULL ;
}
return mixer_handle = = NULL ;
}
void AlsaSoundDevice : : getPlaybackMixerChannels (
int card ,
snd_mixer_t * __mixer_handle ,
TQStringList & retval , TQMap < TQString , AlsaMixerElement > & ch2id )
{
retval . clear ( ) ;
ch2id . clear ( ) ;
snd_mixer_t * mixer_handle = __mixer_handle /*m_hPlaybackMixer*/ ;
bool use_tmp_handle = false ;
if ( ! mixer_handle ) {
openMixerDevice ( mixer_handle , card /*m_PlaybackCard*/ , false , NULL , 0 ) ;
use_tmp_handle = true ;
}
if ( mixer_handle ) {
snd_mixer_elem_t * elem = NULL ;
for ( elem = snd_mixer_first_elem ( mixer_handle ) ; elem ; elem = snd_mixer_elem_next ( elem ) ) {
AlsaMixerElement sid ;
if ( ! snd_mixer_selem_is_active ( elem ) )
continue ;
snd_mixer_selem_get_id ( elem , sid ) ;
TQString name = snd_mixer_selem_id_get_name ( sid ) ;
int idx = snd_mixer_selem_id_get_index ( sid ) ;
if ( idx )
name = i18n ( " context-mixername-number " , " %1 %2 " ) . arg ( name ) . arg ( idx ) ;
if ( snd_mixer_selem_has_playback_volume ( elem ) ) {
ch2id [ name ] = sid ;
retval . append ( name ) ;
}
}
}
if ( use_tmp_handle & & mixer_handle ) {
closeMixerDevice ( mixer_handle , card /*m_PlaybackCard*/ , SoundStreamID : : InvalidID , NULL , true , NULL ) ;
}
}
void AlsaSoundDevice : : getCaptureMixerChannels (
int card ,
snd_mixer_t * __mixer_handle ,
TQStringList & vol_list , TQMap < TQString , AlsaMixerElement > & vol_ch2id ,
TQStringList & sw_list , TQMap < TQString , AlsaMixerElement > & sw_ch2id ,
TQStringList * all_list
)
{
vol_list . clear ( ) ;
sw_list . clear ( ) ;
if ( all_list ) all_list - > clear ( ) ;
vol_ch2id . clear ( ) ;
sw_ch2id . clear ( ) ;
snd_mixer_t * mixer_handle = __mixer_handle /*m_hCaptureMixer*/ ;
bool use_tmp_handle = false ;
if ( ! mixer_handle ) {
// staticLogDebug("AlsaSoundDevice::getCaptureMixerChannels: card == " + TQString::number(card/*m_CaptureCard*/));
openMixerDevice ( mixer_handle , card /*m_CaptureCard*/ , false , NULL , 0 ) ;
use_tmp_handle = true ;
}
if ( mixer_handle ) {
snd_mixer_elem_t * elem = NULL ;
for ( elem = snd_mixer_first_elem ( mixer_handle ) ; elem ; elem = snd_mixer_elem_next ( elem ) ) {
AlsaMixerElement sid ;
if ( ! snd_mixer_selem_is_active ( elem ) )
continue ;
snd_mixer_selem_get_id ( elem , sid ) ;
TQString name = snd_mixer_selem_id_get_name ( sid ) ;
int idx = snd_mixer_selem_id_get_index ( sid ) ;
if ( idx )
name = i18n ( " context-mixerelement-name-number " , " %1 %2 " ) . arg ( name ) . arg ( idx ) ;
bool add2all = false ;
if ( snd_mixer_selem_has_capture_switch ( elem ) ) {
sw_ch2id [ name ] = sid ;
sw_list . append ( name ) ;
add2all = true ;
}
if ( snd_mixer_selem_has_capture_volume ( elem ) ) {
vol_ch2id [ name ] = sid ;
vol_list . append ( name ) ;
add2all = true ;
}
if ( add2all & & all_list ) {
all_list - > append ( name ) ;
}
}
}
if ( use_tmp_handle & & mixer_handle ) {
closeMixerDevice ( mixer_handle , card /*m_CaptureCard*/ , SoundStreamID : : InvalidID , NULL , true , NULL ) ;
}
}
const TQStringList & AlsaSoundDevice : : getPlaybackChannels ( ) const
{
return m_PlaybackChannels ;
}
const TQStringList & AlsaSoundDevice : : getCaptureChannels ( ) const
{
return m_CaptureChannelsSwitch ;
}
bool AlsaSoundDevice : : 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 ) ) {
if ( writePlaybackMixerVolume ( cfg . m_Channel , cfg . m_Volume = volume , cfg . m_Muted ) ) {
notifyPlaybackVolumeChanged ( id , cfg . m_Volume ) ;
}
}
return true ;
}
return false ;
}
bool AlsaSoundDevice : : 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 ) ) {
if ( writeCaptureMixerVolume ( cfg . m_Channel , cfg . m_Volume = volume ) ) {
notifyCaptureVolumeChanged ( id , cfg . m_Volume ) ;
}
}
return true ;
}
return false ;
}
bool AlsaSoundDevice : : 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 AlsaSoundDevice : : 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 AlsaSoundDevice : : checkMixerVolume ( SoundStreamID id )
{
if ( id . isValid ( ) ) {
if ( m_hPlaybackMixer & & m_PassivePlaybackStreams . contains ( id ) | | m_PlaybackStreamID = = id ) {
snd_mixer_handle_events ( m_hPlaybackMixer ) ;
SoundStreamConfig & cfg = m_PlaybackStreams [ id ] ;
bool m = false ;
float v = readPlaybackMixerVolume ( cfg . m_Channel , m ) ;
if ( rint ( 100 * cfg . m_Volume ) ! = rint ( 100 * v ) ) {
cfg . m_Volume = v ;
notifyPlaybackVolumeChanged ( id , v ) ;
}
if ( m ! = cfg . m_Muted ) {
cfg . m_Muted = m ;
notifyMuted ( id , m ) ;
}
}
if ( m_hCaptureMixer & & m_CaptureStreamID = = id ) {
snd_mixer_handle_events ( m_hCaptureMixer ) ;
SoundStreamConfig & cfg = m_CaptureStreams [ id ] ;
if ( m_CaptureChannels2ID . contains ( cfg . m_Channel ) ) {
float v = readCaptureMixerVolume ( cfg . m_Channel ) ;
if ( rint ( 100 * cfg . m_Volume ) ! = rint ( 100 * v ) ) {
cfg . m_Volume = v ;
notifyCaptureVolumeChanged ( id , v ) ;
}
}
}
}
}
float AlsaSoundDevice : : readPlaybackMixerVolume ( const TQString & channel , bool & muted ) const
{
if ( ! m_hPlaybackMixer )
return 0 ; // without error
if ( m_PlaybackChannels2ID . contains ( channel ) & & m_hPlaybackMixer ) {
AlsaMixerElement sid = m_PlaybackChannels2ID [ channel ] ;
snd_mixer_elem_t * elem = snd_mixer_find_selem ( m_hPlaybackMixer , sid ) ;
if ( elem ) {
long min = 0 ;
long max = 0 ;
snd_mixer_selem_get_playback_volume_range ( elem , & min , & max ) ;
if ( min ! = max ) {
long val = min ;
muted = false ;
int m = false ;
if ( snd_mixer_selem_get_playback_switch ( elem , SND_MIXER_SCHN_FRONT_LEFT , & m ) = = 0 ) {
muted = ! m ;
}
if ( snd_mixer_selem_get_playback_volume ( elem , SND_MIXER_SCHN_FRONT_LEFT , & val ) = = 0 ) {
return ( ( float ) ( val - min ) ) / ( float ) ( max - min ) ;
}
}
}
}
logError ( " AlsaSound::readPlaybackMixerVolume: " +
i18n ( " error while reading volume from hwplug:%1,%2 " )
. arg ( m_PlaybackCard )
. arg ( m_PlaybackDevice ) ) ;
return 0 ;
}
float AlsaSoundDevice : : readCaptureMixerVolume ( const TQString & channel ) const
{
if ( ! m_hCaptureMixer )
return 0 ; // without error
if ( m_CaptureChannels2ID . contains ( channel ) & & m_hCaptureMixer ) {
AlsaMixerElement sid = m_CaptureChannels2ID [ channel ] ;
snd_mixer_elem_t * elem = snd_mixer_find_selem ( m_hCaptureMixer , sid ) ;
if ( elem ) {
if ( ! snd_mixer_selem_has_capture_volume ( elem ) )
return 0 ;
long min = 0 ;
long max = 0 ;
snd_mixer_selem_get_capture_volume_range ( elem , & min , & max ) ;
if ( min ! = max ) {
long val = min ;
if ( snd_mixer_selem_get_capture_volume ( elem , SND_MIXER_SCHN_FRONT_LEFT , & val ) = = 0 ) {
return ( ( float ) ( val - min ) ) / ( float ) ( max - min ) ;
}
}
}
}
logError ( " AlsaSound::readCaptureMixerVolume: " +
i18n ( " error while reading volume from hwplug:%1,%2 " )
. arg ( m_CaptureCard )
. arg ( m_CaptureDevice ) ) ;
return 0 ;
}
bool AlsaSoundDevice : : writePlaybackMixerVolume ( const TQString & channel , float & vol , bool muted )
{
if ( vol > 1.0 ) vol = 1.0 ;
if ( vol < 0 ) vol = 0.0 ;
if ( ! m_hPlaybackMixer )
return false ;
if ( m_PlaybackChannels2ID . contains ( channel ) & & m_hPlaybackMixer ) {
AlsaMixerElement sid = m_PlaybackChannels2ID [ channel ] ;
snd_mixer_elem_t * elem = snd_mixer_find_selem ( m_hPlaybackMixer , sid ) ;
if ( elem ) {
long min = 0 ;
long max = 0 ;
snd_mixer_selem_get_playback_volume_range ( elem , & min , & max ) ;
if ( min ! = max ) {
long val = ( int ) rint ( min + ( max - min ) * vol ) ;
vol = ( float ) ( val - min ) / ( float ) ( max - min ) ;
snd_mixer_selem_set_playback_switch_all ( elem , ! muted ) ;
if ( snd_mixer_selem_set_playback_volume_all ( elem , val ) = = 0 ) {
return true ;
}
}
}
}
logError ( " AlsaSound::writePlaybackMixerVolume: " +
i18n ( " error while writing volume %1 to hwplug:%2,%3 " )
. arg ( vol )
. arg ( m_PlaybackCard )
. arg ( m_PlaybackDevice ) ) ;
return false ;
}
bool AlsaSoundDevice : : writeCaptureMixerVolume ( const TQString & channel , float & vol )
{
if ( vol > 1.0 ) vol = 1.0 ;
if ( vol < 0 ) vol = 0.0 ;
if ( ! m_hCaptureMixer )
return false ;
if ( m_CaptureChannels2ID . contains ( channel ) & & m_hCaptureMixer ) {
AlsaMixerElement sid = m_CaptureChannels2ID [ channel ] ;
snd_mixer_elem_t * elem = snd_mixer_find_selem ( m_hCaptureMixer , sid ) ;
if ( elem ) {
long min = 0 ;
long max = 0 ;
snd_mixer_selem_get_capture_volume_range ( elem , & min , & max ) ;
if ( min ! = max ) {
long val = ( int ) rint ( min + ( max - min ) * vol ) ;
vol = ( float ) ( val - min ) / ( float ) ( max - min ) ;
if ( snd_mixer_selem_set_capture_volume_all ( elem , val ) = = 0 ) {
return true ;
}
}
}
}
logError ( " AlsaSound::writeCaptureMixerVolume: " +
i18n ( " error while writing volume %1 to hwplug:%2,%3 " )
. arg ( vol )
. arg ( m_CaptureCard )
. arg ( m_CaptureDevice ) ) ;
return false ;
}
bool AlsaSoundDevice : : writeCaptureMixerSwitch ( const TQString & channel , bool capture )
{
if ( ! m_hCaptureMixer )
return false ;
if ( m_CaptureChannelsSwitch2ID . contains ( channel ) & & m_hCaptureMixer ) {
AlsaMixerElement sid = m_CaptureChannelsSwitch2ID [ channel ] ;
snd_mixer_elem_t * elem = snd_mixer_find_selem ( m_hCaptureMixer , sid ) ;
if ( elem ) {
if ( snd_mixer_selem_set_capture_switch_all ( elem , capture ) = = 0 ) {
return true ;
}
}
}
logError ( " AlsaSound::writeCaptureMixerSwitch: " +
i18n ( " error while setting capture switch %1 for hwplug:%2,%3 " )
. arg ( channel )
. arg ( m_CaptureCard )
. arg ( m_CaptureDevice ) ) ;
return false ;
}
void AlsaSoundDevice : : selectCaptureChannel ( const TQString & channel )
{
writeCaptureMixerSwitch ( channel , true ) ;
const TQString ADC = " ADC " ;
if ( m_CaptureChannels2ID . contains ( ADC ) ) {
float v = readCaptureMixerVolume ( ADC ) ;
if ( rint ( v * 100 ) = = 0 ) {
float tmp_vol = 1.0 ;
writeCaptureMixerVolume ( ADC , tmp_vol ) ;
}
}
const TQString Digital = " Digital " ;
if ( m_CaptureChannels2ID . contains ( Digital ) ) {
float v = readCaptureMixerVolume ( Digital ) ;
if ( rint ( v * 100 ) = = 0 ) {
float tmp_vol = 1.0 ;
writeCaptureMixerVolume ( Digital , tmp_vol ) ;
}
}
const TQString WAVE = " Wave " ;
if ( m_CaptureChannels2ID . contains ( WAVE ) ) {
float x = 0 ;
writeCaptureMixerVolume ( WAVE , x ) ;
}
const TQString Capture = " Capture " ;
if ( m_CaptureChannelsSwitch2ID . contains ( Capture ) ) {
writeCaptureMixerSwitch ( Capture , true ) ;
}
for ( TQMapConstIterator < TQString , AlsaConfigMixerSetting > it = m_CaptureMixerSettings . begin ( ) ; it ! = m_CaptureMixerSettings . end ( ) ; + + it ) {
const AlsaConfigMixerSetting & s = * it ;
if ( s . m_card = = m_CaptureCard & & s . m_use ) {
float vol = s . m_volume ;
if ( m_CaptureChannels2ID . contains ( s . m_name ) )
writeCaptureMixerVolume ( s . m_name , vol ) ;
if ( m_CaptureChannelsSwitch2ID . contains ( s . m_name ) )
writeCaptureMixerSwitch ( s . m_name , s . m_active ) ;
}
}
}
void AlsaSoundDevice : : setHWBufferSize ( int s )
{
m_HWBufferSize = s ;
}
void AlsaSoundDevice : : setBufferSize ( int s )
{
m_BufferSize = s ;
m_PlaybackBuffer . resize ( m_BufferSize ) ;
m_CaptureBuffer . resize ( m_BufferSize ) ;
}
void AlsaSoundDevice : : enablePlayback ( bool on )
{
m_EnablePlayback = on ;
}
void AlsaSoundDevice : : enableCapture ( bool on )
{
m_EnableCapture = on ;
}
void AlsaSoundDevice : : setPlaybackDevice ( int card , int dev )
{
if ( m_PlaybackCard = = card & & m_PlaybackDevice = = dev )
return ;
m_PlaybackCard = card ;
m_PlaybackDevice = dev ;
SoundFormat f = m_PlaybackFormat ;
if ( m_hPlayback )
openPlaybackDevice ( f , /* reopen = */ true ) ;
if ( m_hPlaybackMixer )
openPlaybackMixerDevice ( /* reopen = */ true ) ;
getPlaybackMixerChannels ( m_PlaybackCard ,
m_hPlaybackMixer ,
m_PlaybackChannels , m_PlaybackChannels2ID ) ;
notifyPlaybackChannelsChanged ( m_SoundStreamClientID , m_PlaybackChannels ) ;
}
void AlsaSoundDevice : : setCaptureDevice ( int card , int dev )
{
// logDebug("AlsaSoundDevice::setCaptureDevice-1: m_CaptureCard == " + TQString::number(m_CaptureCard) + ", card == " + TQString::number(card));
if ( m_CaptureCard = = card & & m_CaptureDevice = = dev )
return ;
// logDebug("AlsaSoundDevice::setCaptureDevice-2: m_CaptureCard == " + TQString::number(m_CaptureCard) + ", card == " + TQString::number(card));
m_CaptureCard = card ;
m_CaptureDevice = dev ;
SoundFormat f = m_CaptureFormat ;
if ( m_hCapture )
openCaptureDevice ( f , /* reopen = */ true ) ;
if ( m_hCaptureMixer )
openCaptureMixerDevice ( /* reopen = */ true ) ;
getCaptureMixerChannels ( m_CaptureCard ,
m_hCaptureMixer ,
m_CaptureChannels , m_CaptureChannels2ID , m_CaptureChannelsSwitch , m_CaptureChannelsSwitch2ID ) ;
notifyCaptureChannelsChanged ( m_SoundStreamClientID , m_CaptureChannels ) ;
}
TQString AlsaSoundDevice : : getSoundStreamClientDescription ( ) const
{
return i18n ( " ALSA Sound Device %1 " ) . arg ( PluginBase : : name ( ) ) ;
}
bool AlsaSoundDevice : : mute ( SoundStreamID id , bool mute )
{
if ( id . isValid ( ) & & ( m_PlaybackStreamID = = id | | m_PassivePlaybackStreams . contains ( id ) ) ) {
SoundStreamConfig & cfg = m_PlaybackStreams [ id ] ;
if ( mute ! = cfg . m_Muted ) {
if ( writePlaybackMixerVolume ( cfg . m_Channel , cfg . m_Volume , cfg . m_Muted = mute ) ) {
notifyMuted ( id , cfg . m_Muted ) ;
}
}
return true ;
}
return false ;
}
bool AlsaSoundDevice : : unmute ( SoundStreamID id , bool unmute )
{
if ( id . isValid ( ) & & ( m_PlaybackStreamID = = id | | m_PassivePlaybackStreams . contains ( id ) ) ) {
SoundStreamConfig & cfg = m_PlaybackStreams [ id ] ;
bool mute = ! unmute ;
if ( mute ! = cfg . m_Muted ) {
if ( writePlaybackMixerVolume ( cfg . m_Channel , cfg . m_Volume , cfg . m_Muted = mute ) ) {
notifyMuted ( id , cfg . m_Muted ) ;
}
}
return true ;
}
return false ;
}
bool AlsaSoundDevice : : isMuted ( SoundStreamID id , bool & m ) const
{
if ( id . isValid ( ) & & ( m_PlaybackStreamID = = id | | m_PassivePlaybackStreams . contains ( id ) ) ) {
const SoundStreamConfig & cfg = m_PlaybackStreams [ id ] ;
m = cfg . m_Muted ;
return true ;
}
return false ;
}
void AlsaSoundDevice : : setCaptureMixerSettings ( const TQMap < TQString , AlsaConfigMixerSetting > & map )
{
m_CaptureMixerSettings = map ;
}
// bool AlsaSoundDevice::event(TQEvent *_e)
// {
// bool retval = false;
//
// switch (_e->type()) {
//
// case CaptureTerminated :
// retval = true;
// break;
//
// case CaptureStep :
//
// slotPollCapture();
//
// retval = true;
// break;
//
// case CaptureError :
// case CaptureWarning :
// case CaptureInfo :
// case CaptureDebug :
// if (m_captureThread) {
// AlsaCaptureEvent *e = static_cast<AlsaCaptureEvent*>(_e);
// TQString msg = i18n("ALSA Plugin, device plughw:%1,%2: %3")
// .arg(m_CaptureCard)
// .arg(m_CaptureDevice)
// .arg(e->message());
// switch (_e->type()) {
// case CaptureError :
// logError(msg);
// m_captureThread->resetError();
// break;
// case CaptureWarning :
// logWarning(msg);
// break;
// case CaptureInfo :
// logInfo(msg);
// break;
// case CaptureDebug :
// logDebug(msg);
// break;
// default:
// break;
// }
// }
// retval = true;
// break;
//
// default:
// retval = TQObject::event(_e);
// break;
// }
//
// return retval;
// }
# include "alsa-sound.moc"