cmvr-es/cmvr-es/devices/microphone/ffmpeg_microphone/include/ffmpeg_microphone.h

108 lines
3.5 KiB
C++

#pragma once
#ifndef CMVR_ES_FFMPEG_MICROPHONE_H
#define CMVR_ES_FFMPEG_MICROPHONE_H
#include <atomic>
#include <condition_variable>
#include <memory>
#include <mutex>
#include <queue>
#include <thread>
#include <boost/lockfree/spsc_queue.hpp>
#include "common/base/ring_buffer.h"
#include "microphone/abstract_microphone.h"
#include "speaker/ffmpeg_speaker/include/ffmpeg_ptr.h"
namespace cmvr::device {
class ffmpegMicroPhone final : public AbstractMicrophone {
public:
enum class RecordingState {
STOPPED,
RECORDING,
PAUSED
};
explicit ffmpegMicroPhone(const config::FFMpegMicroPhoneConfig& cfg);
~ffmpegMicroPhone() override;
std::string typeName() const override { return "FFMpegMicroPhone"; }
bool init() override;
bool start() override;
bool stop() override;
void getState(MicrophoneState &state) override;
void startRecording(const std::string& outputFilePath) override;
void stopRecording() override;
void pause() override;
void resume() override;
void setVolume(const int volume) override;
int getVolume() override;
bool startStreaming() override;
void stopStreaming() override;
void getEncodedFrame(AudioStreamFrameData& frame_data, size_t& index) override;
bool waitEncodedFrame(AudioStreamFrameData& frame_data, size_t& index, std::chrono::milliseconds timeout) override;
bool getLatestEncodedFrame(AudioStreamFrameData& frame_data, size_t& next_index) override;
private:
void audioThread();
bool initFFmpeg();
void closeFFmpeg();
bool startCapture_(bool write_file);
void stopCapture_();
bool recoverStreamingCapture_(int read_error);
static int interruptCallback_(void* opaque);
AudioStreamFormat currentStreamFormat_() const;
void pushEncodedPacket_(const AVPacket* packet);
private:
AVFormatContext* input_fmt_ctx;
AVCodecContext* input_codec_ctx;
AVFrame* input_frame;
AVFormatContext* output_fmt_ctx;
const AVOutputFormat* output_fmt;
AVStream* audio_st;
AVCodecContext* audio_codec_ctx;
const AVCodec* audio_codec;
SwrContext* swr_ctx;
AVFrame* audio_frame;
std::string output_file;
std::string format_name;
std::atomic<bool> is_capturing_{false};
std::atomic<bool> interrupt_requested_{false};
std::atomic<bool> write_output_file_{false};
std::atomic<bool> is_paused;
std::mutex pause_mutex;
std::condition_variable pause_cv;
int sample_rate_;
int channels_;
int64_t next_pts;
std::string input_device_;
std::shared_ptr<std::thread> audio_thread_;
// Serializes FFmpeg context start/stop and keeps a new shared lease from
// starting until the previous capture thread has exited and been joined.
std::mutex capture_mutex_;
std::mutex mtx_;
std::shared_ptr<SPMCRingBuffer<AudioStreamFrameData>> stream_frame_buffer_;
// Protected by mtx_. The audio thread snapshots these values while it
// assigns metadata to an encoded frame.
int stream_count_ = 0;
size_t buffer_size_ = 256;
uint64_t stream_epoch_ = 0;
uint64_t stream_sequence_ = 0;
uint32_t codec_config_generation_ = 0;
config::FFMpegMicroPhoneConfig config_;
};
}
#endif // CMVR_ES_FFMPEG_MICROPHONE_H