audio_rtp_session.cpp 8.26 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
44
45
AudioRtpSession::AudioRtpSession(SIPCall &call, ost::RTPDataQueue &queue, ost::Thread &thread) :
    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
    , thread_(thread)
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
88
89
90
91
92
93
94
95
96
    const ost::PayloadType payloadType = getCodecPayloadType();
    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
138
    const ost::StaticPayloadFormat pf(static_cast<ost::StaticPayloadType>(getCodecPayloadType()));
    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_, remote_port_ + 1))
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
int AudioRtpSession::startRtpThread(const std::vector<AudioCodec*> &audioCodecs)
236
{
237
    if (isStarted_)
238
239
        return 0;

240
    DEBUG("Starting main thread");
241

242
    isStarted_ = true;
243
    setSessionTimeouts();
244
    setSessionMedia(audioCodecs);
245
    initBuffers();
246
#if HAVE_SPEEXDSP
247
    initNoiseSuppress();
248
#endif
249

250
    queue_.enableStack();
251
252
    thread_.start();
    return 0;
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
}