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

244 lines
6.9 KiB
C++

/*
*******************************************************************************
* INCLUDE
*******************************************************************************
*/
#include "AudioMixer.h"
#include "System.h"
#include <cstdint>
namespace Video
{
namespace Core
{
/*
*******************************************************************************
* CLASS DEFINE
*******************************************************************************
*/
AudioMixer::Channel::Channel(AudioMixer::Ptr pMixer, uint32_t id)
: AudioAdaptablePipe(Poco::format(pMixer->name() + "/CH#%u", id)), _pMixer(pMixer), _id(id)
{
setAttach(false);
setInput(nullptr);
}
AudioMixer::Channel::~Channel()
{
}
void AudioMixer::Channel::start()
{
}
void AudioMixer::Channel::stop()
{
}
void AudioMixer::Channel::onConfigChanged(ParameterNames& names)
{
if (names.exists(_Input))
unlink(true, false);
if (names.exists(_Attach))
{
auto pInput = getInput();
if (pInput)
{
if (getAttach())
{
getInput()->link(sharedFromThis());
link(mixer());
}
else
getInput()->unlink(sharedFromThis());
}
}
serialCodeWatcher().reset();
}
/*
*******************************************************************************
* CLASS DEFINE
*******************************************************************************
*/
AudioMixer::AudioMixer(const std::string& name): AbstractAudioInput(name)
{
_mixFrame = new Frame();
for (int i = 0; i < Frame::DATA_LINES; i++)
_mixFrame->data[i] = new uint8_t[1024 * 32];
}
AudioMixer::~AudioMixer()
{
}
AudioMixer::Channel::Ptr AudioMixer::getChannel(uint32_t id)
{
if (_channels.find(id) == _channels.end())
{
Channel::Ptr pChannel = new Channel(Ptr(this, true), id);
syncConfigToChannel(pChannel);
_channels[id] = pChannel;
}
return _channels[id];
}
void AudioMixer::syncConfigToChannel(AudioMixer::Channel::Ptr pChannel)
{
pChannel->setSampleRate(getSampleRate());
pChannel->setChannelLayout(getChannelLayout());
pChannel->setSampleFormat(getSampleFormat());
pChannel->setFrameSize(getFrameSize());
}
template <typename T, typename S>
static inline void mix(const S MIN, const S MAX, uint8_t* i0, uint8_t* i1, uint8_t* o, uint32_t bytes)
{
T* p0 = reinterpret_cast<T*>(i0);
T* p1 = reinterpret_cast<T*>(i1);
T* output = reinterpret_cast<T*>(o);
const size_t count = static_cast<size_t>(bytes / sizeof(T));
for (size_t i = 0; i < count; ++i)
{
S a = static_cast<S>(p0[i]);
S b = static_cast<S>(p1[i]);
const int64_t product = static_cast<int64_t>(a) * b;
S c = a + b - static_cast<S>(product >> 0x10);
c = (c > MAX) ? MAX : ((c < MIN) ? MIN : c);
output[i] = static_cast<T>(c);
}
}
void AudioMixer::start()
{
refreshOutputParams();
run();
}
void AudioMixer::stop()
{
cancel();
}
void AudioMixer::onConfigChanged(ParameterNames& names)
{
for (auto& m : _channels)
{
auto pChannel = m.second;
syncConfigToChannel(pChannel);
pChannel->commit();
}
AbstractAudioInput::onConfigChanged(names);
}
Frame::Ptr AudioMixer::readFrame()
{
Frame::Ptr pFrame = nullptr;
uint64_t pts = 0;
uint32_t index = 0;
for (auto& m : _channels)
{
auto pChannel = m.second;
Frame::Ptr pReadFrame;
try
{
pReadFrame = pChannel->readFrame(32);
}
catch (...)
{
pReadFrame = nullptr;
}
if (!pReadFrame.isNull())
{
if (pts == 0 || pts > pReadFrame->timestamp)
pts = pReadFrame->timestamp;
if (pFrame == nullptr)
pFrame = pReadFrame;
else
{
#define AUDIO_DATA(i) index > 0 ? _mixFrame->data[i].get() : pFrame->data[i].get()
switch (getSampleFormat())
{
case SampleFormat::U8:
case SampleFormat::U8P:
for (uint32_t i = 0; i < getChannels(); i++)
mix<uint8_t, uint16_t>(0, UINT8_MAX, AUDIO_DATA(i), pReadFrame->data[i].get(),
_mixFrame->data[i].get(), pFrame->length);
break;
case SampleFormat::S16:
case SampleFormat::S16P:
for (uint32_t i = 0; i < getChannels(); i++)
mix<int16_t, int32_t>(INT16_MIN, INT16_MAX, AUDIO_DATA(i), pReadFrame->data[i].get(),
_mixFrame->data[i].get(), pFrame->length);
break;
case SampleFormat::S32:
case SampleFormat::S32P:
for (uint32_t i = 0; i < getChannels(); i++)
mix<int32_t, int64_t>(INT32_MIN, INT32_MAX, AUDIO_DATA(i), pReadFrame->data[i].get(),
_mixFrame->data[i].get(), pFrame->length);
break;
case SampleFormat::S64:
case SampleFormat::S64P:
for (uint32_t i = 0; i < getChannels(); i++)
mix<int64_t, int64_t>(INT64_MIN, INT64_MAX, AUDIO_DATA(i), pReadFrame->data[i].get(),
_mixFrame->data[i].get(), pFrame->length);
break;
case SampleFormat::FLT:
case SampleFormat::FLTP:
for (uint32_t i = 0; i < getChannels(); i++)
mix<float, float>(-1.0f, 1.0f, AUDIO_DATA(i), pReadFrame->data[i].get(),
_mixFrame->data[i].get(), pFrame->length);
break;
case SampleFormat::DBL:
case SampleFormat::DBLP:
for (uint32_t i = 0; i < getChannels(); i++)
mix<double, double>(-1.0, 1.0, AUDIO_DATA(i), pReadFrame->data[i].get(),
_mixFrame->data[i].get(), pFrame->length);
break;
default:
break;
}
index++;
}
}
}
if (pFrame.isNull())
return nullptr;
_traffic++;
if (index > 0)
{
_mixFrame->timestamp = pts;
_mixFrame->length = pFrame->length;
_mixFrame->code = pFrame->code;
return _mixFrame;
}
else
return pFrame;
}
void AudioMixer::refreshOutputParams()
{
setFrameDuration((float)1000000 / getSampleRate() * getFrameSize());
setChannels(channelLayoutChannels(getChannelLayout()));
setLineSize(sampleFormatCalcLineSize(getSampleFormat(), getChannelLayout(), getFrameSize()));
}
}
}