audio_rtp_session.cpp 9.53 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
 *  Author: Pierre-Luc Bacon <pierre-luc.bacon@savoirfairelinux.com>
 *  Author: Alexandre Bourget <alexandre.bourget@savoirfairelinux.com>
 *  Author: Laurielle Lea <laurielle.lea@savoirfairelinux.com>
 *  Author: Emmanuel Milou <emmanuel.milou@savoirfairelinux.com>
 *  Author: Yan Morin <yan.morin@savoirfairelinux.com>
 *  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
21
 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA.
22
23
24
25
26
27
28
29
30
31
32
33
34
 *
 *  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.
 */

35
#include "audio_rtp_session.h"
36
#include "logger.h"
37
#include "sip/sdp.h"
38
#include "sip/sipcall.h"
39
#include <ccrtp/oqueue.h>
40
#include "manager.h"
41

42
namespace sfl {
43
AudioRtpSession::AudioRtpSession(SIPCall &call, ost::RTPDataQueue &queue) :
44
    AudioRtpRecordHandler(call)
45
46
    , isStarted_(false)
    , queue_(queue)
47
    , call_(call)
48
49
    , timestamp_(0)
    , timestampIncrement_(0)
50
    , transportRate_(20)
51
52
53
    , remote_ip_()
    , remote_port_(0)
    , timestampCount_(0)
54
    , rtpSendThread_(*this)
55
{
56
    queue_.setTypeOfService(ost::RTPDataQueue::tosEnhanced);
57
58
59
60
}

AudioRtpSession::~AudioRtpSession()
{
61
    queue_.disableStack();
62
63
}

64
void AudioRtpSession::updateSessionMedia(const std::vector<AudioCodec*> &audioCodecs)
65
{
66
    int lastSamplingRate = audioRtpRecord_.codecSampleRate_;
67

68
69
    if (codecsDiffer(audioCodecs))
        setSessionMedia(audioCodecs);
70

71
    Manager::instance().audioSamplingRateChanged(audioRtpRecord_.codecSampleRate_);
72

73
#if HAVE_SPEEXDSP
74

75
    if (lastSamplingRate != audioRtpRecord_.codecSampleRate_) {
76
77
        DEBUG("Update noise suppressor with sampling rate %d and frame size %d",
              getCodecSampleRate(), getCodecFrameSize());
78
        initNoiseSuppress();
79
    }
80

81
#endif
82
83
}

84
void AudioRtpSession::setSessionMedia(const std::vector<AudioCodec*> &audioCodecs)
85
{
86
    setRtpMedia(audioCodecs);
87

88
    // G722 requires timestamp to be incremented at 8kHz
89
    const ost::PayloadType payloadType = getEncoderPayloadType();
90

91
92
93
94
95
96
97
98
    if (payloadType == ost::sptG722) {
        const int G722_RTP_TIME_INCREMENT = 160;
        timestampIncrement_ = G722_RTP_TIME_INCREMENT;
    } else
        timestampIncrement_ = getCodecFrameSize();

    if (payloadType == ost::sptG722) {
        const int G722_RTP_CLOCK_RATE = 8000;
99
        queue_.setPayloadFormat(ost::DynamicPayloadFormat(payloadType, G722_RTP_CLOCK_RATE));
100
    } else {
101
102
103
104
        if (getHasDynamicPayload())
            queue_.setPayloadFormat(ost::DynamicPayloadFormat(payloadType, getCodecSampleRate()));
        else
            queue_.setPayloadFormat(ost::StaticPayloadFormat(static_cast<ost::StaticPayloadType>(payloadType)));
105
    }
106
107
108
109
110
111

    call_.setRecordingSmplRate(getCodecSampleRate());

    int transportRate = getCodecFrameSize() / (getCodecSampleRate() / 1000);
    transportRate_ = (transportRate > 0)?transportRate:20;
    DEBUG("Switching to a transport rate of %d ms",transportRate_);
112
}
113

114
void AudioRtpSession::sendDtmfEvent()
115
{
116
117
    DTMFEvent &dtmf(audioRtpRecord_.dtmfQueue_.front());
    DEBUG("Send RTP Dtmf (%d)", dtmf.payload.event);
118

119
120
    const int increment = getIncrementForDTMF();
    timestamp_ += increment;
121
122
123
124
125

    // discard equivalent size of audio
    processDataEncode();

    // change Payload type for DTMF payload
126
    queue_.setPayloadFormat(ost::DynamicPayloadFormat((ost::PayloadType) getDtmfPayloadType(), 8000));
127

128
129
130
    // Set marker in case this is a new Event
    if (dtmf.newevent)
        queue_.setMark(true);
131
132

    queue_.sendImmediate(timestamp_, (const unsigned char *)(& (dtmf.payload)), sizeof(ost::RTPPacket::RFC2833Payload));
133

134
135
136
137
138
139
140
    // This is no longer a new event
    if (dtmf.newevent) {
        dtmf.newevent = false;
        queue_.setMark(false);
    }

    // restore the payload to audio
141
    const ost::StaticPayloadFormat pf(static_cast<ost::StaticPayloadType>(getEncoderPayloadType()));
142
    queue_.setPayloadFormat(pf);
143
144
145
146

    // decrease length remaining to process for this event
    dtmf.length -= increment;
    dtmf.payload.duration++;
147

148
149
150
    // next packet is going to be the last one
    if ((dtmf.length - increment) < increment)
        dtmf.payload.ebit = true;
151

152
153
    if (dtmf.length < increment)
        audioRtpRecord_.dtmfQueue_.pop_front();
154
155
156
}


157
void AudioRtpSession::receiveSpeakerData()
158
{
159
    const ost::AppDataUnit* adu = queue_.getData(queue_.getFirstTimestamp());
160

161
    if (!adu)
162
163
        return;

164
    unsigned char* spkrDataIn = (unsigned char*) adu->getData(); // data in char
165
    size_t size = adu->getSize(); // size in char
166
167

    // DTMF over RTP, size must be over 4 in order to process it as voice data
168
    if (size > 4)
169
        processDataDecode(spkrDataIn, size, adu->getType());
170
171
172
173
174
175
176
177
178
179

    delete adu;
}


void AudioRtpSession::sendMicData()
{
    int compSize = processDataEncode();

    // if no data return
180
    if (compSize == 0)
181
182
183
        return;

    // Increment timestamp for outgoing packet
184
    timestamp_ += timestampIncrement_;
185

186
    // putData puts the data on RTP queue, sendImmediate bypass this queue
187
    queue_.sendImmediate(timestamp_, getMicDataEncoded(), compSize);
188
189
190
}


191
void AudioRtpSession::setSessionTimeouts()
192
{
193
194
    const int schedulingTimeout = 4000;
    const int expireTimeout = 1000000;
195
    DEBUG("Set session scheduling timeout (%d) and expireTimeout (%d)",
196
          schedulingTimeout, expireTimeout);
197

198
199
    queue_.setSchedulingTimeout(schedulingTimeout);
    queue_.setExpireTimeout(expireTimeout);
200
201
}

202
void AudioRtpSession::setDestinationIpAddress()
203
204
{
    // Store remote ip in case we would need to forget current destination
205
    remote_ip_ = ost::InetHostAddress(call_.getLocalSDP()->getRemoteIP().c_str());
206

207
    if (!remote_ip_) {
208
        WARN("Target IP address (%s) is not correct!",
209
             call_.getLocalSDP()->getRemoteIP().data());
210
211
212
213
        return;
    }

    // Store remote port in case we would need to forget current destination
214
    remote_port_ = (unsigned short) call_.getLocalSDP()->getRemoteAudioPort();
215

216
    DEBUG("New remote address for session: %s:%d",
217
          call_.getLocalSDP()->getRemoteIP().data(), remote_port_);
218

219
    if (!queue_.addDestination(remote_ip_, remote_port_)) {
220
        WARN("Can't add new destination to session!");
221
222
223
224
        return;
    }
}

225
void AudioRtpSession::updateDestinationIpAddress()
226
{
227
    DEBUG("Update destination ip address");
228
229
230
231

    // Destination address are stored in a list in ccrtp
    // This method remove the current destination entry

232
    if (!queue_.forgetDestination(remote_ip_, remote_port_))
233
        DEBUG("Did not remove previous destination");
234
235
236
237
238
239
240

    // new destination is stored in call
    // we just need to recall this method
    setDestinationIpAddress();
}


241
void AudioRtpSession::prepareRtpReceiveThread(const std::vector<AudioCodec*> &audioCodecs)
242
{
243
    DEBUG("Preparing receiving thread");
244
    isStarted_ = true;
245
    setSessionTimeouts();
246
    setSessionMedia(audioCodecs);
247
    initBuffers();
248
#if HAVE_SPEEXDSP
249
    initNoiseSuppress();
250
#endif
251

252
    queue_.enableStack();
253
254
255
}


256
bool AudioRtpSession::onRTPPacketRecv(ost::IncomingRTPPkt&)
257
258
259
260
261
{
    receiveSpeakerData();
    return true;
}

262
263
264
265
266
int AudioRtpSession::getIncrementForDTMF() const
{
    return timestampIncrement_;
}

267
268
269
270
271
272
273
274
275
276
277
void AudioRtpSession::startRtpThreads(const std::vector<AudioCodec*> &audioCodecs)
{
    if (isStarted_)
        return;

    prepareRtpReceiveThread(audioCodecs);
    // implemented in subclasses
    startReceiveThread();
    startSendThread();
}

278
279
280
281
282
283
284
AudioRtpSession::AudioRtpSendThread::AudioRtpSendThread(AudioRtpSession &session) :
    running_(false), rtpSession_(session), thread_(0), timer_()
{}

AudioRtpSession::AudioRtpSendThread::~AudioRtpSendThread()
{
    running_ = false;
285

286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
    if (thread_)
        pthread_join(thread_, NULL);
}

void AudioRtpSession::AudioRtpSendThread::start()
{
    running_ = true;
    pthread_create(&thread_, NULL, &runCallback, this);
}

void *
AudioRtpSession::AudioRtpSendThread::runCallback(void *data)
{
    AudioRtpSession::AudioRtpSendThread *context = static_cast<AudioRtpSession::AudioRtpSendThread*>(data);
    context->run();
    return NULL;
}

void AudioRtpSession::AudioRtpSendThread::run()
{
    timer_.setTimer(rtpSession_.transportRate_);
    const int MS_TO_USEC = 1000;

    while (running_) {
        // Send session
        if (rtpSession_.hasDTMFPending())
            rtpSession_.sendDtmfEvent();
        else
            rtpSession_.sendMicData();

        usleep(timer_.getTimer() * MS_TO_USEC);

        timer_.incTimer(rtpSession_.transportRate_);
    }
}


void AudioRtpSession::startSendThread()
{
    rtpSendThread_.start();
}
327
}