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