setup electron app with boilerplate

This commit is contained in:
talksik
2026-02-19 19:41:26 -08:00
parent fc6a5e43db
commit 1f249c47a6
5174 changed files with 8743 additions and 0 deletions
+339
View File
@@ -0,0 +1,339 @@
#include "mediahandler.h"
#include <QPermission>
#include <QMediaCaptureSession>
#include <QApplication>
#include <QCameraDevice>
#include <QCameraFormat>
#include <QMediaRecorder>
#include <QMediaFormat>
#include <QMimeType>
#include <QAudioInput>
#include <QCamera>
#include <QUrl>
MediaHandler::MediaHandler(QObject *parent) : QObject{parent},
m_captureSession{nullptr},
m_audioInput{nullptr},
m_camera{nullptr},
m_videoSink{nullptr},
m_recorder{nullptr}
{
}
MediaHandler::~MediaHandler()
{
}
MediaHandler::State MediaHandler::state() const
{
return m_state;
}
MediaHandler::CaptureMode MediaHandler::captureMode() const
{
return m_captureMode;
}
QVideoSink *MediaHandler::videoSink() const
{
return m_videoSink;
}
void MediaHandler::startPreview(QVideoSink *sink)
{
if (m_state != OFF)
{
return;
}
m_pendingRecord = false;
startCapture(sink);
}
void MediaHandler::startRecording(QVideoSink *sink)
{
if (m_state == RECORDING || m_state == PREPARING)
{
return;
}
if (m_state == ON)
{
m_cancelledRecording = false;
m_recorder->record();
return;
}
// OFF
m_pendingRecord = true;
startCapture(sink);
}
void MediaHandler::startCapture(QVideoSink *sink)
{
setState(PREPARING);
// microphone permission (always needed)
QMicrophonePermission microphonePermission;
switch (qApp->checkPermission(microphonePermission))
{
case Qt::PermissionStatus::Undetermined:
qApp->requestPermission(microphonePermission, this, [this, sink]() {
startCapture(sink);
});
return;
case Qt::PermissionStatus::Denied:
qDebug("Microphone permission is not granted!");
setState(OFF);
emit micPermissionDenied();
return;
case Qt::PermissionStatus::Granted:
qDebug("Mic permission granted.");
break;
}
// camera permission (skip for AUDIO_ONLY)
if (m_captureMode != AUDIO_ONLY)
{
QCameraPermission cameraPermission;
switch (qApp->checkPermission(cameraPermission))
{
case Qt::PermissionStatus::Undetermined:
qApp->requestPermission(cameraPermission, this, [this, sink]() {
startCapture(sink);
});
return;
case Qt::PermissionStatus::Denied:
qDebug("Camera permission is not granted!");
setState(OFF);
emit cameraPermissionDenied();
return;
case Qt::PermissionStatus::Granted:
qDebug("Camera permission granted.");
break;
}
}
// Create capture session and audio input
if (!m_captureSession)
{
m_captureSession = new QMediaCaptureSession{this};
}
// TODO: handle QMediaDevices:audioInputsChanged()
if (!m_audioInput)
{
m_audioInput = new QAudioInput{this};
m_captureSession->setAudioInput(m_audioInput);
}
// Camera setup (skip for AUDIO_ONLY)
// TODO: handle QMediaDevices:videoInputsChanged()
if (m_captureMode != AUDIO_ONLY)
{
if (!m_camera)
{
QCameraDevice cameraDevice = QMediaDevices::defaultVideoInput();
if (cameraDevice.videoFormats().empty())
{
setState(OFF);
emit errorOccurred("Unable to find suitable camera formats");
return;
}
QCameraFormat cameraFormat = cameraDevice.videoFormats().at(0);
for (auto format : cameraDevice.videoFormats())
{
qDebug() << "Format: " << format.resolution();
qDebug() << "framerate: " << format.minFrameRate() << " " << format.maxFrameRate();
if (format.isNull())
{
continue;
}
if (format.resolution().width() == 1280 && format.resolution().height() == 720)
{
cameraFormat = format;
}
}
m_camera = new QCamera(cameraDevice);
m_camera->setCameraFormat(cameraFormat);
connect(m_camera, &QCamera::activeChanged, this, [this](bool active) {
if (active)
{
setState(ON);
if (m_pendingRecord)
{
m_pendingRecord = false;
m_cancelledRecording = false;
m_recorder->record();
}
}
});
connect(m_camera, &QCamera::errorOccurred, this, [this](QCamera::Error error, const QString &message) {
if (error != QCamera::NoError)
{
stop();
emit errorOccurred(message);
}
});
m_captureSession->setCamera(m_camera);
}
m_videoSink = sink;
m_captureSession->setVideoSink(m_videoSink);
}
else
{
// AUDIO_ONLY: no camera
m_captureSession->setCamera(nullptr);
m_captureSession->setVideoSink(nullptr);
m_videoSink = nullptr;
}
// Recorder setup
if (!m_recorder)
{
QMediaFormat mediaFormat{QMediaFormat::MPEG4};
mediaFormat.setAudioCodec(QMediaFormat::AudioCodec::AAC);
if (m_captureMode != AUDIO_ONLY)
{
mediaFormat.setVideoCodec(QMediaFormat::VideoCodec::H264);
}
if (!mediaFormat.isSupported(QMediaFormat::Encode))
{
setState(OFF);
emit errorOccurred("Unsupported codec");
return;
}
m_recorder = new QMediaRecorder(this);
m_captureSession->setRecorder(m_recorder);
m_recorder->setQuality(QMediaRecorder::HighQuality);
m_recorder->setAutoStop(true);
m_recorder->setMediaFormat(mediaFormat);
connect(m_recorder, &QMediaRecorder::recorderStateChanged, this, [this](QMediaRecorder::RecorderState state) {
switch (state)
{
case QMediaRecorder::StoppedState:
if (m_state == RECORDING)
{
setState(ON);
}
if (!m_cancelledRecording)
{
qint64 duration = m_recorder->duration();
QString mimeType = m_recorder->mediaFormat().mimeType().name();
qDebug() << "Recording location " << m_recorder->actualLocation().toString();
emit recordingComplete(m_recorder->actualLocation(), duration, mimeType);
}
m_cancelledRecording = false;
break;
case QMediaRecorder::PausedState:
break;
case QMediaRecorder::RecordingState:
setState(RECORDING);
break;
}
});
}
if (m_captureMode != AUDIO_ONLY)
{
m_camera->start();
}
else
{
// AUDIO_ONLY: no async camera startup, go straight to ON
setState(ON);
if (m_pendingRecord)
{
m_pendingRecord = false;
m_cancelledRecording = false;
m_recorder->record();
}
}
}
void MediaHandler::stop()
{
if (m_state == OFF)
{
return;
}
m_pendingRecord = false;
if (m_state == RECORDING && m_recorder)
{
m_cancelledRecording = true;
m_recorder->stop();
}
if (m_camera)
{
m_camera->stop();
delete m_camera;
m_camera = nullptr;
}
if (m_captureSession)
{
m_captureSession->setVideoSink(nullptr);
}
m_videoSink = nullptr;
if (m_recorder)
{
delete m_recorder;
m_recorder = nullptr;
}
setState(OFF);
}
void MediaHandler::recordStop()
{
if (m_state != RECORDING)
{
return;
}
m_cancelledRecording = false;
m_recorder->stop();
}
void MediaHandler::recordCancel()
{
if (m_state != RECORDING)
{
return;
}
m_cancelledRecording = true;
m_recorder->stop();
}
void MediaHandler::setCaptureMode(CaptureMode newMode)
{
if (m_captureMode == newMode)
{
return;
}
m_captureMode = newMode;
emit captureModeChanged();
}
void MediaHandler::setState(State state)
{
if (m_state == state)
{
return;
}
m_state = state;
emit stateChanged();
}
+99
View File
@@ -0,0 +1,99 @@
#ifndef MEDIAHANDLER_H
#define MEDIAHANDLER_H
#include <QObject>
#include <QMediaDevices>
QT_BEGIN_NAMESPACE
class QMediaCaptureSession;
class QVideoSink;
class QAudioInput;
class QCamera;
class QMediaRecorder;
QT_END_NAMESPACE
// TODO: create simple structs to represent camera and audio input devices
/// MediaHandler allows you to preview and capture video, audio, and screen
class MediaHandler : public QObject
{
Q_OBJECT
public:
explicit MediaHandler(QObject *parent = nullptr);
~MediaHandler();
enum State
{
OFF = 0,
PREPARING,
ON,
RECORDING
};
State state() const;
enum CaptureMode
{
AUDIO_ONLY = 0,
CAMERA,
SCREEN
};
CaptureMode captureMode() const;
QVideoSink *videoSink() const;
// QList<CameraDevices>
// QList<AudioDevices>
public slots:
/// Only impacts the next time start is called
void setCaptureMode(CaptureMode);
/// Start preview: OFF → ON
void startPreview(QVideoSink *sink = nullptr);
/// Start recording: OFF → ON → RECORDING (auto-records when ready)
/// or ON → RECORDING (immediate)
void startRecording(QVideoSink *sink = nullptr);
/// Clean up resources, will stop all capture, recording, preview
void stop();
void recordCancel();
void recordStop();
// void setCameraDevice();
// void setAudioInputDevice();
signals:
/// User has denied mic permission, and must go to settings to enable
void micPermissionDenied();
/// User has denied camera permission, and must go to settings to enable
void cameraPermissionDenied();
void captureModeChanged();
void stateChanged();
void recordingComplete(const QUrl &absoluteFilePath, qint64 durationMs, const QString &mimeType);
void errorOccurred(const QString &);
private:
QMediaCaptureSession *m_captureSession;
QAudioInput *m_audioInput;
QCamera *m_camera;
QVideoSink *m_videoSink;
QMediaRecorder *m_recorder;
QMediaDevices m_devices;
CaptureMode m_captureMode = CAMERA;
State m_state = OFF;
void setState(State);
void startCapture(QVideoSink *sink);
bool m_pendingRecord = false;
bool m_cancelledRecording = false;
};
#endif //MEDIAHANDLER_H