diff options
Diffstat (limited to 'soundman.c')
-rw-r--r-- | soundman.c | 334 |
1 files changed, 334 insertions, 0 deletions
diff --git a/soundman.c b/soundman.c new file mode 100644 index 0000000..376218c --- /dev/null +++ b/soundman.c @@ -0,0 +1,334 @@ +/* + * sndctl - a plugin for the Video Disk Recorder + * file: soundman.c + * description: manager for volume change requests + * + * author: Thomas Hildebrandt <toxym@web.de> + * + * inspired by and reengineered from 'avolctl' + * thanks to Martin Prochnow <nordlichtl@martins-kabuff.de> + */ + +#include "defaults.h" +#include "soundman.h" +#include <stdio.h> + +/********************************************************* + * member functions for class cSoundMan + *********************************************************/ + +/* + * constructor + */ +cSoundMan::cSoundMan( cPluginSndctl *Plugin ){ + vector<string> controls; + vector<string>::iterator it; + + dsyslog( "sndctl (cSoundMan::cSoundMan): cSoundMan created" ); + + plugin = Plugin; + + // create mixer device + mixer = (cMixer*) new cAlsa(); + + // initialize variables + volume = volumeCounter = 0; + soundflash = false; +} + +/* + * destructor + */ +cSoundMan::~cSoundMan(){ + // remove objects + delete mixer; + if (!soundsets.empty()) { + map<string,cSoundSet*>::iterator it; + for( it = soundsets.begin(); it != soundsets.end(); it++ ) { + delete it->second; + } + } +// free( &activeSoundSetID ); +} + +/* + * care for sound set switching, when audio track is changed + */ +void cSoundMan::AudioTrack( const char* Track ){ + string sset; + + dsyslog( "sndctl (cSoundMan::AudioTrack): Audio track switched to '%s'.", Track ); + + if( plugin->GetSetup()->GetBool( SNDCTL_SETUP_DD_AUTO_SWITCH )){ + if( strstr( Track, "dolby" ) != NULL || + strstr( Track, "Dolby" ) != NULL || + strstr( Track, "DOLBY" ) != NULL ) + // switch to DD sound set + sset = plugin->GetSetup()->Get( SNDCTL_SETUP_DD_AUTO_SSET ); + else + // switch back to 'normal' sound set + sset = plugin->GetSetup()->Get( SNDCTL_SETUP_DEFAULT_SSET ); + + dsyslog( "sndctl (cSoundMan::AudioTrack): Doing DD auto switching to '%s'.", sset.c_str()); + SetSoundSet( sset ); + } +} + +/* + * create a new, empty sound set + */ +string cSoundMan::CreateSoundSet(){ + char rnd[6]; + string id; + + // initialize randomizer + srand( time( NULL )); + + // create a new ID + do{ + // create new random number (in range 1000 ~ 1999) + sprintf( rnd, "s%u", (int) ( 1000 + ((double) rand()) / RAND_MAX * 999 )); + id = rnd; + } while( soundsets.find( id ) != soundsets.end()); + + // create a new sound set + soundsets[id] = new cSoundSet( mixer, id ); + + dsyslog( "sndctl (cSoundMan::CreateSoundSet): New sound set with ID '%s' created.", id.c_str()); + + return id; +} + +/* + * delete a sound set + */ +bool cSoundMan::DeleteSoundSet( string Id ){ + string defSoundSet; + map<string,cSoundSet*>::iterator it; + + if (soundsets.size() <= 1) { + esyslog( "sndctl (cSoundMan::DeleteSoundSet): Failed to delete sound set with ID '%s'. Cannot delete last one.", Id.c_str()); + return false; + } + // trying to find the requested sound set + if(( it = soundsets.find( Id )) != soundsets.end()){ + // remove sound set + free( it->second ); + soundsets.erase( it ); + + isyslog( "sndctl (cSoundMan::DeleteSoundSet): Sound set with ID '%s' deleted.", Id.c_str()); + + // do something, when deleted sound set was the active one + if( Id == activeSoundSetID ){ + defSoundSet = plugin->GetSetup()->Get( string( SNDCTL_SETUP_DEFAULT_SSET )); + if( Id != defSoundSet ) + // currently deleted sound set was NOT the default one + // -> set active sound set to default + SetSoundSet( defSoundSet ); + else{ + // currently deleted sound set was the default one + // -> we need a new default one + SetSoundSet( defSoundSet = soundsets.begin()->first ); + isyslog( "sndctl (cSoundMan::DeleteSoundSet): Deleted sound set was the default sound set." ); + plugin->GetSetup()->Set( string( SNDCTL_SETUP_DEFAULT_SSET ), defSoundSet ); + } + + isyslog( "sndctl (cSoundMan::DeleteSoundSet): Active sound set to '%s'.", activeSoundSetID.c_str()); + } + + return true; + } + + esyslog( "sndctl (cSoundMan::DeleteSoundSet): Failed to delete sound set with ID '%s'. Sound set not found.", Id.c_str()); + return false; +} + +/* + * returns the ID of the current active sound set + */ +string cSoundMan::GetCurrentSoundSetID( void ){ + return activeSoundSetID; +} + +/* + * returns a sound set object + */ +cSoundSet *cSoundMan::GetSoundSet( string Id, bool CreateNew ){ + map<string,cSoundSet*>::iterator it; + + // trying to find an already created sound set by its ID + if( soundsets.find( Id ) != soundsets.end()) + return soundsets[Id]; + + // trying to find a sound set by its name + for( it = soundsets.begin(); it != soundsets.end(); it++ ) + if( it->second->GetName() == Id ) + return it->second; + + // no sound set found, create a new one or return nothing + return CreateNew ? soundsets[Id] = new cSoundSet( mixer, Id ) : NULL; +} + +/* + * returns the sound sets map + */ +map<string,cSoundSet*> *cSoundMan::GetSoundSets(){ + return &soundsets; +} + +/* + * checks and correct the default soundset ID + * (it's only done once at start) + */ +string cSoundMan::DefaultSoundSetID( string RequestedID ){ + string id; + + dsyslog( "sndctl (cSoundMan::DefaultSoundSetID): Trying to set default sound set to ID '%s'.", RequestedID.c_str()); + + if( soundsets.find( RequestedID ) != soundsets.end()) + // 'RequestedID' found + id = RequestedID; + + // if no soundset exists, we have to create a first one + else if( soundsets.empty()) + id = CreateSoundSet(); + + // at least, lets take the first one + else + id = soundsets.begin()->first; + + isyslog( "sndctl (cSoundMan::DefaultSoundSetID): Default sound set is '%s'.", id.c_str()); + + // now return the default sound set to store this value + return id; +} + +/* + * returns the current volume value + */ +int cSoundMan::GetVolume( void ){ + return volume; +} + +/* + * sets the active sound set + */ +string cSoundMan::SetSoundSet( string Id ){ + cSoundSet *sset; + + // look for this ID + if( soundsets.find( Id ) == soundsets.end()){ + // look for the name + if(( sset = GetSoundSet( Id, false )) == NULL ){ + esyslog( "sndctl (cSoundMan::SetSoundSet): No sound set with ID or name '%s' found.", Id.c_str()); + return string( "~" ); + } else { + // 'Id' contains a sound set name, but we need an ID + activeSoundSetID = sset->GetID(); + } + } else + activeSoundSetID = Id; + + isyslog( "sndctl (cSoundMan::SetSoundSet): Active sound set is now '%s'.", activeSoundSetID.c_str()); + + // update mixer with sound set parameters + mixer->Update( GetSoundSet( activeSoundSetID )); + + // set volume for new sound set + SetVolume(); + + return activeSoundSetID; +} + +/* + * doing a sound flash + */ +void cSoundMan::SoundFlash( void ){ + int vol; + + isyslog( "sndctl (cSoundMan::SoundFlash): Igniting sound flash." ); + + // mark sound flashing in progress + soundflash = true; + + // save volume + vol = volume; + + // volume up + cDevice::PrimaryDevice()->SetVolume( plugin->GetSetup()->GetInt( SNDCTL_SETUP_SOUNDFLASH_VOL ) / 100 * 255, true); + + // wait + sleep( plugin->GetSetup()->GetInt( SNDCTL_SETUP_SOUNDFLASH_TIME )); + + // change volume back to former value + cDevice::PrimaryDevice()->SetVolume( vol, true); + + // sound flashing is done + soundflash = false; +} + +/* + * set the current volume level + * (and checks the limits of 0..255) + */ +int cSoundMan::SetVolume( int Volume ){ + int initVol; + + // time for a sound flash? + if( plugin->GetSetup()->GetBool( SNDCTL_SETUP_SOUNDFLASH ) && + !soundflash && + lastWasUp && + Volume < volume && + ( time( NULL ) - lastSet ) < plugin->GetSetup()->GetInt( SNDCTL_SETUP_SOUNDFLASH_DELTA )){ + SoundFlash(); + return volume; + } + + // save time and direction of last volume setting + time( &lastSet ); + lastWasUp = Volume > volume; + + // save volume + volume = Volume < 0 ? volume : Volume; + + // care for initial volume? + if( volumeCounter < 2 && plugin->GetSetup()->GetInt( SNDCTL_SETUP_INIT_VOLUME ) >= 0 ){ + volumeCounter++; + initVol = plugin->GetSetup()->GetInt( SNDCTL_SETUP_INIT_VOLUME ); + dsyslog( "sndctl (cSoundMan::SetVolume): Using initial volume %d%%", initVol ); + GetSoundSet( activeSoundSetID )->Volume( initVol ); + return initVol / 100 * 255; + } + + // work with an initial volume? + if( plugin->GetSetup()->GetInt( SNDCTL_SETUP_INIT_VOLUME ) < 0 ) + // no initial volume, save given value + volume = Volume < 0 ? volume : Volume; + else + // initial volume set, count this event + volumeCounter++; + + // check limits + volume = volume < 0 ? 0 : volume; + volume = volume > 255 ? 255 : volume; + + isyslog( "sndctl (cSoundMan::SetVolume): Volume goes to %d (of 255).", volume ); + + // set volume to current soundset + GetSoundSet( activeSoundSetID )->Volume( 100 * volume / 255 ); + + return volume; +} + +/* + * store all soundsets + */ +bool cSoundMan::Store( cPluginSndctl *Plugin ){ + map<string,cSoundSet*>::iterator it; + + // iterate over all soundsets + for( it = soundsets.begin(); it != soundsets.end(); it++ ) + it->second->Store( it->first, Plugin ); + + return true; +} |