108 lines
3.5 KiB
C++
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
|