Browse code

adds support for wideband audio

Raphael Coeffic authored on 21/02/2012 17:26:22
Showing 53 changed files
... ...
@@ -27,6 +27,7 @@ CPPFLAGS += -D_DEBUG \
27 27
 	  -D_THREAD_SAFE -D_REENTRANT \
28 28
 	  -DSEMS_VERSION='"$(RELEASE)"' -DARCH='"$(ARCH)"'\
29 29
 	  -DOS='"$(OS)"' 	\
30
+	  -DSYSTEM_SAMPLECLOCK_RATE=32000
30 31
 #         -DMAX_RTP_SESSIONS=8192 \
31 32
 #	  -DSUPPORT_IPV6 \
32 33
 #	  -DNO_THREADID_LOG \
... ...
@@ -544,7 +544,7 @@ void ConferenceDialog::setupAudio()
544 544
   }
545 545
   else {
546 546
 
547
-    channel.reset(AmConferenceStatus::getChannel(conf_id,getLocalTag()));
547
+    channel.reset(AmConferenceStatus::getChannel(conf_id,getLocalTag(),RTPStream()->getSampleRate()));
548 548
 
549 549
     if (listen_only) {
550 550
 	play_list.addToPlaylist(new AmPlaylistItem(channel.get(),
... ...
@@ -798,14 +798,14 @@ void ConferenceDialog::createDialoutParticipant(const string& uri_user)
798 798
 
799 799
   uri = "sip:" + uri_user + dialout_suffix;
800 800
 
801
-  dialout_channel.reset(AmConferenceStatus::getChannel(getLocalTag(),getLocalTag()));
801
+  dialout_channel.reset(AmConferenceStatus::getChannel(getLocalTag(),getLocalTag(),RTPStream()->getSampleRate()));
802 802
 
803 803
   dialout_id = AmSession::getNewId();
804 804
     
805 805
   ConferenceDialog* dialout_session = 
806 806
     new ConferenceDialog(conf_id,
807 807
 			 AmConferenceStatus::getChannel(getLocalTag(),
808
-							dialout_id));
808
+							dialout_id,RTPStream()->getSampleRate()));
809 809
 
810 810
   ConferenceFactory::setupSessionTimer(dialout_session);
811 811
 
... ...
@@ -865,7 +865,7 @@ void ConferenceDialog::connectMainChannel()
865 865
   if(!channel.get())
866 866
     channel.reset(AmConferenceStatus
867 867
 		  ::getChannel(conf_id,
868
-			       getLocalTag()));
868
+			       getLocalTag(),RTPStream()->getSampleRate()));
869 869
 
870 870
   play_list.addToPlaylist(new AmPlaylistItem(channel.get(),
871 871
 					     channel.get()));
... ...
@@ -130,7 +130,7 @@ static bool ConferenceJoinChannel(DSMConfChannel** dsm_chan,
130 130
       connect_record?"true":"false");
131 131
   
132 132
   AmConferenceChannel* chan = AmConferenceStatus::getChannel(channel_id, 
133
-							     sess->getLocalTag());
133
+							     sess->getLocalTag(), sess->RTPStream()->getSampleRate());
134 134
   if (NULL == chan) {
135 135
     ERROR("obtaining conference channel\n");
136 136
     throw DSMException("conference");
... ...
@@ -255,7 +255,7 @@ EXEC_ACTION_START(ConfTeeJoinAction) {
255 255
   if (NULL == chan) {
256 256
     DBG("not previously in tee-channel, creating new\n");
257 257
     AmConferenceChannel* conf_channel = AmConferenceStatus::getChannel(channel_id, 
258
-								       sess->getLocalTag());
258
+								       sess->getLocalTag(), sess->RTPStream()->getSampleRate());
259 259
     if (NULL == conf_channel) {
260 260
       ERROR("obtaining conference channel\n");
261 261
       throw DSMException("conference");
... ...
@@ -287,7 +287,7 @@ EXEC_ACTION_START(ConfTeeJoinAction) {
287 287
     sc_sess->setInputPlaylist();
288 288
 
289 289
     AmConferenceChannel* conf_channel = AmConferenceStatus::getChannel(channel_id, 
290
-								       sess->getLocalTag());
290
+								       sess->getLocalTag(), sess->RTPStream()->getSampleRate());
291 291
     if (NULL == conf_channel) {
292 292
       ERROR("obtaining conference channel\n");
293 293
       throw DSMException("conference");
... ...
@@ -91,7 +91,7 @@ void WebConferenceDialog::connectConference(const string& room) {
91 91
 
92 92
   // get a channel from the status 
93 93
   if (channel.get() == NULL) 
94
-    channel.reset(AmConferenceStatus::getChannel(conf_id,getLocalTag()));
94
+    channel.reset(AmConferenceStatus::getChannel(conf_id,getLocalTag(),RTPStream()->getSampleRate()));
95 95
   else 
96 96
     AmConferenceStatus::postConferenceEvent(conf_id,
97 97
 					    ConfNewParticipant,getLocalTag());
... ...
@@ -69,11 +69,11 @@ int AmAudioQueue::write(unsigned int user_ts, unsigned int size) {
69 69
     if (it->audio == NULL)
70 70
       continue;
71 71
     if (it->put) {
72
-      if ((size_trav = it->audio->put(user_ts, samples, size_trav)) < 0)
72
+      if ((size_trav = it->audio->put(user_ts, samples, fmt->rate, size_trav)) < 0)
73 73
 	break;
74 74
     }
75 75
     if (it->get) {
76
-      if ((size_trav = it->audio->get(user_ts, samples, size_trav >> 1)) < 0)
76
+      if ((size_trav = it->audio->get(user_ts, samples, fmt->rate, size_trav >> 1)) < 0)
77 77
 	break;
78 78
     }
79 79
   }
... ...
@@ -88,11 +88,11 @@ int AmAudioQueue::read(unsigned int user_ts, unsigned int size) {
88 88
     if (it->audio == NULL)
89 89
       continue;
90 90
     if (it->put) {
91
-      if ((size_trav = it->audio->put(user_ts, samples, size_trav)) < 0)
91
+      if ((size_trav = it->audio->put(user_ts, samples, fmt->rate, size_trav)) < 0)
92 92
 	break;
93 93
     }
94 94
     if (it->get) {
95
-      if ((size_trav = it->audio->get(user_ts, samples, size_trav >> 1)) < 0)
95
+      if ((size_trav = it->audio->get(user_ts, samples, fmt->rate, size_trav >> 1)) < 0)
96 96
 	break;
97 97
     }
98 98
   }
... ...
@@ -233,7 +233,7 @@ int AmAudioDelay::write(unsigned int user_ts, unsigned int size) {
233 233
 }
234 234
 
235 235
 int AmAudioDelay::read(unsigned int user_ts, unsigned int size) { 
236
-  sarr.read((unsigned int) (user_ts  - delay*(float)SYSTEM_SAMPLERATE), (short*)  ((unsigned char*) samples), size >> 1); 
236
+  sarr.read((unsigned int) (user_ts  - delay*(float)SYSTEM_SAMPLECLOCK_RATE), (short*)  ((unsigned char*) samples), size >> 1); 
237 237
   return size;
238 238
 }
239 239
 
... ...
@@ -260,31 +260,31 @@ void AmAudioFrontlist::setBackAudio(AmAudio* new_ba) {
260 260
   ba_mut.unlock();
261 261
 }
262 262
 
263
-int AmAudioFrontlist::put(unsigned int user_ts, unsigned char* buffer, unsigned int size) {
263
+int AmAudioFrontlist::put(unsigned int user_ts, unsigned char* buffer, int input_sample_rate, unsigned int size) {
264 264
   // stay consistent with Playlist - if empty return size
265 265
   int res = size; 
266 266
   ba_mut.lock();
267 267
 
268 268
   if (isEmpty()) {
269 269
     if (back_audio) 
270
-      res = back_audio->put(user_ts, buffer, size);
270
+      res = back_audio->put(user_ts, buffer, input_sample_rate, size);
271 271
   } else {
272
-    res = AmPlaylist::put(user_ts, buffer, size);
272
+    res = AmPlaylist::put(user_ts, buffer, input_sample_rate, size);
273 273
   }
274 274
 
275 275
   ba_mut.unlock();
276 276
   return res;
277 277
 }
278 278
 
279
-int AmAudioFrontlist::get(unsigned int user_ts, unsigned char* buffer, unsigned int size) {
279
+int AmAudioFrontlist::get(unsigned int user_ts, unsigned char* buffer, int output_sample_rate, unsigned int size) {
280 280
   // stay consistent with Playlist - if empty return size
281 281
   int res = size; 
282 282
 
283 283
   ba_mut.lock();
284 284
   if (isEmpty() && back_audio) {
285
-      res = back_audio->get(user_ts, buffer, size);
285
+      res = back_audio->get(user_ts, buffer, output_sample_rate, size);
286 286
   } else {
287
-    res = AmPlaylist::get(user_ts, buffer, size);
287
+    res = AmPlaylist::get(user_ts, buffer, output_sample_rate, size);
288 288
   }
289 289
   ba_mut.unlock();
290 290
   return res;
... ...
@@ -110,8 +110,8 @@ class AmAudioFrontlist : public AmPlaylist {
110 110
   void setBackAudio(AmAudio* new_ba);
111 111
 
112 112
  protected:
113
-  int put(unsigned int user_ts, unsigned char* buffer, unsigned int size);
114
-  int get(unsigned int user_ts, unsigned char* buffer, unsigned int size);
113
+  int put(unsigned int user_ts, unsigned char* buffer, int input_sample_rate, unsigned int size);
114
+  int get(unsigned int user_ts, unsigned char* buffer, int output_sample_rate, unsigned int size);
115 115
 };
116 116
 
117 117
 
... ...
@@ -29,6 +29,8 @@
29 29
 #include "AmPlugIn.h"
30 30
 #include "AmUtils.h"
31 31
 #include "AmSdp.h"
32
+#include "AmRtpStream.h"
33
+#include "AmConfig.h"
32 34
 #include "amci/codecs.h"
33 35
 #include "log.h"
34 36
 
... ...
@@ -49,106 +51,36 @@ struct CodecContainer
49 51
   long h_codec;
50 52
 };
51 53
 
52
-// AmAudioRtpFormat::AmAudioRtpFormat(const vector<SdpPayload *>& payloads)
53
-//   : AmAudioFormat(), m_payloads(payloads), m_currentPayload(-1)
54
-// {
55
-  // for (vector<SdpPayload *>::iterator it = m_payloads.begin();
56
-  // 	  it != m_payloads.end(); ++it)
57
-  // {
58
-  //   m_sdpPayloadByPayload[(*it)->payload_type] = *it;
59
-  // }
60
-  // setCurrentPayload(m_payloads[0]->payload_type);
61
-// }
62
-
63 54
 AmAudioRtpFormat::AmAudioRtpFormat()
55
+  : AmAudioFormat(), codec_id(-1)
64 56
 {
65 57
   
66 58
 }
67 59
 
68
-int AmAudioRtpFormat::setCodecId(int codec_id)
60
+int AmAudioRtpFormat::setCurrentPayload(Payload pl)
69 61
 {
70
-  this->codec_id = codec_id;
71
-  return 0;
72
-}
73
-
74
-#if 0
75
-int AmAudioRtpFormat::setCurrentPayload(int payload)
76
-{
77
-  if (m_currentPayload != payload)
78
-  {
79
-    std::map<int, SdpPayload *>::iterator p = 
80
-      m_sdpPayloadByPayload.find(payload);
81
-    if (p == m_sdpPayloadByPayload.end())
82
-    {
83
-      ERROR("Could not find payload <%i>\n", payload);
84
-      return -1;
85
-    }
86
-    std::map<int, amci_payload_t *>::iterator pp = 
87
-      m_payloadPByPayload.find(payload);
88
-    if (pp == m_payloadPByPayload.end())
89
-    {
90
-      m_currentPayloadP = AmPlugIn::instance()->payload(p->second->int_pt);
91
-      if (m_currentPayloadP == NULL)
92
-      {
93
-	ERROR("Could not find payload <%i>\n", payload);
94
-	return -1;
95
-      }
96
-      m_payloadPByPayload[payload] = m_currentPayloadP;
97
-    }
98
-    else
99
-      m_currentPayloadP = pp->second;
100
-    m_currentPayload = payload;
101
-    sdp_format_parameters = p->second->sdp_format_parameters;
102
-
103
-    std::map<int, CodecContainer *>::iterator c = 
104
-      m_codecContainerByPayload.find(payload);
105
-    if (c == m_codecContainerByPayload.end())
106
-    {
107
-      codec = NULL;
108
-      getCodec();
109
-      if (codec)
110
-      {
111
-	CodecContainer *cc = new CodecContainer();
112
-	cc->codec = codec;
113
-	cc->frame_size = frame_size;
114
-	cc->frame_length = frame_length;
115
-	cc->frame_encoded_size = frame_encoded_size;
116
-	cc->h_codec = h_codec;
117
-	m_codecContainerByPayload[payload] = cc;
118
-      }
119
-    }
120
-    else
121
-    {
122
-      codec = c->second->codec;
123
-      frame_size = c->second->frame_size;
124
-      frame_length = c->second->frame_length;
125
-      frame_encoded_size = c->second->frame_encoded_size;
126
-      h_codec = c->second->h_codec;
127
-    }
128
-    if (m_currentPayloadP && codec) {
129
-      channels = m_currentPayloadP->channels;
130
-      rate = m_currentPayloadP->sample_rate;
131
-    } else {
132
-      ERROR("Could not find payload <%i>\n", payload);
133
-      return -1;
62
+  if (this->codec_id != pl.codec_id) {
63
+    this->codec_id = pl.codec_id;
64
+    this->channels = 1;
65
+    this->rate = pl.clock_rate;
66
+    DBG("fmt.rate = %d", this->rate);
67
+    this->advertized_rate = pl.advertised_clock_rate;
68
+    DBG("fmt.advertized_rate = %d", this->advertized_rate);
69
+    this->frame_size = 20*this->advertized_rate/1000;
70
+    if (this->codec != NULL) {
71
+      destroyCodec();
134 72
     }
135 73
   }
136 74
   return 0;
137 75
 }
138
-#endif
139 76
 
140 77
 AmAudioRtpFormat::~AmAudioRtpFormat()
141 78
 {
142
-  // for (std::map<int, CodecContainer *>::iterator it = 
143
-  // 	 m_codecContainerByPayload.begin(); 
144
-  //      it != m_codecContainerByPayload.end(); ++it)
145
-  //   delete it->second;
146 79
 }
147 80
 
148 81
 AmAudioFormat::AmAudioFormat()
149
-  : channels(-1), rate(-1), codec(NULL),
150
-    //frame_length(20), 
151
-    frame_size(20*SYSTEM_SAMPLERATE/1000), frame_encoded_size(320)
82
+  : channels(-1), rate(-1), advertized_rate(-1), codec(NULL),
83
+    frame_size(20*SYSTEM_SAMPLECLOCK_RATE/1000), frame_encoded_size(320)
152 84
 {
153 85
 
154 86
 }
... ...
@@ -157,7 +89,7 @@ AmAudioSimpleFormat::AmAudioSimpleFormat(int codec_id)
157 89
   : AmAudioFormat(), codec_id(codec_id)
158 90
 {
159 91
   codec = getCodec();
160
-  rate = SYSTEM_SAMPLERATE;
92
+  rate = SYSTEM_SAMPLECLOCK_RATE;
161 93
   channels = 1;
162 94
 }
163 95
 
... ...
@@ -265,25 +197,123 @@ long AmAudioFormat::getHCodec()
265 197
   return h_codec;
266 198
 }
267 199
 
200
+#ifdef USE_LIBSAMPLERATE
201
+AmLibSamplerateResamplingState::AmLibSamplerateResamplingState()
202
+  : resample_state(NULL), resample_buf_samples(0), resample_out_buf_samples(0)
203
+{
204
+}
205
+
206
+AmLibSamplerateResamplingState::~AmLibSamplerateResamplingState()
207
+{
208
+  if (NULL != resample_state) {
209
+    src_delete(resample_state);
210
+    resample_state=NULL;
211
+  }
212
+}
213
+
214
+unsigned int AmLibSamplerateResamplingState::resample(unsigned char* samples, unsigned int s, double ratio)
215
+{
216
+  DBG("resampling packet of size %d with ratio %f", s, ratio);
217
+  if (!resample_state) {
218
+    int src_error;
219
+    // for better quality but more CPU usage, use SRC_SINC_ converters
220
+    resample_state = src_new(SRC_LINEAR, 1, &src_error);
221
+    if (!resample_state) {
222
+      ERROR("samplerate initialization error: ");
223
+    }
224
+  }
225
+
226
+  if (resample_state) {
227
+    if (resample_buf_samples + PCM16_B2S(s) > PCM16_B2S(AUDIO_BUFFER_SIZE) * 2) {
228
+      WARN("resample input buffer overflow! (%lu)\n", resample_buf_samples + PCM16_B2S(s));
229
+    } else if (resample_out_buf_samples + (PCM16_B2S(s) * ratio) + 20 > PCM16_B2S(AUDIO_BUFFER_SIZE)) {
230
+      WARN("resample: possible output buffer overflow! (%lu)\n", (resample_out_buf_samples + (size_t) ((PCM16_B2S(s) * ratio)) + 20));
231
+    } else {
232
+      signed short* samples_s = (signed short*)samples;
233
+      src_short_to_float_array(samples_s, &resample_in[resample_buf_samples], PCM16_B2S(s));
234
+      resample_buf_samples += PCM16_B2S(s);
235
+    }
236
+
237
+    SRC_DATA src_data;
238
+    src_data.data_in = resample_in;
239
+    src_data.input_frames = resample_buf_samples;
240
+    src_data.data_out = &resample_out[resample_out_buf_samples];
241
+    src_data.output_frames = PCM16_B2S(AUDIO_BUFFER_SIZE);
242
+    src_data.src_ratio = ratio;
243
+    src_data.end_of_input = 0;
244
+
245
+    int src_err = src_process(resample_state, &src_data);
246
+    if (src_err) {
247
+      DBG("resample error: '%s'\n", src_strerror(src_err));
248
+    }else {
249
+      signed short* samples_s = (signed short*)(unsigned char*)samples;
250
+      resample_out_buf_samples += src_data.output_frames_gen;
251
+      s *= ratio;
252
+      src_float_to_short_array(resample_out, samples_s, PCM16_B2S(s));
253
+      DBG("resample: output_frames_gen = %ld", src_data.output_frames_gen);
254
+
255
+      if (resample_buf_samples !=  (unsigned int)src_data.input_frames_used) {
256
+	memmove(resample_in, &resample_in[src_data.input_frames_used],
257
+		(resample_buf_samples - src_data.input_frames_used) * sizeof(float));
258
+      }
259
+      resample_buf_samples = resample_buf_samples - src_data.input_frames_used;
260
+
261
+      if (resample_out_buf_samples != s) {
262
+	memmove(resample_out, &resample_out[PCM16_B2S(s)], (resample_out_buf_samples - PCM16_B2S(s)) * sizeof(float));
263
+      }
264
+      resample_out_buf_samples -= PCM16_B2S(s);
265
+    }
266
+  }
267
+
268
+  DBG("resample: output size is %d", s);
269
+  return s;
270
+}
271
+#endif
272
+
273
+#ifdef USE_INTERNAL_RESAMPLER
274
+AmInternalResamplerState::AmInternalResamplerState()
275
+  : rstate(NULL)
276
+{
277
+  rstate = ResampleFactory::createResampleObj(true, 4.0, ResampleFactory::INTERPOL_SINC, ResampleFactory::SAMPLE_MONO);
278
+}
279
+
280
+AmInternalResamplerState::~AmInternalResamplerState()
281
+{
282
+  if (rstate != NULL)
283
+    ResampleFactory::destroyResampleObj(rstate);
284
+}
285
+
286
+unsigned int AmInternalResamplerState::resample(unsigned char *samples, unsigned int s, double ratio)
287
+{
288
+  if (rstate == NULL) {
289
+    ERROR("Uninitialized resampling state");
290
+    return s;
291
+  }
292
+
293
+  //DBG("Resampling with ration %f", ratio);
294
+  //DBG("Putting %d samples in the buffer", PCM16_B2S(s));
295
+  rstate->put_samples((signed short *)samples, PCM16_B2S(s));
296
+  s = rstate->resample((signed short *)samples, ratio, PCM16_B2S(s) * ratio);
297
+  //DBG("Returning %d samples", s);
298
+  return PCM16_S2B(s);
299
+}
300
+#endif
301
+
268 302
 AmAudio::AmAudio()
269 303
   : fmt(new AmAudioSimpleFormat(CODEC_PCM16)),
270 304
     max_rec_time(-1),
271
-    rec_time(0)
272
-#ifdef USE_LIBSAMPLERATE 
273
-  , resample_state(NULL),
274
-    resample_buf_samples(0)
275
-#endif
305
+    rec_time(0),
306
+    input_resampling_state(NULL),
307
+    output_resampling_state(NULL)
276 308
 {
277 309
 }
278 310
 
279 311
 AmAudio::AmAudio(AmAudioFormat *_fmt)
280 312
   : fmt(_fmt),
281 313
     max_rec_time(-1),
282
-    rec_time(0)
283
-#ifdef USE_LIBSAMPLERATE 
284
-  , resample_state(NULL),
285
-    resample_buf_samples(0)
286
-#endif
314
+    rec_time(0),
315
+    input_resampling_state(NULL),
316
+    output_resampling_state(NULL)
287 317
 {
288 318
 }
289 319
 
... ...
@@ -305,10 +335,18 @@ void AmAudio::close()
305 335
 {
306 336
 }
307 337
 
338
+
308 339
 // returns bytes read, else -1 if error (0 is OK)
309
-int AmAudio::get(unsigned int user_ts, unsigned char* buffer, unsigned int nb_samples)
310
-{
311
-  int size = calcBytesToRead(nb_samples);
340
+int AmAudio::get(unsigned int user_ts, unsigned char* buffer, int output_sample_rate, unsigned int nb_samples)
341
+{
342
+  int size = 0;
343
+  if (output_sample_rate < fmt->rate) {
344
+    int rfactor = fmt->rate / output_sample_rate;
345
+    size = calcBytesToRead(nb_samples * rfactor);
346
+  } else {
347
+    int rdivisor = output_sample_rate / fmt->rate;
348
+    size = calcBytesToRead(nb_samples / rdivisor);
349
+  }
312 350
 
313 351
   size = read(user_ts,size);
314 352
   //DBG("size = %d\n",size);
... ...
@@ -322,7 +360,9 @@ int AmAudio::get(unsigned int user_ts, unsigned char* buffer, unsigned int nb_sa
322 360
     return -1; 
323 361
   }
324 362
   size = downMix(size);
325
-    
363
+
364
+  size = resampleOutput((unsigned char*)samples,size, fmt->rate, output_sample_rate);
365
+  
326 366
   if(size>0)
327 367
     memcpy(buffer,(unsigned char*)samples,size);
328 368
 
... ...
@@ -330,7 +370,7 @@ int AmAudio::get(unsigned int user_ts, unsigned char* buffer, unsigned int nb_sa
330 370
 }
331 371
 
332 372
 // returns bytes written, else -1 if error (0 is OK)
333
-int AmAudio::put(unsigned int user_ts, unsigned char* buffer, unsigned int size)
373
+int AmAudio::put(unsigned int user_ts, unsigned char* buffer, int input_sample_rate, unsigned int size)
334 374
 {
335 375
   if(!size){
336 376
     return 0;
... ...
@@ -339,6 +379,7 @@ int AmAudio::put(unsigned int user_ts, unsigned char* buffer, unsigned int size)
339 379
   if(max_rec_time > -1 && rec_time >= max_rec_time)
340 380
     return -1;
341 381
 
382
+  size = resampleInput((unsigned char*)samples, size, input_sample_rate, fmt->rate);
342 383
 
343 384
   memcpy((unsigned char*)samples,buffer,size);
344 385
 
... ...
@@ -346,7 +387,8 @@ int AmAudio::put(unsigned int user_ts, unsigned char* buffer, unsigned int size)
346 387
   if(s>0){
347 388
     //DBG("%s\n",typeid(this).name());
348 389
     incRecordTime(bytes2samples(size));
349
-    return write(user_ts,(unsigned int)s);
390
+    unsigned int wr_ts = user_ts * ((double) fmt->advertized_rate / (double) SYSTEM_SAMPLECLOCK_RATE);
391
+    return write(wr_ts,(unsigned int)s);
350 392
   }
351 393
   else{
352 394
     return s;
... ...
@@ -398,10 +440,10 @@ int AmAudio::encode(unsigned int size)
398 440
 {
399 441
   int s = size;
400 442
 
401
-//   if(!fmt.get()){
402
-//     DBG("no encode fmt\n");
403
-//     return 0;
404
-//   }
443
+  //   if(!fmt.get()){
444
+  //     DBG("no encode fmt\n");
445
+  //     return 0;
446
+  //   }
405 447
 
406 448
   amci_codec_t* codec = fmt->getCodec();
407 449
   long h_codec = fmt->getHCodec();
... ...
@@ -425,7 +467,7 @@ unsigned int AmAudio::downMix(unsigned int size)
425 467
     samples.swap();
426 468
   }
427 469
 
428
-#ifdef USE_LIBSAMPLERATE 
470
+#if 0
429 471
   if (fmt->rate != SYSTEM_SAMPLERATE) {
430 472
     if (!resample_state) {
431 473
       int src_error;
... ...
@@ -476,6 +518,63 @@ unsigned int AmAudio::downMix(unsigned int size)
476 518
   return s;
477 519
 }
478 520
 
521
+unsigned int AmAudio::resampleInput(unsigned char* buffer, unsigned int s, int input_sample_rate, int output_sample_rate)
522
+{
523
+  if ((input_sample_rate == output_sample_rate) && !input_resampling_state.get()) {
524
+    return s;
525
+  }
526
+
527
+  if (!input_resampling_state.get()) {
528
+#ifdef USE_INTERNAL_RESAMPLER
529
+    if (AmConfig::ResamplingImplementationType == AmAudio::INTERNAL_RESAMPLER) {
530
+      DBG("using internal resampler for input");
531
+      input_resampling_state.reset(new AmInternalResamplerState());
532
+    } else
533
+#endif
534
+#ifdef USE_LIBSAMPLERATE
535
+      if (AmConfig::ResamplingImplementationType == AmAudio::LIBSAMPLERATE) {
536
+	input_resampling_state.reset(new AmLibSamplerateResamplingState());
537
+      } else
538
+#endif
539
+	{
540
+	  return s;
541
+	}
542
+  }
543
+
544
+  return resample(*input_resampling_state, buffer, s, input_sample_rate, output_sample_rate);
545
+}
546
+
547
+unsigned int AmAudio::resampleOutput(unsigned char* buffer, unsigned int s, int input_sample_rate, int output_sample_rate)
548
+{
549
+  if ((input_sample_rate == output_sample_rate) && !output_resampling_state.get()) {
550
+    return s;
551
+  }
552
+
553
+  if (!output_resampling_state.get()) {
554
+#ifdef USE_INTERNAL_RESAMPLER
555
+    if (AmConfig::ResamplingImplementationType == AmAudio::INTERNAL_RESAMPLER) {
556
+      DBG("using internal resampler for output");
557
+      output_resampling_state.reset(new AmInternalResamplerState());
558
+    } else
559
+#endif
560
+#ifdef USE_LIBSAMPLERATE
561
+      if (AmConfig::ResamplingImplementationType == AmAudio::LIBSAMPLERATE) {
562
+	output_resampling_state.reset(new AmLibSamplerateResamplingState());
563
+      } else
564
+#endif
565
+	{
566
+	  return s;
567
+	}
568
+  }
569
+
570
+  return resample(*output_resampling_state, buffer, s, input_sample_rate, output_sample_rate);
571
+}
572
+
573
+unsigned int AmAudio::resample(AmResamplingState& rstate, unsigned char* buffer, unsigned int s, int input_sample_rate, int output_sample_rate)
574
+{
575
+  return rstate.resample((unsigned char*) buffer, s, ((double) output_sample_rate) / ((double) input_sample_rate));
576
+}
577
+
479 578
 unsigned int AmAudio::getFrameSize()
480 579
 {
481 580
 
... ...
@@ -485,6 +584,23 @@ unsigned int AmAudio::getFrameSize()
485 584
   return fmt->frame_size;
486 585
 }
487 586
 
587
+int AmAudio::getSampleRate()
588
+{
589
+  if (!fmt.get())
590
+    fmt.reset(new AmAudioSimpleFormat(CODEC_PCM16));
591
+
592
+  return fmt->rate;
593
+}
594
+
595
+unsigned int AmAudio::getSampleRateDivisor()
596
+{
597
+
598
+  if (!fmt.get())
599
+    fmt.reset(new AmAudioSimpleFormat(CODEC_PCM16));
600
+
601
+  return (SYSTEM_SAMPLECLOCK_RATE / fmt->rate);
602
+}
603
+
488 604
 unsigned int AmAudio::calcBytesToRead(unsigned int nb_samples) const
489 605
 {
490 606
   return fmt->calcBytesToRead(nb_samples);
... ...
@@ -509,6 +625,7 @@ int AmAudio::incRecordTime(unsigned int samples)
509 625
 DblBuffer::DblBuffer()
510 626
   : active_buf(0)
511 627
 { 
628
+  memset(samples, 0, AUDIO_BUFFER_SIZE * 2);
512 629
 }
513 630
 
514 631
 DblBuffer::operator unsigned char*()
... ...
@@ -40,17 +40,25 @@ using std::auto_ptr;
40 40
 using std::string;
41 41
 #include <map>
42 42
 
43
-#ifdef USE_LIBSAMPLERATE 
43
+#ifdef USE_LIBSAMPLERATE
44 44
 #include <samplerate.h>
45 45
 #endif
46 46
 
47
+#ifdef USE_INTERNAL_RESAMPLER
48
+#include "resample/resample.h"
49
+#endif
50
+
47 51
 #define PCM16_B2S(b) ((b) >> 1)
48 52
 #define PCM16_S2B(s) ((s) << 1)
49 53
 
50
-#define SYSTEM_SAMPLERATE 8000 // fixme: sr per session
54
+//#define SYSTEM_SAMPLERATE 8000 // fixme: sr per session
55
+#ifndef SYSTEM_SAMPLECLOCK_RATE
56
+#define SYSTEM_SAMPLECLOCK_RATE 32000
57
+#endif
51 58
 
52 59
 struct SdpPayload;
53 60
 struct CodecContainer;
61
+struct Payload;
54 62
 
55 63
 /** \brief Audio Event */
56 64
 class AmAudioEvent: public AmEvent
... ...
@@ -112,6 +120,10 @@ public:
112 120
   int channels;
113 121
   /** Sampling rate. */
114 122
   int rate;
123
+
124
+  /** Sampling rate as advertized in SDP (differs from actual rate for G722) **/
125
+  int advertized_rate;
126
+
115 127
   /* frame length in ms (frame based codecs) - unused */
116 128
   //int frame_length;
117 129
   /* frame size in samples */
... ...
@@ -198,11 +210,49 @@ public:
198 210
   /**
199 211
    * changes payload. returns != 0 on error.
200 212
    */
201
-  //int setCurrentPayload(int payload);
202
-  //int getCurrentPayload() { return m_currentPayload; };
213
+  int setCurrentPayload(Payload pl);
214
+};
215
+
216
+/**
217
+ * \brief keeps the resampling state for one direction (input or output)
218
+ */
219
+class AmResamplingState
220
+{
221
+public:
222
+  virtual unsigned int resample(unsigned char* samples, unsigned int size, double ratio) = 0;
223
+  virtual ~AmResamplingState() {}
224
+};
225
+
226
+#ifdef USE_LIBSAMPLERATE
227
+class AmLibSamplerateResamplingState: public AmResamplingState
228
+{
229
+private:
230
+  SRC_STATE* resample_state;
231
+  float resample_in[PCM16_B2S(AUDIO_BUFFER_SIZE)*2];
232
+  float resample_out[PCM16_B2S(AUDIO_BUFFER_SIZE)];
233
+  size_t resample_buf_samples;
234
+  size_t resample_out_buf_samples;
235
+public:
236
+  AmLibSamplerateResamplingState();
237
+  virtual ~AmLibSamplerateResamplingState();
238
+
239
+  virtual unsigned int resample(unsigned char* samples, unsigned int size, double ratio);
240
+};
241
+#endif
242
+
243
+#ifdef USE_INTERNAL_RESAMPLER
244
+class AmInternalResamplerState: public AmResamplingState
245
+{
246
+private:
247
+  Resample *rstate;
248
+
249
+public:
250
+  AmInternalResamplerState();
251
+  virtual ~AmInternalResamplerState();
203 252
 
204
-  int setCodecId(int codec_id);
253
+  virtual unsigned int resample(unsigned char* samples, unsigned int size, double ratio);
205 254
 };
255
+#endif
206 256
 
207 257
 /**
208 258
  * \brief base for classes that input or output audio.
... ...
@@ -218,12 +268,12 @@ private:
218 268
   int rec_time; // in samples
219 269
   int max_rec_time;
220 270
 
221
-#ifdef USE_LIBSAMPLERATE 
222
-  SRC_STATE* resample_state;
223
-  float resample_in[PCM16_B2S(AUDIO_BUFFER_SIZE)*2];
224
-  float resample_out[PCM16_B2S(AUDIO_BUFFER_SIZE)];
225
-  size_t resample_buf_samples;
226
-#endif
271
+public:
272
+  enum ResamplingImplementationType {
273
+	LIBSAMPLERATE,
274
+	INTERNAL_RESAMPLER,
275
+	UNAVAILABLE
276
+  };
227 277
 
228 278
 protected:
229 279
   /** Sample buffer. */
... ...
@@ -231,6 +281,10 @@ protected:
231 281
   
232 282
   /** Audio format. @see AmAudioFormat */
233 283
   auto_ptr<AmAudioFormat> fmt;
284
+  
285
+  /** Resampling states. @see AmResamplingState */
286
+  auto_ptr<AmResamplingState> input_resampling_state;
287
+  auto_ptr<AmResamplingState> output_resampling_state;
234 288
 
235 289
   AmAudio();
236 290
   AmAudio(AmAudioFormat *);
... ...
@@ -269,6 +323,33 @@ protected:
269 323
    */
270 324
   unsigned int downMix(unsigned int size);
271 325
 
326
+  /**
327
+   * Resamples from the given input sample rate to the given output sample rate
328
+   * using the input resampling state. The input resampling state is created if
329
+   * it does not exist.
330
+   *
331
+   */
332
+  unsigned int resampleInput(unsigned char *buffer, unsigned int size, int input_sample_rate, int output_sample_rate);
333
+
334
+  /**
335
+   * Resamples from the given input sample rate to the given output sample rate
336
+   * using the output resampling state. The output resampling state is created if
337
+   * it does not exist.
338
+   *
339
+   */
340
+  unsigned int resampleOutput(unsigned char *buffer, unsigned int size, int input_sample_rate, int output_sample_rate);
341
+
342
+  /**
343
+   * Resamples from the given input sample rate to the given output sample rate using
344
+   * the given resampling state.
345
+   * <ul><li>input = front buffer</li><li>output = back buffer</li></ul>
346
+   * @param rstate resampling state to be used
347
+   * @param size [in] size in bytes
348
+   * @param output_sample_rate desired output sample rate
349
+   * @return new size in bytes
350
+   */
351
+  unsigned int resample(AmResamplingState& rstate, unsigned char *buffer, unsigned int size, int input_sample_rate, int output_sample_rate);
352
+   
272 353
   /**
273 354
    * Get the number of bytes to read from encoded, depending on the format.
274 355
    */
... ...
@@ -294,7 +375,7 @@ public:
294 375
    * </pre>           whereby the format with/from which the codec works is the reference one.
295 376
    * @return # bytes read, else -1 if error (0 is OK) 
296 377
    */
297
-  virtual int get(unsigned int user_ts, unsigned char* buffer, unsigned int nb_samples);
378
+  virtual int get(unsigned int user_ts, unsigned char* buffer, int output_sample_rate, unsigned int nb_samples);
298 379
 
299 380
   /** 
300 381
    * Put some samples to the output stream.
... ...
@@ -303,9 +384,11 @@ public:
303 384
    * </pre>           whereby the format with/from which the codec works is the reference one.
304 385
    * @return # bytes written, else -1 if error (0 is OK) 
305 386
    */
306
-  virtual int put(unsigned int user_ts, unsigned char* buffer, unsigned int size);
387
+  virtual int put(unsigned int user_ts, unsigned char* buffer, int input_sample_rate, unsigned int size);
307 388
   
308 389
   unsigned int getFrameSize();
390
+  int getSampleRate();
391
+  unsigned int getSampleRateDivisor();
309 392
 
310 393
   void setRecordTime(unsigned int ms);
311 394
   int  incRecordTime(unsigned int samples);
... ...
@@ -421,6 +421,10 @@ int AmAudioFile::write(unsigned int user_ts, unsigned int size)
421 421
     return -1;
422 422
   }
423 423
 
424
+  if (getMode() != AmAudioFile::Write) {
425
+    return size;
426
+  }
427
+
424 428
   int s = fwrite((void*)((unsigned char*)samples),1,size,fp);
425 429
   if(s>0)
426 430
     data_size += s;
... ...
@@ -42,17 +42,17 @@ AmAudioMixIn::AmAudioMixIn(AmAudio* A, AmAudioFile* B,
42 42
 AmAudioMixIn::~AmAudioMixIn() { }
43 43
 
44 44
 int AmAudioMixIn::get(unsigned int user_ts, unsigned char* buffer, 
45
-		      unsigned int nb_samples) {
45
+		      int output_sample_rate, unsigned int nb_samples) {
46 46
   if (!mixing) {
47 47
     if (!next_start_ts_i) {
48 48
       next_start_ts_i = true;
49 49
       next_start_ts = IS_IMMEDIATE_START ? 
50
-	user_ts : user_ts + s*DEFAULT_SAMPLE_RATE;
50
+	user_ts : user_ts + s*output_sample_rate;
51 51
     }
52 52
     if (!ts_less()(user_ts, next_start_ts)) {
53 53
       DBG("starting mix-in\n");
54 54
       mixing = true;
55
-      next_start_ts = user_ts + s*DEFAULT_SAMPLE_RATE;
55
+      next_start_ts = user_ts + s*output_sample_rate;
56 56
     }
57 57
   } 
58 58
   
... ...
@@ -63,13 +63,13 @@ int AmAudioMixIn::get(unsigned int user_ts, unsigned char* buffer,
63 63
 
64 64
   if (!mixing || NULL == B) {
65 65
     B_mut.unlock();
66
-    return A->get(user_ts, buffer, nb_samples);
66
+    return A->get(user_ts, buffer, output_sample_rate, nb_samples);
67 67
   } else {
68 68
     if (l < 0.01) { // epsilon 
69 69
       // only play back from B
70
-      int res = B->get(user_ts, buffer, nb_samples);
70
+      int res = B->get(user_ts, buffer, output_sample_rate, nb_samples);
71 71
       if (res <= 0) { // B empty
72
-	res = A->get(user_ts, buffer, nb_samples);
72
+	res = A->get(user_ts, buffer, output_sample_rate, nb_samples);
73 73
 	mixing = false;
74 74
 	if (IS_ONLY_ONCE)
75 75
 	  B = NULL;
... ...
@@ -82,7 +82,7 @@ int AmAudioMixIn::get(unsigned int user_ts, unsigned char* buffer,
82 82
       int res = 0;
83 83
       short* pdest = (short*)buffer;
84 84
       // get audio from A
85
-      int len = A->get(user_ts, (unsigned char*)mix_buf, nb_samples);
85
+      int len = A->get(user_ts, (unsigned char*)mix_buf, output_sample_rate, nb_samples);
86 86
 
87 87
       if ((len<0) && !IS_FINISH_B_MIX) { // A finished
88 88
 	B_mut.unlock();
... ...
@@ -104,7 +104,7 @@ int AmAudioMixIn::get(unsigned int user_ts, unsigned char* buffer,
104 104
 	       (nb_samples<<1) - len_from_a);
105 105
       
106 106
       // add audio from B
107
-      len = B->get(user_ts, (unsigned char*)mix_buf, nb_samples);
107
+      len = B->get(user_ts, (unsigned char*)mix_buf, output_sample_rate, nb_samples);
108 108
       if (len<0) { // B finished
109 109
 	mixing = false;
110 110
 	
... ...
@@ -126,7 +126,7 @@ int AmAudioMixIn::get(unsigned int user_ts, unsigned char* buffer,
126 126
   }
127 127
 }
128 128
 
129
-int AmAudioMixIn::put(unsigned int user_ts, unsigned char* buffer, unsigned int size) {
129
+int AmAudioMixIn::put(unsigned int user_ts, unsigned char* buffer, int input_sample_rate, unsigned int size) {
130 130
   ERROR("writing not supported\n");
131 131
   return -1;
132 132
 }
... ...
@@ -31,8 +31,8 @@
31 31
 
32 32
 
33 33
 #define MAX_PACKETLENGTH_MS   80
34
-#define MAX_BUF_SAMPLES  SYSTEM_SAMPLERATE * MAX_PACKETLENGTH_MS / 1000
35
-#define DEFAULT_SAMPLE_RATE SYSTEM_SAMPLERATE // eh...
34
+#define MAX_BUF_SAMPLES  SYSTEM_SAMPLECLOCK_RATE * MAX_PACKETLENGTH_MS / 1000
35
+#define DEFAULT_SAMPLE_RATE SYSTEM_SAMPLECLOCK_RATE // eh...
36 36
 
37 37
 /**
38 38
  * \brief \ref AmAudio to mix in every n seconds a file
... ...
@@ -81,8 +81,8 @@ class AmAudioMixIn : public AmAudio {
81 81
   int write(unsigned int user_ts, unsigned int size){ return -1; }
82 82
     
83 83
   // override AmAudio
84
-  int get(unsigned int user_ts, unsigned char* buffer, unsigned int nb_samples);
85
-  int put(unsigned int user_ts, unsigned char* buffer, unsigned int size);
84
+  int get(unsigned int user_ts, unsigned char* buffer, int output_sample_rate, unsigned int nb_samples);
85
+  int put(unsigned int user_ts, unsigned char* buffer, int input_sample_rate, unsigned int size);
86 86
 };
87 87
 
88 88
 
... ...
@@ -27,8 +27,8 @@
27 27
 
28 28
 #include "AmAudioMixer.h"
29 29
 
30
-AmAudioMixer::AmAudioMixer() {
31
-  sink_channel = mixer.addChannel();
30
+AmAudioMixer::AmAudioMixer(int external_sample_rate) {
31
+  sink_channel = mixer.addChannel(external_sample_rate);
32 32
   sink_connector = 
33 33
     new AmAudioMixerConnector(mixer, sink_channel, NULL, 
34 34
 			      &srcsink_mut, &sinks);
... ...
@@ -44,9 +44,9 @@ AmAudioMixer::~AmAudioMixer() {
44 44
   delete sink_connector;
45 45
 }
46 46
 
47
-AmAudio* AmAudioMixer::addSource() {
47
+AmAudio* AmAudioMixer::addSource(int external_sample_rate) {
48 48
   srcsink_mut.lock();
49
-  unsigned int src_channel = mixer.addChannel();
49
+  unsigned int src_channel = mixer.addChannel(external_sample_rate);
50 50
   // the first source will process the media in the mixer channel
51 51
   AmAudioMixerConnector* conn = 
52 52
     new AmAudioMixerConnector(mixer, src_channel, 
... ...
@@ -83,16 +83,17 @@ void AmAudioMixer::releaseSink(AmAudio* s) {
83 83
   srcsink_mut.unlock();
84 84
 }
85 85
 
86
-int AmAudioMixerConnector::get(unsigned int user_ts, unsigned char* buffer, unsigned int nb_samples) {
86
+int AmAudioMixerConnector::get(unsigned int user_ts, unsigned char* buffer, int output_sample_rate, unsigned int nb_samples) {
87 87
   // in fact GCP here only needed for the mixed channel
88
-  mixer.GetChannelPacket(channel, user_ts, buffer, nb_samples);
88
+  unsigned int mixer_sample_rate;
89
+  mixer.GetChannelPacket(channel, user_ts, buffer, nb_samples, mixer_sample_rate);
89 90
 
90 91
   if ((audio_mut != NULL) && (sinks != NULL)) {
91 92
     audio_mut->lock();
92 93
     // write to all sinks
93 94
     for (std::set<AmAudio*>::iterator it=sinks->begin(); 
94 95
 	 it != sinks->end(); it++) {
95
-      (*it)->put(user_ts, buffer, nb_samples);
96
+      (*it)->put(user_ts, buffer, output_sample_rate, nb_samples);
96 97
     }
97 98
     audio_mut->unlock();
98 99
   }
... ...
@@ -100,13 +101,13 @@ int AmAudioMixerConnector::get(unsigned int user_ts, unsigned char* buffer, unsi
100 101
   return nb_samples;
101 102
 }
102 103
 
103
-int AmAudioMixerConnector::put(unsigned int user_ts, unsigned char* buffer, unsigned int size) {
104
+int AmAudioMixerConnector::put(unsigned int user_ts, unsigned char* buffer, int input_sample_rate, unsigned int size) {
104 105
   mixer.PutChannelPacket(channel, user_ts, buffer, size);
105 106
 
106 107
   if (mix_channel != NULL) {
107 108
     // we are processing the media of the mixed channel as well
108 109
     ShortSample mix_buffer[SIZE_MIX_BUFFER];    
109
-    mix_channel->get(user_ts, (unsigned char*)mix_buffer, size);
110
+    mix_channel->get(user_ts, (unsigned char*)mix_buffer, input_sample_rate, size);
110 111
   }
111 112
   return size;
112 113
 }
... ...
@@ -59,10 +59,10 @@ class AmAudioMixer
59 59
   std::set<AmAudio*> sinks;
60 60
 
61 61
  public:
62
-  AmAudioMixer();
62
+  AmAudioMixer(int external_sample_rate);
63 63
   ~AmAudioMixer();
64 64
   
65
-  AmAudio* addSource();
65
+  AmAudio* addSource(int external_sample_rate);
66 66
   void releaseSource(AmAudio* s);
67 67
 
68 68
   void addSink(AmAudio* s);
... ...
@@ -78,8 +78,8 @@ class AmAudioMixerConnector
78 78
   AmAudio* mix_channel;
79 79
 
80 80
  protected:
81
-  int get(unsigned int user_ts, unsigned char* buffer, unsigned int nb_samples);
82
-  int put(unsigned int user_ts, unsigned char* buffer, unsigned int size);
81
+  int get(unsigned int user_ts, unsigned char* buffer, int output_sample_rate, unsigned int nb_samples);
82
+  int put(unsigned int user_ts, unsigned char* buffer, int input_sample_rate, unsigned int size);
83 83
 
84 84
   // dummies for AmAudio's pure virtual methods
85 85
   int read(unsigned int user_ts, unsigned int size){ return -1; }
... ...
@@ -449,7 +449,7 @@ void AmSessionAudioConnector::waitReleased() {
449 449
 
450 450
 // ----------------------- AudioDelayBridge -----------------
451 451
 /** BRIDGE_DELAY is needed because of possible different packet sizes */ 
452
-#define BRIDGE_DELAY 30 * SYSTEM_SAMPLERATE/1000 // 30ms
452
+#define BRIDGE_DELAY 30 * SYSTEM_SAMPLECLOCK_RATE/1000 // 30ms
453 453
 
454 454
 /* AudioBridge */
455 455
 AmAudioDelayBridge::AmAudioDelayBridge()
... ...
@@ -76,15 +76,15 @@ void AmBufferedAudio::clearBufferEOF() {
76 76
   err_code = 0;
77 77
 }
78 78
 
79
-int AmBufferedAudio::get(unsigned int user_ts, unsigned char* buffer, unsigned int nb_samples) {
79
+int AmBufferedAudio::get(unsigned int user_ts, unsigned char* buffer, int output_sample_rate, unsigned int nb_samples) {
80 80
   if (!output_buffer_size) 
81
-    return AmAudio::get(user_ts, buffer, nb_samples);
81
+    return AmAudio::get(user_ts, buffer, output_sample_rate, nb_samples);
82 82
 
83 83
   if (w-r < low_buffer_thresh && !eof) {
84 84
     input_get_audio(user_ts);
85 85
   }
86 86
   
87
-  size_t nget = PCM16_S2B(nb_samples);
87
+  size_t nget = PCM16_S2B(nb_samples * output_sample_rate / fmt->rate);
88 88
   if (w-r < nget) 
89 89
     nget = w-r;
90 90
 
... ...
@@ -97,10 +97,13 @@ int AmBufferedAudio::get(unsigned int user_ts, unsigned char* buffer, unsigned i
97 97
     return 0;
98 98
   }
99 99
  
100
-  memcpy(buffer, &output_buffer[r], nget);
101
-
100
+  memcpy((unsigned char*)samples,&output_buffer[r],nget);
102 101
   r+=nget;
103
-  return nget;
102
+
103
+  int size = resampleOutput(samples,nget,fmt->rate,output_sample_rate);
104
+  memcpy(buffer, (unsigned char*)samples,size);
105
+
106
+  return size;
104 107
 }
105 108
 
106 109
 void AmBufferedAudio::input_get_audio(unsigned int user_ts) {
... ...
@@ -53,7 +53,7 @@ class AmBufferedAudio : public AmAudio {
53 53
   void setBufferSize(size_t _output_buffer_size, size_t _low_buffer_thresh, size_t _full_buffer_thresh);
54 54
 
55 55
  public:
56
-  virtual int get(unsigned int user_ts, unsigned char* buffer, unsigned int nb_samples);
56
+  virtual int get(unsigned int user_ts, unsigned char* buffer, int output_sample_rate, unsigned int nb_samples);
57 57
 
58 58
 };
59 59
 #endif
... ...
@@ -14,15 +14,23 @@ AmConferenceChannel::~AmConferenceChannel()
14 14
     AmConferenceStatus::releaseChannel(conf_id,channel_id);
15 15
 }
16 16
 
17
-int AmConferenceChannel::put(unsigned int user_ts, unsigned char* buffer, unsigned int size)
17
+int AmConferenceChannel::put(unsigned int user_ts, unsigned char* buffer, int input_sample_rate, unsigned int size)
18 18
 {
19
-  status->getMixer()->PutChannelPacket(channel_id,user_ts,buffer,size);
19
+  memcpy((unsigned char*)samples,buffer,size);
20
+  status->getMixer()->lock();
21
+  size = resampleInput(samples,size,input_sample_rate,status->getMixer()->GetCurrentSampleRate());
22
+  status->getMixer()->PutChannelPacket(channel_id,user_ts,(unsigned char*)samples,size);
23
+  status->getMixer()->unlock();
20 24
   return size;
21 25
 }
22 26
 
23
-int AmConferenceChannel::get(unsigned int user_ts, unsigned char* buffer, unsigned int nb_samples)
27
+int AmConferenceChannel::get(unsigned int user_ts, unsigned char* buffer, int output_sample_rate, unsigned int nb_samples)
24 28
 {
25
-  unsigned int size = PCM16_S2B(nb_samples);
26
-  status->getMixer()->GetChannelPacket(channel_id,user_ts,buffer,size);
29
+  status->getMixer()->lock();
30
+  unsigned int size = PCM16_S2B(nb_samples * status->getMixer()->GetCurrentSampleRate() / output_sample_rate);
31
+  unsigned int mixer_sample_rate = 0;
32
+  status->getMixer()->GetChannelPacket(channel_id,user_ts,buffer,size,mixer_sample_rate);
33
+  size = resampleOutput(buffer,size,mixer_sample_rate,output_sample_rate);
34
+  status->getMixer()->unlock();
27 35
   return size;
28 36
 }
... ...
@@ -51,8 +51,8 @@ class AmConferenceChannel: public AmAudio
51 51
   int write(unsigned int user_ts, unsigned int size){ return -1; }
52 52
 
53 53
   // override AmAudio
54
-  int get(unsigned int user_ts, unsigned char* buffer, unsigned int nb_samples);
55
-  int put(unsigned int user_ts, unsigned char* buffer, unsigned int size);
54
+  int get(unsigned int user_ts, unsigned char* buffer, int output_sample_rate, unsigned int nb_samples);
55
+  int put(unsigned int user_ts, unsigned char* buffer, int input_sample_rate, unsigned int size);
56 56
 
57 57
  public:
58 58
   AmConferenceChannel(AmConferenceStatus* status, 
... ...
@@ -41,7 +41,7 @@ AmMutex                         AmConferenceStatus::cid2s_mut;
41 41
 // static methods
42 42
 //
43 43
 AmConferenceChannel* AmConferenceStatus::getChannel(const string& cid, 
44
-						    const string& local_tag)
44
+						    const string& local_tag, int input_sample_rate)
45 45
 {
46 46
   AmConferenceStatus*  st = 0;
47 47
   AmConferenceChannel* ch = 0;
... ...
@@ -59,7 +59,7 @@ AmConferenceChannel* AmConferenceStatus::getChannel(const string& cid,
59 59
     cid2status[cid] = st;
60 60
   }
61 61
 
62
-  ch = st->getChannel(local_tag);
62
+  ch = st->getChannel(local_tag, input_sample_rate);
63 63
   cid2s_mut.unlock();
64 64
 
65 65
   return ch;
... ...
@@ -148,7 +148,7 @@ void AmConferenceStatus::postConferenceEvent(int event_id, const string& sess_id
148 148
   sessions_mut.unlock();
149 149
 }
150 150
 
151
-AmConferenceChannel* AmConferenceStatus::getChannel(const string& sess_id)
151
+AmConferenceChannel* AmConferenceStatus::getChannel(const string& sess_id, int input_sample_rate)
152 152
 {
153 153
   AmConferenceChannel* ch = 0;
154 154
 
... ...
@@ -173,7 +173,7 @@ AmConferenceChannel* AmConferenceStatus::getChannel(const string& sess_id)
173 173
 									     conf_id,sess_id));
174 174
     }
175 175
 
176
-    unsigned int ch_id = mixer.addChannel();
176
+    unsigned int ch_id = mixer.addChannel(input_sample_rate);
177 177
     SessInfo* si = new SessInfo(sess_id,ch_id);
178 178
 
179 179
     sessions[sess_id] = ch_id;
... ...
@@ -94,7 +94,7 @@ class AmConferenceStatus
94 94
   AmConferenceStatus(const string& conference_id);
95 95
   ~AmConferenceStatus();
96 96
 
97
-  AmConferenceChannel* getChannel(const string& sess_id);
97
+  AmConferenceChannel* getChannel(const string& sess_id, int input_sample_rate);
98 98
 
99 99
   int releaseChannel(unsigned int ch_id);
100 100
 
... ...
@@ -105,7 +105,8 @@ public:
105 105
   AmMultiPartyMixer* getMixer()  { return &mixer; }
106 106
 
107 107
   static AmConferenceChannel* getChannel(const string& cid, 
108
-					 const string& local_tag);
108
+					 const string& local_tag,
109
+                                         int input_sample_rate);
109 110
 
110 111
   static void releaseChannel(const string& cid, unsigned int ch_id);
111 112
 
... ...
@@ -117,6 +117,20 @@ AmConfig::DefaultDTMFDetector     = Dtmf::SEMSInternal;
117 117
 bool AmConfig::IgnoreSIGCHLD      = true;
118 118
 bool AmConfig::IgnoreSIGPIPE      = true;
119 119
 
120
+#ifdef USE_LIBSAMPLERATE
121
+#ifndef USE_INTERNAL_RESAMPLER
122
+AmAudio::ResamplingImplementationType AmConfig::ResamplingImplementationType = AmAudio::LIBSAMPLERATE;
123
+#endif
124
+#endif
125
+#ifdef USE_INTERNAL_RESAMPLER
126
+AmAudio::ResamplingImplementationType AmConfig::ResamplingImplementationType = AmAudio::INTERNAL_RESAMPLER;
127
+#endif
128
+#ifndef USE_LIBSAMPLERATE
129
+#ifndef USE_INTERNAL_RESAMPLER
130
+AmAudio::ResamplingImplementationType AmConfig::ResamplingImplementationType = AmAudio::UNAVAILABLE;
131
+#endif
132
+#endif
133
+
120 134
 static int readInterfaces(AmConfigReader& cfg);
121 135
 
122 136
 AmConfig::IP_interface::IP_interface()
... ...
@@ -570,6 +584,13 @@ int AmConfig::readConfiguration()
570 584
     }
571 585
   }
572 586
 
587
+  if (cfg.hasParameter("resampling_library")) {
588
+	string resamplings = cfg.getParameter("resampling_library");
589
+	if (resamplings == "libsamplerate") {
590
+	  ResamplingImplementationType = AmAudio::LIBSAMPLERATE;
591
+	}
592
+  }
593
+
573 594
   return ret;
574 595
 }	
575 596
 
... ...
@@ -32,6 +32,7 @@
32 32
 #include "AmDtmfDetector.h"
33 33
 #include "AmSipDialog.h"
34 34
 #include "AmUtils.h"
35
+#include "AmAudio.h"
35 36
 
36 37
 #include <string>
37 38
 using std::string;
... ...
@@ -206,6 +207,8 @@ struct AmConfig
206 207
 
207 208
   static int UnhandledReplyLoglevel;
208 209
 
210
+  static AmAudio::ResamplingImplementationType ResamplingImplementationType;
211
+
209 212
   /** Read global configuration file and insert values. Maybe overwritten by
210 213
    * command line arguments */
211 214
   static int readConfiguration();
... ...
@@ -185,21 +185,21 @@ AmDtmfDetector::AmDtmfDetector(AmSession *session)
185 185
     m_currentEvent(-1),
186 186
     m_current_eventid_i(false)
187 187
 {
188
-#ifndef USE_SPANDSP
189
-  setInbandDetector(Dtmf::SEMSInternal);
190
-#else
191
-  setInbandDetector(AmConfig::DefaultDTMFDetector);
192
-#endif
188
+  //#ifndef USE_SPANDSP
189
+  //  setInbandDetector(Dtmf::SEMSInternal, m_session->RTPStream()->getSampleRate());
190
+  //#else
191
+  //  setInbandDetector(AmConfig::DefaultDTMFDetector, m_session->RTPStream()->getSampleRate());
192
+  //#endif
193 193
 }
194 194
 
195
-void AmDtmfDetector::setInbandDetector(Dtmf::InbandDetectorType t) {
195
+void AmDtmfDetector::setInbandDetector(Dtmf::InbandDetectorType t, int sample_rate) {
196 196
 #ifndef USE_SPANDSP
197 197
   if (t == Dtmf::SpanDSP) {
198 198
     ERROR("trying to use spandsp DTMF detector without support for it"
199 199
 	  "recompile with -D USE_SPANDSP\n");
200 200
   }
201 201
   if (!m_inbandDetector.get())
202
-    m_inbandDetector.reset(new AmSemsInbandDtmfDetector(this));
202
+    m_inbandDetector.reset(new AmSemsInbandDtmfDetector(this, sample_rate));
203 203
 
204 204
   return;
205 205
 #else
... ...
@@ -207,10 +207,10 @@ void AmDtmfDetector::setInbandDetector(Dtmf::InbandDetectorType t) {
207 207
   if ((t != m_inband_type) || (!m_inbandDetector.get())) {
208 208
     if (t == Dtmf::SEMSInternal) {
209 209
       DBG("Setting internal DTMF detector\n");
210
-      m_inbandDetector.reset(new AmSemsInbandDtmfDetector(this));
210
+      m_inbandDetector.reset(new AmSemsInbandDtmfDetector(this, sample_rate));
211 211
     } else { // if t == SpanDSP
212 212
       DBG("Setting spandsp DTMF detector\n");
213
-      m_inbandDetector.reset(new AmSpanDSPInbandDtmfDetector(this));
213
+      m_inbandDetector.reset(new AmSpanDSPInbandDtmfDetector(this, sample_rate));
214 214
     }
215 215
     m_inband_type = t;
216 216
   }
... ...
@@ -539,12 +539,12 @@ static char dtmf_matrix[4][4] =
539 539
     {'*', '0', '#', 'D'}
540 540
   };
541 541
 
542
-AmSemsInbandDtmfDetector::AmSemsInbandDtmfDetector(AmKeyPressSink *keysink)
542
+AmSemsInbandDtmfDetector::AmSemsInbandDtmfDetector(AmKeyPressSink *keysink, int sample_rate)
543 543
   : AmInbandDtmfDetector(keysink),
544 544
     m_last(' '),
545 545
     m_idx(0),
546 546
     m_count(0),
547
-    SAMPLERATE(SYSTEM_SAMPLERATE)
547
+    SAMPLERATE(sample_rate)
548 548
 {
549 549
   /* precalculate 2 * cos (2 PI k / N) */
550 550
   for(unsigned i = 0; i < NELEMSOF(rel_cos2pik); i++) {
... ...
@@ -718,7 +718,7 @@ int AmSemsInbandDtmfDetector::streamPut(const unsigned char* samples, unsigned i
718 718
 
719 719
 #ifdef USE_SPANDSP
720 720
 
721
-AmSpanDSPInbandDtmfDetector::AmSpanDSPInbandDtmfDetector(AmKeyPressSink *keysink)
721
+AmSpanDSPInbandDtmfDetector::AmSpanDSPInbandDtmfDetector(AmKeyPressSink *keysink, int sample_rate)
722 722
   : AmInbandDtmfDetector(keysink) 
723 723
 {
724 724
 #ifdef HAVE_OLD_SPANDSP_CALLBACK
... ...
@@ -272,7 +272,7 @@ class AmSemsInbandDtmfDetector
272 272
   void isdn_audio_calc_dtmf(const signed short* buf, int len, unsigned int ts);
273 273
 
274 274
  public:
275
-  AmSemsInbandDtmfDetector(AmKeyPressSink *keysink);
275
+  AmSemsInbandDtmfDetector(AmKeyPressSink *keysink, int sample_rate);
276 276
   ~AmSemsInbandDtmfDetector();
277 277
   /**
278 278
    * Entry point for audio stream
... ...
@@ -302,7 +302,7 @@ class AmSpanDSPInbandDtmfDetector
302 302
 /*   void dtmf_rx_f(const char* digits, int len); */
303 303
 
304 304
  public: 
305
-  AmSpanDSPInbandDtmfDetector(AmKeyPressSink *keysink);
305
+  AmSpanDSPInbandDtmfDetector(AmKeyPressSink *keysink, int sample_rate);
306 306
   ~AmSpanDSPInbandDtmfDetector();
307 307
 
308 308
   /**
... ...
@@ -456,7 +456,7 @@ class AmDtmfDetector
456 456
   void checkTimeout();
457 457
   void putDtmfAudio(const unsigned char *, int size, int user_ts);
458 458
 
459
-  void setInbandDetector(Dtmf::InbandDetectorType t);
459
+  void setInbandDetector(Dtmf::InbandDetectorType t, int sample_rate);
460 460
   friend class AmSipDtmfDetector;
461 461
   friend class AmRtpDtmfDetector;
462 462
   friend class AmInbandDtmfDetector;
... ...
@@ -33,8 +33,8 @@
33 33
 #include "AmThread.h"
34 34
 #include "SampleArray.h"
35 35
 
36
-#define INITIAL_JITTER	    80 * SYSTEM_SAMPLERATE / 1000 // 80 miliseconds
37
-#define MAX_JITTER	    2  * SYSTEM_SAMPLERATE // 2 seconds
36
+#define INITIAL_JITTER	    80 * SYSTEM_SAMPLECLOCK_RATE / 1000 // 80 miliseconds
37
+#define MAX_JITTER	    2  * SYSTEM_SAMPLECLOCK_RATE // 2 seconds
38 38
 #define RESYNC_THRESHOLD    5 // resync backward if RESYNC_THRESHOLD packets arrive late
39 39
 
40 40
 class Packet {
... ...
@@ -256,7 +256,7 @@ void AmMediaProcessorThread::run()
256 256
     events.processEvents();
257 257
     processDtmfEvents();
258 258
 
259
-    ts += 10 * SYSTEM_SAMPLERATE / 1000; // 10 ms
259
+    ts += 10 * SYSTEM_SAMPLECLOCK_RATE / 1000; // 10 ms
260 260
     timeradd(&tick,&next_tick,&next_tick);
261 261
   }
262 262
 }
... ...
@@ -281,11 +281,9 @@ void AmMediaProcessorThread::processAudio(unsigned int ts)
281 281
       it != sessions.end(); it++){
282 282
 
283 283
     AmSession* s = (*it);
284
-    // todo: get frame size/checkInterval from local audio if local in+out (?)
285
-    unsigned int f_size = s->RTPStream()->getFrameSize(); 
286 284
 
287 285
     // complete frame time reached? 
288
-    if (s->RTPStream()->checkInterval(ts, f_size)) {
286
+    if (s->RTPStream()->checkInterval(ts)) {
289 287
       s->lockAudio();
290 288
 
291 289
       int got_audio = -1;
... ...
@@ -315,7 +313,7 @@ void AmMediaProcessorThread::processAudio(unsigned int ts)
315 313
 	      break;
316 314
 	    }
317 315
 	  } else {
318
-	    got_audio = s->RTPStream()->get(ts,buffer,f_size);
316
+	    got_audio = s->RTPStream()->get(ts,buffer,s->RTPStream()->getSampleRate(),s->RTPStream()->getFrameSize());
319 317
 	    
320 318
 	    if (s->isDtmfDetectionEnabled() && got_audio > 0)
321 319
 	      s->putDtmfAudio(buffer, got_audio, ts);
... ...
@@ -325,7 +323,7 @@ void AmMediaProcessorThread::processAudio(unsigned int ts)
325 323
 	// input is local - get audio from local_in
326 324
 	AmAudio* local_input = s->getLocalInput(); 
327 325
 	if (local_input) {
328
-	  got_audio = local_input->get(ts,buffer,f_size);
326
+	  got_audio = local_input->get(ts,buffer,s->RTPStream()->getSampleRate(),s->RTPStream()->getFrameSize());
329 327
 	}
330 328
       }
331 329
 
... ...
@@ -333,7 +331,7 @@ void AmMediaProcessorThread::processAudio(unsigned int ts)
333 331
       if (got_audio >= 0) {
334 332
 	AmAudio* input = s->getInput();
335 333
 	if (input) {
336
-	  int ret = input->put(ts,buffer,got_audio);
334
+	  int ret = input->put(ts,buffer,s->RTPStream()->getSampleRate(),got_audio);
337 335
 	  if(ret < 0){
338 336
 	    DBG("input->put() returned: %i\n",ret);
339 337
 	    postRequest(new SchedRequest(AmMediaProcessor::ClearSession,s));
... ...
@@ -355,7 +353,7 @@ void AmMediaProcessorThread::processAudio(unsigned int ts)
355 353
 	    
356 354
     if(output && s->RTPStream()->sendIntReached()){
357 355
 		
358
-      int size = output->get(ts,buffer,s->RTPStream()->getFrameSize());
356
+      int size = output->get(ts,buffer,s->RTPStream()->getSampleRate(), s->RTPStream()->getFrameSize());
359 357
       if(size <= 0){
360 358
 	DBG("output->get() returned: %i\n",size);
361 359
 	postRequest(new SchedRequest(AmMediaProcessor::ClearSession,s)); 
... ...
@@ -364,14 +362,14 @@ void AmMediaProcessorThread::processAudio(unsigned int ts)
364 362
 	if (!s->getAudioLocal(AM_AUDIO_OUT)) {
365 363
 	  // audio should go to RTP
366 364
 	  if(!s->RTPStream()->mute){	     
367
-	    if(s->RTPStream()->put(ts,buffer,size)<0)
365
+	    if(s->RTPStream()->put(ts,buffer,s->RTPStream()->getSampleRate(),size)<0)
368 366
 	      postRequest(new SchedRequest(AmMediaProcessor::ClearSession,s));
369 367
 	  }
370 368
 	} else {
371 369
 	  // output is local - audio should go in local_out
372 370
 	  AmAudio* local_output = s->getLocalOutput(); 
373 371
 	  if (local_output) {
374
-	    if (local_output->put(ts,buffer,size) < 0) {
372
+	    if (local_output->put(ts,buffer,s->RTPStream()->getSampleRate(),size) < 0) {
375 373
 	      postRequest(new SchedRequest(AmMediaProcessor::ClearSession,s));
376 374
 	    }
377 375
 	  }
... ...
@@ -35,46 +35,99 @@
35 35
 
36 36
 // the internal delay of the mixer (between put and get)
37 37
 #define MIXER_DELAY_MS 20
38
-#define MIXER_DELAY    MIXER_DELAY_MS*SYSTEM_SAMPLERATE/1000
38
+
39
+struct MixerBufferState
40
+{
41
+  typedef std::map<int,SampleArrayShort*> ChannelMap;
42
+
43
+  unsigned int sample_rate;
44
+  unsigned int last_ts;
45
+  ChannelMap channels;
46
+  SampleArrayInt *mixed_channel;
47
+
48
+  MixerBufferState(unsigned int sample_rate, std::set<int>& channelids);
49
+  MixerBufferState(const MixerBufferState& other);
50
+  ~MixerBufferState();
51
+
52
+  void add_channel(unsigned int channel_id);
53
+  void remove_channel(unsigned int channel_id);
54
+  SampleArrayShort* get_channel(unsigned int channel_id);
55
+  void fix_channels(std::set<int>& curchannelids);
56
+  void free_channels();
57
+};
58
+
59
+void DEBUG_MIXER_BUFFER_STATE(const MixerBufferState& mbs, const string& context)
60
+{
61
+  DBG("XXDebugMixerXX: dump of MixerBufferState %s", context.c_str());
62
+  DBG("XXDebugMixerXX: sample_rate = %u", mbs.sample_rate);
63
+  DBG("XXDebugMixerXX: last_ts = %u", mbs.last_ts);
64
+  for (MixerBufferState::ChannelMap::const_iterator it = mbs.channels.begin(); it != mbs.channels.end(); it++) {
65
+    DBG("XXDebugMixerXX: channel #%d present", it->first);
66
+  }
67
+  DBG("XXDebugMixerXX: end of MixerBufferState dump");
68
+}
39 69
 
40 70
 AmMultiPartyMixer::AmMultiPartyMixer()
41
-  : channels(),
42
-    cur_channel_id(0),
43
-    scaling_factor(16)
71
+  : sampleratemap(), samplerates(),
72
+    channelids(), scaling_factor(16),
73
+    buffer_state(), audio_mut()
44 74
 {
45 75
 }
46 76
 
47 77
 AmMultiPartyMixer::~AmMultiPartyMixer()
48 78
 {
79
+  for (std::deque<MixerBufferState>::iterator it = buffer_state.begin();
80
+       it != buffer_state.end(); it++) {
81
+    it->free_channels();
82
+  }
49 83