Line data Source code
1 : /* 2 : * Copyright (C) 2004-2026 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 "localrecorder.h" 19 : #include "audio/ringbufferpool.h" 20 : #include "client/videomanager.h" 21 : #include "media_stream.h" 22 : #include "manager.h" 23 : #include "logger.h" 24 : #include "client/videomanager.h" 25 : 26 : namespace jami { 27 : 28 0 : LocalRecorder::LocalRecorder(const std::string& inputUri) 29 : { 30 0 : inputUri_ = inputUri; 31 0 : isAudioOnly_ = inputUri_.empty(); 32 0 : recorder_->audioOnly(isAudioOnly_); 33 0 : } 34 : 35 0 : LocalRecorder::~LocalRecorder() 36 : { 37 0 : if (isRecording()) 38 0 : stopRecording(); 39 0 : } 40 : 41 : void 42 0 : LocalRecorder::setPath(const std::string& path) 43 : { 44 0 : if (isRecording()) { 45 0 : JAMI_ERR("Unable to set path while recording"); 46 0 : return; 47 : } 48 : 49 0 : recorder_->setPath(path); 50 0 : path_ = path; 51 : } 52 : 53 : bool 54 0 : LocalRecorder::start() 55 : { 56 0 : if (isRecording()) { 57 0 : JAMI_ERR("Recording already started!"); 58 0 : return false; 59 : } 60 : 61 0 : if (path_.empty()) { 62 0 : JAMI_ERR("Unable to start recording (path not set)"); 63 0 : return false; 64 : } 65 : 66 0 : if (!recorder_) { 67 0 : JAMI_ERR("Unable to start recording (no recorder)"); 68 0 : return false; 69 : } 70 : 71 : // audio recording 72 : // create read offset in RingBuffer 73 0 : Manager::instance().getRingBufferPool().bindHalfDuplexOut(path_, RingBufferPool::DEFAULT_ID); 74 : 75 0 : audioInput_ = getAudioInput(path_); 76 0 : audioInput_->setFormat(AudioFormat::STEREO()); 77 0 : audioInput_->attach(recorder_->addStream(audioInput_->getInfo())); 78 0 : audioInput_->switchInput(""); 79 : 80 : #ifdef ENABLE_VIDEO 81 : // video recording 82 0 : if (!isAudioOnly_) { 83 0 : videoInput_ = std::static_pointer_cast<video::VideoInput>(getVideoInput(inputUri_)); 84 0 : if (videoInput_) { 85 0 : videoInput_->attach(recorder_->addStream(videoInput_->getInfo())); 86 : } else { 87 0 : JAMI_ERR() << "Unable to record video (no video input)"; 88 0 : return false; 89 : } 90 : } 91 : #endif 92 : 93 0 : return Recordable::startRecording(path_); 94 : } 95 : 96 : void 97 0 : LocalRecorder::stopRecording() 98 : { 99 0 : if (auto* ob = recorder_->getStream(audioInput_->getInfo().name)) 100 0 : audioInput_->detach(ob); 101 : #ifdef ENABLE_VIDEO 102 0 : if (videoInput_) 103 0 : if (auto* ob = recorder_->getStream(videoInput_->getInfo().name)) 104 0 : videoInput_->detach(ob); 105 : #endif 106 0 : Manager::instance().getRingBufferPool().unBindHalfDuplexOut(path_, RingBufferPool::DEFAULT_ID); 107 : // NOTE stopRecording should be last call to avoid data races 108 0 : Recordable::stopRecording(); 109 0 : } 110 : 111 : } // namespace jami