audio_rtp_session.cpp 6.31 KB
Newer Older
1
/*
Guillaume Roguez's avatar
Guillaume Roguez committed
2
 *  Copyright (C) 2014-2018 Savoir-faire Linux Inc.
Guillaume Roguez's avatar
Guillaume Roguez committed
3
 *
4
 *  Author: Tristan Matthews <tristan.matthews@savoirfairelinux.com>
5
 *  Author: Philippe Gorley <philippe.gorley@savoirfairelinux.com>
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
 *
 *  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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA.
 */
21 22 23

#include "libav_deps.h" // MUST BE INCLUDED FIRST

Guillaume Roguez's avatar
Guillaume Roguez committed
24
#include "audio_rtp_session.h"
25 26 27 28

#include "logger.h"
#include "noncopyable.h"
#include "sip/sdp.h"
29

30 31
#include "audio_receive_thread.h"
#include "audio_sender.h"
32
#include "socket_pair.h"
33
#include "media_recorder.h"
34 35 36
#include "media_encoder.h"
#include "media_decoder.h"
#include "media_io_handle.h"
37 38
#include "media_device.h"

39
#include "audio/audio_input.h"
40 41 42
#include "audio/audiobuffer.h"
#include "audio/ringbufferpool.h"
#include "audio/resampler.h"
43
#include "client/videomanager.h"
44
#include "manager.h"
45
#include "observer.h"
Gasuleg's avatar
Gasuleg committed
46
#include "smartools.h"
47 48
#include <sstream>

Adrien Béraud's avatar
Adrien Béraud committed
49
namespace ring {
50

51 52
constexpr static auto NEWPARAMS_TIMEOUT = std::chrono::milliseconds(1000);

Guillaume Roguez's avatar
Guillaume Roguez committed
53 54
AudioRtpSession::AudioRtpSession(const std::string& id)
    : RtpSession(id)
55 56
{
    // don't move this into the initializer list or Cthulus will emerge
Guillaume Roguez's avatar
Guillaume Roguez committed
57
    ringbuffer_ = Manager::instance().getRingBufferPool().createRingBuffer(callID_);
58 59
}

Guillaume Roguez's avatar
Guillaume Roguez committed
60
AudioRtpSession::~AudioRtpSession()
61 62 63 64 65
{
    stop();
}

void
Guillaume Roguez's avatar
Guillaume Roguez committed
66
AudioRtpSession::startSender()
67
{
68
    if (not send_.enabled or send_.holding) {
Guillaume Roguez's avatar
Guillaume Roguez committed
69
        RING_WARN("Audio sending disabled");
70
        if (sender_) {
Guillaume Roguez's avatar
Guillaume Roguez committed
71 72 73
            if (socketPair_)
                socketPair_->interrupt();
            sender_.reset();
74 75
        }
        return;
Guillaume Roguez's avatar
Guillaume Roguez committed
76
    }
77 78

    if (sender_)
Adrien Béraud's avatar
Adrien Béraud committed
79
        RING_WARN("Restarting audio sender");
80

81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96
    // sender sets up input correctly, we just keep a reference in case startSender is called
    audioInput_ = ring::getAudioInput(callID_);
    auto newParams = audioInput_->switchInput(input_);
    try {
        if (newParams.valid() &&
            newParams.wait_for(NEWPARAMS_TIMEOUT) == std::future_status::ready) {
            localAudioParams_ = newParams.get();
        } else {
            RING_ERR() << "No valid new audio parameters";
            return;
        }
    } catch (const std::exception& e) {
        RING_ERR() << "Exception while retrieving audio parameters: " << e.what();
        return;
    }

97 98 99 100
    // be sure to not send any packets before saving last RTP seq value
    socketPair_->stopSendOp();
    if (sender_)
        initSeqVal_ = sender_->getLastSeqValue() + 1;
101
    try {
102 103
        sender_.reset();
        socketPair_->stopSendOp(false);
104
        sender_.reset(new AudioSender(callID_, getRemoteRtpUri(), send_,
105
                                      *socketPair_, initSeqVal_, muteState_, mtu_));
106
    } catch (const MediaEncoderException &e) {
Adrien Béraud's avatar
Adrien Béraud committed
107
        RING_ERR("%s", e.what());
108
        send_.enabled = false;
109 110 111
    }
}

112 113 114 115
void
AudioRtpSession::restartSender()
{
    std::lock_guard<std::recursive_mutex> lock(mutex_);
116 117 118 119
    // ensure that start has been called before restart
    if (not socketPair_)
        return;

120 121 122
    startSender();
}

123
void
Guillaume Roguez's avatar
Guillaume Roguez committed
124
AudioRtpSession::startReceiver()
125
{
126
    if (not receive_.enabled or receive_.holding) {
Guillaume Roguez's avatar
Guillaume Roguez committed
127
        RING_WARN("Audio receiving disabled");
128
        receiveThread_.reset();
Guillaume Roguez's avatar
Guillaume Roguez committed
129
        return;
130
    }
Guillaume Roguez's avatar
Guillaume Roguez committed
131 132 133 134

    if (receiveThread_)
        RING_WARN("Restarting audio receiver");

135
    auto accountAudioCodec = std::static_pointer_cast<AccountAudioCodecInfo>(receive_.codec);
136
    receiveThread_.reset(new AudioReceiveThread(callID_, accountAudioCodec->audioformat,
137 138
                                                receive_.receiving_sdp,
                                                mtu_));
Guillaume Roguez's avatar
Guillaume Roguez committed
139 140
    receiveThread_->addIOContext(*socketPair_);
    receiveThread_->startLoop();
141 142 143
}

void
144
AudioRtpSession::start(std::unique_ptr<IceSocket> rtp_sock, std::unique_ptr<IceSocket> rtcp_sock)
145 146 147
{
    std::lock_guard<std::recursive_mutex> lock(mutex_);

148
    if (not send_.enabled and not receive_.enabled) {
149 150 151 152
        stop();
        return;
    }

Guillaume Roguez's avatar
Guillaume Roguez committed
153
    try {
154 155 156 157 158
        if (rtp_sock and rtcp_sock)
            socketPair_.reset(new SocketPair(std::move(rtp_sock), std::move(rtcp_sock)));
        else
            socketPair_.reset(new SocketPair(getRemoteRtpUri().c_str(), receive_.addr.getPort()));

159 160 161 162 163
        if (send_.crypto and receive_.crypto) {
            socketPair_->createSRTP(receive_.crypto.getCryptoSuite().c_str(),
                                    receive_.crypto.getSrtpKeyInfo().c_str(),
                                    send_.crypto.getCryptoSuite().c_str(),
                                    send_.crypto.getSrtpKeyInfo().c_str());
Adrien Béraud's avatar
Adrien Béraud committed
164
        }
165 166
    } catch (const std::runtime_error& e) {
        RING_ERR("Socket creation failed: %s", e.what());
Guillaume Roguez's avatar
Guillaume Roguez committed
167 168
        return;
    }
169 170 171 172 173

    startSender();
    startReceiver();
}

174
void
Guillaume Roguez's avatar
Guillaume Roguez committed
175
AudioRtpSession::stop()
176 177 178 179 180 181 182 183 184 185
{
    std::lock_guard<std::recursive_mutex> lock(mutex_);

    if (socketPair_)
        socketPair_->interrupt();

    receiveThread_.reset();
    sender_.reset();
    socketPair_.reset();
}
Éloi Bail's avatar
Éloi Bail committed
186 187 188 189
void
AudioRtpSession::setMuted(bool isMuted)
{
    std::lock_guard<std::recursive_mutex> lock(mutex_);
190 191
    if (sender_) {
        muteState_ = isMuted;
Éloi Bail's avatar
Éloi Bail committed
192
        sender_->setMuted(isMuted);
193
    }
Éloi Bail's avatar
Éloi Bail committed
194
}
195

196
void
197
AudioRtpSession::initRecorder(std::shared_ptr<MediaRecorder>& rec)
198
{
199 200 201 202
    if (receiveThread_)
        receiveThread_->attach(rec->addStream(receiveThread_->getInfo()));
    if (auto input = ring::getAudioInput(callID_))
        input->attach(rec->addStream(input->getInfo()));
203 204 205 206 207
}

void
AudioRtpSession::deinitRecorder(std::shared_ptr<MediaRecorder>& rec)
{
208 209 210 211 212 213 214 215 216 217
    if (receiveThread_) {
        if (auto ob = rec->getStream(receiveThread_->getInfo().name)) {
            receiveThread_->detach(ob);
        }
    }
    if (auto input = ring::getAudioInput(callID_)) {
        if (auto ob = rec->getStream(input->getInfo().name)) {
            input->detach(ob);
        }
    }
218 219
}

Guillaume Roguez's avatar
Guillaume Roguez committed
220
} // namespace ring