parent
2a46eecdc6
commit
a9531c86a4
@ -0,0 +1,42 @@ |
||||
#pragma once |
||||
|
||||
#include <memory> |
||||
#include <optional> |
||||
#include <string> |
||||
|
||||
#include "freertos/portmacro.h" |
||||
|
||||
#include "audio_element.hpp" |
||||
#include "himem.hpp" |
||||
#include "stream_info.hpp" |
||||
|
||||
namespace audio { |
||||
|
||||
static const std::size_t kPipelineBufferSize = 32 * 1024; |
||||
|
||||
class Pipeline { |
||||
public: |
||||
Pipeline(IAudioElement* output); |
||||
~Pipeline(); |
||||
auto AddInput(IAudioElement* input) -> Pipeline*; |
||||
|
||||
auto OutputElement() const -> IAudioElement*; |
||||
|
||||
auto NumInputs() const -> std::size_t; |
||||
|
||||
auto InStreams(std::vector<MappableRegion<kPipelineBufferSize>>*, |
||||
std::vector<MutableStream>*) -> void; |
||||
|
||||
auto OutStream(MappableRegion<kPipelineBufferSize>*) -> MutableStream; |
||||
|
||||
auto GetIterationOrder() -> std::vector<Pipeline*>; |
||||
|
||||
private: |
||||
IAudioElement* root_; |
||||
std::vector<std::unique_ptr<Pipeline>> subtrees_; |
||||
|
||||
HimemAlloc<kPipelineBufferSize> output_buffer_; |
||||
StreamInfo output_info_; |
||||
}; |
||||
|
||||
} // namespace audio
|
@ -0,0 +1,52 @@ |
||||
#include "pipeline.hpp" |
||||
#include "stream_info.hpp" |
||||
|
||||
namespace audio { |
||||
|
||||
Pipeline::Pipeline(IAudioElement* output) : root_(output), subtrees_() {} |
||||
Pipeline::~Pipeline() {} |
||||
|
||||
auto Pipeline::AddInput(IAudioElement* input) -> Pipeline* { |
||||
subtrees_.emplace_back(input); |
||||
return subtrees_.back().get(); |
||||
} |
||||
|
||||
auto Pipeline::OutputElement() const -> IAudioElement* { |
||||
return root_; |
||||
} |
||||
|
||||
auto Pipeline::NumInputs() const -> std::size_t { |
||||
return subtrees_.size(); |
||||
} |
||||
|
||||
auto Pipeline::InStreams( |
||||
std::vector<MappableRegion<kPipelineBufferSize>>* regions, |
||||
std::vector<MutableStream>* out) -> void { |
||||
for (int i = 0; i < subtrees_.size(); i++) { |
||||
MutableStream s = subtrees_[i]->OutStream(®ions->at(i)); |
||||
out->push_back(s); |
||||
} |
||||
} |
||||
|
||||
auto Pipeline::OutStream(MappableRegion<kPipelineBufferSize>* region) |
||||
-> MutableStream { |
||||
return {&output_info_, region->Map(output_buffer_)}; |
||||
} |
||||
|
||||
auto Pipeline::GetIterationOrder() -> std::vector<Pipeline*> { |
||||
std::vector<Pipeline*> to_search{this}; |
||||
std::vector<Pipeline*> found; |
||||
|
||||
while (!to_search.empty()) { |
||||
Pipeline* current = to_search.back(); |
||||
to_search.pop_back(); |
||||
found.push_back(current); |
||||
|
||||
to_search.insert(to_search.end(), current->subtrees_.begin(), |
||||
current->subtrees_.end()); |
||||
} |
||||
|
||||
return found; |
||||
} |
||||
|
||||
} // namespace audio
|
@ -1,2 +1,2 @@ |
||||
idf_component_register(SRCS "arena.cpp" INCLUDE_DIRS "include" REQUIRES "span") |
||||
idf_component_register(SRCS "arena.cpp" INCLUDE_DIRS "include" REQUIRES "span" "esp_psram") |
||||
target_compile_options(${COMPONENT_LIB} PRIVATE ${EXTRA_WARNINGS}) |
||||
|
@ -0,0 +1,78 @@ |
||||
#pragma once |
||||
|
||||
#include <cstddef> |
||||
#include <cstdint> |
||||
|
||||
#include "esp32/himem.h" |
||||
#include "span.hpp" |
||||
|
||||
/*
|
||||
* Wrapper around an ESP-IDF himem allocation, which uses RAII to clean up after |
||||
* itself. |
||||
*/ |
||||
template <std::size_t size> |
||||
class HimemAlloc { |
||||
public: |
||||
esp_himem_handle_t handle; |
||||
const bool is_valid; |
||||
|
||||
HimemAlloc() : is_valid(esp_himem_alloc(size, &handle) == ESP_OK) {} |
||||
|
||||
~HimemAlloc() { |
||||
if (is_valid) { |
||||
esp_himem_free(handle); |
||||
} |
||||
} |
||||
|
||||
// Not copyable or movable.
|
||||
HimemAlloc(const HimemAlloc&) = delete; |
||||
HimemAlloc& operator=(const HimemAlloc&) = delete; |
||||
}; |
||||
|
||||
/*
|
||||
* Wrapper around an ESP-IDF himem allocation, which maps a HimemAlloc into the |
||||
* usable address space. Instances always contain the last memory region that |
||||
* was mapped within them. |
||||
*/ |
||||
template <std::size_t size> |
||||
class MappableRegion { |
||||
private: |
||||
std::byte* bytes_; |
||||
|
||||
public: |
||||
esp_himem_rangehandle_t range_handle; |
||||
const bool is_valid; |
||||
|
||||
MappableRegion() |
||||
: bytes_(nullptr), |
||||
is_valid(esp_himem_alloc_map_range(size, &range_handle) == ESP_OK) {} |
||||
|
||||
~MappableRegion() { |
||||
if (bytes_ != nullptr) { |
||||
esp_himem_unmap(range_handle, bytes_, size); |
||||
} |
||||
if (is_valid) { |
||||
esp_himem_free_map_range(range_handle); |
||||
} |
||||
} |
||||
|
||||
auto Get() -> cpp::span<std::byte> { |
||||
if (bytes_ != nullptr) { |
||||
return {}; |
||||
} |
||||
return {bytes_, size}; |
||||
} |
||||
|
||||
auto Map(const HimemAlloc<size> &alloc) -> cpp::span<std::byte> { |
||||
if (bytes_ != nullptr) { |
||||
ESP_ERROR_CHECK(esp_himem_unmap(range_handle, bytes_, size)); |
||||
} |
||||
ESP_ERROR_CHECK(esp_himem_map(alloc.handle, range_handle, 0, 0, size, 0, |
||||
reinterpret_cast<void**>(&bytes_))); |
||||
return Get(); |
||||
} |
||||
|
||||
// Not copyable or movable.
|
||||
MappableRegion(const MappableRegion&) = delete; |
||||
MappableRegion& operator=(const MappableRegion&) = delete; |
||||
}; |
Loading…
Reference in new issue