LCOV - code coverage report
Current view: top level - src/media/audio - audio_frame_resizer.cpp (source / functions) Hit Total Coverage
Test: jami-coverage-filtered.info Lines: 60 70 85.7 %
Date: 2024-11-15 09:04:49 Functions: 7 11 63.6 %

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