audio_rtp_record_handler.cpp 10.9 KB
Newer Older
1
/*
2
 *  Copyright (C) 2004-2012 Savoir-Faire Linux Inc.
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
 *  Author: Alexandre Savard <alexandre.savard@savoirfairelinux.com>
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 3 of the License, or
 *  (at your option) any later version.
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 *  Additional permission under GNU GPL version 3 section 7:
 *
 *  If you modify this program, or any covered work, by linking or
 *  combining it with the OpenSSL project's OpenSSL library (or a
 *  modified version of that library), containing parts covered by the
 *  terms of the OpenSSL or SSLeay licenses, Savoir-Faire Linux Inc.
 *  grants you additional permission to convey the resulting work.
 *  Corresponding Source for a non-source form of such a combination
 *  shall include the source code for the parts of OpenSSL used as well
 *  as that of the covered work.
 */

30 31 32 33
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

34
#include "audio_rtp_record_handler.h"
35
#include <fstream>
36
#include <algorithm>
37

38
#include "logger.h"
Rafaël Carré's avatar
Rafaël Carré committed
39
#include "sip/sipcall.h"
40 41 42
#include "audio/audiolayer.h"
#include "manager.h"

43 44
#include <fstream>

45
namespace sfl {
46

47 48 49 50 51
#ifdef RECTODISK
std::ofstream rtpResampled ("testRtpOutputResampled.raw", std::ifstream::binary);
std::ofstream rtpNotResampled("testRtpOutput.raw", std::ifstream::binary);
#endif

52
DTMFEvent::DTMFEvent(char digit) : payload(), newevent(true), length(1000)
53
{
54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82
/*
   From RFC2833:

   Event  encoding (decimal)
   _________________________
   0--9                0--9
   *                     10
   #                     11
   A--D              12--15
   Flash                 16
*/

    switch (digit) {
        case '*':
            digit = 10;
            break;
        case '#':
            digit = 11;
            break;
        case 'A' ... 'D':
            digit = digit - 'A' + 12;
            break;
        case '0' ... '9':
            digit = digit - '0';
            break;
        default:
            ERROR("Unexpected DTMF %c", digit);
    }

83 84 85 86 87 88
    payload.event = digit;
    payload.ebit = false; // end of event bit
    payload.rbit = false; // reserved bit
    payload.duration = 1; // duration for this event
}

89
AudioRtpRecord::AudioRtpRecord() :
90 91 92 93
      callId_("")
    , codecSampleRate_(0)
    , dtmfQueue_()
    , audioCodec_(0)
94 95
    , audioCodecMutex_()
    , codecPayloadType_(0)
96
    , hasDynamicPayloadType_(false)
97 98 99
    , decData_()     // std::tr1::arrays will be 0-initialized
    , resampledData_()
    , encodedData_()
100 101
    , converterEncode_(0)
    , converterDecode_(0)
102
    , codecFrameSize_(0)
103
    , converterSamplingRate_(0)
104
    , fadeFactor_(1.0 / 32000.0)
105
#if HAVE_SPEEXDSP
106
    , noiseSuppressEncode_(0)
107
    , noiseSuppressDecode_(0)
108
    , audioProcessMutex_()
109
#endif
110
    , dtmfPayloadType_(101) // same as Asterisk
111
    , dead_(false)
112
{}
113

114 115 116 117 118 119 120 121 122 123
// Call from processData*
bool AudioRtpRecord::isDead()
{
#ifdef CCPP_PREFIX
    return (int) dead_;
#else
    return *dead_;
#endif
}

124 125
AudioRtpRecord::~AudioRtpRecord()
{
126
    dead_ = true;
127 128 129 130 131 132
#ifdef RECTODISK
    rtpResampled.close();
    rtpNotResampled.close();
#endif

    delete converterEncode_;
133
    converterEncode_ = 0;
134
    delete converterDecode_;
135
    converterDecode_ = 0;
136 137 138
    {
        ost::MutexLock lock(audioCodecMutex_);
        delete audioCodec_;
139
        audioCodec_ = 0;
140
    }
141
#if HAVE_SPEEXDSP
142 143 144
    {
        ost::MutexLock lock(audioProcessMutex_);
        delete noiseSuppressDecode_;
145
        noiseSuppressDecode_ = 0;
146
        delete noiseSuppressEncode_;
147
        noiseSuppressEncode_ = 0;
148
    }
149
#endif
150 151 152
}


153 154 155 156
AudioRtpRecordHandler::AudioRtpRecordHandler(SIPCall &call) :
    audioRtpRecord_(),
    id_(call.getCallId()),
    gainController(8000, -10.0)
157
{}
158 159


160
AudioRtpRecordHandler::~AudioRtpRecordHandler() {}
161

162
void AudioRtpRecordHandler::setRtpMedia(AudioCodec *audioCodec)
Alexandre Savard's avatar
Alexandre Savard committed
163
{
164
    ost::MutexLock lock(audioRtpRecord_.audioCodecMutex_);
165

166
    delete audioRtpRecord_.audioCodec_;
Alexandre Savard's avatar
Alexandre Savard committed
167
    // Set varios codec info to reduce indirection
168 169 170 171 172
    audioRtpRecord_.audioCodec_ = audioCodec;
    audioRtpRecord_.codecPayloadType_ = audioCodec->getPayloadType();
    audioRtpRecord_.codecSampleRate_ = audioCodec->getClockRate();
    audioRtpRecord_.codecFrameSize_ = audioCodec->getFrameSize();
    audioRtpRecord_.hasDynamicPayloadType_ = audioCodec->hasDynamicPayload();
173 174
}

175
void AudioRtpRecordHandler::initBuffers()
176 177
{
    // Set sampling rate, main buffer choose the highest one
178
    Manager::instance().audioSamplingRateChanged(audioRtpRecord_.codecSampleRate_);
179 180 181

    // initialize SampleRate converter using AudioLayer's sampling rate
    // (internal buffers initialized with maximal sampling rate and frame size)
182 183 184 185
    delete audioRtpRecord_.converterEncode_;
    audioRtpRecord_.converterEncode_ = new SamplerateConverter(getCodecSampleRate());
    delete audioRtpRecord_.converterDecode_;
    audioRtpRecord_.converterDecode_ = new SamplerateConverter(getCodecSampleRate());
186 187
}

188
#if HAVE_SPEEXDSP
189 190
void AudioRtpRecordHandler::initNoiseSuppress()
{
191
    ost::MutexLock lock(audioRtpRecord_.audioProcessMutex_);
192 193
    delete audioRtpRecord_.noiseSuppressEncode_;
    audioRtpRecord_.noiseSuppressEncode_ = new NoiseSuppress(getCodecFrameSize(), getCodecSampleRate());
194 195
    delete audioRtpRecord_.noiseSuppressDecode_;
    audioRtpRecord_.noiseSuppressDecode_ = new NoiseSuppress(getCodecFrameSize(), getCodecSampleRate());
196
}
197
#endif
198

199
void AudioRtpRecordHandler::putDtmfEvent(char digit)
200
{
201 202
    DTMFEvent dtmf(digit);
    audioRtpRecord_.dtmfQueue_.push_back(dtmf);
203 204
}

205 206
#define RETURN_IF_NULL(A, VAL, M, ...) if (!(A)) { ERROR(M, ##__VA_ARGS__); return VAL; }

207
int AudioRtpRecordHandler::processDataEncode()
208
{
209 210 211
    if (audioRtpRecord_.isDead())
        return 0;

212
    int codecSampleRate = getCodecSampleRate();
213
    int mainBufferSampleRate = Manager::instance().getMainBuffer().getInternalSamplingRate();
asavard's avatar
asavard committed
214

215
    double resampleFactor = (double) mainBufferSampleRate / codecSampleRate;
asavard's avatar
asavard committed
216

217 218
    // compute nb of byte to get coresponding to 1 audio frame
    int samplesToGet = resampleFactor * getCodecFrameSize();
219
    const size_t bytesToGet = samplesToGet * sizeof(SFLDataFormat);
220

221
    if (Manager::instance().getMainBuffer().availableForGet(id_) < bytesToGet)
Alexandre Savard's avatar
Alexandre Savard committed
222
        return 0;
asavard's avatar
asavard committed
223

224
    SFLDataFormat *micData = audioRtpRecord_.decData_.data();
225
    const size_t bytes = Manager::instance().getMainBuffer().getData(micData, bytesToGet, id_);
226

227 228 229 230
#ifdef RECTODISK
    rtpNotResampled.write((const char *)micData, bytes);
#endif

231
    if (bytes != bytesToGet) {
232
        ERROR("Asked for %d bytes from mainbuffer, got %d", bytesToGet, bytes);
Rafaël Carré's avatar
Rafaël Carré committed
233
        return 0;
234
    }
asavard's avatar
asavard committed
235

236 237
    int samples = bytesToGet / sizeof(SFLDataFormat);

238
    audioRtpRecord_.fadeInDecodedData(samples);
239

240 241
    SFLDataFormat *out = micData;

242
    if (codecSampleRate != mainBufferSampleRate) {
243
        RETURN_IF_NULL(audioRtpRecord_.converterEncode_, 0, "Converter already destroyed");
244 245

        audioRtpRecord_.converterEncode_->resample(micData,
246
                audioRtpRecord_.resampledData_.data(),
247 248
                audioRtpRecord_.resampledData_.size(),
                mainBufferSampleRate, codecSampleRate,
249
                samplesToGet);
250 251 252 253 254

#ifdef RECTODISK
        rtpResampled.write((const char *)audioRtpRecord_.resampledData_.data(), samplesToGet*sizeof(SFLDataFormat)/2 );
#endif

255
        out = audioRtpRecord_.resampledData_.data();
256
    }
257

258
#if HAVE_SPEEXDSP
259
    if (Manager::instance().audioPreference.getNoiseReduce()) {
260
        ost::MutexLock lock(audioRtpRecord_.audioProcessMutex_);
261
        RETURN_IF_NULL(audioRtpRecord_.noiseSuppressEncode_, 0, "Noise suppressor already destroyed");
262
        audioRtpRecord_.noiseSuppressEncode_->process(micData, getCodecFrameSize());
263
    }
264
#endif
265

266 267
    {
        ost::MutexLock lock(audioRtpRecord_.audioCodecMutex_);
268
        RETURN_IF_NULL(audioRtpRecord_.audioCodec_, 0, "Audio codec already destroyed");
269
        unsigned char *micDataEncoded = audioRtpRecord_.encodedData_.data();
Tristan Matthews's avatar
Tristan Matthews committed
270
        return audioRtpRecord_.audioCodec_->encode(micDataEncoded, out, getCodecFrameSize());
271
    }
272
}
273 274 275
#undef RETURN_IF_NULL

#define RETURN_IF_NULL(A, M, ...) if (!(A)) { ERROR(M, ##__VA_ARGS__); return; }
276

Tristan Matthews's avatar
Tristan Matthews committed
277
void AudioRtpRecordHandler::processDataDecode(unsigned char *spkrData, size_t size, int payloadType)
278
{
279
    if (audioRtpRecord_.isDead() or getCodecPayloadType() != payloadType)
280
        return;
281

282
    int inSamples = 0;
283
    size = std::min(size, audioRtpRecord_.decData_.size());
284
    SFLDataFormat *spkrDataDecoded = audioRtpRecord_.decData_.data();
285 286
    {
        ost::MutexLock lock(audioRtpRecord_.audioCodecMutex_);
287
        RETURN_IF_NULL(audioRtpRecord_.audioCodec_, "Audio codec already destroyed");
288
        // Return the size of data in samples
289
        inSamples = audioRtpRecord_.audioCodec_->decode(spkrDataDecoded, spkrData, size);
290
    }
291

292
#if HAVE_SPEEXDSP
293 294
    if (Manager::instance().audioPreference.getNoiseReduce()) {
        ost::MutexLock lock(audioRtpRecord_.audioProcessMutex_);
295
        RETURN_IF_NULL(audioRtpRecord_.noiseSuppressDecode_, "Noise suppressor already destroyed");
296 297
        audioRtpRecord_.noiseSuppressDecode_->process(spkrDataDecoded, getCodecFrameSize());
    }
298
#endif
299

300
    audioRtpRecord_.fadeInDecodedData(inSamples);
301

302
    // Normalize incomming signal
303
    gainController.process(spkrDataDecoded, inSamples);
304

305 306
    SFLDataFormat *out = spkrDataDecoded;
    int outSamples = inSamples;
307

308
    int codecSampleRate = getCodecSampleRate();
309
    int mainBufferSampleRate = Manager::instance().getMainBuffer().getInternalSamplingRate();
310

Alexandre Savard's avatar
Alexandre Savard committed
311
    // test if resampling is required
312
    if (codecSampleRate != mainBufferSampleRate) {
313
        RETURN_IF_NULL(audioRtpRecord_.converterDecode_, "Converter already destroyed");
314
        out = audioRtpRecord_.resampledData_.data();
Alexandre Savard's avatar
Alexandre Savard committed
315
        // Do sample rate conversion
316
        outSamples = ((float) inSamples * ((float) mainBufferSampleRate / (float) codecSampleRate));
317
        audioRtpRecord_.converterDecode_->resample(spkrDataDecoded, out,
318 319
                audioRtpRecord_.resampledData_.size(), codecSampleRate,
                mainBufferSampleRate, inSamples);
Alexandre Savard's avatar
Alexandre Savard committed
320
    }
321

322
    Manager::instance().getMainBuffer().putData(out, outSamples * sizeof(SFLDataFormat), id_);
323
}
324
#undef RETURN_IF_NULL
325

326
void AudioRtpRecord::fadeInDecodedData(size_t size)
327
{
328 329
    // if factor reaches 1, this function should have no effect
    if (fadeFactor_ >= 1.0 or size > decData_.size())
330
        return;
Alexandre Savard's avatar
Alexandre Savard committed
331

332
    std::transform(decData_.begin(), decData_.begin() + size, decData_.begin(),
333
            std::bind1st(std::multiplies<double>(), fadeFactor_));
334

335
    // Factor used to increase volume in fade in
336 337
    const double FADEIN_STEP_SIZE = 4.0;
    fadeFactor_ *= FADEIN_STEP_SIZE;
338
}
339
}