Files
MuditaOS/module-audio/Audio/AudioMux.cpp
Hubert Chrzaniuk 6b36d35507 [EGD-5009] Change messy callback logic in audio module
Refactor audio module to use only one callback for communication
with audio service. This also simplifies the logic and removes
necessity to define defaults for audio values in multiple places.
2020-12-18 14:52:57 +01:00

165 lines
5.6 KiB
C++

// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
#include "AudioMux.hpp"
#include "Audio.hpp"
namespace audio
{
namespace
{
const std::map<PlaybackType, uint8_t> PlaybackTypePriority = {
{PlaybackType::CallRingtone, 2},
{PlaybackType::TextMessageRingtone, 3},
{PlaybackType::Notifications, 3},
{PlaybackType::Multimedia, 4},
{PlaybackType::KeypadSound, 5},
{PlaybackType::None, static_cast<uint8_t>(PlaybackType::Last)},
};
} // namespace
AudioMux::AudioMux(AudioServiceMessage::Callback callback, size_t audioInputsCount)
: audioInputs(audioInputsInternal)
{
audioInputsCount = audioInputsCount > 0 ? audioInputsCount : 1;
audioInputsInternal.reserve(audioInputsCount);
for (size_t i = 0; i < audioInputsCount; i++) {
audioInputsInternal.emplace_back(Input(std::make_unique<Audio>(callback), refToken.IncrementToken()));
}
}
std::optional<AudioMux::Input *> AudioMux::GetRoutingInput(bool force)
{
if (auto input = GetInput({Audio::State::Routing})) {
return input;
}
if (force) {
auto *lowInput = &audioInputs.front();
for (auto &audioInput : audioInputs) {
auto lowestPrio = GetPlaybackPriority(lowInput->audio->GetCurrentOperationPlaybackType());
auto currentPrio = GetPlaybackPriority(audioInput.audio->GetCurrentOperationPlaybackType());
if (currentPrio > lowestPrio) {
lowInput = &audioInput;
}
}
LOG_DEBUG("Routing took over audio input.");
return lowInput;
}
return std::nullopt;
}
std::optional<AudioMux::Input *> AudioMux::GetPlaybackInput(const audio::PlaybackType &playbackType)
{
// if routing or recording we cannot continue
if (GetInput({Audio::State::Routing, Audio::State::Recording})) {
return std::nullopt;
}
// try get with priority
if (auto input = GetAvailableInput(playbackType)) {
return input;
}
return std::nullopt;
}
std::optional<AudioMux::Input *> AudioMux::GetIdleInput()
{
return GetInput({Audio::State::Idle});
}
std::optional<AudioMux::Input *> AudioMux::GetActiveInput()
{
// first return active routing inputs
if (auto routingInput = GetInput({Audio::State::Routing}); routingInput) {
return routingInput;
}
for (auto &audioInput : audioInputs) {
if (audioInput.audio->GetCurrentState() != Audio::State::Idle) {
return &audioInput;
}
}
return std::nullopt;
}
std::optional<AudioMux::Input *> AudioMux::GetInput(const std::vector<Audio::State> &states)
{
for (auto &audioInput : audioInputs) {
if (std::find(states.begin(), states.end(), audioInput.audio->GetCurrentState()) != std::end(states)) {
return &audioInput;
}
}
return std::nullopt;
}
std::optional<AudioMux::Input *> AudioMux::GetInput(const Token &token)
{
if (!token.IsValid()) {
return std::nullopt;
}
for (auto &audioInput : audioInputs) {
// if has token - match or reject
if (token == audioInput.token) {
return &audioInput;
}
}
return std::nullopt;
}
std::optional<AudioMux::Input *> AudioMux::GetAvailableInput(const audio::PlaybackType &playbackType)
{
std::optional<AudioMux::Input *> idleInput;
std::optional<AudioMux::Input *> overridableInput;
for (auto &audioInput : audioInputs) {
auto currentPlaybackType = audioInput.audio->GetCurrentOperationPlaybackType();
auto currentInputPrior = GetPlaybackPriority(currentPlaybackType);
// check busy input
if (audioInput.audio->GetCurrentState() != Audio::State::Idle) {
// handle priorities
if (GetPlaybackPriority(playbackType) > currentInputPrior) {
return std::nullopt;
}
else if (GetPlaybackPriority(playbackType) <= currentInputPrior) {
if (currentPlaybackType == playbackType && IsMergable(currentPlaybackType)) {
// merge the sound if needed
overridableInput = std::nullopt;
break;
}
overridableInput = &audioInput;
}
}
else {
idleInput = &audioInput;
}
}
return idleInput ? idleInput : overridableInput;
}
const Token AudioMux::ResetInput(std::optional<AudioMux::Input *> input)
{
if (input) {
(*input)->DisableVibration();
return (*input)->token = refToken.IncrementToken();
}
return refToken.IncrementToken();
}
uint8_t AudioMux::GetPlaybackPriority(const std::optional<audio::PlaybackType> type)
{
const auto &pmap = audio::PlaybackTypePriority;
if (type && pmap.find(*type) != pmap.end()) {
return pmap.at(*type);
}
return static_cast<uint8_t>(PlaybackType::Last);
}
constexpr bool AudioMux::IsMergable(const audio::PlaybackType &type) const
{
return !(type == audio::PlaybackType::Multimedia);
}
} // namespace audio