Commit a774e0f4 authored by Hugo Lefeuvre's avatar Hugo Lefeuvre Committed by Adrien Béraud

audio: implement audio_input class

The audioInput class allows easy retrieval of local audio stream
without being in a running call. For now it is only used to record
audio data but might be employed for other purposes with little design
changes.

Change-Id: Icdf6a9799f341367b0c50aaff76b8642f42d0d1c
parent 9050b05f
......@@ -39,6 +39,7 @@ endif
libaudio_la_SOURCES = \
audiobuffer.cpp \
audio_input.cpp \
audioloop.cpp \
ringbuffer.cpp \
ringbufferpool.cpp \
......@@ -59,13 +60,14 @@ endif
noinst_HEADERS = \
audiobuffer.h \
audio_input.h \
audioloop.h \
ringbuffer.h \
ringbufferpool.h \
audiolayer.h \
resampler.h \
$(RING_SPEEXDSP_HEAD) \
dcblocker.h \
resampler.h \
audio_rtp_session.h \
tonecontrol.h
......
/*
* Copyright (C) 2018 Savoir-faire Linux Inc.
*
* Author: Hugo Lefeuvre <hugo.lefeuvre@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "audio_input.h"
#include <future>
#include <chrono>
#include "socket_pair.h"
#include "audio/ringbufferpool.h"
#include "manager.h"
#include "smartools.h"
namespace ring { namespace audio {
AudioInput::AudioInput(const std::string& id) :
id_(id),
loop_([] {return true;}, // setup()
[this] {return process();},
[this] {return cleanup();})
{
loop_.start();
}
AudioInput::~AudioInput()
{
if (auto rec = recorder_.lock())
rec->stopRecording();
loop_.join();
}
// seq: frame number for video, sent samples audio
// sampleFreq: fps for video, sample rate for audio
// clock: stream time base (packetization interval times)
// FIXME duplicate code from media encoder
int64_t
getNextTimestamp(int64_t seq, rational<int64_t> sampleFreq, rational<int64_t> clock)
{
return (seq / (sampleFreq * clock)).real<int64_t>();
}
void
AudioInput::process()
{
auto& mainBuffer = Manager::instance().getRingBufferPool();
auto ringBuffer = mainBuffer.getRingBuffer(id_);
auto bufferFormat = ringBuffer->getFormat();
// compute number of bytes contained in a frame with duration msPerPacket_
auto bytesPerPacket = msPerPacket_ * bufferFormat.sample_rate;
const std::size_t bytesToGet = std::chrono::duration_cast<std::chrono::seconds>(bytesPerPacket).count();
if (ringBuffer->availableForGet(id_) < bytesToGet
&& not ringBuffer->waitForDataAvailable(id_, bytesToGet)) {
return;
}
// get data
micData_.setFormat(bufferFormat);
micData_.resize(bytesToGet);
const auto samples = ringBuffer->get(micData_, id_);
if (samples != bytesToGet)
return;
if (muteState_) // audio is muted, set samples to 0
micData_.reset();
// record frame
AVFrame* frame = micData_.toAVFrame();
auto ms = MediaStream("a:local", micData_.getFormat());
frame->pts = getNextTimestamp(sent_samples, ms.sampleRate, static_cast<rational<int64_t>>(ms.timeBase));
sent_samples += frame->nb_samples;
{
auto rec = recorder_.lock();
if (rec && rec->isRecording()) {
rec->recordData(frame, ms);
}
}
}
void
AudioInput::cleanup()
{
micData_.clear();
}
void
AudioInput::setMuted(bool isMuted)
{
muteState_ = isMuted;
}
std::shared_future<DeviceParams>
AudioInput::switchInput(const std::string& resource)
{
// TODO not implemented yet
return {};
}
void
AudioInput::initRecorder(const std::shared_ptr<MediaRecorder>& rec)
{
rec->incrementExpectedStreams(1);
recorder_ = rec;
}
}} // namespace ring::audio
/*
* Copyright (C) 2018 Savoir-faire Linux Inc.
*
* Author: Hugo Lefeuvre <hugo.lefeuvre@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#pragma once
#include <future>
#include "audio/audiobuffer.h"
#include "media/media_recorder.h"
#include "audio/resampler.h"
namespace ring {
class MediaRecorder;
}
namespace ring { namespace audio {
class AudioInput
{
public:
AudioInput(const std::string& id);
~AudioInput();
std::shared_future<DeviceParams> switchInput(const std::string& resource);
void setMuted(bool isMuted);
void initRecorder(const std::shared_ptr<MediaRecorder>& rec);
private:
std::weak_ptr<MediaRecorder> recorder_;
uint64_t sent_samples = 0;
std::string id_;
AudioBuffer micData_;
bool muteState_ = false;
const std::chrono::milliseconds msPerPacket_ {20};
ThreadLoop loop_;
void process();
void cleanup();
};
}} // namespace ring::audio
......@@ -222,6 +222,7 @@ AudioSender::process()
if (audioEncoder_->encodeAudio(frame) < 0)
RING_ERR("encoding failed");
}
void
AudioSender::setMuted(bool isMuted)
{
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment