mirror of
https://github.com/AlexandreRouma/SDRPlusPlus.git
synced 2024-11-14 22:42:52 +01:00
saving work
This commit is contained in:
parent
0277232bdb
commit
ff655caf31
286
core/src/signal_path/stream.cpp
Normal file
286
core/src/signal_path/stream.cpp
Normal file
@ -0,0 +1,286 @@
|
||||
// #include "stream.h"
|
||||
// #include <utils/flog.h>
|
||||
|
||||
// Sink::Sink(dsp::stream<dsp::stereo_t>* stream, const std::string& name, SinkID id) :
|
||||
// stream(stream),
|
||||
// streamName(name),
|
||||
// id(id)
|
||||
// {}
|
||||
|
||||
// void Sink::showMenu() {}
|
||||
|
||||
// AudioStream::AudioStream(StreamManager* manager, const std::string& name, dsp::stream<dsp::stereo_t>* stream, double samplerate) :
|
||||
// manager(manager),
|
||||
// name(name)
|
||||
// {
|
||||
// this->samplerate = samplerate;
|
||||
|
||||
// // Initialize DSP
|
||||
// split.init(stream);
|
||||
// split.start();
|
||||
// }
|
||||
|
||||
// void AudioStream::setInput(dsp::stream<dsp::stereo_t>* stream, double samplerate = 0.0) {
|
||||
// std::lock_guard<std::recursive_mutex> lck1(mtx);
|
||||
|
||||
// // If all that's needed is to set the input, do it and return
|
||||
// if (samplerate == 0.0) {
|
||||
// split.setInput(stream);
|
||||
// return;
|
||||
// }
|
||||
|
||||
// // Lock sink list
|
||||
// {
|
||||
// std::unique_lock<std::shared_mutex> lck2(sinksMtx);
|
||||
// this->samplerate = samplerate;
|
||||
|
||||
// // Stop DSP
|
||||
// split.stop();
|
||||
// for (auto& [id, sink] : sinks) {
|
||||
// sink->stopDSP();
|
||||
// }
|
||||
|
||||
// // Set input and samplerate
|
||||
// split.setInput(stream);
|
||||
// for (auto& [id, sink] : sinks) {
|
||||
// sink->setInputSamplerate(samplerate);
|
||||
// }
|
||||
|
||||
// // Start DSP
|
||||
// for (auto& [id, sink] : sinks) {
|
||||
// sink->startDSP();
|
||||
// }
|
||||
// split.start();
|
||||
// }
|
||||
// }
|
||||
|
||||
// SinkID AudioStream::addSink(const std::string& type, SinkID id = -1) {
|
||||
// std::unique_lock<std::shared_mutex> lck(sinksMtx);
|
||||
|
||||
// // Find a free ID if not provided
|
||||
// if (id < 0) {
|
||||
// for (id = 0;; id++) {
|
||||
// if (sinks.find(id) != sinks.end()) { continue; }
|
||||
// }
|
||||
// }
|
||||
// else {
|
||||
// // Check that the provided ID is valid
|
||||
// if (sinks.find(id) != sinks.end()) {
|
||||
// flog::error("Tried to create sink for stream '{}' with existing ID: {}", name, id);
|
||||
// return -1;
|
||||
// }
|
||||
// }
|
||||
|
||||
// // Create sink entry
|
||||
// std::shared_ptr<SinkEntry> sink;
|
||||
// try {
|
||||
// sink = std::make_shared<SinkEntry>(type, id, samplerate);
|
||||
// }
|
||||
// catch (SinkEntryCreateException e) {
|
||||
// flog::error("Tried to create sink for stream '{}' with ID '{}': {}", name, id, e.what());
|
||||
// return -1;
|
||||
// }
|
||||
|
||||
// // Start the sink and DSP
|
||||
// sink->startSink();
|
||||
// sink->startDSP();
|
||||
|
||||
// // Bind the sinks's input
|
||||
// split.bindStream(&sink->input);
|
||||
|
||||
// // Add sink to list
|
||||
// sinks[id] = sink;
|
||||
|
||||
// // Release lock and emit event
|
||||
// lck.unlock();
|
||||
// onSinkAdded(sink);
|
||||
// }
|
||||
|
||||
// void AudioStream::removeSink(SinkID id, bool forgetSettings = true) {
|
||||
// // Acquire shared lock
|
||||
// std::shared_ptr<SinkEntry> sink;
|
||||
// {
|
||||
// std::shared_lock<std::shared_mutex> lck(sinksMtx);
|
||||
|
||||
// // Check that the ID exists
|
||||
// if (sinks.find(id) == sinks.end()) {
|
||||
// flog::error("Tried to remove sink with unknown ID: {}", id);
|
||||
// return;
|
||||
// }
|
||||
|
||||
// // Get sink
|
||||
// sink = sinks[id];
|
||||
// }
|
||||
|
||||
// // Emit event
|
||||
// onSinkRemove(sink);
|
||||
|
||||
// // Acquire unique lock
|
||||
// {
|
||||
// std::unique_lock<std::shared_mutex> lck(sinksMtx);
|
||||
|
||||
// // Check that it's still in the list
|
||||
// if (sinks.find(id) == sinks.end()) {
|
||||
// flog::error("Tried to remove sink with unknown ID: {}", id);
|
||||
// return;
|
||||
// }
|
||||
|
||||
// // Remove from list
|
||||
// sinks.erase(id);
|
||||
|
||||
// // Unbind the sink's steam
|
||||
// split.unbindStream(&sink->input);
|
||||
|
||||
// // Stop the sink and DSP
|
||||
// sink->stopDSP();
|
||||
// sink->stopSink();
|
||||
// }
|
||||
// }
|
||||
|
||||
// std::shared_lock<std::shared_mutex> AudioStream::getSinksLock() {
|
||||
// return std::shared_lock<std::shared_mutex>(sinksMtx);
|
||||
// }
|
||||
|
||||
// const std::map<SinkID, std::shared_ptr<SinkEntry>>& AudioStream::getSinks() const {
|
||||
// return sinks;
|
||||
// }
|
||||
|
||||
// std::shared_ptr<AudioStream> StreamManager::createStream(const std::string& name, dsp::stream<dsp::stereo_t>* stream, double samplerate) {
|
||||
// std::unique_lock<std::shared_mutex> lck(streamsMtx);
|
||||
|
||||
// // Check that no stream with that name already exists
|
||||
// if (streams.find(name) != streams.end()) {
|
||||
// flog::error("Tried to created stream with an existing name: {}", name);
|
||||
// return NULL;
|
||||
// }
|
||||
|
||||
// // Create and save stream
|
||||
// auto newStream = std::make_shared<AudioStream>(this, name, stream, samplerate);
|
||||
// streams[name] = newStream;
|
||||
|
||||
// // Release lock and emit event
|
||||
// lck.unlock();
|
||||
// onStreamCreated(newStream);
|
||||
// }
|
||||
|
||||
// void StreamManager::destroyStream(std::shared_ptr<AudioStream>& stream) {
|
||||
// // Emit event
|
||||
// onStreamDestroy(stream);
|
||||
|
||||
// // Aquire complete lock on the stream list
|
||||
// {
|
||||
// std::unique_lock<std::shared_mutex> lck(streamsMtx);
|
||||
|
||||
// // Get iterator of the stream
|
||||
// auto it = std::find_if(streams.begin(), streams.end(), [&stream](std::shared_ptr<AudioStream>& s) {
|
||||
// return s == stream;
|
||||
// });
|
||||
// if (it == streams.end()) {
|
||||
// flog::error("Tried to delete a stream using an invalid pointer. Stream not found in list");
|
||||
// return;
|
||||
// }
|
||||
|
||||
// // Delete entry from list
|
||||
// flog::debug("Stream pointer uses, should be 2 and is {}", stream.use_count());
|
||||
// streams.erase(it);
|
||||
// }
|
||||
|
||||
// // Reset passed pointer
|
||||
// stream.reset();
|
||||
// }
|
||||
|
||||
// std::shared_lock<std::shared_mutex> StreamManager::getStreamsLock() {
|
||||
// return std::shared_lock<std::shared_mutex>(streamsMtx);
|
||||
// }
|
||||
|
||||
// const std::map<std::string, std::shared_ptr<AudioStream>>& StreamManager::getStreams() const {
|
||||
// return streams;
|
||||
// }
|
||||
|
||||
// void StreamManager::registerSinkProvider(const std::string& name, SinkProvider* provider) {
|
||||
// std::unique_lock<std::shared_mutex> lck(providersMtx);
|
||||
|
||||
// // Check that a provider with that name doesn't already exist
|
||||
// if (providers.find(name) != providers.end()) {
|
||||
// flog::error("Tried to register a sink provider with an existing name: {}", name);
|
||||
// return;
|
||||
// }
|
||||
|
||||
// // Add provider to the list and sort name list
|
||||
// providers[name] = provider;
|
||||
// sinkTypes.push_back(name);
|
||||
// std::sort(sinkTypes.begin(), sinkTypes.end());
|
||||
|
||||
// // Release lock and emit event
|
||||
// lck.unlock();
|
||||
// onSinkProviderRegistered(name);
|
||||
// }
|
||||
|
||||
// void StreamManager::unregisterSinkProvider(SinkProvider* provider) {
|
||||
// // Get provider name for event
|
||||
// std::string type;
|
||||
// {
|
||||
// std::shared_lock<std::shared_mutex> lck(providersMtx);
|
||||
// auto it = std::find_if(providers.begin(), providers.end(), [&provider](SinkProvider* p) {
|
||||
// p == provider;
|
||||
// });
|
||||
// if (it == providers.end()) {
|
||||
// flog::error("Tried to unregister sink provider using invalid pointer");
|
||||
// return;
|
||||
// }
|
||||
// type = (*it).first;
|
||||
// }
|
||||
|
||||
// // Emit event
|
||||
// onSinkProviderUnregister(type);
|
||||
|
||||
// // Acquire shared lock on streams
|
||||
// {
|
||||
// std::shared_lock<std::shared_mutex> lck(streamsMtx);
|
||||
// for (auto& [name, stream] : streams) {
|
||||
// std::vector<SinkID> toRemove;
|
||||
|
||||
// // Aquire lock on sink list
|
||||
// auto sLock = stream->getSinksLock();
|
||||
// auto sinks = stream->getSinks();
|
||||
|
||||
// // Find all sinks with the type that is about to be removed
|
||||
// for (auto& [id, sink] : sinks) {
|
||||
// if (sink->getType() != type) { continue; }
|
||||
// toRemove.push_back(id);
|
||||
// }
|
||||
|
||||
// // Remove them all (TODO: THERE IS RACE CONDITION IF A SINK IS CHANGED AFTER LISTING)
|
||||
// for (auto& id : toRemove) {
|
||||
// stream->removeSink(id);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// // Remove from the lists
|
||||
// {
|
||||
// std::unique_lock<std::shared_mutex> lck(providersMtx);
|
||||
// if (providers.find(type) != providers.end()) {
|
||||
// providers.erase(type);
|
||||
// }
|
||||
// else {
|
||||
// flog::error("Could not remove sink provider from list");
|
||||
// }
|
||||
|
||||
// auto it = std::find(sinkTypes.begin(), sinkTypes.end(), type);
|
||||
// if (it != sinkTypes.end()) {
|
||||
// sinkTypes.erase(it);
|
||||
// }
|
||||
// else {
|
||||
// flog::error("Could not remove sink provider from sink type list");
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// std::shared_lock<std::shared_mutex> StreamManager::getSinkTypesLock() {
|
||||
// return std::shared_lock<std::shared_mutex>(providersMtx);
|
||||
// }
|
||||
|
||||
// const std::vector<std::string>& StreamManager::getSinkTypes() const {
|
||||
// return sinkTypes;
|
||||
// }
|
@ -9,25 +9,41 @@
|
||||
#include <dsp/audio/volume.h>
|
||||
#include <utils/new_event.h>
|
||||
#include <shared_mutex>
|
||||
#include <stdexcept>
|
||||
|
||||
class AudioStream;
|
||||
|
||||
using SinkID = int;
|
||||
|
||||
class Sink {
|
||||
public:
|
||||
Sink(dsp::stream<dsp::stereo_t>* stream, const std::string& name, SinkID id);
|
||||
|
||||
virtual void start() = 0;
|
||||
virtual void stop() = 0;
|
||||
virtual void showMenu();
|
||||
|
||||
private:
|
||||
dsp::stream<dsp::stereo_t>* stream;
|
||||
AudioStream* audioStream = NULL;
|
||||
dsp::stream<dsp::stereo_t>* const stream;
|
||||
const std::string streamName;
|
||||
const SinkID id;
|
||||
};
|
||||
|
||||
class SinkEntryCreateException : public std::runtime_error {
|
||||
public:
|
||||
SinkEntryCreateException(const char* what) : std::runtime_error(what) {}
|
||||
};
|
||||
|
||||
class SinkEntry {
|
||||
friend AudioStream;
|
||||
SinkEntry(dsp::stream<dsp::stereo_t>* stream, const std::string& type, int index);
|
||||
SinkEntry(const std::string& type, SinkID id, double inputSamplerate);
|
||||
public:
|
||||
~SinkEntry();
|
||||
|
||||
/**
|
||||
* Get the type of the sink.
|
||||
* @return Type of the sink.
|
||||
*/
|
||||
const std::string& getType();
|
||||
|
||||
/**
|
||||
* Change the type of the sink.
|
||||
@ -35,15 +51,21 @@ public:
|
||||
*/
|
||||
void setType(const std::string& type);
|
||||
|
||||
/**
|
||||
* Get the ID of the sink.
|
||||
* @return ID of the sink.
|
||||
*/
|
||||
SinkID getID();
|
||||
|
||||
/**
|
||||
* Get sink volume.
|
||||
* @return Volume as value between 0 and 1.
|
||||
* @return Volume as value between 0.0 and 1.0.
|
||||
*/
|
||||
float getVolume() const;
|
||||
|
||||
/**
|
||||
* Set sink volume.
|
||||
* @param volume Volume as value between 0 and 1.
|
||||
* @param volume Volume as value between 0.0 and 1.0.
|
||||
*/
|
||||
void setVolume(float volume);
|
||||
|
||||
@ -61,21 +83,39 @@ public:
|
||||
|
||||
/**
|
||||
* Get sink panning.
|
||||
* @return Panning as value between -1 and 1 meaning panning to the left and right respectively.
|
||||
* @return Panning as value between -1.0 and 1.0 meaning panning to the left and right respectively.
|
||||
*/
|
||||
float getPanning() const;
|
||||
|
||||
/**
|
||||
* Set sink panning.
|
||||
* @param panning Panning as value between -1 and 1 meaning panning to the left and right respectively.
|
||||
* @param panning Panning as value between -1.0 and 1.0 meaning panning to the left and right respectively.
|
||||
*/
|
||||
void setPanning(float panning);
|
||||
|
||||
// Emitted when the type of the sink was changed
|
||||
NewEvent<const std::string&> onTypeChanged;
|
||||
// Emmited when volume of the sink was changed
|
||||
NewEvent<float> onVolumeChanged;
|
||||
// Emitted when the muted state of the sink was changed
|
||||
NewEvent<bool> onMutedChanged;
|
||||
// Emitted when the panning of the sink was changed
|
||||
NewEvent<float> onPanningChanged;
|
||||
|
||||
private:
|
||||
void startSink();
|
||||
void stopSink();
|
||||
void startDSP();
|
||||
void stopDSP();
|
||||
void setInputSamplerate(double samplerate);
|
||||
|
||||
dsp::stream<dsp::stereo_t> input;
|
||||
dsp::multirate::RationalResampler<dsp::stereo_t> resamp;
|
||||
dsp::audio::Volume volumeAdjust;
|
||||
|
||||
std::unique_ptr<Sink> sink;
|
||||
const int index;
|
||||
double inputSamplerate;
|
||||
const SinkID id;
|
||||
float volume = 1.0f;
|
||||
bool muted = false;
|
||||
float panning = 0.0f;
|
||||
@ -91,8 +131,9 @@ public:
|
||||
/**
|
||||
* Set DSP stream input.
|
||||
* @param stream DSP stream.
|
||||
* @param samplerate New samplerate (optional, 0.0 if not used).
|
||||
*/
|
||||
void setInput(dsp::stream<dsp::stereo_t>* stream);
|
||||
void setInput(dsp::stream<dsp::stereo_t>* stream, double samplerate = 0.0);
|
||||
|
||||
/**
|
||||
* Set the samplerate of the input stream.
|
||||
@ -106,18 +147,23 @@ public:
|
||||
*/
|
||||
const std::string& getName() const;
|
||||
|
||||
// TODO: USING AN INDEX IS BAD!
|
||||
// THIS IS BECAUSE THEY WILL CHANGE AS SOME ARE REMOVED OR ADDED
|
||||
|
||||
/**
|
||||
* Add a sink to the stream.
|
||||
* @param type Type of the sink.
|
||||
* @return Index of the new sink or -1 on error.
|
||||
* @param id ID of the sink. Optional, -1 if automatic.
|
||||
* @return ID of the new sink or -1 on error.
|
||||
*/
|
||||
int addSink(const std::string& type);
|
||||
SinkID addSink(const std::string& type, SinkID id = -1);
|
||||
|
||||
/**
|
||||
* Remove a sink from a stream.
|
||||
* @param index Index of the sink.
|
||||
* @param id ID of the sink.
|
||||
* @param forgetSettings Forget the settings for the sink.
|
||||
*/
|
||||
void removeSink(int index);
|
||||
void removeSink(SinkID id, bool forgetSettings = true);
|
||||
|
||||
/**
|
||||
* Aquire a lock for the sink list.
|
||||
@ -129,16 +175,23 @@ public:
|
||||
* Get the list of all sinks belonging to this stream.
|
||||
* @return Sink list.
|
||||
*/
|
||||
const std::vector<std::shared_ptr<SinkEntry>>& getSinks() const;
|
||||
const std::map<SinkID, std::shared_ptr<SinkEntry>>& getSinks() const;
|
||||
|
||||
// Emitted when the samplerate of the stream was changed
|
||||
NewEvent<double> onSamplerateChanged;
|
||||
// Emitted when a sink was added
|
||||
NewEvent<std::shared_ptr<SinkEntry>> onSinkAdded;
|
||||
// Emitted when a sink is being removed
|
||||
NewEvent<std::shared_ptr<SinkEntry>> onSinkRemove;
|
||||
|
||||
private:
|
||||
std::recursive_mutex mtx;
|
||||
StreamManager* manager;
|
||||
std::string name;
|
||||
const StreamManager* manager;
|
||||
const std::string name;
|
||||
double samplerate;
|
||||
dsp::routing::Splitter<dsp::stereo_t> split;
|
||||
|
||||
std::vector<std::shared_ptr<SinkEntry>> sinks;
|
||||
std::map<SinkID, std::shared_ptr<SinkEntry>> sinks;
|
||||
std::shared_mutex sinksMtx;
|
||||
};
|
||||
|
||||
@ -159,7 +212,6 @@ public:
|
||||
};
|
||||
|
||||
class StreamManager {
|
||||
friend AudioStream;
|
||||
public:
|
||||
/**
|
||||
* Create an audio stream.
|
||||
@ -180,9 +232,7 @@ public:
|
||||
* Aquire a lock for the stream list.
|
||||
* @return Shared lock for the stream list.
|
||||
*/
|
||||
std::shared_lock<std::shared_mutex> getStreamsLock() {
|
||||
return std::shared_lock<std::shared_mutex>(streamsMtx);
|
||||
}
|
||||
std::shared_lock<std::shared_mutex> getStreamsLock();
|
||||
|
||||
/**
|
||||
* Get a list of streams and their associated names.
|
||||
@ -211,7 +261,7 @@ public:
|
||||
|
||||
/**
|
||||
* Get a list of sink types.
|
||||
* @return List of sink type names.
|
||||
* @return List of sink type names in alphabetical order.
|
||||
*/
|
||||
const std::vector<std::string>& getSinkTypes() const;
|
||||
|
||||
@ -220,14 +270,17 @@ public:
|
||||
// Emitted when a stream is about to be destroyed
|
||||
NewEvent<std::shared_ptr<AudioStream>> onStreamDestroy;
|
||||
// Emitted when a sink provider was registered
|
||||
NewEvent<std::string> onSinkProviderRegistered;
|
||||
NewEvent<const std::string&> onSinkProviderRegistered;
|
||||
// Emitted when a sink provider is about to be unregistered
|
||||
NewEvent<std::string> onSinkProviderUnregister;
|
||||
NewEvent<const std::string&> onSinkProviderUnregister;
|
||||
|
||||
private:
|
||||
std::map<std::string, std::shared_ptr<AudioStream>> streams;
|
||||
std::shared_mutex streamsMtx;
|
||||
|
||||
// TODO: Switch all this shit to a recursive mutex RW locks are shit
|
||||
// Or maybe not actually
|
||||
|
||||
std::map<std::string, SinkProvider*> providers;
|
||||
std::vector<std::string> sinkTypes;
|
||||
std::shared_mutex providersMtx;
|
||||
|
Loading…
Reference in New Issue
Block a user