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-04-18 08:01:59 Functions: 7 11 63.6 %

          Line data    Source code
       1             : /*
       2             :  *  Copyright (C) 2004-2024 Savoir-faire Linux Inc.
       3             :  *
       4             :  *  Author: Philippe Gorley <philippe.gorley@savoirfairelinux.com>
       5             :  *
       6             :  *  This program is free software; you can redistribute it and/or modify
       7             :  *  it under the terms of the GNU General Public License as published by
       8             :  *  the Free Software Foundation; either version 3 of the License, or
       9             :  *  (at your option) any later version.
      10             :  *
      11             :  *  This program is distributed in the hope that it will be useful,
      12             :  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
      13             :  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      14             :  *  GNU General Public License for more details.
      15             :  *
      16             :  *  You should have received a copy of the GNU General Public License
      17             :  *  along with this program; if not, write to the Free Software
      18             :  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA.
      19             :  */
      20             : 
      21             : #include "audio_frame_resizer.h"
      22             : #include "libav_deps.h"
      23             : #include "logger.h"
      24             : 
      25             : extern "C" {
      26             : #include <libavutil/audio_fifo.h>
      27             : }
      28             : 
      29             : #include <stdexcept>
      30             : 
      31             : namespace jami {
      32             : 
      33         700 : AudioFrameResizer::AudioFrameResizer(const AudioFormat& format,
      34             :                                      int size,
      35         700 :                                      std::function<void(std::shared_ptr<AudioFrame>&&)> cb)
      36         700 :     : format_(format)
      37         700 :     , frameSize_(size)
      38         700 :     , cb_(cb)
      39         700 :     , queue_(av_audio_fifo_alloc(format.sampleFormat, format.nb_channels, frameSize_))
      40         700 : {}
      41             : 
      42         700 : AudioFrameResizer::~AudioFrameResizer()
      43             : {
      44         700 :     av_audio_fifo_free(queue_);
      45         700 : }
      46             : 
      47             : int
      48         388 : AudioFrameResizer::samples() const
      49             : {
      50         388 :     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         283 : AudioFrameResizer::setFormat(const AudioFormat& format, int size)
      67             : {
      68         283 :     if (size)
      69         283 :         setFrameSize(size);
      70         283 :     if (format != format_) {
      71         186 :         if (auto discarded = samples())
      72           1 :             JAMI_WARN("Discarding %d samples", discarded);
      73         186 :         av_audio_fifo_free(queue_);
      74         186 :         format_ = format;
      75         186 :         queue_ = av_audio_fifo_alloc(format.sampleFormat, format.nb_channels, frameSize_);
      76             :     }
      77         283 : }
      78             : 
      79             : void
      80         283 : AudioFrameResizer::setFrameSize(int frameSize)
      81             : {
      82         283 :     if (frameSize_ != frameSize) {
      83         185 :         frameSize_ = frameSize;
      84         185 :         if (cb_)
      85         185 :             while (auto frame = dequeue())
      86         185 :                 cb_(std::move(frame));
      87             :     }
      88         283 : }
      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         191 : AudioFrameResizer::dequeue()
     130             : {
     131         191 :     if (samples() < frameSize_)
     132         189 :         return {};
     133             : 
     134           2 :     auto frame = std::make_shared<AudioFrame>(format_, frameSize_);
     135             :     int ret;
     136           6 :     if ((ret = av_audio_fifo_read(queue_,
     137           2 :                                   reinterpret_cast<void**>(frame->pointer()->data),
     138             :                                   frameSize_))
     139           2 :         < 0) {
     140           0 :         JAMI_ERR() << "Could not read samples from queue: " << libav_utils::getError(ret);
     141           0 :         return {};
     142             :     }
     143           2 :     frame->pointer()->pts = nextOutputPts_;
     144           2 :     frame->has_voice = hasVoice_;
     145           2 :     nextOutputPts_ += frameSize_;
     146           2 :     return frame;
     147           2 : }
     148             : 
     149             : } // namespace jami

Generated by: LCOV version 1.14