implemented base audio playback and scrubbing

This commit is contained in:
itsmattkc
2019-10-14 11:38:29 +11:00
parent b942300aea
commit fe2b0f2dc2
7 changed files with 215 additions and 22 deletions
+4
View File
@@ -16,6 +16,10 @@
set(OLIVE_SOURCES
${OLIVE_SOURCES}
audio/audiohybriddevice.h
audio/audiohybriddevice.cpp
audio/audiolayouts.h
audio/audiolayouts.cpp
audio/audiomanager.h
audio/audiomanager.cpp
PARENT_SCOPE
+93
View File
@@ -0,0 +1,93 @@
#include "audiohybriddevice.h"
#include <QDebug>
#include <QtMath>
AudioHybridDevice::AudioHybridDevice(QObject *parent) :
QIODevice(parent),
device_(nullptr),
sample_index_(0)
{
}
void AudioHybridDevice::Push(const QByteArray& samples)
{
pushed_samples_ = samples;
sample_index_ = 0;
if (!pushed_samples_.isEmpty()) {
emit HasSamples();
}
}
void AudioHybridDevice::Stop()
{
// Whatever is happening, stop it
pushed_samples_.clear();
device_ = nullptr;
}
void AudioHybridDevice::ConnectDevice(QIODevice *device)
{
// Clear any previous device or pushed sample
Stop();
device_ = device;
if (device_ != nullptr) {
emit HasSamples();
}
}
bool AudioHybridDevice::IsIdle()
{
return device_ == nullptr && pushed_samples_.isEmpty();
}
qint64 AudioHybridDevice::readData(char *data, qint64 maxSize)
{
// If a device is connected, passthrough to it
if (device_ != nullptr) {
qint64 read_count = device_->read(data, maxSize);
// Stop reading this device
if (device_->atEnd()) {
device_ = nullptr;
}
return read_count;
}
// If there are samples to push, push those
if (!pushed_samples_.isEmpty()) {
qint64 read_count = qMin(maxSize, pushed_samples_.size() - sample_index_);
memcpy(data, pushed_samples_.data()+sample_index_, static_cast<size_t>(read_count));
sample_index_ += read_count;
if (sample_index_ == pushed_samples_.size()) {
pushed_samples_.clear();
}
if (read_count < maxSize) {
memset(data + read_count, 0, static_cast<size_t>(maxSize - read_count));
}
return maxSize;
}
memset(data, 0, static_cast<size_t>(maxSize));
return maxSize;
}
qint64 AudioHybridDevice::writeData(const char *data, qint64 maxSize)
{
Q_UNUSED(data)
Q_UNUSED(maxSize)
// This device doesn't support writing
return -1;
}
+37
View File
@@ -0,0 +1,37 @@
#ifndef AUDIOHYBRIDDEVICE_H
#define AUDIOHYBRIDDEVICE_H
#include <QIODevice>
typedef float sample;
class AudioHybridDevice : public QIODevice
{
Q_OBJECT
public:
AudioHybridDevice(QObject* parent = nullptr);
void Push(const QByteArray &samples);
void Stop();
void ConnectDevice(QIODevice* device);
bool IsIdle();
signals:
void HasSamples();
protected:
virtual qint64 readData(char *data, qint64 maxSize) override;
virtual qint64 writeData(const char *data, qint64 maxSize) override;
private:
QIODevice* device_;
QByteArray pushed_samples_;
qint64 sample_index_;
};
#endif // AUDIOHYBRIDDEVICE_H
+36 -14
View File
@@ -61,32 +61,29 @@ bool AudioManager::IsRefreshing()
return refreshing_devices_;
}
void AudioManager::PushToOutput(const QByteArray &samples)
{
output_manager_.Push(samples);
}
void AudioManager::StartOutput(QIODevice *device)
{
if (output_ == nullptr) {
return;
}
output_file_ = device;
output_->start(output_file_);
output_manager_.ConnectDevice(device);
}
void AudioManager::StopOutput()
{
if (output_ == nullptr || output_file_ == nullptr) {
return;
}
output_->stop();
output_file_->close();
delete output_file_;
output_file_ = nullptr;
output_manager_.Stop();
}
void AudioManager::SetOutputDevice(const QAudioDeviceInfo &info)
{
StopOutput();
QAudioFormat format;
format.setSampleRate(48000);
format.setChannelCount(2);
@@ -96,6 +93,8 @@ void AudioManager::SetOutputDevice(const QAudioDeviceInfo &info)
format.setSampleType(QAudioFormat::Float);
output_ = std::unique_ptr<QAudioOutput>(new QAudioOutput(info, format, this));
connect(output_.get(), SIGNAL(stateChanged(QAudio::State)), this, SLOT(OutputStateChanged(QAudio::State)));
connect(output_.get(), SIGNAL(notify()), this, SLOT(OutputNotified()));
output_device_info_ = info;
}
@@ -117,14 +116,17 @@ const QList<QAudioDeviceInfo> &AudioManager::ListOutputDevices()
AudioManager::AudioManager() :
output_(nullptr),
output_file_(nullptr),
input_(nullptr),
input_file_(nullptr),
refreshing_devices_(false)
{
connect(&refresh_thread_, SIGNAL(ListsReady()), this, SLOT(RefreshThreadDone()));
RefreshDevices();
connect(&refresh_thread_, SIGNAL(ListsReady()), this, SLOT(RefreshThreadDone()));
connect(&output_manager_, SIGNAL(HasSamples()), this, SLOT(OutputManagerHasSamples()));
output_manager_.open(AudioHybridDevice::ReadOnly);
}
void AudioManager::RefreshThreadDone()
@@ -169,6 +171,26 @@ void AudioManager::RefreshThreadDone()
emit DeviceListReady();
}
void AudioManager::OutputManagerHasSamples()
{
if (output_ != nullptr && output_->state() != QAudio::ActiveState) {
output_->start(&output_manager_);
}
}
void AudioManager::OutputStateChanged(QAudio::State state)
{
qDebug() << state;
}
void AudioManager::OutputNotified()
{
qDebug() << "Notified";
if (output_manager_.IsIdle()) {
static_cast<QAudioOutput*>(sender())->stop();
}
}
AudioRefreshDevicesThread::AudioRefreshDevicesThread()
{
}
+12 -1
View File
@@ -26,6 +26,8 @@
#include <QAudioOutput>
#include <QThread>
#include "audiohybriddevice.h"
/**
* @brief A thread for refreshing the total list of devices on the system
*
@@ -62,6 +64,8 @@ public:
bool IsRefreshing();
void PushToOutput(const QByteArray& samples);
/**
* @brief Start playing audio from QIODevice
*
@@ -93,9 +97,10 @@ private:
static AudioManager* audio_;
AudioHybridDevice output_manager_;
std::unique_ptr<QAudioOutput> output_;
QAudioDeviceInfo output_device_info_;
QIODevice* output_file_;
std::unique_ptr<QAudioInput> input_;
QAudioDeviceInfo input_device_info_;
@@ -108,6 +113,12 @@ private:
private slots:
void RefreshThreadDone();
void OutputManagerHasSamples();
void OutputStateChanged(QAudio::State state);
void OutputNotified();
};
#endif // AUDIOMANAGER_H