p26001-store-acs-soc-fw-app/video/core/AbstractAudioInput.cpp
2026-09-28 21:33:04 +08:00

284 lines
7.9 KiB
C++

/*
*******************************************************************************
* INCLUDE
*******************************************************************************
*/
#include "AbstractAudioInput.h"
#include "System.h"
#include "Logger.h"
#include "util/Math.h"
#include <atomic>
#include <climits>
#include <cmath>
#include <unistd.h>
namespace Video
{
namespace Core
{
/*
*******************************************************************************
* CLASS DEFINE
*******************************************************************************
*/
AbstractAudioInput::AbstractAudioInput(const std::string& name)
: AudioComponent(name)
{
const auto len = 1024 * 32;
_pSilentData = new uint8_t[len];
memset(_pSilentData, 0x00, len);
_silentDataCode = serialCodeManager().code();
_pSilentFrame = new Frame;
for (int i = 0; i < Frame::DATA_LINES; i++)
_pSilentFrame->data[i] = _pSilentData;
}
AbstractAudioInput::~AbstractAudioInput()
{
}
void AbstractAudioInput::run()
{
updateSilentFrame();
_task.run(
[this](std::atomic<bool>& isCancelled) -> void
{
Util::Task probeTask;
std::atomic<bool> attached(true);
setSignalLost(false);
Frame::Ptr pFrame;
SerialCodeWatcher watcher;
uint64_t timeline = 0;
while (!isCancelled)
{
if (attached)
{
pFrame = tryReadFrame(true);
if (pFrame.isNull())
{
probeTask.run(
[&](std::atomic<bool>& isCancelled) -> void
{
while (!isCancelled)
{
if (!tryReadFrame(false).isNull())
{
attached = true;
setSignalLost(false);
break;
}
Poco::Thread::sleep(2000);
}
});
attached = false;
setSignalLost(true);
continue;
}
const int gain = _gain.load(std::memory_order_relaxed);
if (gain != 0)
applyGain(pFrame, gain);
const int64_t ptsOffset = _ptsOffsetUs.load(std::memory_order_relaxed);
if (ptsOffset != 0)
applyPTSOffset(pFrame, ptsOffset);
pFrame->code = serialCodeManager().code();
if (watcher.isChanged(pFrame->code, true))
{
updateSilentFrame();
}
}
else
{
pFrame = readSilent(false);
}
if (pFrame->timestamp < timeline)
pFrame->timestamp = timeline;
else
timeline = pFrame->timestamp;
if (_isMute)
pFrame = readSilent(true);
postToNextComponents(sharedFromThis(), pFrame, MediaType::AUDIO, isCancelled);
}
probeTask.cancel();
});
}
void AbstractAudioInput::cancel()
{
_task.cancel();
}
void AbstractAudioInput::onConfigChanged(ParameterNames& names)
{
updateSilentFrame();
if (names.exists(_Gain))
_gain.store(getGain(), std::memory_order_relaxed);
if (names.exists(_PTSOffset))
_ptsOffsetUs.store(getPTSOffset(), std::memory_order_relaxed);
}
Frame::Ptr AbstractAudioInput::tryReadFrame(bool shouldLog)
{
try
{
return readFrame();
}
catch (Poco::Exception& e)
{
if (shouldLog)
logger().error("%s: %s", name(), e.displayText());
}
catch (std::exception& e)
{
if (shouldLog)
logger().error("%s: %s", name(), std::string(e.what()));
}
return nullptr;
}
Frame::Ptr AbstractAudioInput::readSilent(bool freezeChannel)
{
uint64_t now = System::timestamp();
_pSilentFrame->timestamp = now;
_pSilentFrame->code = _silentDataCode;
if (!freezeChannel)
{
std::this_thread::sleep_for(std::chrono::microseconds(_duration));
}
return _pSilentFrame;
}
void AbstractAudioInput::updateSilentFrame()
{
_pSilentFrame->length = Core::sampleFormatCalcLineSize(getSampleFormat(), getChannelLayout(), getFrameSize());
_duration = (float)1000000 / getSampleRate() * getFrameSize() * 0.85;
_silentDataCode = serialCodeManager().code();
}
void AbstractAudioInput::applyGain(Frame::Ptr pFrame, int gain)
{
gain = ::Util::Math::clamp(gain, -50, 20);
if (gain == 0)
return;
const auto format = getSampleFormat();
if (format == SampleFormat::NONE)
return;
const uint32_t channels = (uint32_t)channelLayoutChannels(getChannelLayout());
const uint32_t samplesPerChannel = getFrameSize();
const double scale = std::pow(10.0, (double)gain / 20.0);
auto apply = [&](uint8_t* base, uint32_t n)
{
switch (format)
{
case SampleFormat::U8:
case SampleFormat::U8P:
{
auto p = (uint8_t*)base;
for (uint32_t i = 0; i < n; i++)
{
const int64_t v = (int64_t)(p[i] * scale + 0.5);
p[i] = (uint8_t)::Util::Math::clamp(v, (int64_t)0, (int64_t)255);
}
break;
}
case SampleFormat::S16:
case SampleFormat::S16P:
{
auto p = (int16_t*)base;
for (uint32_t i = 0; i < n; i++)
{
const int64_t v = (int64_t)(p[i] * scale + 0.5);
p[i] = (int16_t)::Util::Math::clamp(v, (int64_t)INT16_MIN, (int64_t)INT16_MAX);
}
break;
}
case SampleFormat::S32:
case SampleFormat::S32P:
{
auto p = (int32_t*)base;
for (uint32_t i = 0; i < n; i++)
{
const int64_t v = (int64_t)(p[i] * scale + 0.5);
p[i] = (int32_t)::Util::Math::clamp(v, (int64_t)INT32_MIN, (int64_t)INT32_MAX);
}
break;
}
case SampleFormat::S64:
case SampleFormat::S64P:
{
auto p = (int64_t*)base;
for (uint32_t i = 0; i < n; i++)
p[i] = (int64_t)(p[i] * scale);
break;
}
case SampleFormat::FLT:
case SampleFormat::FLTP:
{
auto p = (float*)base;
for (uint32_t i = 0; i < n; i++)
p[i] = (float)(p[i] * scale);
break;
}
case SampleFormat::DBL:
case SampleFormat::DBLP:
{
auto p = (double*)base;
for (uint32_t i = 0; i < n; i++)
p[i] *= scale;
break;
}
default:
break;
}
};
if (sampleFormatIsPlanar(format))
{
for (uint32_t ch = 0; ch < channels; ch++)
{
if (!pFrame->data[ch])
continue;
apply(pFrame->data[ch].get(), samplesPerChannel);
}
}
else
{
if (!pFrame->data[0])
return;
apply(pFrame->data[0].get(), samplesPerChannel * channels);
}
}
void AbstractAudioInput::applyPTSOffset(Frame::Ptr pFrame, int64_t ptsOffset)
{
if (ptsOffset != 0)
{
const int64_t ts = (int64_t)pFrame->timestamp + ptsOffset;
pFrame->timestamp = (ts > 0) ? (uint64_t)ts : 0ULL;
}
}
void AbstractAudioInput::reset()
{
}
}
}