/* ******************************************************************************* * INCLUDE ******************************************************************************* */ #include "AbstractAudioInput.h" #include "System.h" #include "Logger.h" #include "util/Math.h" #include #include #include #include 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& isCancelled) -> void { Util::Task probeTask; std::atomic 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& 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() { } } }