// Copyright (c) 2017-2024, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/blob/master/LICENSE.md
#include "Audio.hpp"
#include "Operation/Operation.hpp"
#include <log/log.hpp>
#include <bsp/headset/headset.hpp>
namespace audio
{
Audio::Audio(AudioServiceMessage::Callback callback) : currentOperation(), serviceCallback(std::move(callback))
{
auto ret = Operation::Create(
Operation::Type::Idle, "", audio::PlaybackType::None, audio::PlaybackMode::Single, serviceCallback);
if (ret) {
currentOperation = std::move(ret);
}
audioSinkState.setConnected(EventType::JackState, bsp::headset::IsInserted());
}
Position Audio::GetPosition()
{
return currentOperation->GetPosition();
}
audio::RetCode Audio::SendEvent(std::shared_ptr<Event> evt)
{
audioSinkState.UpdateState(evt);
UpdateProfiles();
return currentOperation->SendEvent(std::move(evt));
}
audio::RetCode Audio::SetOutputVolume(float vol)
{
return currentOperation->SetOutputVolume(static_cast<float>(vol));
}
audio::RetCode Audio::SetInputGain(Gain gain)
{
auto gainToSet = gain;
if (gain > maxGain) {
gainToSet = maxGain;
}
if (gain < minGain) {
gainToSet = minGain;
}
return currentOperation->SetInputGain(gainToSet);
}
audio::RetCode Audio::Start(Operation::Type op,
audio::Token token,
const std::string &filePath,
const audio::PlaybackType &playbackType,
const audio::PlaybackMode &playbackMode)
{
try {
auto ret = Operation::Create(op, filePath, playbackType, playbackMode, serviceCallback);
switch (op) {
case Operation::Type::Playback:
currentState = State::Playback;
break;
case Operation::Type::Recorder:
currentState = State::Recording;
break;
case Operation::Type::Router:
currentState = State::Routing;
break;
case Operation::Type::Idle:
break;
}
currentOperation = std::move(ret);
UpdateProfiles(playbackType);
}
catch (const AudioInitException &audioException) {
// If creating operation failed fallback to IdleOperation which is guaranteed to work
LOG_ERROR(
"Failed to create operation type %s, error message: %s", Operation::c_str(op), audioException.what());
currentOperation = Operation::Create(Operation::Type::Idle);
currentState = State::Idle;
return audioException.getErrorCode();
}
return currentOperation->Start(token);
}
audio::RetCode Audio::Start()
{
if (currentState != State::Idle) {
currentOperation->Stop();
}
return Start(currentOperation->GetOperationType(),
currentOperation->GetToken(),
currentOperation->GetFilePath(),
currentOperation->GetPlaybackType());
}
audio::RetCode Audio::Stop()
{
if (currentState == State::Idle) {
return RetCode::Success;
}
auto retStop = currentOperation->Stop();
if (retStop != RetCode::Success) {
LOG_ERROR("Operation STOP failure: %s", audio::str(retStop).c_str());
}
muted = Muted::False;
auto ret = Operation::Create(Operation::Type::Idle);
if (ret) {
currentState = State::Idle;
currentOperation = std::move(ret);
return RetCode::Success;
}
else {
return RetCode::OperationCreateFailed;
}
}
audio::RetCode Audio::Pause()
{
if (currentState == State::Idle) {
return RetCode::InvokedInIncorrectState;
}
return currentOperation->Pause();
}
audio::RetCode Audio::Resume()
{
if (currentState == State::Idle) {
return RetCode::InvokedInIncorrectState;
}
return currentOperation->Resume();
}
audio::RetCode Audio::Mute()
{
muted = Muted::True;
return SetOutputVolume(0.0f);
}
void Audio::SendUpdateEventsToCurrentOperation()
{
auto updateEvents = audioSinkState.getUpdateEvents();
for (auto &event : updateEvents) {
currentOperation->SendEvent(event);
}
}
void Audio::UpdateProfiles()
{
SendUpdateEventsToCurrentOperation();
currentOperation->SwitchToPriorityProfile();
}
void Audio::UpdateProfiles(audio::PlaybackType playbackType)
{
SendUpdateEventsToCurrentOperation();
currentOperation->SwitchToPriorityProfile(playbackType);
}
} // namespace audio