saving work

This commit is contained in:
AlexandreRouma 2023-05-17 03:55:47 +02:00
parent 0277232bdb
commit ff655caf31
2 changed files with 364 additions and 25 deletions

View 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;
// }

View File

@ -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;