blob: 75aeddcff5338b52d189699b27b7bcf366940e89 [file] [log] [blame]
// Copyright 2020 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef SRC_MEDIA_AUDIO_AUDIO_CORE_LINK_MATRIX_H_
#define SRC_MEDIA_AUDIO_AUDIO_CORE_LINK_MATRIX_H_
#include <fuchsia/media/cpp/fidl.h>
#include <memory>
#include <mutex>
#include <unordered_map>
#include <unordered_set>
#include "src/media/audio/audio_core/audio_object.h"
#include "src/media/audio/audio_core/loudness_transform.h"
#include "src/media/audio/audio_core/threading_model.h"
namespace media::audio {
// The link matrix contains a matrix of connections between audio objects.
// It handles establishing, storing, removing, and accessing links.
class LinkMatrix {
public:
struct LinkHandle {
std::shared_ptr<AudioObject> object;
std::shared_ptr<const LoudnessTransform> loudness_transform;
std::shared_ptr<ReadableStream> stream;
std::shared_ptr<Mixer> mixer;
// This pointer remains valid as long as both sides of the link are valid.
// As soon as one side of the link is destructed, this pointer may be destructed.
// It's guaranteed to live for the duration of ForEach{Dest,Source}Link.
ExecutionDomain* mix_domain;
};
zx_status_t LinkObjects(std::shared_ptr<AudioObject> source, std::shared_ptr<AudioObject> dest,
std::shared_ptr<const LoudnessTransform> loudness_transform);
void Unlink(AudioObject& object);
void ForEachDestLink(const AudioObject& object, fit::function<void(LinkHandle)> f);
void ForEachSourceLink(const AudioObject& object, fit::function<void(LinkHandle)> f);
size_t DestLinkCount(const AudioObject& object);
size_t SourceLinkCount(const AudioObject& object);
// Functions to retrieve the set of links for an object. Use the same vector each time to
// skip unnecessary allocations.
void DestLinks(const AudioObject& object, std::vector<LinkHandle>* store);
void SourceLinks(const AudioObject& object, std::vector<LinkHandle>* store);
// Returns true iff the source and dest are linked.
bool AreLinked(const AudioObject& source, AudioObject& dest);
private:
struct Link {
explicit Link(const AudioObject* _key) : key(_key) {}
Link(std::shared_ptr<AudioObject> _object,
std::shared_ptr<const LoudnessTransform> _loudness_transform,
std::shared_ptr<ReadableStream> _stream, std::shared_ptr<Mixer> _mixer,
ExecutionDomain* _mix_domain)
: key(_object.get()),
object(std::move(_object)),
loudness_transform(std::move(_loudness_transform)),
stream(std::move(_stream)),
mixer(std::move(_mixer)),
mix_domain(_mix_domain) {}
bool operator==(const Link& rhs) const noexcept { return key == rhs.key; }
const AudioObject* key;
std::weak_ptr<AudioObject> object;
std::shared_ptr<const LoudnessTransform> loudness_transform;
std::shared_ptr<ReadableStream> stream;
std::shared_ptr<Mixer> mixer;
// This may be owned by key or object.
// - If owned by key, then this field is valid until the key is unlinked.
// - If owned by object, we must obtain a strong reference to object before using this field.
ExecutionDomain* mix_domain;
};
struct LinkHash {
std::size_t operator()(Link const& link) const noexcept {
return std::hash<const AudioObject*>{}(link.key);
}
};
using LinkSet = std::unordered_set<Link, LinkHash>;
// There may be a gap between an object dropping, and their removal from the matrix due
// to there being no common enforced mechanism for the removal.
//
// We can remove this filter if there is a mechanism to enforce that dropped object immediately
// remove themselves.
void OnlyStrongLinks(LinkSet& link_set, std::vector<LinkHandle>* store);
// Returns the link source set for the object. Inserts the key if it
// is not already present in the matrix.
LinkSet& SourceLinkSet(const AudioObject* object);
LinkSet& DestLinkSet(const AudioObject* object);
std::mutex lock_;
std::unordered_map<const AudioObject*, LinkSet> sources_ FXL_GUARDED_BY(lock_);
std::unordered_map<const AudioObject*, LinkSet> dests_ FXL_GUARDED_BY(lock_);
};
} // namespace media::audio
#endif // SRC_MEDIA_AUDIO_AUDIO_CORE_LINK_MATRIX_H_