From b626904724b907c309f5e96f6d21edc0bbdbebef Mon Sep 17 00:00:00 2001 From: Emmanuel Milou <emmanuel.milou@savoirfairelinux.com> Date: Fri, 23 May 2008 17:16:41 -0400 Subject: [PATCH] Playback functional - Capture not problem with capture: delay and audio quality Dtmf, ringtones missing --- src/audio/audiortp.cpp | 1 - src/audio/audiostream.cpp | 8 +++- src/audio/audiostream.h | 1 + src/audio/pulselayer.cpp | 94 ++++++++++++++++++++++++++++++++------- src/audio/pulselayer.h | 4 ++ src/managerimpl.cpp | 8 ++-- 6 files changed, 93 insertions(+), 23 deletions(-) diff --git a/src/audio/audiortp.cpp b/src/audio/audiortp.cpp index 513b29db58..788feb6193 100644 --- a/src/audio/audiortp.cpp +++ b/src/audio/audiortp.cpp @@ -1,5 +1,4 @@ /* - * * Copyright (C) 2004-2008 Savoir-Faire Linux inc. * Author: Emmanuel Milou <emmanuel.milou@savoirfairelinux.com> * Author: Alexandre Bourget <alexandre.bourget@savoirfairelinux.com> diff --git a/src/audio/audiostream.cpp b/src/audio/audiostream.cpp index 97a5edda2d..c3164d06fe 100644 --- a/src/audio/audiostream.cpp +++ b/src/audio/audiostream.cpp @@ -29,7 +29,8 @@ AudioStream::AudioStream( pa_context* context, int type, std::string desc ) sample_spec.rate = 44100; sample_spec.channels = 1; channel_map.channels = 1; - flag = PA_STREAM_AUTO_TIMING_UPDATE; + flag = PA_STREAM_AUTO_TIMING_UPDATE ; + volume = PA_VOLUME_NORM; _audiostream = createStream( context ); } @@ -64,6 +65,7 @@ AudioStream::createStream( pa_context* c ) { _debug("Creating %s stream...\n" , _streamDescription.c_str()); pa_stream* s; + pa_cvolume cv; assert(pa_sample_spec_valid(&sample_spec)); assert(pa_channel_map_valid(&channel_map)); @@ -74,7 +76,9 @@ AudioStream::createStream( pa_context* c ) assert( s ); if( _streamType == PLAYBACK_STREAM ){ - pa_stream_connect_playback( s , NULL , NULL , flag , NULL, NULL ); + pa_stream_connect_playback( s , NULL , NULL , + PA_STREAM_INTERPOLATE_TIMING, + pa_cvolume_set(&cv, sample_spec.channels , volume) , NULL ); } else if( _streamType == CAPTURE_STREAM ){ pa_stream_connect_record( s , NULL , NULL , flag ); diff --git a/src/audio/audiostream.h b/src/audio/audiostream.h index a4464500f5..c2411d4812 100644 --- a/src/audio/audiostream.h +++ b/src/audio/audiostream.h @@ -59,6 +59,7 @@ class AudioStream { pa_stream_flags_t flag; pa_sample_spec sample_spec ; //pa_channel_map channel_map; + pa_volume_t volume; }; diff --git a/src/audio/pulselayer.cpp b/src/audio/pulselayer.cpp index 480dde04e1..e26bdb63b2 100644 --- a/src/audio/pulselayer.cpp +++ b/src/audio/pulselayer.cpp @@ -21,11 +21,13 @@ int framesPerBuffer = 4096; +const pa_buffer_attr *a; -PulseLayer::PulseLayer(ManagerImpl* manager) + PulseLayer::PulseLayer(ManagerImpl* manager) : AudioLayer( manager , PULSEAUDIO ) , _urgentRingBuffer( SIZEBUF) - ,_mainSndRingBuffer( SIZEBUF ) + ,_mainSndRingBuffer( SIZEBUF ) + ,_micRingBuffer( SIZEBUF ) { _debug("Pulse audio constructor: Create context\n"); } @@ -86,7 +88,7 @@ PulseLayer::context_state_callback( pa_context* c, void* user_data ) break; case PA_CONTEXT_FAILED: default: - _debug(" Error : %s" , pa_strerror(pa_context_errno(c))); + _debug(" Error : %n" , pa_strerror(pa_context_errno(c))); exit(1); } } @@ -96,11 +98,14 @@ PulseLayer::createStreams( pa_context* c ) { playback = new AudioStream(c, PLAYBACK_STREAM, "SFLphone out"); pa_stream_set_write_callback( playback->pulseStream() , audioCallback, this); + pa_stream_set_overflow_callback( playback->pulseStream() , overflow , this); record = new AudioStream(c, CAPTURE_STREAM, "SFLphone in"); pa_stream_set_read_callback( record->pulseStream() , audioCallback, this); + pa_stream_set_underflow_callback( playback->pulseStream() , underflow , this); cache = new AudioStream(c, UPLOAD_STREAM, "Cache samples"); pa_threaded_mainloop_signal(m , 0); + } bool @@ -162,6 +167,7 @@ PulseLayer::putMain(void* buffer, int toCopy) void PulseLayer::flushMain() { + _mainSndRingBuffer.flush(); } int @@ -179,25 +185,37 @@ PulseLayer::putUrgent(void* buffer, int toCopy) int PulseLayer::canGetMic() { - return 882; + if( record ) + { + int a = _micRingBuffer.AvailForGet(); + _debug("available for get = %i\n" , a); + return a; + } + else + return 0; } int PulseLayer::getMic(void *buffer, int toCopy) { - return 160; + if( record ){ + return _micRingBuffer.Get(buffer, toCopy, 100); + } + else + return 0; } void PulseLayer::flushMic() { + _micRingBuffer.flush(); } /* bool -PulseLayer::isStreamStopped (void) -{ -} -*/ + PulseLayer::isStreamStopped (void) + { + } + */ void PulseLayer::startStream (void) { @@ -221,16 +239,35 @@ PulseLayer::audioCallback ( pa_stream* s, size_t bytes, void* userdata ) { PulseLayer* pulse = (PulseLayer*) userdata; assert( s && bytes ); + assert( bytes > 0 ); pulse->write(); + pulse->read(); +} + + void +PulseLayer::underflow ( pa_stream* s, void* userdata ) +{ + _debug("Buffer Underflow\n"); +} + + + void +PulseLayer::overflow ( pa_stream* s, void* userdata ) +{ + _debug("Buffer Overflow\n"); } void PulseLayer::write( void ) { + // a = pa_stream_get_buffer_attr(record->pulseStream()); + //if (a) + //_debug("Buffer attributes: maxlength=%u , fragsize=%u\n" , a->maxlength, a->fragsize ); + //_debug("Device name = %s ; device index = %i\n" , pa_stream_get_device_name( playback->pulseStream()) , pa_stream_get_device_index( playback->pulseStream())); int toGet; int urgentAvail; // number of data right and data left int normalAvail; // number of data right and data left - SFLDataFormat* out = (SFLDataFormat*)malloc(framesPerBuffer * sizeof(SFLDataFormat)); + SFLDataFormat* out = (SFLDataFormat*)pa_xmalloc(framesPerBuffer * sizeof(SFLDataFormat)); urgentAvail = _urgentRingBuffer.AvailForGet(); if (urgentAvail > 0) { // Urgent data (dtmf, incoming call signal) come first. @@ -242,14 +279,14 @@ PulseLayer::write( void ) } else { - AudioLoop* tone = _manager->getTelephoneTone(); + AudioLoop* tone = 0;//_manager->getTelephoneTone(); if ( tone != 0) { - tone->getNext(out, framesPerBuffer, 100); + //tone->getNext(out, framesPerBuffer, 100); toGet = framesPerBuffer; - } else if ( (tone=_manager->getTelephoneFile()) != 0 ) { + } /*else if ( (tone=_manager->getTelephoneFile()) != 0 ) { tone->getNext(out, framesPerBuffer, 100); toGet = framesPerBuffer; - } else { + } */else { normalAvail = _mainSndRingBuffer.AvailForGet(); toGet = (normalAvail < (int)(framesPerBuffer * sizeof(SFLDataFormat))) ? normalAvail : framesPerBuffer * sizeof(SFLDataFormat); if (toGet) { @@ -264,7 +301,34 @@ PulseLayer::write( void ) pa_stream_write( playback->pulseStream() , out , toGet , pa_xfree, 0 , PA_SEEK_RELATIVE); } -int + void +PulseLayer::read( void ) +{ + //assert( record->pulseStream() ); + int micAvailPut; + size_t toPut; + const void* data; + // Handle the mic's audio stream + micAvailPut = _micRingBuffer.AvailForPut(); + toPut = 2048; + //toPut = (micAvailPut <= (size_t)(framesPerBuffer * sizeof(SFLDataFormat))) ? micAvailPut : framesPerBuffer * sizeof(SFLDataFormat); + //_debug("micAvailPut: %i - - toPut : %i\n", micAvailPut, toPut); + + if( pa_stream_peek( record->pulseStream() , &data , &toPut ) < 0 ){ + _debug("pa_stream_peek() failed: %s\n" , pa_strerror( pa_context_errno( context) )); + return; + } + + _debug("- toPut : %i\n", toPut); + if( data != NULL ) + _micRingBuffer.Put( (void*)data , toPut, 100); + + if( pa_stream_drop( record->pulseStream()) < 0 ) + _debug("pa_stream_drop() failed: %s\n" , pa_strerror( pa_context_errno( context) )); + +} + + int PulseLayer::putInCache( char code, void *buffer, int toCopy ) { _debug("Put the DTMF in cache\n"); diff --git a/src/audio/pulselayer.h b/src/audio/pulselayer.h index 947df7fca1..9e864caf37 100644 --- a/src/audio/pulselayer.h +++ b/src/audio/pulselayer.h @@ -76,6 +76,8 @@ class PulseLayer : public AudioLayer { int playSamples(void* buffer, int toCopy, bool isTalking) ; static void audioCallback ( pa_stream* s, size_t bytes, void* userdata ); + static void overflow ( pa_stream* s, void* userdata ); + static void underflow ( pa_stream* s, void* userdata ); static void context_state_callback( pa_context* c, void* user_data ); @@ -125,6 +127,7 @@ class PulseLayer : public AudioLayer { void closeCaptureStream( void ); void write( void ); + void read( void ); void createStreams( pa_context* c ); /** * Drop the pending frames and close the playback device @@ -136,6 +139,7 @@ class PulseLayer : public AudioLayer { /** Ringbuffers for data */ RingBuffer _mainSndRingBuffer; RingBuffer _urgentRingBuffer; + RingBuffer _micRingBuffer; /** PulseAudio streams and context */ pa_context* context; diff --git a/src/managerimpl.cpp b/src/managerimpl.cpp index 90f17c965d..8053c79da3 100644 --- a/src/managerimpl.cpp +++ b/src/managerimpl.cpp @@ -497,11 +497,10 @@ ManagerImpl::playDtmf(char code, bool isTalking) // put the size in bytes... // so size * 1 channel (mono) * sizeof (bytes for the data) #if CHECK_INTERFACE( layer , ALSA ) - _debug("%i No good\n", layer); audiolayer->playSamples(_buf, size * sizeof(SFLDataFormat), isTalking); #else - _debug("%i Good\n" , layer); - audiolayer->putUrgent( _buf, size * sizeof(SFLDataFormat) ); + _debug("DTMF disabled\n"); + //audiolayer->putUrgent( _buf, size * sizeof(SFLDataFormat) ); #endif } returnValue = true; @@ -832,14 +831,13 @@ ManagerImpl::ringtone() _audiofile.start(); _toneMutex.leaveMutex(); #if CHECK_INTERFACE( layer, ALSA ) - _debug() int size = _audiofile.getSize(); SFLDataFormat output[ size ]; _audiofile.getNext(output, size , 100); audiolayer->putUrgent( output , size ); #else // pulseaudio code - audiolayer->startStream(); + //audiolayer->startStream(); #endif } else { ringback(); -- GitLab