144 lines
3.6 KiB
C++
144 lines
3.6 KiB
C++
/*
|
|
*******************************************************************************
|
|
* 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;
|
|
}
|
|
}
|
|
}
|