Line data Source code
1 : /* 2 : * Copyright (C) 2004-2024 Savoir-faire Linux Inc. 3 : * 4 : * Author: Yan Morin <yan.morin@savoirfairelinux.com> 5 : * 6 : * Inspired by tonegenerator of 7 : * Laurielle Lea <laurielle.lea@savoirfairelinux.com> (2004) 8 : * Inspired by ringbuffer of Audacity Project 9 : * 10 : * This program is free software; you can redistribute it and/or modify 11 : * it under the terms of the GNU General Public License as published by 12 : * the Free Software Foundation; either version 3 of the License, or 13 : * (at your option) any later version. 14 : * 15 : * This program is distributed in the hope that it will be useful, 16 : * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 : * GNU General Public License for more details. 19 : * 20 : * You should have received a copy of the GNU General Public License 21 : * along with this program; if not, write to the Free Software 22 : * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 23 : */ 24 : 25 : #ifdef HAVE_CONFIG_H 26 : #include "config.h" 27 : #endif 28 : 29 : #include "audioloop.h" 30 : #include "logger.h" 31 : #include "libav_deps.h" 32 : 33 : #include <algorithm> // std::min 34 : 35 : namespace jami { 36 : 37 465 : AudioLoop::AudioLoop(AudioFormat format) 38 465 : : format_(format) 39 465 : , buffer_(av_frame_alloc()) 40 465 : , pos_(0) 41 : { 42 465 : } 43 : 44 465 : AudioLoop::~AudioLoop() 45 465 : {} 46 : 47 : void 48 0 : AudioLoop::seek(double relative_position) 49 : { 50 0 : pos_ = static_cast<double>(getSize() * relative_position * 0.01); 51 0 : } 52 : 53 : void 54 0 : AudioLoop::getNext(AVFrame* output, bool mute) 55 : { 56 0 : if (!buffer_) { 57 0 : JAMI_ERR("buffer is NULL"); 58 0 : return; 59 : } 60 : 61 0 : const size_t buf_samples = buffer_->nb_samples; 62 0 : size_t pos = pos_; 63 0 : size_t total_samples = output->nb_samples; 64 0 : size_t output_pos = 0; 65 : 66 0 : if (buf_samples == 0) { 67 0 : JAMI_ERR("Audio loop size is 0"); 68 0 : av_samples_set_silence(output->data, 0, output->nb_samples, format_.nb_channels, format_.sampleFormat); 69 0 : return; 70 0 : } else if (pos >= buf_samples) { 71 0 : JAMI_ERR("Invalid loop position %zu", pos); 72 0 : return; 73 : } 74 : 75 0 : while (total_samples != 0) { 76 0 : size_t samples = std::min(total_samples, buf_samples - pos); 77 0 : if (not mute) 78 0 : av_samples_copy(output->data, buffer_->data, output_pos, pos, samples, format_.nb_channels, format_.sampleFormat); 79 : else 80 0 : av_samples_set_silence(output->data, output_pos, samples, format_.nb_channels, format_.sampleFormat); 81 0 : output_pos += samples; 82 0 : pos = (pos + samples) % buf_samples; 83 0 : total_samples -= samples; 84 : } 85 : 86 0 : pos_ = pos; 87 0 : onBufferFinish(); 88 : } 89 : 90 : void 91 0 : AudioLoop::onBufferFinish() 92 0 : {} 93 : 94 : std::unique_ptr<AudioFrame> 95 0 : AudioLoop::getNext(size_t samples, bool mute) 96 : { 97 0 : if (samples == 0) { 98 0 : samples = buffer_->sample_rate / 50; 99 : } 100 0 : auto buffer = std::make_unique<AudioFrame>(format_, samples); 101 0 : getNext(buffer->pointer(), mute); 102 0 : return buffer; 103 0 : } 104 : 105 : } // namespace jami