Line data Source code
1 : /* 2 : * Copyright (C) 2004-2024 Savoir-faire Linux Inc. 3 : * 4 : * This program is free software: you can redistribute it and/or modify 5 : * it under the terms of the GNU General Public License as published by 6 : * the Free Software Foundation, either version 3 of the License, or 7 : * (at your option) any later version. 8 : * 9 : * This program is distributed in the hope that it will be useful, 10 : * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 : * GNU General Public License for more details. 13 : * 14 : * You should have received a copy of the GNU General Public License 15 : * along with this program. If not, see <https://www.gnu.org/licenses/>. 16 : */ 17 : 18 : #include "audio_sender.h" 19 : #include "client/videomanager.h" 20 : #include "libav_deps.h" 21 : #include "logger.h" 22 : #include "media_encoder.h" 23 : #include "media_io_handle.h" 24 : #include "media_stream.h" 25 : #include "resampler.h" 26 : 27 : #include <memory> 28 : 29 : namespace jami { 30 : 31 190 : AudioSender::AudioSender(const std::string& dest, 32 : const MediaDescription& args, 33 : SocketPair& socketPair, 34 : const uint16_t seqVal, 35 190 : const uint16_t mtu) 36 190 : : dest_(dest) 37 190 : , args_(args) 38 190 : , seqVal_(seqVal) 39 380 : , mtu_(mtu) 40 : { 41 190 : setup(socketPair); 42 190 : } 43 : 44 380 : AudioSender::~AudioSender() 45 : { 46 190 : audioEncoder_.reset(); 47 190 : muxContext_.reset(); 48 380 : } 49 : 50 : bool 51 190 : AudioSender::setup(SocketPair& socketPair) 52 : { 53 190 : audioEncoder_.reset(new MediaEncoder); 54 190 : muxContext_.reset(socketPair.createIOContext(mtu_)); 55 : 56 : try { 57 : /* Encoder setup */ 58 190 : JAMI_DBG("audioEncoder_->openOutput %s", dest_.c_str()); 59 190 : audioEncoder_->openOutput(dest_, "rtp"); 60 190 : audioEncoder_->setOptions(args_); 61 190 : auto codec = std::static_pointer_cast<SystemAudioCodecInfo>(args_.codec); 62 380 : auto ms = MediaStream("audio sender", codec->audioformat); 63 190 : audioEncoder_->setOptions(ms); 64 190 : audioEncoder_->addStream(*args_.codec); 65 190 : audioEncoder_->setInitSeqVal(seqVal_); 66 190 : audioEncoder_->setIOContext(muxContext_->getContext()); 67 190 : } catch (const MediaEncoderException& e) { 68 0 : JAMI_ERR("%s", e.what()); 69 0 : return false; 70 0 : } 71 : #ifdef DEBUG_SDP 72 : audioEncoder_->print_sdp(); 73 : #endif 74 : 75 190 : return true; 76 : } 77 : 78 : void 79 0 : AudioSender::update(Observable<std::shared_ptr<jami::MediaFrame>>* /*obs*/, 80 : const std::shared_ptr<jami::MediaFrame>& framePtr) 81 : { 82 0 : auto frame = framePtr->pointer(); 83 0 : frame->pts = sent_samples; 84 0 : sent_samples += frame->nb_samples; 85 : 86 : // check for change in voice activity, if so, call callback 87 : // downcast MediaFrame to AudioFrame 88 0 : bool hasVoice = std::dynamic_pointer_cast<AudioFrame>(framePtr)->has_voice; 89 0 : if (hasVoice != voice_) { 90 0 : voice_ = hasVoice; 91 0 : if (voiceCallback_) { 92 0 : voiceCallback_(voice_); 93 : } else { 94 0 : JAMI_ERR("AudioSender no voice callback!"); 95 : } 96 : } 97 : 98 0 : if (audioEncoder_->encodeAudio(*std::static_pointer_cast<AudioFrame>(framePtr)) < 0) 99 0 : JAMI_ERR("encoding failed"); 100 0 : } 101 : 102 : void 103 209 : AudioSender::setVoiceCallback(std::function<void(bool)> cb) 104 : { 105 209 : if (cb) { 106 209 : voiceCallback_ = std::move(cb); 107 : } else { 108 0 : JAMI_ERR("AudioSender attempting to set invalid voice callback"); 109 : } 110 209 : } 111 : 112 : uint16_t 113 0 : AudioSender::getLastSeqValue() 114 : { 115 0 : return audioEncoder_->getLastSeqValue(); 116 : } 117 : 118 : int 119 0 : AudioSender::setPacketLoss(uint64_t pl) 120 : { 121 : // The encoder may be destroy during a bitrate change 122 : // when a codec parameter like auto quality change 123 0 : if (!audioEncoder_) 124 0 : return -1; // NOK 125 : 126 0 : return audioEncoder_->setPacketLoss(pl); 127 : } 128 : 129 : } // namespace jami