diff --git a/sflphone-common/src/audio/alsa/alsalayer.cpp b/sflphone-common/src/audio/alsa/alsalayer.cpp index ddd1303f39487f4008a2341c7e5cee6f5a24c446..2938219c8af8e04e96903b9fcd1d4725ad77623a 100644 --- a/sflphone-common/src/audio/alsa/alsalayer.cpp +++ b/sflphone-common/src/audio/alsa/alsalayer.cpp @@ -161,8 +161,8 @@ AlsaLayer::startStream (void) startPlaybackStream (); _urgentRingBuffer.flush(); - _mainBuffer.flushAllBuffers(); - _mainBuffer.flushDefault(); + getMainBuffer()->flushAllBuffers(); + getMainBuffer()->flushDefault(); if(_audioThread == NULL) { try { @@ -853,6 +853,10 @@ void AlsaLayer::audioCallback (void) spkrVolume = _manager->getSpkrVolume(); micVolume = _manager->getMicVolume(); + /* + int writeableSize = snd_pcm_avail_update(_PlaybackHandle); + _debug("writeableSize %i\n", writeableSize); + */ // AvailForGet tell the number of chars inside the buffer // framePerBuffer are the number of data for one channel (left) @@ -871,7 +875,7 @@ void AlsaLayer::audioCallback (void) out=0; // Consume the regular one as well (same amount of bytes) - _mainBuffer.discard (toGet); + getMainBuffer()->discard (toGet); } else { @@ -924,14 +928,14 @@ void AlsaLayer::audioCallback (void) maxNbBytesToGet = maxNbSamplesToGet * sizeof(SFLDataFormat); - normalAvailBytes = _mainBuffer.availForGet(); + normalAvailBytes = getMainBuffer()->availForGet(); toGet = (normalAvailBytes < (int)maxNbBytesToGet) ? normalAvailBytes : maxNbBytesToGet; out = (SFLDataFormat*) malloc (maxNbBytesToGet); if (normalAvailBytes) { - _mainBuffer.getData(out, toGet, spkrVolume); + getMainBuffer()->getData(out, toGet, spkrVolume); if (_mainBufferSampleRate && ((int)_audioSampleRate != _mainBufferSampleRate)) { @@ -994,7 +998,7 @@ void AlsaLayer::audioCallback (void) // _debug("micAvailBytes %i\n", micAvailBytes); if(micAvailBytes > 0) { - micAvailPut = _mainBuffer.availForPut(); + micAvailPut = getMainBuffer()->availForPut(); toPut = (micAvailBytes <= framesPerBufferAlsa) ? micAvailBytes : framesPerBufferAlsa; in = (SFLDataFormat*)malloc(toPut * sizeof(SFLDataFormat)); toPut = read (in, toPut* sizeof(SFLDataFormat)); @@ -1017,14 +1021,14 @@ void AlsaLayer::audioCallback (void) dcblocker->filter_signal(rsmpl_out, nbSample); - _mainBuffer.putData(rsmpl_out, nbSample * sizeof (SFLDataFormat), 100); + getMainBuffer()->putData(rsmpl_out, nbSample * sizeof (SFLDataFormat), 100); free(rsmpl_out); rsmpl_out = 0; } else { - _mainBuffer.putData(in, toPut, 100); + getMainBuffer()->putData(in, toPut, 100); } } free(in); in=0; diff --git a/sflphone-common/src/audio/audiolayer.cpp b/sflphone-common/src/audio/audiolayer.cpp index 8966eb6aba086a30183d9dfa048ec3d42f5350f8..0dcace767bab39182c745c4f3ac37ca000bc9fd7 100644 --- a/sflphone-common/src/audio/audiolayer.cpp +++ b/sflphone-common/src/audio/audiolayer.cpp @@ -24,7 +24,7 @@ void AudioLayer::flushMain (void) ost::MutexLock guard (_mutex); // should pass call id - _mainBuffer.flushAllBuffers(); + getMainBuffer()->flushAllBuffers(); } void AudioLayer::flushUrgent (void) @@ -36,7 +36,7 @@ void AudioLayer::flushUrgent (void) void AudioLayer::flushMic (void) { ost::MutexLock guard (_mutex); - _mainBuffer.flushDefault(); + getMainBuffer()->flushDefault(); } int AudioLayer::putUrgent (void* buffer, int toCopy) @@ -60,13 +60,13 @@ int AudioLayer::putMain (void *buffer, int toCopy, CallID call_id) int a; ost::MutexLock guard (_mutex); - a = _mainBuffer.availForPut(call_id); + a = getMainBuffer()->availForPut(call_id); if (a >= toCopy) { - return _mainBuffer.putData (buffer, toCopy, _defaultVolume, call_id); + return getMainBuffer()->putData (buffer, toCopy, _defaultVolume, call_id); } else { _debug ("Chopping sound, Ouch! RingBuffer full ?\n"); - return _mainBuffer.putData (buffer, a, _defaultVolume, call_id); + return getMainBuffer()->putData (buffer, a, _defaultVolume, call_id); } return 0; diff --git a/sflphone-common/src/audio/audiolayer.h b/sflphone-common/src/audio/audiolayer.h index 75921da755bb7f9ceb34489f5f2a10be3d85566d..2e3dbee8e2e9eb484ea13f16dadfb3b0c1086653 100644 --- a/sflphone-common/src/audio/audiolayer.h +++ b/sflphone-common/src/audio/audiolayer.h @@ -208,7 +208,12 @@ class AudioLayer { * * @return MainBuffer* a pointer to the MainBuffer instance */ - MainBuffer* getMainBuffer( void ) { return &_mainBuffer; } + MainBuffer* getMainBuffer( void ) { return _mainBuffer; } + + /** + * Set the mainbuffer once the audiolayer is created + */ + void setMainBuffer( MainBuffer* mainbuffer ) { _mainBuffer = mainbuffer; } /** * Default volume for incoming RTP and Urgent sounds. @@ -256,7 +261,7 @@ class AudioLayer { * Audio instances must be registered into the MainBuffer and bound together via the ManagerImpl. * */ - MainBuffer _mainBuffer; + MainBuffer* _mainBuffer; /** * A pointer to the recordable instance (may be a call or a conference) diff --git a/sflphone-common/src/audio/pulseaudio/audiostream.cpp b/sflphone-common/src/audio/pulseaudio/audiostream.cpp index 614d2e5c27490bee99880ecae0a9116fd80d610c..565ef8b78349b8a2d5f303e4a59166c05cc61cd2 100644 --- a/sflphone-common/src/audio/pulseaudio/audiostream.cpp +++ b/sflphone-common/src/audio/pulseaudio/audiostream.cpp @@ -192,30 +192,23 @@ AudioStream::createStream (pa_context* c) // parameters are defined as number of bytes // 2048 bytes (1024 int16) is 20 ms at 44100 Hz if (_streamType == PLAYBACK_STREAM) { - + + // 20 ms framesize TODO: take framesize value from config attributes->maxlength = (uint32_t) -1; - attributes->tlength = pa_usec_to_bytes(20 * PA_USEC_PER_MSEC, &sample_spec); + attributes->tlength = pa_usec_to_bytes(50 * PA_USEC_PER_MSEC, &sample_spec); attributes->prebuf = (uint32_t) -1; attributes->minreq = (uint32_t) -1; attributes->fragsize = (uint32_t) -1; - - _debug("tlength: %i\n", pa_usec_to_bytes(20 * PA_USEC_PER_MSEC, &sample_spec)); - /* - attributes->maxlength = 88200; - attributes->tlength = 4096; - attributes->prebuf = 4096; - attributes->minreq = 2048; - attributes->fragsize = 4096; - */ pa_stream_connect_playback( s , NULL , attributes, PA_STREAM_ADJUST_LATENCY, &_volume, NULL); } else if (_streamType == CAPTURE_STREAM) { - + + // 20 ms framesize TODO: take framesize value from config attributes->maxlength = (uint32_t) -1; attributes->tlength = (uint32_t) -1; attributes->prebuf = (uint32_t) -1; attributes->minreq = (uint32_t) -1; - attributes->fragsize = 4096; + attributes->fragsize = pa_usec_to_bytes(50 * PA_USEC_PER_MSEC, &sample_spec); diff --git a/sflphone-common/src/audio/pulseaudio/pulselayer.cpp b/sflphone-common/src/audio/pulseaudio/pulselayer.cpp index 4c5dc0e64574bc6636a699e0210fedce817c9654..47eebfe2d9b64302fd083f4e321741d0928cee42 100644 --- a/sflphone-common/src/audio/pulseaudio/pulselayer.cpp +++ b/sflphone-common/src/audio/pulseaudio/pulselayer.cpp @@ -43,18 +43,19 @@ static void capture_callback (pa_stream* s, size_t bytes, void* userdata) // static_cast<PulseLayer*> (userdata)->processData(); } - +/* static void stream_suspended_callback (pa_stream *s UNUSED, void *userdata UNUSED) { _debug("PulseLayer::Stream Suspended\n"); } +*/ - +/* static void stream_moved_callback(pa_stream *s UNUSED, void *userdata UNUSED) { _debug("PulseLayer::Stream Moved\n"); } - +*/ static void playback_underflow_callback (pa_stream* s, void* userdata UNUSED) { @@ -357,14 +358,11 @@ void PulseLayer::startStream (void) // Create Streams connectPulseAudioServer(); - // _urgentRingBuffer.flushAll(); - // _mainBuffer.flushAllBuffers(); - is_started = true; } _urgentRingBuffer.flushAll(); - _mainBuffer.flushAllBuffers(); + getMainBuffer()->flushAllBuffers(); } @@ -378,12 +376,11 @@ PulseLayer::stopStream (void) pa_stream_flush (playback->pulseStream(), NULL, NULL); pa_stream_flush (record->pulseStream(), NULL, NULL); - disconnectAudioStream(); - if (m) { pa_threaded_mainloop_stop (m); } + disconnectAudioStream(); _debug("Disconnecting PulseAudio context\n"); @@ -484,15 +481,9 @@ void PulseLayer::writeToSpeaker (void) int urgentAvailBytes; /** Bytes available in the regular ringbuffer ( reserved for voice ) */ int normalAvailBytes; + /** Bytes to get in the ring buffer **/ int byteToGet; - int toPlay; - // const pa_timing_info* info = pa_stream_get_timing_info(s); - - // _debug(" pa write_index: %i", info->write_index); - // _debug(" pa write_index_corupt (if not 0): %i" info->write_index_corrupt); - // _debug(" pa read_index: %i", info->read_index); - // _debug(" pa read_index_corrupt (if not 0): %i", info->read_index_corrupt); SFLDataFormat* out;// = (SFLDataFormat*)pa_xmalloc(framesPerBuffer); urgentAvailBytes = _urgentRingBuffer.AvailForGet(); @@ -513,7 +504,7 @@ void PulseLayer::writeToSpeaker (void) pa_stream_write (playback->pulseStream(), out, writeableSize, pa_xfree, 0, PA_SEEK_RELATIVE); // Consume the regular one as well (same amount of bytes) - _mainBuffer.discard (writeableSize); + getMainBuffer()->discard (writeableSize); } else { @@ -552,22 +543,16 @@ void PulseLayer::writeToSpeaker (void) } else { int _mainBufferSampleRate = getMainBuffer()->getInternalSamplingRate(); - // int maxNbSamplesToGet = 0; + int maxNbBytesToGet = 0; - _debug("--------------- Playback -----------\n"); - _debug("writeableSize: %i\n", writeableSize); // test if audio resampling is needed if (_mainBufferSampleRate && ((int)_audioSampleRate != _mainBufferSampleRate)) { // upsamplefactor is used to compute the number of bytes to get in the ring buffer double upsampleFactor = (double) _mainBufferSampleRate / _audioSampleRate; - _debug("upsampleFactor: %f\n", upsampleFactor); - // maxNbSamplesToGet is the number of sample to get in the ring buffer which, - // once resampled, will not be over the writeableSize - // maxNbSamplesToGet = (int) ((double) framesPerBuffer * upsampleFactor); maxNbBytesToGet = ((double) writeableSize * upsampleFactor); } else { @@ -577,23 +562,19 @@ void PulseLayer::writeToSpeaker (void) } - // maxNbBytesToGet = maxNbSamplesToGet * sizeof(SFLDataFormat); - _debug("maxNbBytesToGet: %i\n", maxNbBytesToGet); - out = (SFLDataFormat*) pa_xmalloc (maxNbBytesToGet); - normalAvailBytes = _mainBuffer.availForGet(); - _debug("normalAvailBytes: %i\n", normalAvailBytes); + normalAvailBytes = getMainBuffer()->availForGet(); byteToGet = (normalAvailBytes < (int)(maxNbBytesToGet)) ? normalAvailBytes : maxNbBytesToGet; - _debug("byteToGet: %i\n", byteToGet); if (byteToGet) { - // TODO, find out where this problem occurs to get rid of this hack + // Sending an odd number of byte breaks the audio! + // TODO, find out where the problem occurs to get rid of this hack if( (byteToGet%2) != 0 ) byteToGet = byteToGet-1; - _mainBuffer.getData (out, byteToGet, 100); + getMainBuffer()->getData (out, byteToGet, 100); // test if resampling is required if (_mainBufferSampleRate && ((int)_audioSampleRate != _mainBufferSampleRate)) { @@ -602,12 +583,8 @@ void PulseLayer::writeToSpeaker (void) // Do sample rate conversion int nb_sample_down = byteToGet / sizeof(SFLDataFormat); - _debug("nbSampleDown: %i\n", nb_sample_down); - int nbSample = _converter->upsampleData((SFLDataFormat*)out, rsmpl_out, _mainBufferSampleRate, _audioSampleRate, nb_sample_down); - _debug("nbSample converted: %i\n", nbSample); - _debug("bytes to be written: %i\n", nbSample*sizeof(SFLDataFormat)); pa_stream_write (playback->pulseStream(), rsmpl_out, nbSample*sizeof(SFLDataFormat), NULL, 0, PA_SEEK_RELATIVE); @@ -623,24 +600,18 @@ void PulseLayer::writeToSpeaker (void) } else { if((tone == 0) && (file_tone == 0)) { - - // _debug("maxNbBytesToGet: %i\n", maxNbBytesToGet); SFLDataFormat* zeros = (SFLDataFormat*)pa_xmalloc (writeableSize); bzero (zeros, writeableSize); pa_stream_write(playback->pulseStream(), zeros, writeableSize, pa_xfree, 0, PA_SEEK_RELATIVE); - // pa_xfree (zeros); - - } } _urgentRingBuffer.Discard(byteToGet); - // pa_xfree (out); } } @@ -652,8 +623,6 @@ void PulseLayer::readFromMic (void) const char* data = NULL; size_t r; - // _debug("--------------- Capture -----------\n"); - if (pa_stream_peek (record->pulseStream() , (const void**) &data , &r) < 0 || !data) { _debug("pa_stream_peek() failed: %s\n" , pa_strerror( pa_context_errno( context) )); } @@ -671,24 +640,20 @@ void PulseLayer::readFromMic (void) int nbSample = r / sizeof(SFLDataFormat); int nb_sample_up = nbSample; - // _debug("nbSample from mic: %i\n", nbSample); - nbSample = _converter->downsampleData ((SFLDataFormat*)data, rsmpl_out, _mainBufferSampleRate, _audioSampleRate, nb_sample_up); // remove dc offset dcblocker->filter_signal( rsmpl_out, nbSample ); - // _debug("nbSample copied: %i\n", nbSample); - - _mainBuffer.putData ( (void*) rsmpl_out, nbSample*sizeof(SFLDataFormat), 100); + getMainBuffer()->putData ( (void*) rsmpl_out, nbSample*sizeof(SFLDataFormat), 100); pa_xfree (rsmpl_out); } else { // no resampling required - _mainBuffer.putData ( (void*) data, r, 100); + getMainBuffer()->putData ( (void*) data, r, 100); } diff --git a/sflphone-common/src/managerimpl.cpp b/sflphone-common/src/managerimpl.cpp index 18aca9f6969729b377ecbf08122f1f04f4d7dd39..6f8304964d4f0af7c4670b3f5444394d57d104bd 100644 --- a/sflphone-common/src/managerimpl.cpp +++ b/sflphone-common/src/managerimpl.cpp @@ -1707,9 +1707,8 @@ ManagerImpl::playDtmf (char code, bool isTalking) // put the size in bytes... // so size * 1 channel (mono) * sizeof (bytes for the data) // audiolayer->flushUrgent(); - - audiolayer->startStream(); - audiolayer->putUrgent (buf, size * sizeof (SFLDataFormat)); + audiolayer->startStream(); + audiolayer->putUrgent (buf, size * sizeof (SFLDataFormat)); } else { _debug(" playDtmf: Error cannot play dtmf\n"); @@ -1920,22 +1919,22 @@ ManagerImpl::peerHungupCall (const CallID& call_id) if (isCurrentCall(call_id)) { stopTone (true); - - int nbCalls = getCallList().size(); - - // stop streams - if (nbCalls <= 1) - { - _debug(" hangupCall: stop audio stream, ther is only %i call(s) remaining\n", nbCalls); - - AudioLayer* audiolayer = getAudioDriver(); - audiolayer->stopStream(); - } switchCall (""); } } + int nbCalls = getCallList().size(); + + // stop streams + if (nbCalls <= 1) + { + _debug(" hangupCall: stop audio stream, ther is only %i call(s) remaining\n", nbCalls); + + AudioLayer* audiolayer = getAudioDriver(); + audiolayer->stopStream(); + } + /* Direct IP to IP call */ if (getConfigFromCall (call_id) == Call::IPtoIP) { SIPVoIPLink::instance (AccountNULL)->hangup (call_id); @@ -2039,8 +2038,8 @@ bool ManagerImpl::playATone (Tone::TONEID toneId) if (audiolayer) { - audiolayer->startStream(); audiolayer->flushUrgent(); + audiolayer->startStream(); } if (_telephoneTone != 0) { @@ -3072,12 +3071,15 @@ ManagerImpl::initAudioDriver (void) if (getConfigInt (PREFERENCES , CONFIG_AUDIO) == ALSA) { _audiodriver = new AlsaLayer (this); + _audiodriver->setMainBuffer(&_mainBuffer); } else if (getConfigInt (PREFERENCES , CONFIG_AUDIO) == PULSEAUDIO) { if (app_is_running ("pulseaudio") == 0) { _audiodriver = new PulseLayer (this); + _audiodriver->setMainBuffer(&_mainBuffer); } else { _audiodriver = new AlsaLayer (this); setConfig (PREFERENCES, CONFIG_AUDIO, ALSA); + _audiodriver->setMainBuffer(&_mainBuffer); } } else _debug ("Error - Audio API unknown\n"); @@ -3176,7 +3178,7 @@ void ManagerImpl::switchAudioManager (void) _debug ("Deleting current layer... \n"); - //_audiodriver->closeLayer(); + // _audiodriver->closeLayer(); delete _audiodriver; _audiodriver = NULL; @@ -3186,11 +3188,13 @@ void ManagerImpl::switchAudioManager (void) case ALSA: _debug ("Creating Pulseaudio layer...\n"); _audiodriver = new PulseLayer (this); + _audiodriver->setMainBuffer(&_mainBuffer); break; case PULSEAUDIO: _debug ("Creating ALSA layer...\n"); _audiodriver = new AlsaLayer (this); + _audiodriver->setMainBuffer(&_mainBuffer); break; default: @@ -3209,12 +3213,16 @@ void ManagerImpl::switchAudioManager (void) _debug ("has current call: %i \n", hasCurrentCall()); + if(hasCurrentCall()) + _audiodriver->startStream(); + + // need to stop audio streams if there is currently no call - if ( (type != PULSEAUDIO) && (!hasCurrentCall())) { + // if ( (type != PULSEAUDIO) && (!hasCurrentCall())) { // _debug("There is currently a call!!\n"); - _audiodriver->stopStream(); + // _audiodriver->stopStream(); - } + // } } /** diff --git a/sflphone-common/src/managerimpl.h b/sflphone-common/src/managerimpl.h index 19904a204ca692ef02e3dedf4a7254214d6ab123..9689044a087e78186e9150744e70c96b063430b9 100644 --- a/sflphone-common/src/managerimpl.h +++ b/sflphone-common/src/managerimpl.h @@ -43,6 +43,8 @@ #include "audio/sound/dtmf.h" // DTMF class contained by value here #include "audio/codecs/codecDescriptor.h" // CodecDescriptor class contained by value here +#include "audio/mainbuffer.h" + class AudioLayer; class GuiFramework; class TelephoneTone; @@ -1191,6 +1193,17 @@ class ManagerImpl { * Unload the account (delete them) */ void unloadAccountMap(); + + + /** + * Instance of the MainBuffer for the whole application + * + * In order to send signal to other parts of the application, one must pass through the mainbuffer. + * Audio instances must be registered into the MainBuffer and bound together via the ManagerImpl. + * + */ + MainBuffer _mainBuffer; + public: @@ -1252,6 +1265,8 @@ class ManagerImpl { // ConferenceMap _conferencemap; + + private: // Copy Constructor