-
Task
-
Resolution: Duplicate
-
P2: Important
-
None
-
None
-
None
Currently, we work with audio data through QIODevice, and the current use case is supposed to be used from the user thread.
Advanced users often need to be able to access the underlying audio thread through a callback, so we're providing a new api for running QAudioSink/QAudioSource with a callback.
We want to have the API type-safe: run a callback for the data type relevant to the underlying sample format. It means that for covering current formats, the callback should be a callable object with one of the signatures (might be extended later on).
void(QSpan<int8_t>), void(QSpan<uint16_t>), void(QSpan<uint32_t>), void(QSpan<float>)
Suggestions on how we can do so:
1. 4 overloads
void start(std::function<void(QSpan<int8_t>)> &&);
void start(std::function<void(QSpan<int16_t>)> &&);
void start(std::function<void(QSpan<int32_t>)> &&);
void start(std::function<void(QSpan<float>)> &&);
Pros:
- Self-descriptive methods signatures
- Straight-forward and simple.
- Easy to add a new type
Cons:
- We already have 2 starts for pull/push mode; adding 4 ones makes the number of explicit overloads a bit excessive.
- We should probably duplicate the documentation details for each method.
2. std::variant
using Callback = std::variant<
std::function<void(QSpan<int8_t>)>,
std::function<void(QSpan<int16_t>)>,
std::function<void(QSpan<int32_t>)>,
std::function<void(QSpan<float>)>
>;
void start(Callback &&);
Pros:
- One method with explicit type.
Cons:
- Hard to add a new type because of ABI.
3. Template + private impl
template <typename Callback> using if_audio_callback = std::enable_if_t</*check if the signature is proper*/, bool>; public: template <typename Callback, typename if_audio_callback<Callback> = true> void start(Callback &&callback) { startInternal({ std::forward<Callback>(callback) }); } private: struct CallbackData { std::variant<....> callback; }; // pass the type only by ref to get around void startInternal(CallbackData&& cbData);
Pros:
- Easy to add a new callback type
- Documentation of the new start describes the calling consideration once. We just describe the signatures we can take. In other words, we get 3 starts for different purposes: QIDevice-pull, QIDevice-push, and audio thread callback.
Cons:
- It needs a private startInternal(CallbackData&&), and we have to support the private ABI. However, if we make CallbackData as a structure and pass it by ref, it should be easy.