LCOV - code coverage report
Current view: top level - foo/src/media/audio - audio_frame_resizer.cpp (source / functions) Hit Total Coverage
Test: jami-coverage-filtered.info Lines: 58 68 85.3 %
Date: 2026-02-28 10:41:24 Functions: 7 11 63.6 %

          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 "audio_frame_resizer.h"
      19             : #include "libav_deps.h"
      20             : #include "libav_utils.h"
      21             : #include "logger.h"
      22             : #include <libavutil/frame.h>
      23             : 
      24             : extern "C" {
      25             : #include <libavutil/audio_fifo.h>
      26             : }
      27             : 
      28             : #include <stdexcept>
      29             : #include <utility>
      30             : 
      31             : namespace jami {
      32             : 
      33         745 : AudioFrameResizer::AudioFrameResizer(const AudioFormat& format,
      34             :                                      int size,
      35         745 :                                      std::function<void(std::shared_ptr<AudioFrame>&&)> cb)
      36         745 :     : format_(format)
      37         745 :     , frameSize_(size)
      38         745 :     , cb_(std::move(cb))
      39         745 :     , queue_(av_audio_fifo_alloc(format.sampleFormat, static_cast<int>(format.nb_channels), frameSize_))
      40         745 : {}
      41             : 
      42         745 : AudioFrameResizer::~AudioFrameResizer()
      43             : {
      44         745 :     av_audio_fifo_free(queue_);
      45         745 : }
      46             : 
      47             : int
      48         350 : AudioFrameResizer::samples() const
      49             : {
      50         350 :     return av_audio_fifo_size(queue_);
      51             : }
      52             : 
      53             : int
      54           0 : AudioFrameResizer::frameSize() const
      55             : {
      56           0 :     return frameSize_;
      57             : }
      58             : 
      59             : AudioFormat
      60           0 : AudioFrameResizer::format() const
      61             : {
      62           0 :     return format_;
      63             : }
      64             : 
      65             : void
      66         251 : AudioFrameResizer::setFormat(const AudioFormat& format, int size)
      67             : {
      68         251 :     if (size)
      69         251 :         setFrameSize(size);
      70         251 :     if (format != format_) {
      71         167 :         if (auto discarded = samples())
      72           1 :             JAMI_WARN("Discarding %d samples", discarded);
      73         167 :         av_audio_fifo_free(queue_);
      74         167 :         format_ = format;
      75         167 :         queue_ = av_audio_fifo_alloc(format.sampleFormat, static_cast<int>(format.nb_channels), frameSize_);
      76             :     }
      77         251 : }
      78             : 
      79             : void
      80         251 : AudioFrameResizer::setFrameSize(int frameSize)
      81             : {
      82         251 :     if (frameSize_ != frameSize) {
      83         166 :         frameSize_ = frameSize;
      84         166 :         if (cb_)
      85         166 :             while (auto frame = dequeue())
      86         166 :                 cb_(std::move(frame));
      87             :     }
      88         251 : }
      89             : 
      90             : void
      91           5 : AudioFrameResizer::enqueue(std::shared_ptr<AudioFrame>&& frame)
      92             : {
      93           5 :     if (not frame or frame->pointer() == nullptr)
      94           1 :         return;
      95             : 
      96           5 :     int ret = 0;
      97           5 :     auto* f = frame->pointer();
      98           5 :     AudioFormat format(f->sample_rate, f->ch_layout.nb_channels, (AVSampleFormat) f->format);
      99           5 :     if (format != format_) {
     100           0 :         JAMI_WARNING("Expected {} but got {}", format_.toString(), format.toString());
     101           0 :         setFormat(format, frameSize_);
     102             :     }
     103             : 
     104           5 :     auto nb_samples = samples();
     105           5 :     if (cb_ && nb_samples == 0 && f->nb_samples == frameSize_) {
     106           1 :         nextOutputPts_ = frame->pointer()->pts + frameSize_;
     107           1 :         cb_(std::move(frame));
     108           1 :         return; // return if frame was just passed through
     109             :     }
     110             : 
     111             :     // voice activity
     112           4 :     hasVoice_ = frame->has_voice;
     113             : 
     114             :     // queue reallocates itself if need be
     115           4 :     if ((ret = av_audio_fifo_write(queue_, reinterpret_cast<void**>(f->data), f->nb_samples)) < 0) {
     116           0 :         JAMI_ERR() << "Audio resizer error: " << libav_utils::getError(ret);
     117           0 :         throw std::runtime_error("Failed to add audio to frame resizer");
     118             :     }
     119             : 
     120           4 :     if (nextOutputPts_ == 0)
     121           3 :         nextOutputPts_ = frame->pointer()->pts - nb_samples;
     122             : 
     123           4 :     if (cb_)
     124           6 :         while (auto frame = dequeue())
     125           8 :             cb_(std::move(frame));
     126             : }
     127             : 
     128             : std::shared_ptr<AudioFrame>
     129         172 : AudioFrameResizer::dequeue()
     130             : {
     131         172 :     if (samples() < frameSize_)
     132         170 :         return {};
     133             : 
     134           2 :     auto frame = std::make_shared<AudioFrame>(format_, frameSize_);
     135             :     int ret;
     136           2 :     if ((ret = av_audio_fifo_read(queue_, reinterpret_cast<void**>(frame->pointer()->data), frameSize_)) < 0) {
     137           0 :         JAMI_ERR() << "Unable to read samples from queue: " << libav_utils::getError(ret);
     138           0 :         return {};
     139             :     }
     140           2 :     frame->pointer()->pts = nextOutputPts_;
     141           2 :     frame->has_voice = hasVoice_;
     142           2 :     nextOutputPts_ += frameSize_;
     143           2 :     return frame;
     144           2 : }
     145             : 
     146             : } // namespace jami

Generated by: LCOV version 1.14