From d52a1a44f8cd6b87362188f63cbbbbcb0f660987 Mon Sep 17 00:00:00 2001 From: Green Sky Date: Wed, 24 Apr 2024 22:29:08 +0200 Subject: [PATCH] start sketching --- src/CMakeLists.txt | 5 +++ src/content/content.hpp | 48 +++++++++++++++++++++++++ src/content/stream_reader.hpp | 15 ++++++++ src/content/stream_reader_sdl_audio.cpp | 39 ++++++++++++++++++++ src/content/stream_reader_sdl_audio.hpp | 31 ++++++++++++++++ 5 files changed, 138 insertions(+) create mode 100644 src/content/content.hpp create mode 100644 src/content/stream_reader.hpp create mode 100644 src/content/stream_reader_sdl_audio.cpp create mode 100644 src/content/stream_reader_sdl_audio.hpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index cacd6b1..c49cf6e 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -74,6 +74,11 @@ add_executable(tomato ./chat_gui4.hpp ./chat_gui4.cpp + + ./content/content.hpp + ./content/stream_reader.hpp + ./content/stream_reader_sdl_audio.hpp + ./content/stream_reader_sdl_audio.cpp ) target_compile_features(tomato PUBLIC cxx_std_17) diff --git a/src/content/content.hpp b/src/content/content.hpp new file mode 100644 index 0000000..ddf4e4d --- /dev/null +++ b/src/content/content.hpp @@ -0,0 +1,48 @@ +#pragma once + +#include +#include +#include + +#include +#include + +#include + +enum class Content1 : uint32_t {}; +using ContentRegistry = entt::basic_registry; +using ContentHandle = entt::basic_handle; + +namespace Content::Components { + + // or something + struct TagFile {}; + struct TagAudioStream {}; + struct TagVideoStream {}; + + // the associated messages, if any + // useful if you want to update progress on the message + struct Messages { + std::vector messages; + }; + + // ? + struct SuspectedParticipants { + entt::dense_set participants; + }; + + struct ReadHeadHint { + // points to the first byte we want + // this is just a hint, that can be set from outside + // to guide the sequential "piece picker" strategy + // the strategy *should* set this to the first byte we dont yet have + uint64_t offset_into_file {0u}; + }; + +} // Content::Components + +// TODO: i have no idea +struct RawFile2ReadFromContentFactoryI { + virtual std::shared_ptr open(ContentHandle h) = 0; +}; + diff --git a/src/content/stream_reader.hpp b/src/content/stream_reader.hpp new file mode 100644 index 0000000..722f076 --- /dev/null +++ b/src/content/stream_reader.hpp @@ -0,0 +1,15 @@ +#pragma once + +#include + +// most media that can be counted as "stream" comes in packets/frames/messages +// so this class provides an interface for ideal async fetching of frames +struct RawFrameStreamReaderI { + // return the number of ready frames in cache + // returns -1 if unknown + virtual int64_t have(void) = 0; + + // get next frame, empty if none + virtual ByteSpan getNext(void) = 0; +}; + diff --git a/src/content/stream_reader_sdl_audio.cpp b/src/content/stream_reader_sdl_audio.cpp new file mode 100644 index 0000000..5b88c88 --- /dev/null +++ b/src/content/stream_reader_sdl_audio.cpp @@ -0,0 +1,39 @@ +#include "./stream_reader_sdl_audio.hpp" + +SDLAudioFrameStreamReader::SDLAudioFrameStreamReader(int32_t buffer_size) : _buffer_size(buffer_size), _stream{nullptr, &SDL_DestroyAudioStream} { + _buffer.resize(_buffer_size); + + const SDL_AudioSpec spec = { SDL_AUDIO_S16, 1, 48000 }; + + _stream = { + SDL_OpenAudioDeviceStream(SDL_AUDIO_DEVICE_DEFAULT_CAPTURE, &spec, nullptr, nullptr), + &SDL_DestroyAudioStream + }; +} + +Span SDLAudioFrameStreamReader::getNextAudioFrame(void) { + const int32_t needed_bytes = (_buffer.size() - _remaining_size) * sizeof(int16_t); + const auto read_bytes = SDL_GetAudioStreamData(_stream.get(), _buffer.data()+_remaining_size, needed_bytes); + if (read_bytes < 0) { + // error + return {}; + } + if (read_bytes < needed_bytes) { + // HACK: we are just assuming here that sdl never gives us half a sample! + _remaining_size += read_bytes / sizeof(int16_t); + return {}; + } + + _remaining_size = 0; + return Span{_buffer}; +} + +int64_t SDLAudioFrameStreamReader::have(void) { + return -1; +} + +ByteSpan SDLAudioFrameStreamReader::getNext(void) { + auto next_frame_span = getNextAudioFrame(); + return ByteSpan{reinterpret_cast(next_frame_span.ptr), next_frame_span.size}; +} + diff --git a/src/content/stream_reader_sdl_audio.hpp b/src/content/stream_reader_sdl_audio.hpp new file mode 100644 index 0000000..1050c8d --- /dev/null +++ b/src/content/stream_reader_sdl_audio.hpp @@ -0,0 +1,31 @@ +#pragma once + +#include "./stream_reader.hpp" + +#include + +#include +#include +#include + +struct SDLAudioFrameStreamReader : public RawFrameStreamReaderI { + // count samples per buffer + const int32_t _buffer_size {1024}; + std::vector _buffer; + size_t _remaining_size {0}; // data still in buffer, that was remaining from last call and not enough to fill a full frame + + // meh, empty default + std::unique_ptr _stream; + + // buffer_size in number of samples + SDLAudioFrameStreamReader(int32_t buffer_size = 1024); + + // data owned by StreamReader, overwritten by next call to getNext*() + Span getNextAudioFrame(void); + + public: // interface + int64_t have(void) override; + + ByteSpan getNext(void) override; +}; +