mirror of https://github.com/f1xpl/openauto.git
Merge remote-tracking branch 'remotes/origin/feature/audio_enhancements' into development
commit
4623f6b09b
|
@ -32,6 +32,7 @@ find_package(libusb-1.0 REQUIRED)
|
|||
find_package(Qt5 COMPONENTS Multimedia MultimediaWidgets Bluetooth)
|
||||
find_package(Protobuf REQUIRED)
|
||||
find_package(OpenSSL REQUIRED)
|
||||
find_package(rtaudio REQUIRED)
|
||||
|
||||
if(WIN32)
|
||||
set(WINSOCK2_LIBRARIES "ws2_32")
|
||||
|
@ -54,6 +55,7 @@ include_directories(${CMAKE_CURRENT_BINARY_DIR}
|
|||
${LIBUSB_1_INCLUDE_DIRS}
|
||||
${PROTOBUF_INCLUDE_DIR}
|
||||
${OPENSSL_INCLUDE_DIR}
|
||||
${RTAUDIO_INCLUDE_DIRS}
|
||||
${AASDK_PROTO_INCLUDE_DIRS}
|
||||
${AASDK_INCLUDE_DIRS}
|
||||
${BCM_HOST_INCLUDE_DIRS}
|
||||
|
@ -80,6 +82,7 @@ target_link_libraries(autoapp
|
|||
${BCM_HOST_LIBRARIES}
|
||||
${ILCLIENT_LIBRARIES}
|
||||
${WINSOCK2_LIBRARIES}
|
||||
${RTAUDIO_LIBRARIES}
|
||||
${AASDK_PROTO_LIBRARIES}
|
||||
${AASDK_LIBRARIES})
|
||||
|
||||
|
|
|
@ -42,6 +42,7 @@ Copyrights (c) 2018 f1x.studio (Michal Szwaj)
|
|||
- [Boost libraries](http://www.boost.org/)
|
||||
- [Qt libraries](https://www.qt.io/)
|
||||
- [CMake](https://cmake.org/)
|
||||
- [RtAudio](https://www.music.mcgill.ca/~gary/rtaudio/playback.html)
|
||||
- Broadcom ilclient from RaspberryPI 3 firmware
|
||||
- OpenMAX IL API
|
||||
|
||||
|
|
|
@ -0,0 +1,70 @@
|
|||
#
|
||||
# This file is part of openauto project.
|
||||
# Copyright (C) 2018 f1x.studio (Michal Szwaj)
|
||||
#
|
||||
# openauto is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
|
||||
# openauto is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with openauto. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
if (RTAUDIO_LIBRARIES AND RTAUDIO_INCLUDE_DIRS)
|
||||
# in cache already
|
||||
set(RTAUDIO_FOUND TRUE)
|
||||
else (RTAUDIO_LIBRARIES AND RTAUDIO_INCLUDE_DIRS)
|
||||
find_path(RTAUDIO_INCLUDE_DIR
|
||||
NAMES
|
||||
RtAudio.h
|
||||
PATHS
|
||||
/usr/include
|
||||
/usr/local/include
|
||||
/opt/local/include
|
||||
/sw/include
|
||||
PATH_SUFFIXES
|
||||
rtaudio
|
||||
)
|
||||
|
||||
find_library(RTAUDIO_LIBRARY
|
||||
NAMES
|
||||
rtaudio
|
||||
PATHS
|
||||
/usr/lib
|
||||
/usr/local/lib
|
||||
/opt/local/lib
|
||||
/sw/lib
|
||||
)
|
||||
|
||||
set(RTAUDIO_INCLUDE_DIRS
|
||||
${RTAUDIO_INCLUDE_DIR}
|
||||
)
|
||||
set(RTAUDIO_LIBRARIES
|
||||
${RTAUDIO_LIBRARY}
|
||||
)
|
||||
|
||||
if (RTAUDIO_INCLUDE_DIRS AND RTAUDIO_LIBRARIES)
|
||||
set(RTAUDIO_FOUND TRUE)
|
||||
endif (RTAUDIO_INCLUDE_DIRS AND RTAUDIO_LIBRARIES)
|
||||
|
||||
if (RTAUDIO_FOUND)
|
||||
if (NOT rtaudio_FIND_QUIETLY)
|
||||
message(STATUS "Found rtaudio:")
|
||||
message(STATUS " - Includes: ${RTAUDIO_INCLUDE_DIRS}")
|
||||
message(STATUS " - Libraries: ${RTAUDIO_LIBRARIES}")
|
||||
endif (NOT rtaudio_FIND_QUIETLY)
|
||||
else (RTAUDIO_FOUND)
|
||||
if (rtaudio_FIND_REQUIRED)
|
||||
message(FATAL_ERROR "Could not find rtaudio")
|
||||
endif (rtaudio_FIND_REQUIRED)
|
||||
endif (RTAUDIO_FOUND)
|
||||
|
||||
mark_as_advanced(RTAUDIO_INCLUDE_DIRS RTAUDIO_LIBRARIES)
|
||||
|
||||
endif (RTAUDIO_LIBRARIES AND RTAUDIO_INCLUDE_DIRS)
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* This file is part of openauto project.
|
||||
* Copyright (C) 2018 f1x.studio (Michal Szwaj)
|
||||
*
|
||||
* openauto is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
|
||||
* openauto is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with openauto. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace f1x
|
||||
{
|
||||
namespace openauto
|
||||
{
|
||||
namespace autoapp
|
||||
{
|
||||
namespace configuration
|
||||
{
|
||||
|
||||
enum class AudioOutputBackendType
|
||||
{
|
||||
RTAUDIO,
|
||||
QT
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -69,6 +69,8 @@ public:
|
|||
void setMusicAudioChannelEnabled(bool value) override;
|
||||
bool speechAudioChannelEnabled() const override;
|
||||
void setSpeechAudioChannelEnabled(bool value) override;
|
||||
AudioOutputBackendType getAudioOutputBackendType() const override;
|
||||
void setAudioOutputBackendType(AudioOutputBackendType value) override;
|
||||
|
||||
private:
|
||||
void readButtonCodes(boost::property_tree::ptree& iniConfig);
|
||||
|
@ -88,6 +90,7 @@ private:
|
|||
std::string bluetoothRemoteAdapterAddress_;
|
||||
bool musicAudioChannelEnabled_;
|
||||
bool speechAudiochannelEnabled_;
|
||||
AudioOutputBackendType audioOutputBackendType_;
|
||||
|
||||
static const std::string cConfigFileName;
|
||||
|
||||
|
@ -103,6 +106,7 @@ private:
|
|||
|
||||
static const std::string cAudioMusicAudioChannelEnabled;
|
||||
static const std::string cAudioSpeechAudioChannelEnabled;
|
||||
static const std::string cAudioOutputBackendType;
|
||||
|
||||
static const std::string cBluetoothAdapterTypeKey;
|
||||
static const std::string cBluetoothRemoteAdapterAddressKey;
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#include <aasdk_proto/ButtonCodeEnum.pb.h>
|
||||
#include <f1x/openauto/autoapp/Configuration/BluetootAdapterType.hpp>
|
||||
#include <f1x/openauto/autoapp/Configuration/HandednessOfTrafficType.hpp>
|
||||
#include <f1x/openauto/autoapp/Configuration/AudioOutputBackendType.hpp>
|
||||
|
||||
namespace f1x
|
||||
{
|
||||
|
@ -77,6 +78,8 @@ public:
|
|||
virtual void setMusicAudioChannelEnabled(bool value) = 0;
|
||||
virtual bool speechAudioChannelEnabled() const = 0;
|
||||
virtual void setSpeechAudioChannelEnabled(bool value) = 0;
|
||||
virtual AudioOutputBackendType getAudioOutputBackendType() const = 0;
|
||||
virtual void setAudioOutputBackendType(AudioOutputBackendType value) = 0;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <f1x/aasdk/Messenger/Timestamp.hpp>
|
||||
#include <f1x/aasdk/Common/Data.hpp>
|
||||
|
||||
namespace f1x
|
||||
|
@ -39,7 +40,7 @@ public:
|
|||
virtual ~IAudioOutput() = default;
|
||||
|
||||
virtual bool open() = 0;
|
||||
virtual void write(const aasdk::common::DataConstBuffer& buffer) = 0;
|
||||
virtual void write(aasdk::messenger::Timestamp::ValueType timestamp, const aasdk::common::DataConstBuffer& buffer) = 0;
|
||||
virtual void start() = 0;
|
||||
virtual void stop() = 0;
|
||||
virtual void suspend() = 0;
|
||||
|
|
|
@ -32,11 +32,11 @@ namespace autoapp
|
|||
namespace projection
|
||||
{
|
||||
|
||||
class AudioInput: public QObject, public IAudioInput
|
||||
class QtAudioInput: public QObject, public IAudioInput
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
AudioInput(uint32_t channelCount, uint32_t sampleSize, uint32_t sampleRate);
|
||||
QtAudioInput(uint32_t channelCount, uint32_t sampleSize, uint32_t sampleRate);
|
||||
|
||||
bool open() override;
|
||||
bool isActive() const override;
|
|
@ -32,14 +32,14 @@ namespace autoapp
|
|||
namespace projection
|
||||
{
|
||||
|
||||
class AudioOutput: public QObject, public IAudioOutput
|
||||
class QtAudioOutput: public QObject, public IAudioOutput
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
AudioOutput(uint32_t channelCount, uint32_t sampleSize, uint32_t sampleRate);
|
||||
QtAudioOutput(uint32_t channelCount, uint32_t sampleSize, uint32_t sampleRate);
|
||||
bool open() override;
|
||||
void write(const aasdk::common::DataConstBuffer& buffer) override;
|
||||
void write(aasdk::messenger::Timestamp::ValueType, const aasdk::common::DataConstBuffer& buffer) override;
|
||||
void start() override;
|
||||
void stop() override;
|
||||
void suspend() override;
|
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
* This file is part of openauto project.
|
||||
* Copyright (C) 2018 f1x.studio (Michal Szwaj)
|
||||
*
|
||||
* openauto is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
|
||||
* openauto is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with openauto. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <RtAudio.h>
|
||||
#include <f1x/openauto/autoapp/Projection/IAudioOutput.hpp>
|
||||
#include <f1x/openauto/autoapp/Projection/SequentialBuffer.hpp>
|
||||
|
||||
namespace f1x
|
||||
{
|
||||
namespace openauto
|
||||
{
|
||||
namespace autoapp
|
||||
{
|
||||
namespace projection
|
||||
{
|
||||
|
||||
class RtAudioOutput: public IAudioOutput
|
||||
{
|
||||
public:
|
||||
RtAudioOutput(uint32_t channelCount, uint32_t sampleSize, uint32_t sampleRate);
|
||||
bool open() override;
|
||||
void write(aasdk::messenger::Timestamp::ValueType timestamp, const aasdk::common::DataConstBuffer& buffer) override;
|
||||
void start() override;
|
||||
void stop() override;
|
||||
void suspend() override;
|
||||
uint32_t getSampleSize() const override;
|
||||
uint32_t getChannelCount() const override;
|
||||
uint32_t getSampleRate() const override;
|
||||
|
||||
private:
|
||||
void doSuspend();
|
||||
static int audioBufferReadHandler(void* outputBuffer, void* inputBuffer, unsigned int nBufferFrames,
|
||||
double streamTime, RtAudioStreamStatus status, void* userData);
|
||||
|
||||
uint32_t channelCount_;
|
||||
uint32_t sampleSize_;
|
||||
uint32_t sampleRate_;
|
||||
SequentialBuffer audioBuffer_;
|
||||
std::unique_ptr<RtAudio> dac_;
|
||||
std::mutex mutex_;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -40,6 +40,7 @@ private:
|
|||
IService::Pointer createVideoService(aasdk::messenger::IMessenger::Pointer messenger);
|
||||
IService::Pointer createBluetoothService(aasdk::messenger::IMessenger::Pointer messenger);
|
||||
IService::Pointer createInputService(aasdk::messenger::IMessenger::Pointer messenger);
|
||||
void createAudioServices(ServiceList& serviceList, aasdk::messenger::IMessenger::Pointer messenger);
|
||||
|
||||
boost::asio::io_service& ioService_;
|
||||
configuration::IConfiguration::Pointer configuration_;
|
||||
|
|
|
@ -42,6 +42,7 @@ const std::string Configuration::cVideoMarginHeight = "Video.MarginHeight";
|
|||
|
||||
const std::string Configuration::cAudioMusicAudioChannelEnabled = "Audio.MusicAudioChannelEnabled";
|
||||
const std::string Configuration::cAudioSpeechAudioChannelEnabled = "Audio.SpeechAudioChannelEnabled";
|
||||
const std::string Configuration::cAudioOutputBackendType = "Audio.OutputBackendType";
|
||||
|
||||
const std::string Configuration::cBluetoothAdapterTypeKey = "Bluetooth.AdapterType";
|
||||
const std::string Configuration::cBluetoothRemoteAdapterAddressKey = "Bluetooth.RemoteAdapterAddress";
|
||||
|
@ -101,6 +102,7 @@ void Configuration::load()
|
|||
|
||||
musicAudioChannelEnabled_ = iniConfig.get<bool>(cAudioMusicAudioChannelEnabled, true);
|
||||
speechAudiochannelEnabled_ = iniConfig.get<bool>(cAudioSpeechAudioChannelEnabled, true);
|
||||
audioOutputBackendType_ = static_cast<AudioOutputBackendType>(iniConfig.get<uint32_t>(cAudioOutputBackendType, static_cast<uint32_t>(AudioOutputBackendType::RTAUDIO)));
|
||||
}
|
||||
catch(const boost::property_tree::ini_parser_error& e)
|
||||
{
|
||||
|
@ -126,6 +128,7 @@ void Configuration::reset()
|
|||
bluetoothRemoteAdapterAddress_ = "";
|
||||
musicAudioChannelEnabled_ = true;
|
||||
speechAudiochannelEnabled_ = true;
|
||||
audioOutputBackendType_ = AudioOutputBackendType::RTAUDIO;
|
||||
}
|
||||
|
||||
void Configuration::save()
|
||||
|
@ -149,6 +152,7 @@ void Configuration::save()
|
|||
|
||||
iniConfig.put<bool>(cAudioMusicAudioChannelEnabled, musicAudioChannelEnabled_);
|
||||
iniConfig.put<bool>(cAudioSpeechAudioChannelEnabled, speechAudiochannelEnabled_);
|
||||
iniConfig.put<uint32_t>(cAudioOutputBackendType, static_cast<uint32_t>(audioOutputBackendType_));
|
||||
boost::property_tree::ini_parser::write_ini(cConfigFileName, iniConfig);
|
||||
}
|
||||
|
||||
|
@ -282,6 +286,16 @@ void Configuration::setSpeechAudioChannelEnabled(bool value)
|
|||
speechAudiochannelEnabled_ = value;
|
||||
}
|
||||
|
||||
AudioOutputBackendType Configuration::getAudioOutputBackendType() const
|
||||
{
|
||||
return audioOutputBackendType_;
|
||||
}
|
||||
|
||||
void Configuration::setAudioOutputBackendType(AudioOutputBackendType value)
|
||||
{
|
||||
audioOutputBackendType_ = value;
|
||||
}
|
||||
|
||||
void Configuration::readButtonCodes(boost::property_tree::ptree& iniConfig)
|
||||
{
|
||||
this->insertButtonCode(iniConfig, cInputPlayButtonKey, aasdk::proto::enums::ButtonCode::PLAY);
|
||||
|
|
|
@ -93,6 +93,12 @@ void AudioService::onChannelOpenRequest(const aasdk::proto::messages::ChannelOpe
|
|||
OPENAUTO_LOG(info) << "[AudioService] open request"
|
||||
<< ", channel: " << aasdk::messenger::channelIdToString(channel_->getId())
|
||||
<< ", priority: " << request.priority();
|
||||
|
||||
OPENAUTO_LOG(debug) << "[AudioService] channel: " << aasdk::messenger::channelIdToString(channel_->getId())
|
||||
<< " audio output sample rate: " << audioOutput_->getSampleRate()
|
||||
<< ", sample size: " << audioOutput_->getSampleSize()
|
||||
<< ", channel count: " << audioOutput_->getChannelCount();
|
||||
|
||||
const aasdk::proto::enums::Status::Enum status = audioOutput_->open() ? aasdk::proto::enums::Status::OK : aasdk::proto::enums::Status::FAIL;
|
||||
OPENAUTO_LOG(info) << "[AudioService] open status: " << status
|
||||
<< ", channel: " << aasdk::messenger::channelIdToString(channel_->getId());
|
||||
|
@ -146,14 +152,9 @@ void AudioService::onAVChannelStopIndication(const aasdk::proto::messages::AVCha
|
|||
channel_->receive(this->shared_from_this());
|
||||
}
|
||||
|
||||
void AudioService::onAVMediaWithTimestampIndication(aasdk::messenger::Timestamp::ValueType, const aasdk::common::DataConstBuffer& buffer)
|
||||
void AudioService::onAVMediaWithTimestampIndication(aasdk::messenger::Timestamp::ValueType timestamp, const aasdk::common::DataConstBuffer& buffer)
|
||||
{
|
||||
this->onAVMediaIndication(buffer);
|
||||
}
|
||||
|
||||
void AudioService::onAVMediaIndication(const aasdk::common::DataConstBuffer& buffer)
|
||||
{
|
||||
audioOutput_->write(buffer);
|
||||
audioOutput_->write(timestamp, buffer);
|
||||
aasdk::proto::messages::AVMediaAckIndication indication;
|
||||
indication.set_session(session_);
|
||||
indication.set_value(1);
|
||||
|
@ -164,6 +165,11 @@ void AudioService::onAVMediaIndication(const aasdk::common::DataConstBuffer& buf
|
|||
channel_->receive(this->shared_from_this());
|
||||
}
|
||||
|
||||
void AudioService::onAVMediaIndication(const aasdk::common::DataConstBuffer& buffer)
|
||||
{
|
||||
this->onAVMediaWithTimestampIndication(0, buffer);
|
||||
}
|
||||
|
||||
void AudioService::onChannelError(const aasdk::error::Error& e)
|
||||
{
|
||||
OPENAUTO_LOG(error) << "[AudioService] channel error: " << e.what()
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
*/
|
||||
|
||||
#include <QApplication>
|
||||
#include <f1x/openauto/autoapp/Projection/AudioInput.hpp>
|
||||
#include <f1x/openauto/autoapp/Projection/QtAudioInput.hpp>
|
||||
#include <f1x/openauto/Common/Log.hpp>
|
||||
|
||||
namespace f1x
|
||||
|
@ -29,7 +29,7 @@ namespace autoapp
|
|||
namespace projection
|
||||
{
|
||||
|
||||
AudioInput::AudioInput(uint32_t channelCount, uint32_t sampleSize, uint32_t sampleRate)
|
||||
QtAudioInput::QtAudioInput(uint32_t channelCount, uint32_t sampleSize, uint32_t sampleRate)
|
||||
: ioDevice_(nullptr)
|
||||
{
|
||||
qRegisterMetaType<IAudioInput::StartPromise::Pointer>("StartPromise::Pointer");
|
||||
|
@ -42,32 +42,32 @@ AudioInput::AudioInput(uint32_t channelCount, uint32_t sampleSize, uint32_t samp
|
|||
audioFormat_.setSampleType(QAudioFormat::SignedInt);
|
||||
|
||||
this->moveToThread(QApplication::instance()->thread());
|
||||
connect(this, &AudioInput::startRecording, this, &AudioInput::onStartRecording, Qt::QueuedConnection);
|
||||
connect(this, &AudioInput::stopRecording, this, &AudioInput::onStopRecording, Qt::QueuedConnection);
|
||||
connect(this, &QtAudioInput::startRecording, this, &QtAudioInput::onStartRecording, Qt::QueuedConnection);
|
||||
connect(this, &QtAudioInput::stopRecording, this, &QtAudioInput::onStopRecording, Qt::QueuedConnection);
|
||||
QMetaObject::invokeMethod(this, "createAudioInput", Qt::BlockingQueuedConnection);
|
||||
}
|
||||
|
||||
void AudioInput::createAudioInput()
|
||||
void QtAudioInput::createAudioInput()
|
||||
{
|
||||
OPENAUTO_LOG(debug) << "[AudioInput] create.";
|
||||
audioInput_ = (std::make_unique<QAudioInput>(QAudioDeviceInfo::defaultInputDevice(), audioFormat_));
|
||||
}
|
||||
|
||||
bool AudioInput::open()
|
||||
bool QtAudioInput::open()
|
||||
{
|
||||
std::lock_guard<decltype(mutex_)> lock(mutex_);
|
||||
|
||||
return ioDevice_ == nullptr;
|
||||
}
|
||||
|
||||
bool AudioInput::isActive() const
|
||||
bool QtAudioInput::isActive() const
|
||||
{
|
||||
std::lock_guard<decltype(mutex_)> lock(mutex_);
|
||||
|
||||
return ioDevice_ != nullptr;
|
||||
}
|
||||
|
||||
void AudioInput::read(ReadPromise::Pointer promise)
|
||||
void QtAudioInput::read(ReadPromise::Pointer promise)
|
||||
{
|
||||
std::lock_guard<decltype(mutex_)> lock(mutex_);
|
||||
|
||||
|
@ -85,32 +85,32 @@ void AudioInput::read(ReadPromise::Pointer promise)
|
|||
}
|
||||
}
|
||||
|
||||
void AudioInput::start(StartPromise::Pointer promise)
|
||||
void QtAudioInput::start(StartPromise::Pointer promise)
|
||||
{
|
||||
emit startRecording(std::move(promise));
|
||||
}
|
||||
|
||||
void AudioInput::stop()
|
||||
void QtAudioInput::stop()
|
||||
{
|
||||
emit stopRecording();
|
||||
}
|
||||
|
||||
uint32_t AudioInput::getSampleSize() const
|
||||
uint32_t QtAudioInput::getSampleSize() const
|
||||
{
|
||||
return audioFormat_.sampleSize();
|
||||
}
|
||||
|
||||
uint32_t AudioInput::getChannelCount() const
|
||||
uint32_t QtAudioInput::getChannelCount() const
|
||||
{
|
||||
return audioFormat_.channelCount();
|
||||
}
|
||||
|
||||
uint32_t AudioInput::getSampleRate() const
|
||||
uint32_t QtAudioInput::getSampleRate() const
|
||||
{
|
||||
return audioFormat_.sampleRate();
|
||||
}
|
||||
|
||||
void AudioInput::onStartRecording(StartPromise::Pointer promise)
|
||||
void QtAudioInput::onStartRecording(StartPromise::Pointer promise)
|
||||
{
|
||||
std::lock_guard<decltype(mutex_)> lock(mutex_);
|
||||
|
||||
|
@ -118,7 +118,7 @@ void AudioInput::onStartRecording(StartPromise::Pointer promise)
|
|||
|
||||
if(ioDevice_ != nullptr)
|
||||
{
|
||||
connect(ioDevice_, &QIODevice::readyRead, this, &AudioInput::onReadyRead, Qt::QueuedConnection);
|
||||
connect(ioDevice_, &QIODevice::readyRead, this, &QtAudioInput::onReadyRead, Qt::QueuedConnection);
|
||||
promise->resolve();
|
||||
}
|
||||
else
|
||||
|
@ -127,7 +127,7 @@ void AudioInput::onStartRecording(StartPromise::Pointer promise)
|
|||
}
|
||||
}
|
||||
|
||||
void AudioInput::onStopRecording()
|
||||
void QtAudioInput::onStopRecording()
|
||||
{
|
||||
std::lock_guard<decltype(mutex_)> lock(mutex_);
|
||||
|
||||
|
@ -147,7 +147,7 @@ void AudioInput::onStopRecording()
|
|||
audioInput_->stop();
|
||||
}
|
||||
|
||||
void AudioInput::onReadyRead()
|
||||
void QtAudioInput::onReadyRead()
|
||||
{
|
||||
std::lock_guard<decltype(mutex_)> lock(mutex_);
|
||||
|
|
@ -17,7 +17,7 @@
|
|||
*/
|
||||
|
||||
#include <QApplication>
|
||||
#include <f1x/openauto/autoapp/Projection/AudioOutput.hpp>
|
||||
#include <f1x/openauto/autoapp/Projection/QtAudioOutput.hpp>
|
||||
#include <f1x/openauto/Common/Log.hpp>
|
||||
|
||||
namespace f1x
|
||||
|
@ -29,7 +29,7 @@ namespace autoapp
|
|||
namespace projection
|
||||
{
|
||||
|
||||
AudioOutput::AudioOutput(uint32_t channelCount, uint32_t sampleSize, uint32_t sampleRate)
|
||||
QtAudioOutput::QtAudioOutput(uint32_t channelCount, uint32_t sampleSize, uint32_t sampleRate)
|
||||
: playbackStarted_(false)
|
||||
{
|
||||
audioFormat_.setChannelCount(channelCount);
|
||||
|
@ -40,63 +40,60 @@ AudioOutput::AudioOutput(uint32_t channelCount, uint32_t sampleSize, uint32_t sa
|
|||
audioFormat_.setSampleType(QAudioFormat::SignedInt);
|
||||
|
||||
this->moveToThread(QApplication::instance()->thread());
|
||||
connect(this, &AudioOutput::startPlayback, this, &AudioOutput::onStartPlayback);
|
||||
connect(this, &AudioOutput::suspendPlayback, this, &AudioOutput::onSuspendPlayback);
|
||||
connect(this, &AudioOutput::stopPlayback, this, &AudioOutput::onStopPlayback);
|
||||
connect(this, &QtAudioOutput::startPlayback, this, &QtAudioOutput::onStartPlayback);
|
||||
connect(this, &QtAudioOutput::suspendPlayback, this, &QtAudioOutput::onSuspendPlayback);
|
||||
connect(this, &QtAudioOutput::stopPlayback, this, &QtAudioOutput::onStopPlayback);
|
||||
|
||||
QMetaObject::invokeMethod(this, "createAudioOutput", Qt::BlockingQueuedConnection);
|
||||
}
|
||||
|
||||
void AudioOutput::createAudioOutput()
|
||||
void QtAudioOutput::createAudioOutput()
|
||||
{
|
||||
OPENAUTO_LOG(debug) << "[AudioOutput] create.";
|
||||
OPENAUTO_LOG(debug) << "[QtAudioOutput] create.";
|
||||
audioOutput_ = std::make_unique<QAudioOutput>(QAudioDeviceInfo::defaultOutputDevice(), audioFormat_);
|
||||
|
||||
// Default volume level (max) produces crackles
|
||||
audioOutput_->setVolume(static_cast<qreal>(0.90));
|
||||
}
|
||||
|
||||
bool AudioOutput::open()
|
||||
bool QtAudioOutput::open()
|
||||
{
|
||||
return audioBuffer_.open(QIODevice::ReadWrite);
|
||||
}
|
||||
|
||||
void AudioOutput::write(const aasdk::common::DataConstBuffer& buffer)
|
||||
void QtAudioOutput::write(aasdk::messenger::Timestamp::ValueType, const aasdk::common::DataConstBuffer& buffer)
|
||||
{
|
||||
audioBuffer_.write(reinterpret_cast<const char*>(buffer.cdata), buffer.size);
|
||||
}
|
||||
|
||||
void AudioOutput::start()
|
||||
void QtAudioOutput::start()
|
||||
{
|
||||
emit startPlayback();
|
||||
}
|
||||
|
||||
void AudioOutput::stop()
|
||||
void QtAudioOutput::stop()
|
||||
{
|
||||
emit stopPlayback();
|
||||
}
|
||||
|
||||
void AudioOutput::suspend()
|
||||
void QtAudioOutput::suspend()
|
||||
{
|
||||
emit suspendPlayback();
|
||||
}
|
||||
|
||||
uint32_t AudioOutput::getSampleSize() const
|
||||
uint32_t QtAudioOutput::getSampleSize() const
|
||||
{
|
||||
return audioFormat_.sampleSize();
|
||||
}
|
||||
|
||||
uint32_t AudioOutput::getChannelCount() const
|
||||
uint32_t QtAudioOutput::getChannelCount() const
|
||||
{
|
||||
return audioFormat_.channelCount();
|
||||
}
|
||||
|
||||
uint32_t AudioOutput::getSampleRate() const
|
||||
uint32_t QtAudioOutput::getSampleRate() const
|
||||
{
|
||||
return audioFormat_.sampleRate();
|
||||
}
|
||||
|
||||
void AudioOutput::onStartPlayback()
|
||||
void QtAudioOutput::onStartPlayback()
|
||||
{
|
||||
if(!playbackStarted_)
|
||||
{
|
||||
|
@ -109,12 +106,12 @@ void AudioOutput::onStartPlayback()
|
|||
}
|
||||
}
|
||||
|
||||
void AudioOutput::onSuspendPlayback()
|
||||
void QtAudioOutput::onSuspendPlayback()
|
||||
{
|
||||
audioOutput_->suspend();
|
||||
}
|
||||
|
||||
void AudioOutput::onStopPlayback()
|
||||
void QtAudioOutput::onStopPlayback()
|
||||
{
|
||||
if(playbackStarted_)
|
||||
{
|
|
@ -0,0 +1,155 @@
|
|||
/*
|
||||
* This file is part of openauto project.
|
||||
* Copyright (C) 2018 f1x.studio (Michal Szwaj)
|
||||
*
|
||||
* openauto is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
|
||||
* openauto is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with openauto. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <f1x/openauto/autoapp/Projection/RtAudioOutput.hpp>
|
||||
#include <f1x/openauto/Common/Log.hpp>
|
||||
|
||||
namespace f1x
|
||||
{
|
||||
namespace openauto
|
||||
{
|
||||
namespace autoapp
|
||||
{
|
||||
namespace projection
|
||||
{
|
||||
|
||||
RtAudioOutput::RtAudioOutput(uint32_t channelCount, uint32_t sampleSize, uint32_t sampleRate)
|
||||
: channelCount_(channelCount)
|
||||
, sampleSize_(sampleSize)
|
||||
, sampleRate_(sampleRate)
|
||||
{
|
||||
std::vector<RtAudio::Api> apis;
|
||||
RtAudio::getCompiledApi(apis);
|
||||
dac_ = std::find(apis.begin(), apis.end(), RtAudio::LINUX_PULSE) == apis.end() ? std::make_unique<RtAudio>() : std::make_unique<RtAudio>(RtAudio::LINUX_PULSE);
|
||||
}
|
||||
|
||||
bool RtAudioOutput::open()
|
||||
{
|
||||
std::lock_guard<decltype(mutex_)> lock(mutex_);
|
||||
|
||||
if(dac_->getDeviceCount() > 0)
|
||||
{
|
||||
RtAudio::StreamParameters parameters;
|
||||
parameters.deviceId = dac_->getDefaultOutputDevice();
|
||||
parameters.nChannels = channelCount_;
|
||||
parameters.firstChannel = 0;
|
||||
|
||||
try
|
||||
{
|
||||
uint32_t bufferFrames = 128;
|
||||
dac_->openStream(¶meters, nullptr, RTAUDIO_SINT16, sampleRate_, &bufferFrames, &RtAudioOutput::audioBufferReadHandler, static_cast<void*>(this), nullptr);
|
||||
return audioBuffer_.open(QIODevice::ReadWrite);
|
||||
}
|
||||
catch(const RtAudioError& e)
|
||||
{
|
||||
OPENAUTO_LOG(error) << "[RtAudioOutput] Failed to open audio output, what: " << e.what();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
OPENAUTO_LOG(error) << "[RtAudioOutput] No output devices found.";
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void RtAudioOutput::write(aasdk::messenger::Timestamp::ValueType timestamp, const aasdk::common::DataConstBuffer& buffer)
|
||||
{
|
||||
audioBuffer_.write(reinterpret_cast<const char*>(buffer.cdata), buffer.size);
|
||||
}
|
||||
|
||||
void RtAudioOutput::start()
|
||||
{
|
||||
std::lock_guard<decltype(mutex_)> lock(mutex_);
|
||||
|
||||
if(dac_->isStreamOpen() && !dac_->isStreamRunning())
|
||||
{
|
||||
try
|
||||
{
|
||||
dac_->startStream();
|
||||
}
|
||||
catch(const RtAudioError& e)
|
||||
{
|
||||
OPENAUTO_LOG(error) << "[RtAudioOutput] Failed to start audio output, what: " << e.what();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RtAudioOutput::stop()
|
||||
{
|
||||
std::lock_guard<decltype(mutex_)> lock(mutex_);
|
||||
|
||||
this->doSuspend();
|
||||
|
||||
if(dac_->isStreamOpen())
|
||||
{
|
||||
dac_->closeStream();
|
||||
}
|
||||
}
|
||||
|
||||
void RtAudioOutput::suspend()
|
||||
{
|
||||
std::lock_guard<decltype(mutex_)> lock(mutex_);
|
||||
this->doSuspend();
|
||||
}
|
||||
|
||||
uint32_t RtAudioOutput::getSampleSize() const
|
||||
{
|
||||
return sampleSize_;
|
||||
}
|
||||
|
||||
uint32_t RtAudioOutput::getChannelCount() const
|
||||
{
|
||||
return channelCount_;
|
||||
}
|
||||
|
||||
uint32_t RtAudioOutput::getSampleRate() const
|
||||
{
|
||||
return sampleRate_;
|
||||
}
|
||||
|
||||
void RtAudioOutput::doSuspend()
|
||||
{
|
||||
if(!dac_->isStreamOpen() && !dac_->isStreamRunning())
|
||||
{
|
||||
try
|
||||
{
|
||||
dac_->stopStream();
|
||||
}
|
||||
catch(const RtAudioError& e)
|
||||
{
|
||||
OPENAUTO_LOG(error) << "[RtAudioOutput] Failed to suspend audio output, what: " << e.what();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int RtAudioOutput::audioBufferReadHandler(void* outputBuffer, void* inputBuffer, unsigned int nBufferFrames,
|
||||
double streamTime, RtAudioStreamStatus status, void* userData)
|
||||
{
|
||||
RtAudioOutput* self = static_cast<RtAudioOutput*>(userData);
|
||||
std::lock_guard<decltype(self->mutex_)> lock(self->mutex_);
|
||||
|
||||
const auto bufferSize = nBufferFrames * (self->sampleSize_ / 8) * self->channelCount_;
|
||||
self->audioBuffer_.read(reinterpret_cast<char*>(outputBuffer), bufferSize);
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -32,8 +32,9 @@
|
|||
#include <f1x/openauto/autoapp/Projection/InputService.hpp>
|
||||
#include <f1x/openauto/autoapp/Projection/QtVideoOutput.hpp>
|
||||
#include <f1x/openauto/autoapp/Projection/OMXVideoOutput.hpp>
|
||||
#include <f1x/openauto/autoapp/Projection/AudioOutput.hpp>
|
||||
#include <f1x/openauto/autoapp/Projection/AudioInput.hpp>
|
||||
#include <f1x/openauto/autoapp/Projection/RtAudioOutput.hpp>
|
||||
#include <f1x/openauto/autoapp/Projection/QtAudioOutput.hpp>
|
||||
#include <f1x/openauto/autoapp/Projection/QtAudioInput.hpp>
|
||||
#include <f1x/openauto/autoapp/Projection/InputDevice.hpp>
|
||||
#include <f1x/openauto/autoapp/Projection/LocalBluetoothDevice.hpp>
|
||||
#include <f1x/openauto/autoapp/Projection/RemoteBluetoothDevice.hpp>
|
||||
|
@ -59,24 +60,9 @@ ServiceList ServiceFactory::create(aasdk::messenger::IMessenger::Pointer messeng
|
|||
{
|
||||
ServiceList serviceList;
|
||||
|
||||
IAudioInput::Pointer audioInput(new AudioInput(1, 16, 16000), std::bind(&QObject::deleteLater, std::placeholders::_1));
|
||||
IAudioInput::Pointer audioInput(new QtAudioInput(1, 16, 16000), std::bind(&QObject::deleteLater, std::placeholders::_1));
|
||||
serviceList.emplace_back(std::make_shared<AudioInputService>(ioService_, messenger, std::move(audioInput)));
|
||||
|
||||
if(configuration_->musicAudioChannelEnabled())
|
||||
{
|
||||
IAudioOutput::Pointer mediaAudioOutput(new AudioOutput(2, 16, 48000), std::bind(&QObject::deleteLater, std::placeholders::_1));
|
||||
serviceList.emplace_back(std::make_shared<MediaAudioService>(ioService_, messenger, std::move(mediaAudioOutput)));
|
||||
}
|
||||
|
||||
if(configuration_->speechAudioChannelEnabled())
|
||||
{
|
||||
IAudioOutput::Pointer speechAudioOutput(new AudioOutput(1, 16, 16000), std::bind(&QObject::deleteLater, std::placeholders::_1));
|
||||
serviceList.emplace_back(std::make_shared<SpeechAudioService>(ioService_, messenger, std::move(speechAudioOutput)));
|
||||
}
|
||||
|
||||
IAudioOutput::Pointer systemAudioOutput(new AudioOutput(1, 16, 16000), std::bind(&QObject::deleteLater, std::placeholders::_1));
|
||||
serviceList.emplace_back(std::make_shared<SystemAudioService>(ioService_, messenger, std::move(systemAudioOutput)));
|
||||
|
||||
this->createAudioServices(serviceList, messenger);
|
||||
serviceList.emplace_back(std::make_shared<SensorService>(ioService_, messenger));
|
||||
serviceList.emplace_back(this->createVideoService(messenger));
|
||||
serviceList.emplace_back(this->createBluetoothService(messenger));
|
||||
|
@ -141,6 +127,33 @@ IService::Pointer ServiceFactory::createInputService(aasdk::messenger::IMessenge
|
|||
return std::make_shared<InputService>(ioService_, messenger, std::move(inputDevice));
|
||||
}
|
||||
|
||||
void ServiceFactory::createAudioServices(ServiceList& serviceList, aasdk::messenger::IMessenger::Pointer messenger)
|
||||
{
|
||||
if(configuration_->musicAudioChannelEnabled())
|
||||
{
|
||||
auto mediaAudioOutput = configuration_->getAudioOutputBackendType() == configuration::AudioOutputBackendType::RTAUDIO ?
|
||||
std::make_shared<RtAudioOutput>(2, 16, 48000) :
|
||||
IAudioOutput::Pointer(new QtAudioOutput(2, 16, 48000), std::bind(&QObject::deleteLater, std::placeholders::_1));
|
||||
|
||||
serviceList.emplace_back(std::make_shared<MediaAudioService>(ioService_, messenger, std::move(mediaAudioOutput)));
|
||||
}
|
||||
|
||||
if(configuration_->speechAudioChannelEnabled())
|
||||
{
|
||||
auto speechAudioOutput = configuration_->getAudioOutputBackendType() == configuration::AudioOutputBackendType::RTAUDIO ?
|
||||
std::make_shared<RtAudioOutput>(1, 16, 16000) :
|
||||
IAudioOutput::Pointer(new QtAudioOutput(1, 16, 16000), std::bind(&QObject::deleteLater, std::placeholders::_1));
|
||||
|
||||
serviceList.emplace_back(std::make_shared<SpeechAudioService>(ioService_, messenger, std::move(speechAudioOutput)));
|
||||
}
|
||||
|
||||
auto systemAudioOutput = configuration_->getAudioOutputBackendType() == configuration::AudioOutputBackendType::RTAUDIO ?
|
||||
std::make_shared<RtAudioOutput>(1, 16, 16000) :
|
||||
IAudioOutput::Pointer(new QtAudioOutput(1, 16, 16000), std::bind(&QObject::deleteLater, std::placeholders::_1));
|
||||
|
||||
serviceList.emplace_back(std::make_shared<SystemAudioService>(ioService_, messenger, std::move(systemAudioOutput)));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -97,6 +97,7 @@ void SettingsWindow::onSave()
|
|||
|
||||
configuration_->setMusicAudioChannelEnabled(ui_->checkBoxMusicAudioChannel->isChecked());
|
||||
configuration_->setSpeechAudioChannelEnabled(ui_->checkBoxSpeechAudioChannel->isChecked());
|
||||
configuration_->setAudioOutputBackendType(ui_->radioButtonRtAudio->isChecked() ? configuration::AudioOutputBackendType::RTAUDIO : configuration::AudioOutputBackendType::QT);
|
||||
|
||||
configuration_->save();
|
||||
this->close();
|
||||
|
@ -149,6 +150,10 @@ void SettingsWindow::load()
|
|||
|
||||
ui_->checkBoxMusicAudioChannel->setChecked(configuration_->musicAudioChannelEnabled());
|
||||
ui_->checkBoxSpeechAudioChannel->setChecked(configuration_->speechAudioChannelEnabled());
|
||||
|
||||
const auto& audioOutputBackendType = configuration_->getAudioOutputBackendType();
|
||||
ui_->radioButtonRtAudio->setChecked(audioOutputBackendType == configuration::AudioOutputBackendType::RTAUDIO);
|
||||
ui_->radioButtonQtAudio->setChecked(audioOutputBackendType == configuration::AudioOutputBackendType::QT);
|
||||
}
|
||||
|
||||
void SettingsWindow::loadButtonCheckBoxes()
|
||||
|
|
|
@ -486,6 +486,45 @@ color: rgb(238, 238, 236);</string>
|
|||
</property>
|
||||
</widget>
|
||||
</widget>
|
||||
<widget class="QGroupBox" name="groupBoxAudioOutputBackend">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>130</y>
|
||||
<width>621</width>
|
||||
<height>61</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>Output backend</string>
|
||||
</property>
|
||||
<widget class="QRadioButton" name="radioButtonRtAudio">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>10</x>
|
||||
<y>30</y>
|
||||
<width>112</width>
|
||||
<height>23</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>RT audio</string>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QRadioButton" name="radioButtonQtAudio">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>140</x>
|
||||
<y>30</y>
|
||||
<width>112</width>
|
||||
<height>23</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Qt</string>
|
||||
</property>
|
||||
</widget>
|
||||
</widget>
|
||||
</widget>
|
||||
<widget class="QWidget" name="tabInput">
|
||||
<attribute name="title">
|
||||
|
@ -969,6 +1008,8 @@ color: rgb(238, 238, 236);</string>
|
|||
<tabstop>horizontalSliderScreenDPI</tabstop>
|
||||
<tabstop>checkBoxMusicAudioChannel</tabstop>
|
||||
<tabstop>checkBoxSpeechAudioChannel</tabstop>
|
||||
<tabstop>radioButtonRtAudio</tabstop>
|
||||
<tabstop>radioButtonQtAudio</tabstop>
|
||||
<tabstop>checkBoxEnableTouchscreen</tabstop>
|
||||
<tabstop>listWidgetButtons</tabstop>
|
||||
<tabstop>checkBoxPlayButton</tabstop>
|
||||
|
|
Loading…
Reference in New Issue