audio_rtp_session.cpp 7.8 KB
Newer Older
1
/*
2
 *  Copyright (C) 2004, 2005, 2006, 2008, 2009, 2010, 2011 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
30
31
32
33
34
 *  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
 *   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.
 */

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
48
    , timestamp_(0)
    , timestampIncrement_(0)
    , queue_(queue)
49
50
51
52
    , isStarted_(false)
    , remote_ip_()
    , remote_port_(0)
    , timestampCount_(0)
53
    , thread_(thread)
54
{
55
    queue_.setTypeOfService(ost::RTPDataQueue::tosEnhanced);
56
57
58
59
}

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

63
void AudioRtpSession::updateSessionMedia(AudioCodec &audioCodec)
64
{
65
    int lastSamplingRate = audioRtpRecord_.codecSampleRate_;
66

67
    setSessionMedia(audioCodec);
68

69
    Manager::instance().audioSamplingRateChanged(audioRtpRecord_.codecSampleRate_);
70

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

78
void AudioRtpSession::setSessionMedia(AudioCodec &audioCodec)
79
{
80
    setRtpMedia(&audioCodec);
81
82
83
84
85
86
87

    // store codec info locally
    int payloadType = getCodecPayloadType();
    int frameSize = getCodecFrameSize();
    int smplRate = getCodecSampleRate();
    bool dynamic = getHasDynamicPayload();

88
    // G722 requires timestamp to be incremented at 8kHz
89
    if (payloadType == g722PayloadType)
90
        timestampIncrement_ = g722RtpTimeincrement;
91
    else
92
        timestampIncrement_ = frameSize;
93

94
95
96
97
    DEBUG("Codec payload: %d", payloadType);
    DEBUG("Codec sampling rate: %d", smplRate);
    DEBUG("Codec frame size: %d", frameSize);
    DEBUG("RTP timestamp increment: %d", timestampIncrement_);
98
99

    if (payloadType == g722PayloadType) {
100
        DEBUG("Setting G722 payload format");
101
        queue_.setPayloadFormat(ost::DynamicPayloadFormat((ost::PayloadType) payloadType, g722RtpClockRate));
102
103
    } else {
        if (dynamic) {
104
            DEBUG("Setting dynamic payload format");
105
            queue_.setPayloadFormat(ost::DynamicPayloadFormat((ost::PayloadType) payloadType, smplRate));
106
        } else {
107
            DEBUG("Setting static payload format");
108
            queue_.setPayloadFormat(ost::StaticPayloadFormat((ost::StaticPayloadType) payloadType));
109
110
        }
    }
111
}
112

113
114
115
void AudioRtpSession::incrementTimestampForDTMF()
{
    timestamp_ += timestampIncrement_;
116
117
}

118
void AudioRtpSession::sendDtmfEvent()
119
{
120
    ost::RTPPacket::RFC2833Payload payload;
121

122
    payload.event = audioRtpRecord_.dtmfQueue_.front();
123
124
125
126
    payload.ebit = false; // end of event bit
    payload.rbit = false; // reserved bit
    payload.duration = 1; // duration for this event

127
    audioRtpRecord_.dtmfQueue_.pop_front();
128

129
    DEBUG("Send RTP Dtmf (%d)", payload.event);
130

131
    incrementTimestampForDTMF();
132
133
134
135
136

    // discard equivalent size of audio
    processDataEncode();

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

139
140
141
    queue_.setMark(true);
    queue_.sendImmediate(timestamp_, (const unsigned char *)(&payload), sizeof(payload));
    queue_.setMark(false);
142
143

    // get back the payload to audio
144
    queue_.setPayloadFormat(ost::StaticPayloadFormat((ost::StaticPayloadType) getCodecPayloadType()));
145
146
147
}


148
void AudioRtpSession::receiveSpeakerData()
149
{
150
    const ost::AppDataUnit* adu = queue_.getData(queue_.getFirstTimestamp());
151

152
    if (!adu)
153
154
        return;

155
    unsigned char* spkrDataIn = (unsigned char*) adu->getData(); // data in char
156
    size_t size = adu->getSize(); // size in char
157
158

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

    delete adu;
}


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

    // if no data return
171
    if (compSize == 0)
172
173
174
        return;

    // Increment timestamp for outgoing packet
175
    timestamp_ += timestampIncrement_;
176

177
    // putData puts the data on RTP queue, sendImmediate bypass this queue
178
    queue_.sendImmediate(timestamp_, getMicDataEncoded(), compSize);
179
180
181
}


182
void AudioRtpSession::setSessionTimeouts()
183
{
184
185
    DEBUG("Set session scheduling timeout (%d) and expireTimeout (%d)",
            sfl::schedulingTimeout, sfl::expireTimeout);
186

187
188
    queue_.setSchedulingTimeout(sfl::schedulingTimeout);
    queue_.setExpireTimeout(sfl::expireTimeout);
189
190
}

191
void AudioRtpSession::setDestinationIpAddress()
192
193
{
    // Store remote ip in case we would need to forget current destination
194
    remote_ip_ = ost::InetHostAddress(call_.getLocalSDP()->getRemoteIP().c_str());
195

196
    if (!remote_ip_) {
197
        WARN("Target IP address (%s) is not correct!",
198
              call_.getLocalSDP()->getRemoteIP().data());
199
200
201
202
        return;
    }

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

205
    DEBUG("New remote address for session: %s:%d",
206
          call_.getLocalSDP()->getRemoteIP().data(), remote_port_);
207

208
    if (!queue_.addDestination(remote_ip_, remote_port_)) {
209
        WARN("Can't add new destination to session!");
210
211
212
213
        return;
    }
}

214
void AudioRtpSession::updateDestinationIpAddress()
215
{
216
    DEBUG("Update destination ip address");
217
218
219
220

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

221
    if (!queue_.forgetDestination(remote_ip_, remote_port_, remote_port_ + 1))
222
        DEBUG("Did not remove previous destination");
223
224
225
226
227
228
229

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


230
int AudioRtpSession::startRtpThread(AudioCodec &audiocodec)
231
{
232
    if (isStarted_)
233
234
        return 0;

235
    DEBUG("Starting main thread");
236

237
    isStarted_ = true;
238
    setSessionTimeouts();
239
    setSessionMedia(audiocodec);
240
241
242
    initBuffers();
    initNoiseSuppress();

243
    queue_.enableStack();
244
245
    thread_.start();
    return 0;
246
247
248
}


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

}