Implementation of audio path manager
This commit is contained in:
parent
a7521ccc5f
commit
6d9ad2b947
|
|
@ -49,6 +49,7 @@ openrtx_src = ['openrtx/src/core/state.c',
|
|||
'openrtx/src/core/datetime.c',
|
||||
'openrtx/src/core/openrtx.c',
|
||||
'openrtx/src/core/audio_codec.c',
|
||||
'openrtx/src/core/audio_path.cpp',
|
||||
'openrtx/src/core/data_conversion.c',
|
||||
'openrtx/src/core/memory_profiling.cpp',
|
||||
'openrtx/src/core/voicePrompts.c',
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@
|
|||
#define AUDIO_PATH_H
|
||||
|
||||
#include <interfaces/audio.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
|
|
@ -41,27 +42,27 @@ typedef int32_t pathId;
|
|||
* with an higher priority.
|
||||
*
|
||||
* @param source: identifier of the input audio peripheral.
|
||||
* @param destination: identifier of the output audio peripheral.
|
||||
* @param sink: identifier of the output audio peripheral.
|
||||
* @param prio: priority of the requester.
|
||||
* @return a unique identifier of the opened path or -1 if path is already in use.
|
||||
*/
|
||||
pathId audioPath_request(enum AudioSource source, enum AudioSink destination,
|
||||
pathId audioPath_request(enum AudioSource source, enum AudioSink sink,
|
||||
enum AudioPriority prio);
|
||||
|
||||
/**
|
||||
* Get the current status of an audio path.
|
||||
*
|
||||
* @param pathId: ID of the audio path.
|
||||
* @param id: ID of the audio path.
|
||||
* @return status of the path queried.
|
||||
*/
|
||||
enum PathStatus audioPath_getStatus(const pathId pathId);
|
||||
enum PathStatus audioPath_getStatus(const pathId id);
|
||||
|
||||
/**
|
||||
* Release an audio path.
|
||||
*
|
||||
* @param pathId: identifier of the path.
|
||||
* @param id: identifier of the path.
|
||||
*/
|
||||
void audioPath_release(const pathId pathId);
|
||||
void audioPath_release(const pathId id);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,184 @@
|
|||
/***************************************************************************
|
||||
* Copyright (C) 2022 by Alain Carlucci, *
|
||||
* Federico Amedeo Izzo IU2NUO, *
|
||||
* Niccolò Izzo IU2KIN *
|
||||
* Silvano Seva IU2KWO *
|
||||
* *
|
||||
* This program 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. *
|
||||
* *
|
||||
* This program 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 this program; if not, see <http://www.gnu.org/licenses/> *
|
||||
***************************************************************************/
|
||||
|
||||
#include <audio_path.h>
|
||||
#include <map>
|
||||
#include <set>
|
||||
|
||||
/**
|
||||
* \internal
|
||||
* Data structure representing an audio path with source, destination and
|
||||
* priority.
|
||||
*/
|
||||
struct Path
|
||||
{
|
||||
int8_t source = -1; ///< Source endpoint of the path.
|
||||
int8_t destination = -1; ///< Destination endpoint of the path.
|
||||
int8_t priority = -1; ///< Path priority level.
|
||||
|
||||
bool isValid() const
|
||||
{
|
||||
return (source != -1) &&
|
||||
(destination != -1) &&
|
||||
(priority != -1);
|
||||
}
|
||||
|
||||
bool operator<(const Path& other) const
|
||||
{
|
||||
return (source < other.source) &&
|
||||
(destination < other.destination);
|
||||
}
|
||||
|
||||
bool isCompatible(const Path& other) const
|
||||
{
|
||||
enum AudioSource p1Source = (enum AudioSource) source;
|
||||
enum AudioSource p2Source = (enum AudioSource) other.source;
|
||||
enum AudioSink p1Sink = (enum AudioSink) destination;
|
||||
enum AudioSink p2Sink = (enum AudioSink) other.destination;
|
||||
|
||||
return audio_checkPathCompatibility(p1Source, p1Sink, p2Source, p2Sink);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* \internal
|
||||
* Data structure representing an established audio route.
|
||||
*/
|
||||
struct Route
|
||||
{
|
||||
Path path; ///< Path associated to this route.
|
||||
std::set< int > suspendList; ///< Suspended paths with lower priority.
|
||||
std::set< int > suspendBy; ///< List of paths which suspended this route.
|
||||
|
||||
bool isActive() const
|
||||
{
|
||||
return suspendBy.empty();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
static std::set< int > activePaths; // IDs of currently active paths.
|
||||
static std::map< int, Route > routes; // Route data of currently active paths.
|
||||
static int pathCounter = 1; // Counter for path ID generation.
|
||||
|
||||
|
||||
pathId audioPath_request(enum AudioSource source, enum AudioSink sink,
|
||||
enum AudioPriority prio)
|
||||
{
|
||||
const Path path{source, sink, prio};
|
||||
if (!path.isValid())
|
||||
return -1;
|
||||
|
||||
std::set< int > pathsToSuspend;
|
||||
|
||||
// Check if this new path can be activated, otherwise return -1
|
||||
for (const auto& i : activePaths)
|
||||
{
|
||||
const Path& activePath = routes.at(i).path;
|
||||
if(path.isCompatible(activePath))
|
||||
continue;
|
||||
|
||||
// Not compatible where active one has higher priority
|
||||
if (activePath.priority >= path.priority)
|
||||
return -1;
|
||||
|
||||
// Active path has lower priority than this new one
|
||||
pathsToSuspend.insert(i);
|
||||
}
|
||||
|
||||
// New path can be activated
|
||||
const int newPathId = pathCounter;
|
||||
pathCounter += 1;
|
||||
const Route newRoute{path, pathsToSuspend, {}};
|
||||
|
||||
// Move active paths that should be suspended to the suspend-list
|
||||
for (const auto& i : pathsToSuspend)
|
||||
{
|
||||
// Move path to suspended-list
|
||||
activePaths.erase(i);
|
||||
|
||||
routes.at(i).suspendBy.insert(newPathId);
|
||||
}
|
||||
|
||||
// Set this new path as active
|
||||
routes.insert(std::make_pair(newPathId, newRoute));
|
||||
activePaths.insert(newPathId);
|
||||
|
||||
return newPathId;
|
||||
}
|
||||
|
||||
enum PathStatus audioPath_getStatus(const pathId id)
|
||||
{
|
||||
const auto it = routes.find(id);
|
||||
|
||||
if(it == routes.end())
|
||||
return PATH_CLOSED;
|
||||
|
||||
if(it->second.isActive())
|
||||
return PATH_OPEN;
|
||||
|
||||
return PATH_SUSPENDED;
|
||||
}
|
||||
|
||||
void audioPath_release(const pathId id)
|
||||
{
|
||||
auto it = routes.find(id);
|
||||
if (it == routes.end()) // Does not exists
|
||||
return;
|
||||
|
||||
Route dataToRemove = it->second;
|
||||
routes.erase(it);
|
||||
activePaths.erase(id);
|
||||
|
||||
// For each path that suspended me
|
||||
for (const auto& i : dataToRemove.suspendBy)
|
||||
{
|
||||
auto& suspendList = routes.at(i).suspendList;
|
||||
|
||||
// Remove myself from its suspend-list
|
||||
suspendList.erase(id);
|
||||
|
||||
// Add who I suspended
|
||||
for (const auto& j : dataToRemove.suspendList)
|
||||
suspendList.insert(j);
|
||||
}
|
||||
|
||||
// For each path suspended by me
|
||||
for (const auto& i : dataToRemove.suspendList)
|
||||
{
|
||||
auto& suspendBy = routes.at(i).suspendBy;
|
||||
|
||||
// Remove myself
|
||||
suspendBy.erase(id);
|
||||
|
||||
if (!dataToRemove.suspendBy.empty())
|
||||
{
|
||||
// If I was suspended, propagate who suspended me
|
||||
for (const auto& j : dataToRemove.suspendBy)
|
||||
suspendBy.insert(j);
|
||||
}
|
||||
else
|
||||
{
|
||||
// This path can be started again
|
||||
if (suspendBy.empty())
|
||||
activePaths.insert(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue