blob: 1eb9efa41c7ae262af691a3822fa303c9144b87a [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_STREAM_USAGE_H_
#define SRC_MEDIA_AUDIO_AUDIO_CORE_STREAM_USAGE_H_
#include <fuchsia/media/cpp/fidl.h>
#include <lib/fidl/cpp/enum.h>
#include <lib/syslog/cpp/macros.h>
#include <type_traits>
#include <unordered_set>
#include <variant>
namespace media::audio {
static_assert(fuchsia::media::RENDER_USAGE_COUNT == 5);
#define EXPAND_EACH_FIDL_RENDER_USAGE \
EXPAND_RENDER_USAGE(BACKGROUND) \
EXPAND_RENDER_USAGE(MEDIA) \
EXPAND_RENDER_USAGE(INTERRUPTION) \
EXPAND_RENDER_USAGE(SYSTEM_AGENT) \
EXPAND_RENDER_USAGE(COMMUNICATION)
static constexpr uint32_t kStreamInternalRenderUsageCount = 1;
#define EXPAND_EACH_INTERNAL_RENDER_USAGE EXPAND_RENDER_USAGE(ULTRASOUND)
#define EXPAND_EACH_RENDER_USAGE \
EXPAND_EACH_FIDL_RENDER_USAGE \
EXPAND_EACH_INTERNAL_RENDER_USAGE
static_assert(fuchsia::media::CAPTURE_USAGE_COUNT == 4);
#define EXPAND_EACH_FIDL_CAPTURE_USAGE \
EXPAND_CAPTURE_USAGE(BACKGROUND) \
EXPAND_CAPTURE_USAGE(FOREGROUND) \
EXPAND_CAPTURE_USAGE(SYSTEM_AGENT) \
EXPAND_CAPTURE_USAGE(COMMUNICATION)
static constexpr uint32_t kStreamInternalCaptureUsageCount = 2;
#define EXPAND_EACH_INTERNAL_CAPTURE_USAGE \
EXPAND_CAPTURE_USAGE(LOOPBACK) \
EXPAND_CAPTURE_USAGE(ULTRASOUND)
#define EXPAND_EACH_CAPTURE_USAGE \
EXPAND_EACH_FIDL_CAPTURE_USAGE \
EXPAND_EACH_INTERNAL_CAPTURE_USAGE
static constexpr uint32_t kStreamRenderUsageCount =
fuchsia::media::RENDER_USAGE_COUNT + kStreamInternalRenderUsageCount;
enum class RenderUsage : std::underlying_type_t<fuchsia::media::AudioRenderUsage> {
#define EXPAND_RENDER_USAGE(U) U = fidl::ToUnderlying(fuchsia::media::AudioRenderUsage::U),
EXPAND_EACH_FIDL_RENDER_USAGE
#undef EXPAND_RENDER_USAGE
#define EXPAND_RENDER_USAGE(U) U,
EXPAND_EACH_INTERNAL_RENDER_USAGE
#undef EXPAND_RENDER_USAGE
};
constexpr std::array<RenderUsage, fuchsia::media::RENDER_USAGE_COUNT> kFidlRenderUsages = {{
#define EXPAND_RENDER_USAGE(U) RenderUsage::U,
EXPAND_EACH_FIDL_RENDER_USAGE
#undef EXPAND_RENDER_USAGE
}};
constexpr std::array<RenderUsage, kStreamRenderUsageCount> kRenderUsages = {{
#define EXPAND_RENDER_USAGE(U) RenderUsage::U,
EXPAND_EACH_RENDER_USAGE
#undef EXPAND_RENDER_USAGE
}};
static constexpr uint32_t kStreamCaptureUsageCount =
fuchsia::media::CAPTURE_USAGE_COUNT + kStreamInternalCaptureUsageCount;
enum class CaptureUsage : std::underlying_type_t<fuchsia::media::AudioCaptureUsage> {
#define EXPAND_CAPTURE_USAGE(U) U = fidl::ToUnderlying(fuchsia::media::AudioCaptureUsage::U),
EXPAND_EACH_FIDL_CAPTURE_USAGE
#undef EXPAND_CAPTURE_USAGE
#define EXPAND_CAPTURE_USAGE(U) U,
EXPAND_EACH_INTERNAL_CAPTURE_USAGE
#undef EXPAND_CAPTURE_USAGE
};
constexpr std::array<CaptureUsage, fuchsia::media::CAPTURE_USAGE_COUNT> kFidlCaptureUsages = {{
#define EXPAND_CAPTURE_USAGE(U) CaptureUsage::U,
EXPAND_EACH_FIDL_CAPTURE_USAGE
#undef EXPAND_CAPTURE_USAGE
}};
static constexpr uint32_t kStreamUsageCount = kStreamRenderUsageCount + kStreamCaptureUsageCount;
// Since we define the RenderUsage enum to have the same numeric values for each fidl enum entry,
// we can convert by casting the underlying numeric value.
static RenderUsage RenderUsageFromFidlRenderUsage(fuchsia::media::AudioRenderUsage u) {
return static_cast<RenderUsage>(fidl::ToUnderlying(u));
}
static CaptureUsage CaptureUsageFromFidlCaptureUsage(fuchsia::media::AudioCaptureUsage u) {
return static_cast<CaptureUsage>(fidl::ToUnderlying(u));
}
std::optional<fuchsia::media::AudioRenderUsage> FidlRenderUsageFromRenderUsage(RenderUsage u);
std::optional<fuchsia::media::AudioCaptureUsage> FidlCaptureUsageFromCaptureUsage(CaptureUsage u);
const char* RenderUsageToString(const RenderUsage& usage);
const char* CaptureUsageToString(const CaptureUsage& usage);
class StreamUsage {
public:
static constexpr StreamUsage WithRenderUsage(RenderUsage u) { return StreamUsage(u); }
static constexpr StreamUsage WithCaptureUsage(CaptureUsage u) { return StreamUsage(u); }
static constexpr StreamUsage WithRenderUsage(fuchsia::media::AudioRenderUsage u) {
return StreamUsage(RenderUsageFromFidlRenderUsage(u));
}
static constexpr StreamUsage WithCaptureUsage(fuchsia::media::AudioCaptureUsage u) {
return StreamUsage(CaptureUsageFromFidlCaptureUsage(u));
}
constexpr StreamUsage() = default;
constexpr bool operator==(const StreamUsage& other) const { return usage_ == other.usage_; }
constexpr bool operator!=(const StreamUsage& other) const { return !(*this == other); }
// RenderUsage
constexpr bool is_render_usage() const { return std::holds_alternative<RenderUsage>(usage_); }
constexpr StreamUsage& set_render_usage(RenderUsage usage) {
usage_ = usage;
return *this;
}
constexpr RenderUsage render_usage() const {
FX_DCHECK(is_render_usage());
return std::get<RenderUsage>(usage_);
}
// CaptureUsage
constexpr bool is_capture_usage() const { return std::holds_alternative<CaptureUsage>(usage_); }
constexpr StreamUsage& set_capture_usage(CaptureUsage usage) {
usage_ = usage;
return *this;
}
constexpr CaptureUsage capture_usage() const {
FX_DCHECK(is_capture_usage());
return std::get<CaptureUsage>(usage_);
}
// A |StreamUsage| is empty if it contains neither a render usage or a capture usage. This state
// exists to be similar to the semantics of a FIDL union in C++.
constexpr bool is_empty() const { return std::holds_alternative<std::monostate>(usage_); }
const char* ToString() const;
private:
using Usage = std::variant<std::monostate, RenderUsage, CaptureUsage>;
explicit constexpr StreamUsage(RenderUsage usage) : usage_(usage) {}
explicit constexpr StreamUsage(CaptureUsage usage) : usage_(usage) {}
Usage usage_;
};
constexpr std::array<StreamUsage, kStreamUsageCount> kStreamUsages = {{
#define EXPAND_RENDER_USAGE(U) StreamUsage::WithRenderUsage(RenderUsage::U),
EXPAND_EACH_RENDER_USAGE
#undef EXPAND_RENDER_USAGE
#define EXPAND_CAPTURE_USAGE(U) StreamUsage::WithCaptureUsage(CaptureUsage::U),
EXPAND_EACH_CAPTURE_USAGE
#undef EXPAND_CAPTURE_USAGE
}};
// Guaranteed to be dense, with values ranging from 0 to kStreamUsageCount inclusive.
static constexpr uint32_t HashStreamUsage(const StreamUsage& u) {
if (u.is_render_usage()) {
return static_cast<uint32_t>(u.render_usage());
}
if (u.is_capture_usage()) {
return static_cast<uint32_t>(u.capture_usage()) + kStreamRenderUsageCount;
}
return kStreamUsageCount;
}
namespace internal {
struct EnumHash {
template <typename T>
size_t operator()(T t) const {
return static_cast<size_t>(t);
}
};
struct StreamUsageHash {
size_t operator()(StreamUsage u) const { return HashStreamUsage(u); }
};
} // namespace internal
using RenderUsageSet = std::unordered_set<RenderUsage, internal::EnumHash>;
using CaptureUsageSet = std::unordered_set<CaptureUsage, internal::EnumHash>;
using StreamUsageSet = std::unordered_set<StreamUsage, internal::StreamUsageHash>;
StreamUsage StreamUsageFromFidlUsage(const fuchsia::media::Usage& usage);
template <typename Container>
static StreamUsageSet StreamUsageSetFromRenderUsages(const Container& container) {
static_assert(std::is_same<typename Container::value_type, RenderUsage>::value);
StreamUsageSet result;
std::transform(container.cbegin(), container.cend(), std::inserter(result, result.begin()),
[](const auto& u) { return StreamUsage::WithRenderUsage(u); });
return result;
}
template <typename Container>
static StreamUsageSet StreamUsageSetFromCaptureUsages(const Container& container) {
static_assert(std::is_same<typename Container::value_type, CaptureUsage>::value);
StreamUsageSet result;
std::transform(container.cbegin(), container.cend(), std::inserter(result, result.begin()),
[](const auto& u) { return StreamUsage::WithCaptureUsage(u); });
return result;
}
// A set of StreamUsages represented as a bitmask.
class StreamUsageMask final {
public:
constexpr StreamUsageMask() = default;
constexpr StreamUsageMask(const StreamUsageMask& other) = default;
constexpr StreamUsageMask(std::initializer_list<StreamUsage> usages) {
for (const auto& usage : usages) {
insert(usage);
}
}
constexpr StreamUsageMask& operator=(const StreamUsageMask& other) = default;
// Insert `usage` into the bitmask.
constexpr void insert(const StreamUsage& usage) {
if (!usage.is_empty()) {
mask_ |= (1 << HashStreamUsage(usage));
}
}
// Insert all of the StreamUsages from `other`.
constexpr void insert_all(const StreamUsageMask& other) { mask_ |= other.mask_; }
// Unsets `usage` from the bitmask.
constexpr void erase(const StreamUsage& usage) {
if (!usage.is_empty()) {
mask_ &= ~(1 << HashStreamUsage(usage));
}
}
// Returns true iff there are no usages in the mask.
constexpr bool is_empty() const { return mask_ == 0; }
// Clears all elements from the bitmask.
constexpr void clear() { mask_ = 0; }
// Returns true iff `usage` is set.
constexpr bool contains(const StreamUsage& usage) const {
return !usage.is_empty() && mask_ & (1 << HashStreamUsage(usage));
}
// Returns the raw bitmask.
constexpr uint32_t mask() const { return mask_; }
constexpr bool operator==(const StreamUsageMask& other) const { return mask_ == other.mask_; }
constexpr bool operator!=(const StreamUsageMask& other) const { return !(*this == other); }
private:
uint32_t mask_ = 0;
};
} // namespace media::audio
#endif // SRC_MEDIA_AUDIO_AUDIO_CORE_STREAM_USAGE_H_