/* ******************************************************************************* * INCLUDE ******************************************************************************* */ #include "Input.h" #include "Util.h" #include "../core/System.h" #include "Logger.h" namespace Video { namespace ALSA { /* ******************************************************************************* * CLASS DEFINE ******************************************************************************* */ Input::Input(const std::string& name): Core::AbstractAudioInput(name) { setSoundCard(nullptr); } Input::~Input() { } void Input::start() { _established = tryEstablishSoundCard(); run(); } void Input::stop() { cancel(); if (_established) { _pcm.close(); _established = false; } } void Input::onConfigChanged(ParameterNames& names) { if (!started()) return; stop(); start(); AbstractAudioInput::onConfigChanged(names); } Core::Frame::Ptr Input::readFrame() { if (!_established) _established = tryEstablishSoundCard(); if (!_established) { _traffic = 0; return nullptr; } Core::Frame::Ptr pFrame = new Core::Frame; pFrame->length = _linesize; pFrame->timestamp = Core::System::timestamp(); int rc; if (SND_PCM_ACCESS_RW_NONINTERLEAVED == _access) { uint8_t* ptrs[_channels]; for (int i = 0; i < _channels; i++) { pFrame->data[i] = new uint8_t[_linesize]; ptrs[i] = pFrame->data[i].get(); } rc = _pcm.read(ptrs, _samples); } else { pFrame->data[0] = new uint8_t[_linesize]; uint8_t* ptr = pFrame->data[0].get(); rc = _pcm.read(ptr, _samples); } if (rc < 0) { _established = false; _pcm.close(); _traffic = 0; return nullptr; } _traffic++; return pFrame; } bool Input::tryEstablishSoundCard() { auto pCard = getSoundCard(); if (pCard) { int rc = _pcm.open(pCard, SND_PCM_STREAM_CAPTURE); if (rc >= 0) { const auto sampleRate = Util::getSuitableSampleRate(pCard, getSampleRate()); const auto access = Util::getSuitableAccess(pCard, sampleFormatIsPlanar(getSampleFormat())); const auto format = Util::getSuitableSampleFormat(pCard, getSampleFormat()); const auto sampleFormat = Util::convertSampleFormat(format, access == SND_PCM_ACCESS_RW_INTERLEAVED); logger().debug("%s: Suitable config found: %s %s %uHz", name(), std::string(snd_pcm_access_name(access)), std::string(snd_pcm_format_name(format)), sampleRate); rc = _pcm.config(access, format, pCard->info().channels, sampleRate, getFrameSize(), sampleFormatBytesPerSample(sampleFormat)); if (rc >= 0) { if (pCard->info().channels == 1 && getChannelLayout() != Core::ChannelLayout::MONO) setChannelLayout(Core::ChannelLayout::MONO); setSampleRate(sampleRate); setSampleFormat(sampleFormat); _linesize = sampleFormatCalcLineSize(sampleFormat, getChannelLayout(), getFrameSize()); _channels = channelLayoutChannels(getChannelLayout()); _samples = getFrameSize(); _access = access; serialCodeManager().increment(); return true; } _pcm.close(); } } return false; } } }