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
45
    AudioRtpRecordHandler(call)
    , call_(call)
46
47
    , timestamp_(0)
    , timestampIncrement_(0)
48
    , transportRate_(20)
49
    , queue_(queue)
50
51
52
53
    , isStarted_(false)
    , 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
    if (lastSamplingRate != audioRtpRecord_.codecSampleRate_) {
75
76
        DEBUG("Update noise suppressor with sampling rate %d and frame size %d",
              getCodecSampleRate(), getCodecFrameSize());
77
        initNoiseSuppress();
78
    }
79
#endif
80
81
}

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

86
    // G722 requires timestamp to be incremented at 8kHz
87
    const ost::PayloadType payloadType = getEncoderPayloadType();
88
89
90
91
92
93
94
95
96
    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;
        queue_.setPayloadFormat(ost::DynamicPayloadFormat( payloadType, G722_RTP_CLOCK_RATE));
97
    } else {
98
99
100
101
        if (getHasDynamicPayload())
            queue_.setPayloadFormat(ost::DynamicPayloadFormat(payloadType, getCodecSampleRate()));
        else
            queue_.setPayloadFormat(ost::StaticPayloadFormat(static_cast<ost::StaticPayloadType>(payloadType)));
102
    }
103
104
105
106
107
108

    call_.setRecordingSmplRate(getCodecSampleRate());

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

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

116
117
    const int increment = getIncrementForDTMF();
    timestamp_ += increment;
118
119
120
121
122

    // discard equivalent size of audio
    processDataEncode();

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

125
126
127
128
    // Set marker in case this is a new Event
    if (dtmf.newevent)
        queue_.setMark(true);
    queue_.sendImmediate(timestamp_, (const unsigned char *) (& (dtmf.payload)), sizeof (ost::RTPPacket::RFC2833Payload));
129

130
131
132
133
134
135
136
    // This is no longer a new event
    if (dtmf.newevent) {
        dtmf.newevent = false;
        queue_.setMark(false);
    }

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

    // decrease length remaining to process for this event
    dtmf.length -= increment;
    dtmf.payload.duration++;
    // next packet is going to be the last one
    if ((dtmf.length - increment) < increment)
        dtmf.payload.ebit = true;
    if (dtmf.length < increment)
        audioRtpRecord_.dtmfQueue_.pop_front();
148
149
150
}


151
void AudioRtpSession::receiveSpeakerData()
152
{
153
    const ost::AppDataUnit* adu = queue_.getData(queue_.getFirstTimestamp());
154

155
    if (!adu)
156
157
        return;

158
    unsigned char* spkrDataIn = (unsigned char*) adu->getData(); // data in char
159
    size_t size = adu->getSize(); // size in char
160
161

    // DTMF over RTP, size must be over 4 in order to process it as voice data
162
    if (size > 4)
163
        processDataDecode(spkrDataIn, size, adu->getType());
164
165
166
167
168
169
170
171
172
173

    delete adu;
}


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

    // if no data return
174
    if (compSize == 0)
175
176
177
        return;

    // Increment timestamp for outgoing packet
178
    timestamp_ += timestampIncrement_;
179

180
    // putData puts the data on RTP queue, sendImmediate bypass this queue
181
    queue_.sendImmediate(timestamp_, getMicDataEncoded(), compSize);
182
183
184
}


185
void AudioRtpSession::setSessionTimeouts()
186
{
187
188
    const int schedulingTimeout = 4000;
    const int expireTimeout = 1000000;
189
    DEBUG("Set session scheduling timeout (%d) and expireTimeout (%d)",
190
          schedulingTimeout, expireTimeout);
191

192
193
    queue_.setSchedulingTimeout(schedulingTimeout);
    queue_.setExpireTimeout(expireTimeout);
194
195
}

196
void AudioRtpSession::setDestinationIpAddress()
197
198
{
    // Store remote ip in case we would need to forget current destination
199
    remote_ip_ = ost::InetHostAddress(call_.getLocalSDP()->getRemoteIP().c_str());
200

201
    if (!remote_ip_) {
202
        WARN("Target IP address (%s) is not correct!",
203
              call_.getLocalSDP()->getRemoteIP().data());
204
205
206
207
        return;
    }

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

210
    DEBUG("New remote address for session: %s:%d",
211
          call_.getLocalSDP()->getRemoteIP().data(), remote_port_);
212

213
    if (!queue_.addDestination(remote_ip_, remote_port_)) {
214
        WARN("Can't add new destination to session!");
215
216
217
218
        return;
    }
}

219
void AudioRtpSession::updateDestinationIpAddress()
220
{
221
    DEBUG("Update destination ip address");
222
223
224
225

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

226
    if (!queue_.forgetDestination(remote_ip_, remote_port_))
227
        DEBUG("Did not remove previous destination");
228
229
230
231
232
233
234

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


235
void AudioRtpSession::prepareRtpReceiveThread(const std::vector<AudioCodec*> &audioCodecs)
236
{
237
    DEBUG("Preparing receiving thread");
238
    isStarted_ = true;
239
    setSessionTimeouts();
240
    setSessionMedia(audioCodecs);
241
    initBuffers();
242
#if HAVE_SPEEXDSP
243
    initNoiseSuppress();
244
#endif
245

246
    queue_.enableStack();
247
248
249
}


250
bool AudioRtpSession::onRTPPacketRecv(ost::IncomingRTPPkt&)
251
252
253
254
255
{
    receiveSpeakerData();
    return true;
}

256
257
258
259
260
int AudioRtpSession::getIncrementForDTMF() const
{
    return timestampIncrement_;
}

261
262
263
264
265
266
267
268
269
270
271
void AudioRtpSession::startRtpThreads(const std::vector<AudioCodec*> &audioCodecs)
{
    if (isStarted_)
        return;

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

272
273
274
275
276
277
278
279
280
281
282
283
284
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
AudioRtpSession::AudioRtpSendThread::AudioRtpSendThread(AudioRtpSession &session) :
    running_(false), rtpSession_(session), thread_(0), timer_()
{}

AudioRtpSession::AudioRtpSendThread::~AudioRtpSendThread()
{
    running_ = false;
    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();
}
320
}