Verified Commit a1901e35 authored by Phobos D'thorga's avatar Phobos D'thorga 🐲
Browse files

* The opus encoder now works to a certain degree.

* The right file-paths are now passed around, function-to-function.
* Multithreading with regard to audio encoding is more orderly now.
parent 8694b61d
Pipeline #1032 passed with stages
in 30 minutes and 40 seconds
......@@ -185,7 +185,6 @@ namespace GekkoFyre {
#define AUDIO_OPUS_FRAMES_PER_BUFFER (960) // This is specific to the Opus multimedia encoding/decoding library.
#define AUDIO_OPUS_MAX_FRAMES_PER_BUFFER (1276)
#define AUDIO_OPUS_INT_SIZE (2)
#define AUDIO_OPUS_MAX_FRAME_SIZE (1276)
#define AUDIO_OPUS_FILE_PTR_READ_SIZE (256) // To be used with `fread` <http://www.cplusplus.com/reference/cstdio/fread/>.
#define AUDIO_OPUS_DEFAULT_SAMPLE_RATE (48000) // The default sampling rate to use when encoding/decoding with Ogg Opus audio (measured in kHz).
#define AUDIO_ENCODING_VAR_PRIME_SLEEP_MILLISECS (1000) // The amount of time to wait for (in milliseconds) while the buffers prime themselves, before continuing with the rest of the encoding functions!
......
......@@ -109,8 +109,6 @@ GkAudioEncoding::GkAudioEncoding(const QPointer<QBuffer> &audioInputBuf, const Q
this, SLOT(handleError(const QString &, const GekkoFyre::System::Events::Logging::GkSeverity &)));
QObject::connect(this, SIGNAL(recStatus(const GekkoFyre::GkAudioFramework::GkAudioRecordStatus &)),
this, SLOT(setRecStatus(const GekkoFyre::GkAudioFramework::GkAudioRecordStatus &)));
QObject::connect(this, SIGNAL(updateAudioBuffers(const GekkoFyre::Database::Settings::GkAudioSource &)),
this, SLOT(refreshAudioBuffers(const GekkoFyre::Database::Settings::GkAudioSource &)));
return;
}
......@@ -244,11 +242,7 @@ void GkAudioEncoding::startCaller(const QFileInfo &media_path, const qint32 &bit
m_buffer.shrink_to_fit();
//
// Initiate variables
if (media_path.exists()) {
m_file_path = media_path; // The location of where to make the recording!
}
// Set frame-size!
m_frameSize = frame_size;
if (audio_source == GkAudioSource::Input) {
......@@ -285,8 +279,7 @@ void GkAudioEncoding::startCaller(const QFileInfo &media_path, const qint32 &bit
m_encodeOpusThread.join();
}
m_encodeOpusThread = std::thread(&GkAudioEncoding::encodeOpus, this, std::ref(bitrate), std::ref(audio_source),
std::ref(frame_size));
m_encodeOpusThread = std::thread(&GkAudioEncoding::encodeOpus, this, bitrate, std::ref(audio_source), media_path, m_frameSize);
m_encodeOpusThread.detach();
} else if (codec_choice == CodecSupport::OggVorbis) {
//
......@@ -296,8 +289,8 @@ void GkAudioEncoding::startCaller(const QFileInfo &media_path, const qint32 &bit
m_encodeVorbisThread.join();
}
m_encodeVorbisThread = std::thread(&GkAudioEncoding::encodeVorbis, this, std::ref(bitrate), gkAudioInput->format().sampleRate(),
std::ref(audio_source), std::ref(frame_size));
m_encodeVorbisThread = std::thread(&GkAudioEncoding::encodeVorbis, this, bitrate, gkAudioInput->format().sampleRate(),
std::ref(audio_source), media_path, m_frameSize);
m_encodeVorbisThread.detach();
} else if (codec_choice == CodecSupport::FLAC) {
//
......@@ -307,8 +300,8 @@ void GkAudioEncoding::startCaller(const QFileInfo &media_path, const qint32 &bit
m_encodeFLACThread.join();
}
m_encodeFLACThread = std::thread(&GkAudioEncoding::encodeFLAC, this, std::ref(bitrate), gkAudioInput->format().sampleRate(),
std::ref(audio_source), std::ref(frame_size));
m_encodeFLACThread = std::thread(&GkAudioEncoding::encodeFLAC, this, bitrate, gkAudioInput->format().sampleRate(),
std::ref(audio_source), media_path, m_frameSize);
m_encodeFLACThread.detach();
} else {
throw std::invalid_argument(tr("Invalid audio encoding codec specified! It is either not supported yet or an error was made.").toStdString());
......@@ -365,33 +358,27 @@ void GkAudioEncoding::setRecStatus(const GekkoFyre::GkAudioFramework::GkAudioRec
* @param bitrate The data rate (in kilobits per second, i.e. '192' without the quotes) at which you wish to encode the
* multimedia file in question.
* @param sample_rate The sample rate at which to encode with (i.e. 48,000 Hz).
* @param media_path The absolute path to where the encoded information will be written.
* @param frame_size The size of the audio frame(s) in question.
*/
void GkAudioEncoding::encodeOpus(const qint32 &bitrate, const GkAudioSource &audio_src, const qint32 &frame_size)
void GkAudioEncoding::encodeOpus(const qint32 &bitrate, const GkAudioSource &audio_src, const QFileInfo &media_path,
const qint32 &frame_size)
{
//
// Ogg Opus
//
try {
//
// Ogg Opus
//
std::lock_guard<std::mutex> lock_g(m_encodeOggOpusMtx);
const QDir dir_tmp = m_file_path.path(); // NOTE: Returns the file's path. This doesn't include the file name.
const QString dir_path = dir_tmp.path();
if (!dir_tmp.exists()) {
bool ret = QDir().mkpath(dir_path);
if (!ret) {
throw std::runtime_error(tr("Unsuccessfully created directory, \"%1\"!").arg(dir_path).toStdString());
}
}
QDir::setCurrent(dir_path);
m_out_file.setFileName(m_file_path.fileName());
if (m_file_path.exists()) {
m_out_file.remove();
QDir::setCurrent(media_path.absolutePath());
m_out_file.setFileName(media_path.fileName());
if (media_path.exists() && media_path.isFile()) {
throw std::invalid_argument(tr("Attempting to encode towards file, \"%1\", has failed! Error: file already exists.")
.arg(media_path.absoluteFilePath()).toStdString());
}
m_out_file.open(QIODevice::ReadWrite, QIODevice::NewOnly);
if (!m_out_file.isOpen()) {
throw std::runtime_error(tr("Error with opening file, \"%1\"!").arg(m_file_path.fileName()).toStdString());
throw std::runtime_error(tr("Error with opening file, \"%1\"!").arg(media_path.absoluteFilePath()).toStdString());
}
//
......@@ -422,7 +409,7 @@ void GkAudioEncoding::encodeOpus(const qint32 &bitrate, const GkAudioSource &aud
throw std::runtime_error(gkStringFuncs->handleOpusError(err).toStdString());
}
emit updateAudioBuffers(audio_src); // Execute this just once before the do-while loop, in order to prime the variables beforehand!
refreshAudioBuffers(audio_src, m_size); // Execute this just once before the do-while loop, in order to prime the variables beforehand!
// std::this_thread::sleep_for (std::chrono::milliseconds(AUDIO_ENCODING_VAR_PRIME_SLEEP_MILLISECS));
do {
......@@ -460,8 +447,8 @@ void GkAudioEncoding::encodeOpus(const qint32 &bitrate, const GkAudioSource &aud
throw std::invalid_argument(tr("An invalid or currently unsupported audio source has been chosen!").toStdString());
}
emit updateAudioBuffers(audio_src);
const auto result = opusEncodeHelper(m_opusEncoder, frame_size, m_size, AUDIO_OPUS_MAX_FRAME_SIZE * 3);
refreshAudioBuffers(audio_src, m_size);
const auto result = opusEncodeHelper(m_opusEncoder, frame_size, m_size, AUDIO_OPUS_MAX_FRAMES_PER_BUFFER * 3);
if (!result.isEmpty()) {
//
// Write out the encoded, Ogg Opus data, to the given output file in question!
......@@ -507,36 +494,29 @@ void GkAudioEncoding::encodeOpus(const qint32 &bitrate, const GkAudioSource &aud
* @param bitrate The data rate (in kilobits per second, i.e. '192' without the quotes) at which you wish to encode the
* multimedia file in question.
* @param sample_rate The sample rate at which to encode with (i.e. 48,000 Hz).
* @param media_path The absolute path to where the encoded information will be written.
* @param frame_size The size of the audio frame(s) in question.
*/
void GkAudioEncoding::encodeVorbis(const qint32 &bitrate, qint32 sample_rate, const GkAudioSource &audio_src,
const qint32 &frame_size)
const QFileInfo &media_path, const qint32 &frame_size)
{
//
// Ogg Vorbis
// https://github.com/libsndfile/libsndfile/blob/master/examples/sndfilehandle.cc
// https://github.com/libsndfile/libsndfile/blob/master/examples/sfprocess.c
//
try {
//
// Ogg Vorbis
// https://github.com/libsndfile/libsndfile/blob/master/examples/sndfilehandle.cc
// https://github.com/libsndfile/libsndfile/blob/master/examples/sfprocess.c
//
std::lock_guard<std::mutex> lock_g(m_encodeOggVorbisMtx);
const QDir dir_tmp = m_file_path.path(); // NOTE: Returns the file's path. This doesn't include the file name.
const QString dir_path = dir_tmp.path();
if (!dir_tmp.exists()) {
bool ret = QDir().mkpath(dir_path);
if (!ret) {
throw std::runtime_error(tr("Unsuccessfully created directory, \"%1\"!").arg(dir_path).toStdString());
}
}
QDir::setCurrent(dir_path);
m_out_file.setFileName(m_file_path.fileName());
if (m_file_path.exists()) {
m_out_file.remove();
QDir::setCurrent(media_path.absolutePath());
m_out_file.setFileName(media_path.fileName());
if (media_path.exists() && media_path.isFile()) {
throw std::invalid_argument(tr("Attempting to encode towards file, \"%1\", has failed! Error: file already exists.")
.arg(media_path.absoluteFilePath()).toStdString());
}
m_out_file.open(QIODevice::ReadWrite, QIODevice::NewOnly);
if (!m_out_file.isOpen()) {
throw std::runtime_error(tr("Error with opening file, \"%1\"!").arg(m_file_path.fileName()).toStdString());
throw std::runtime_error(tr("Error with opening file, \"%1\"!").arg(media_path.absoluteFilePath()).toStdString());
}
//
......@@ -605,36 +585,29 @@ void GkAudioEncoding::encodeVorbis(const qint32 &bitrate, qint32 sample_rate, co
* @param bitrate The data rate (in kilobits per second, i.e. '192' without the quotes) at which you wish to encode the
* multimedia file in question.
* @param sample_rate The sample rate at which to encode with (i.e. 48,000 Hz).
* @param media_path The absolute path to where the encoded information will be written.
* @param frame_size The size of the audio frame(s) in question.
*/
void GkAudioEncoding::encodeFLAC(const qint32 &bitrate, qint32 sample_rate, const GkAudioSource &audio_src,
const qint32 &frame_size)
const QFileInfo &media_path, const qint32 &frame_size)
{
//
// FLAC
// https://github.com/libsndfile/libsndfile/blob/master/examples/sndfilehandle.cc
// https://github.com/libsndfile/libsndfile/blob/master/examples/sfprocess.c
//
try {
//
// FLAC
// https://github.com/libsndfile/libsndfile/blob/master/examples/sndfilehandle.cc
// https://github.com/libsndfile/libsndfile/blob/master/examples/sfprocess.c
//
std::lock_guard<std::mutex> lock_g(m_encodeFlacMtx);
const QDir dir_tmp = m_file_path.path(); // NOTE: Returns the file's path. This doesn't include the file name.
const QString dir_path = dir_tmp.path();
if (!dir_tmp.exists()) {
bool ret = QDir().mkpath(dir_path);
if (!ret) {
throw std::runtime_error(tr("Unsuccessfully created directory, \"%1\"!").arg(dir_path).toStdString());
}
}
QDir::setCurrent(dir_path);
m_out_file.setFileName(m_file_path.fileName());
if (m_file_path.exists()) {
m_out_file.remove();
QDir::setCurrent(media_path.absolutePath());
m_out_file.setFileName(media_path.fileName());
if (media_path.exists() && media_path.isFile()) {
throw std::invalid_argument(tr("Attempting to encode towards file, \"%1\", has failed! Error: file already exists.")
.arg(media_path.absoluteFilePath()).toStdString());
}
m_out_file.open(QIODevice::ReadWrite, QIODevice::NewOnly);
if (!m_out_file.isOpen()) {
throw std::runtime_error(tr("Error with opening file, \"%1\"!").arg(m_file_path.fileName()).toStdString());
throw std::runtime_error(tr("Error with opening file, \"%1\"!").arg(media_path.absoluteFilePath()).toStdString());
}
//
......@@ -702,29 +675,31 @@ void GkAudioEncoding::encodeFLAC(const qint32 &bitrate, qint32 sample_rate, cons
* devices.
* @author Phobos A. D'thorga <phobos.gekko@gekkofyre.io>
* @param audio_src The audio source for which buffers to update henceforth.
* @param buf_size The minimum size of the buffer that must be reached to exit the internal loop within this function.
*/
void GkAudioEncoding::refreshAudioBuffers(const GkAudioSource &audio_src)
void GkAudioEncoding::refreshAudioBuffers(const GkAudioSource &audio_src, const qint32 &buf_size)
{
std::lock_guard<std::mutex> lock_guard(m_refreshAudioBufs);
if (audio_src == GkAudioSource::Input) {
if (gkAudioInput->state() != QAudio::ActiveState) {
emit recStatus(GkAudioRecordStatus::Defunct);
m_recActive = GkAudioRecordStatus::Defunct; // Has to modify the variable directly, since we are working from differing threads than the main, GUI-thread!
return;
}
do {
gkAudioInputBuf->seek(0);
m_buffer.append(gkAudioInputBuf->readAll());
} while (m_buffer.isEmpty());
} while (m_buffer.isEmpty() && m_buffer.size() < buf_size);
} else if (audio_src == GkAudioSource::Output) {
if (gkAudioOutput->state() != QAudio::ActiveState) {
emit recStatus(GkAudioRecordStatus::Defunct);
m_recActive = GkAudioRecordStatus::Defunct; // Has to modify the variable directly, since we are working from differing threads than the main, GUI-thread!
return;
}
do {
gkAudioOutputBuf->seek(0);
m_buffer.append(gkAudioOutputBuf->readAll());
} while (m_buffer.isEmpty());
} while (m_buffer.isEmpty() && m_buffer.size() < buf_size);
} else {
return;
}
......@@ -751,18 +726,20 @@ QByteArray GkAudioEncoding::opusEncodeHelper(OpusEncoder *opusEncoder, const qin
}
QByteArray input = m_buffer.mid(0, m_size);
QByteArray output = QByteArray(AUDIO_OPUS_MAX_FRAME_SIZE * 3, char(0));
QByteArray output = QByteArray(AUDIO_OPUS_MAX_FRAMES_PER_BUFFER * 3, char(0));
m_buffer.remove(0, m_size);
if (input.isEmpty()) {
emit error(tr("No input data to work with!"), GkSeverity::Error);
return QByteArray();
}
//
// Encode the frame...
const qint32 nbBytes = opus_encode_float(opusEncoder, reinterpret_cast<const float *>(input.constData()), frame_size,
reinterpret_cast<uchar *>(output.data()), max_packet_size);
if (nbBytes < 0) {
emit error(tr("Error encoding to file: %1").arg(m_file_path.path()), GkSeverity::Fatal);
opusCleanup();
return QByteArray();
throw std::runtime_error(tr("Error encoding with Opus. Given output was expected to be larger than zero, but instead were: %1 bytes.")
.arg(QString::number(nbBytes)).toStdString());
}
//
......
......@@ -141,8 +141,8 @@ public slots:
void startCaller(const QFileInfo &media_path, const qint32 &bitrate, const GekkoFyre::GkAudioFramework::CodecSupport &codec_choice,
const GekkoFyre::Database::Settings::GkAudioSource &audio_source, const qint32 &frame_size = AUDIO_FRAMES_PER_BUFFER,
const qint32 &application = OPUS_APPLICATION_AUDIO);
void stopEncode();
void stopEncode();
void setRecStatus(const GekkoFyre::GkAudioFramework::GkAudioRecordStatus &status);
private slots:
......@@ -150,13 +150,13 @@ private slots:
void handleError(const QString &msg, const GekkoFyre::System::Events::Logging::GkSeverity &severity);
void encodeOpus(const qint32 &bitrate, const GekkoFyre::Database::Settings::GkAudioSource &audio_src,
const qint32 &frame_size = AUDIO_OPUS_MAX_FRAME_SIZE);
const QFileInfo &media_path, const qint32 &frame_size = AUDIO_OPUS_FRAMES_PER_BUFFER);
void encodeVorbis(const qint32 &bitrate, qint32 sample_rate, const GekkoFyre::Database::Settings::GkAudioSource &audio_src,
const qint32 &frame_size = AUDIO_FRAMES_PER_BUFFER);
const QFileInfo &media_path, const qint32 &frame_size = AUDIO_FRAMES_PER_BUFFER);
void encodeFLAC(const qint32 &bitrate, qint32 sample_rate, const GekkoFyre::Database::Settings::GkAudioSource &audio_src,
const qint32 &frame_size = AUDIO_FRAMES_PER_BUFFER);
const QFileInfo &media_path, const qint32 &frame_size = AUDIO_FRAMES_PER_BUFFER);
void refreshAudioBuffers(const GekkoFyre::Database::Settings::GkAudioSource &audio_src);
void refreshAudioBuffers(const GekkoFyre::Database::Settings::GkAudioSource &audio_src, const qint32 &buf_size);
signals:
void pauseEncode();
......@@ -166,7 +166,6 @@ signals:
void initialize();
void recStatus(const GekkoFyre::GkAudioFramework::GkAudioRecordStatus &status);
void updateAudioBuffers(const GekkoFyre::Database::Settings::GkAudioSource &audio_src);
private:
QPointer<GekkoFyre::GkLevelDb> gkDb;
......@@ -185,7 +184,6 @@ private:
//
// Encoder variables
bool m_initialized = false; // Whether an encoding operation has begun or not; therefore block other attempts until this singular one has stopped.
QFileInfo m_file_path; // The file-path to the audio file where the encoded information will be written.
QByteArray m_buffer; // A QByteArray, providing more readily accessible information as needed by the FLAC, Ogg Vorbis, Ogg Opus, etc. encoders.
QByteArray m_fileData; // For any pre-existing data, such as an Ogg Opus file that had already started encoding previously.
QPointer<QBuffer> gkAudioInputBuf; // For reading RAW PCM audio data from a given QAudioInput into.
......@@ -206,6 +204,7 @@ private:
std::mutex m_encodeOggOpusMtx;
std::mutex m_encodeOggVorbisMtx;
std::mutex m_encodeFlacMtx;
std::mutex m_refreshAudioBufs;
std::thread m_encodeOpusThread;
std::thread m_encodeVorbisThread;
std::thread m_encodeFLACThread;
......
......@@ -339,7 +339,7 @@ void GkFFTAudio::samplesUpdated()
{
try {
std::vector<double> remainder;
auto splitAudioSamples = gkStringFuncs->chunker(audioSamples, (AUDIO_FRAMES_PER_BUFFER * 2));
const auto splitAudioSamples = gkStringFuncs->chunker(audioSamples, (AUDIO_FRAMES_PER_BUFFER * 2));
for (const auto &samples_vec: splitAudioSamples) {
if (!samples_vec.empty()) {
if (samples_vec.size() == (AUDIO_FRAMES_PER_BUFFER * 2)) {
......
......@@ -236,7 +236,7 @@ GkXmppClient::GkXmppClient(const GkUserConn &connection_details, QPointer<GekkoF
QObject::connect(m_rosterManager.get(), SIGNAL(presenceChanged(const QString &, const QString &)), this, SLOT(presenceChanged(const QString &, const QString &)));
QObject::connect(m_rosterManager.get(), SIGNAL(rosterReceived()), this, SLOT(handleRosterReceived()));
QObject::connect(m_rosterManager.get(), SIGNAL(subscriptionReceived(const QString &)), this, SLOT(notifyNewSubscription(const QString &)));
QObject::connect(m_rosterManager.get(), SIGNAL(subscriptionRequestReceived (const QString &, const QXmppPresence &)),
QObject::connect(m_rosterManager.get(), SIGNAL(subscriptionRequestReceived (const QString &, const QXmppPresence &)), // TODO: No such signal?
this, SLOT(notifyNewSubscription(const QString &, const QXmppPresence &)));
QObject::connect(m_rosterManager.get(), SIGNAL(itemAdded(const QString &)), this, SLOT(itemAdded(const QString &)));
QObject::connect(m_rosterManager.get(), SIGNAL(itemRemoved(const QString &)), this, SLOT(itemRemoved(const QString &)));
......
......@@ -120,14 +120,16 @@ void GkPaAudioPlayer::play(const GkAudioFramework::CodecSupport &supported_codec
* @author Phobos A. D'thorga <phobos.gekko@gekkofyre.io>
* @param supported_codec The codec to use when creating the recording, whether it be Opus, PCM, FLAC, etc.
* @param record_dir The directory to which recordings are to be saved towards.
* @param bitrate The encoding bitrate to use.
* @param audio_source The audio device to record from, which is either the input or output, or even a mix of the
* aforementioned two.
*/
void GkPaAudioPlayer::record(const CodecSupport &supported_codec, const QDir &record_dir, const GkAudioSource &audio_source)
void GkPaAudioPlayer::record(const CodecSupport &supported_codec, const QDir &record_dir, const qint32 &bitrate,
const GkAudioSource &audio_source)
{
try {
streamHandler->processEvent(GkAudioFramework::AudioEventType::record, audio_source, record_dir,
supported_codec, false);
supported_codec, false, bitrate);
} catch (const std::exception &e) {
std::throw_with_nested(std::runtime_error(tr("A stream processing error has occurred with regards to the multimedia library handling functions. Error:\n\n%1")
.arg(QString::fromStdString(e.what())).toStdString()));
......
......@@ -73,7 +73,7 @@ public:
void play(const GekkoFyre::GkAudioFramework::CodecSupport &supported_codec,
const GekkoFyre::Database::Settings::GkAudioSource &audio_source);
void record(const GekkoFyre::GkAudioFramework::CodecSupport &supported_codec, const QDir &record_dir,
const GekkoFyre::Database::Settings::GkAudioSource &audio_source);
const qint32 &bitrate, const GekkoFyre::Database::Settings::GkAudioSource &audio_source);
void loop(const GekkoFyre::GkAudioFramework::CodecSupport &supported_codec, const QFileInfo &audio_file,
const GekkoFyre::Database::Settings::GkAudioSource &audio_source);
void stop(const QFileInfo &audio_file, const GekkoFyre::Database::Settings::GkAudioSource &audio_source);
......
......@@ -101,8 +101,6 @@ GkPaStreamHandler::GkPaStreamHandler(QPointer<GekkoFyre::GkLevelDb> database, QP
//
// Recording of multimedia files
QObject::connect(this, SIGNAL(recordMedia(const QFileInfo &, const GekkoFyre::GkAudioFramework::CodecSupport &, const GekkoFyre::Database::Settings::GkAudioSource &, qint32,)),
this, SLOT(recordMediaFile(const QFileInfo &, const GekkoFyre::GkAudioFramework::CodecSupport &, const GekkoFyre::Database::Settings::GkAudioSource &, qint32)));
QObject::connect(this, SIGNAL(recordMedia(const QDir &, const GekkoFyre::GkAudioFramework::CodecSupport &, const GekkoFyre::Database::Settings::GkAudioSource &, qint32)),
this, SLOT(recordMediaFile(const QDir &, const GekkoFyre::GkAudioFramework::CodecSupport &, const GekkoFyre::Database::Settings::GkAudioSource &, qint32)));
......@@ -116,6 +114,7 @@ GkPaStreamHandler::GkPaStreamHandler(QPointer<GekkoFyre::GkLevelDb> database, QP
QObject::connect(this, SIGNAL(startLoopback()), this, SLOT(startMediaLoopback()));
QObject::connect(this, SIGNAL(initEncode(const QFileInfo &, const qint32 &, const GekkoFyre::GkAudioFramework::CodecSupport &, const GekkoFyre::Database::Settings::GkAudioSource &, const qint32 &, const qint32 &)),
gkAudioEncoding, SLOT(startCaller(const QFileInfo &, const qint32 &, const GekkoFyre::GkAudioFramework::CodecSupport &, const GekkoFyre::Database::Settings::GkAudioSource &, const qint32 &, const qint32 &)));
return;
}
......@@ -153,9 +152,8 @@ void GkPaStreamHandler::processEvent(GkAudioFramework::AudioEventType audioEvent
break;
case GkAudioFramework::AudioEventType::record:
if (mediaFilePath.isReadable()) {
emit recordMedia(mediaFilePath, supported_codec, audio_source, encode_bitrate);
}
//
// NOTE: Only handled with a QDir-enabled function!
break;
case GkAudioFramework::AudioEventType::loopback:
......@@ -212,7 +210,10 @@ void GkPaStreamHandler::processEvent(GkAudioFramework::AudioEventType audioEvent
break;
case GkAudioFramework::AudioEventType::loopback:
{
emit startLoopback();
}
break;
case GkAudioFramework::AudioEventType::stop:
if (mediaFilePath.isReadable()) {
......@@ -275,7 +276,7 @@ void GkPaStreamHandler::playMediaFile(const QDir &media_path, const CodecSupport
* @param audio_source The audio source in question, whether it is input, output, or a mix of the two.
* @param encoding_bitrate The bitrate at which to encode with (i.e. 192 kbit/sec).
*/
void GkPaStreamHandler::recordMediaFile(const QFileInfo &media_path, const GkAudioFramework::CodecSupport &supported_codec,
void GkPaStreamHandler::recordMediaFile(const QDir &media_path, const CodecSupport &supported_codec,
const GkAudioSource &audio_source, qint32 encoding_bitrate)
{
try {
......@@ -302,42 +303,6 @@ void GkPaStreamHandler::recordMediaFile(const QFileInfo &media_path, const GkAud
return;
}
/**
* @brief GkPaStreamHandler::recordMediaFile record data to a multimedia file on the end-user's storage media of choice.
* @author Phobos A. D'thorga <phobos.gekko@gekkofyre.io>
* @param media_path The multimedia file to make the recording towards.
* @param supported_codec The codec you would like to make the recording with.
* @param audio_source The audio source in question, whether it is input, output, or a mix of the two.
* @param encoding_bitrate The bitrate at which to encode with (i.e. 192 kbit/sec).
*/
void GkPaStreamHandler::recordMediaFile(const QDir &media_path, const CodecSupport &supported_codec,
const GkAudioSource &audio_source, qint32 encoding_bitrate)
{
try {
const QFileInfo file_info_tmp(media_path.path());
if (audio_source == GkAudioSource::Input) {
if (!gkAudioInput.isNull()) {
recordMediaFileHelper(file_info_tmp, supported_codec, audio_source, encoding_bitrate);
} else {
throw std::invalid_argument(tr("You must configure a suitable audio device within the Settings before continuing!").toStdString());
}
} else if (audio_source == GkAudioSource::Output) {
if (!gkAudioOutput.isNull()) {
recordMediaFileHelper(file_info_tmp, supported_codec, audio_source, encoding_bitrate);
} else {
throw std::invalid_argument(tr("You must configure a suitable audio device within the Settings before continuing!").toStdString());
}
} else {
throw std::invalid_argument(tr("An invalid or currently unsupported audio source has been chosen!").toStdString());
}
} catch (const std::exception &e) {
gkEventLogger->publishEvent(QString::fromStdString(e.what()), GkSeverity::Fatal, "",
false, true, false, true, false);
}
return;
}
/**
* @brief GkPaStreamHandler::startMediaLoopback
* @author Phobos A. D'thorga <phobos.gekko@gekkofyre.io>
......@@ -392,6 +357,30 @@ void GkPaStreamHandler::stopMediaFile(const QFileInfo &media_path)
}
gkSounds.remove(media_path.path()); // Must be deleted outside of the loop!
return;
}
/**
* @brief GkPaStreamHandler::stopMediaFile
* @author Phobos A. D'thorga <phobos.gekko@gekkofyre.io>
* @param media_path
*/
void GkPaStreamHandler::stopMediaFile(const QDir &media_path)
{
for (auto media = gkSounds.begin(); media != gkSounds.end(); ++media) {
if (media.key() == media_path.path()) {
gkPcmFileStream->stop();
if (gkAudioOutput->state() == QAudio::ActiveState) {
gkAudioOutput->stop();
}
break;
}
}
gkSounds.remove(media_path.path()); // Must be deleted outside of the loop!
return;
}
/*
......@@ -453,30 +442,6 @@ void GkPaStreamHandler::recordingHandleStateChanged(QAudio::State changed_state)
return;
}
/**
* @brief GkPaStreamHandler::createRecordMediaFile
* @author Phobos A. D'thorga <phobos.gekko@gekkofyre.io>
* @param media_path The path to where the file is stored.
* @param supported_codec The file extension to use.
* @return
*/
QFileInfo GkPaStreamHandler::createRecordMediaFile(const QFileInfo &media_path, const CodecSupport &supported_codec)
{
try {
std::lock_guard<std::mutex> lock_guard(m_createRecordMediaFileInfoMutex);
const auto randStr = gkDb->createRandomString(16);
const auto epochSecs = QDateTime::currentSecsSinceEpoch();
const auto extension = gkDb->convCodecFormatToFileExtension(supported_codec);
const QFileInfo mediaRetPath = QFileInfo(media_path.path() + "/" + QString::number(epochSecs) + "_" + QString::fromStdString(randStr) + extension);
return mediaRetPath;
} catch (const std::exception &e) {
std::throw_with_nested(e.what());
}
return QFileInfo();
}
/**
* @brief GkPaStreamHandler::createRecordMediaFile
* @author Phobos A. D'thorga <phobos.gekko@gekkofyre.io>
......@@ -491,7 +456,11 @@ QFileInfo GkPaStreamHandler::createRecordMediaFile(const QDir &media_path, const
const auto randStr = gkDb->createRandomString(16);
const auto epochSecs = QDateTime::currentSecsSinceEpoch();
const auto extension = gkDb->convCodecFormatToFileExtension(supported_codec);
const QFileInfo mediaRetPath = QFileInfo(media_path.path() + "/" + QString::number(epochSecs) + "_" + QString::fromStdString(randStr) + extension);
QFileInfo mediaRetPath;
mediaRetPath.setFile(media_path.absolutePath() + "/" + QString::number(epochSecs) + "_" + QString::fromStdString(randStr) + extension);
if (mediaRetPath.exists()) { // Retry and until we get to a folder name that does not already exist!
mediaRetPath = createRecordMediaFile(media_path, supported_codec);
}
return mediaRetPath;
} catch (const std::exception &e) {
......@@ -595,15 +564,15 @@ void GkPaStreamHandler::playMediaFileHelper(QFileInfo media_path, const CodecSup
}
/**
* @brief GkPaStreamHandler::recordMediaFile record data to a multimedia file on the end-user's storage media of choice.
* @brief GkPaStreamHandler::recordMediaFileHelper record data to a multimedia file on the end-user's storage media of choice.
* @author Phobos A. D'thorga <phobos.gekko@gekkofyre.io>
* @param media_path The multimedia file to make the recording towards.
* @param supported_codec The codec you would like to make the recording with.
* @param audio_source The audio source in question, whether it is input, output, or a mix of the two.
* @param encoding_bitrate The bitrate at which to encode with (i.e. 192 kbit/sec).
*/
void GkPaStreamHandler::recordMediaFileHelper(QFileInfo media_path, const CodecSupport &supported_codec,
const GkAudioSource &audio_source, qint32 encoding_bitrate)
void GkPaStreamHandler::recordMediaFileHelper(QDir media_path, const CodecSupport &supported_codec,
const Settings::GkAudioSource &audio_source, qint32 encoding_bitrate)
{
try {
std::lock_guard<std::mutex> lock_guard(m_recordMediaFileHelperMutex);
......@@ -618,7 +587,7 @@ void GkPaStreamHandler::recordMediaFileHelper(QFileInfo media_path, const CodecS
//
// Use a differing FRAME SIZE for Opus!
// Ogg Opus only
emit initEncode(m_mediaFile, encoding_bitrate, supported_codec, audio_source, AUDIO_OPUS_MAX_FRAME_SIZE);
emit initEncode(m_mediaFile, encoding_bitrate, supported_codec, audio_source, AUDIO_OPUS_FRAMES_PER_BUFFER);
} else {
//
// Create a media file with a randomized name within the given path, for recording purposes!
......@@ -635,4 +604,6 @@ void GkPaStreamHandler::recordMediaFileHelper(QFileInfo media_path, const CodecS
} catch (const std::exception &e) {
gkEventLogger->publishEvent(QString::fromStdString(e.what()), GkSeverity::Fatal, "", false, true, false, true);
}
return;
}
......@@ -84,7 +84,6 @@ public:
const QDir &mediaFilePath = QDir(), const GekkoFyre::GkAudioFramework::CodecSupport &supported_codec = GekkoFyre::GkAudioFramework::CodecSupport::Unknown,
bool loop_media = false, qint32 encode_bitrate = 8);