More scoping!!!
This commit is contained in:
@@ -1,3 +1,13 @@
|
||||
/// ReMixer
|
||||
/// A Public Domain C++ Audio Playback Library
|
||||
/// By william @ RedactedSoftware. Thanks to Dawsh & Maxine.
|
||||
/// (c) 2024 Redacted Software
|
||||
/// This work is explicitly dedicated to the public domain, for the hopeful betterment of the software industry.
|
||||
|
||||
/// @file PulseSubsystem.h
|
||||
/// @desc A PulseAudio implementation of the AudioSubsystem class.
|
||||
/// @edit 2024-08-29
|
||||
|
||||
#include <pulse/pulseaudio.h>
|
||||
#include <pulse/thread-mainloop.h>
|
||||
#include <iostream>
|
||||
@@ -18,6 +28,19 @@ namespace ReMixer
|
||||
/// A PulseAudio implementation of the SoundSubsystem.
|
||||
class PulseAudioSubsystem : public SoundSubsystem
|
||||
{
|
||||
std::map<std::string, PulseStream> streams;
|
||||
public:
|
||||
/// Constructs a new PulseAudio context with the given name.
|
||||
/// @param context_name The context name. All streams created with this context will be grouped together by this name.
|
||||
PulseAudioSubsystem(const std::string& context_name);
|
||||
|
||||
void Play(const PulseStream& stream, const Sound& sound);
|
||||
|
||||
bool Connected();
|
||||
|
||||
PulseStream CreateStream(const std::string& stream_name);
|
||||
protected:
|
||||
private:
|
||||
struct pa_impl
|
||||
{
|
||||
pa_threaded_mainloop* mainloop;
|
||||
@@ -30,201 +53,8 @@ namespace ReMixer
|
||||
|
||||
int operation_success;
|
||||
};
|
||||
std::map<std::string, PulseStream> streams;
|
||||
public:
|
||||
/// Constructs a new PulseAudio context with the given name.
|
||||
/// @param name The context name. All streams created with this context will be grouped together by this name.
|
||||
PulseAudioSubsystem(const std::string& context_name) : SoundSubsystem()
|
||||
{
|
||||
const char *server = NULL;
|
||||
pa = pa_xnew(pa_impl, 1);
|
||||
|
||||
int error = PA_ERR_INTERNAL;
|
||||
|
||||
if (!(pa->mainloop = pa_threaded_mainloop_new()))
|
||||
{
|
||||
throw std::runtime_error("Failed to create a PulseAudio mainloop.");
|
||||
}
|
||||
|
||||
pa->api = pa_threaded_mainloop_get_api(pa->mainloop);
|
||||
|
||||
if (!(pa->context = pa_context_new(pa->api, context_name.c_str())))
|
||||
{
|
||||
throw std::runtime_error("Failed to create a PulseAudio context.");
|
||||
}
|
||||
|
||||
pa_context_flags flags = pa_context_flags::PA_CONTEXT_NOAUTOSPAWN;
|
||||
|
||||
pa_context_set_state_callback(pa->context, OnCtxStateChange, pa);
|
||||
|
||||
|
||||
if (pa_context_connect(pa->context, server, flags, NULL) < 0)
|
||||
{
|
||||
error = pa_context_errno(pa->context);
|
||||
throw std::runtime_error(std::format("Failed to connect to context {}", error));
|
||||
} else{
|
||||
ctx_connected = true;
|
||||
}
|
||||
|
||||
pa_threaded_mainloop_lock(pa->mainloop);
|
||||
|
||||
if (pa_threaded_mainloop_start(pa->mainloop) < 0) {
|
||||
throw std::runtime_error("Failed to start thread mainloop.");
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
pa_context_state_t state;
|
||||
state = pa_context_get_state(pa->context);
|
||||
|
||||
if (state == PA_CONTEXT_READY)
|
||||
break;
|
||||
|
||||
if (!PA_CONTEXT_IS_GOOD(state)) {
|
||||
error = pa_context_errno(pa->context);
|
||||
|
||||
throw std::runtime_error(std::format("Context was not good: {}", error));
|
||||
}
|
||||
|
||||
// Wait until the context is ready.
|
||||
pa_threaded_mainloop_wait(pa->mainloop);
|
||||
}
|
||||
pa_threaded_mainloop_unlock(pa->mainloop);
|
||||
std::cout << "PulseAudio context is ready." << std::endl;
|
||||
}
|
||||
|
||||
void Play(const PulseStream& stream, const Sound& sound)
|
||||
{
|
||||
pa_threaded_mainloop_lock(pa->mainloop);
|
||||
|
||||
size_t length = sound.DataSize();
|
||||
|
||||
const void* data = sound.ptr();
|
||||
|
||||
while(length > 0)
|
||||
{
|
||||
size_t l;
|
||||
int r;
|
||||
while(!(l = pa_stream_writable_size(stream.stream))) {
|
||||
pa_threaded_mainloop_wait(pa->mainloop);
|
||||
}
|
||||
|
||||
if (l > length)
|
||||
l = length;
|
||||
|
||||
r = pa_stream_write(stream.stream, data, l, nullptr, 0LL, PA_SEEK_RELATIVE);
|
||||
data = (const char*) data + l;
|
||||
length -= l;
|
||||
}
|
||||
|
||||
pa_threaded_mainloop_unlock(pa->mainloop);
|
||||
}
|
||||
|
||||
bool Connected()
|
||||
{
|
||||
return ctx_connected;
|
||||
}
|
||||
|
||||
|
||||
PulseStream CreateStream(const std::string& stream_name)
|
||||
{
|
||||
|
||||
// Assumed defaults
|
||||
// TODO: Expose to the API later
|
||||
static const pa_sample_spec ss = {
|
||||
.format = PA_SAMPLE_S16LE,
|
||||
.rate = 44100,
|
||||
.channels = 2
|
||||
};
|
||||
|
||||
const pa_cvolume* volume = NULL;
|
||||
pa_channel_map* map = NULL;
|
||||
const char* dev = NULL;
|
||||
pa_buffer_attr* attr = NULL;
|
||||
|
||||
PulseStream new_stream = PulseStream();
|
||||
pa_threaded_mainloop_lock(pa->mainloop);
|
||||
|
||||
if (!(new_stream.stream = pa_stream_new(pa->context, stream_name.c_str(), &ss, map)))
|
||||
{
|
||||
throw std::runtime_error("Failed to create a new PulseAudio stream.");
|
||||
}
|
||||
|
||||
pa_stream_set_state_callback(new_stream.stream, PulseStream::OnStreamStateChanged, pa->mainloop);
|
||||
pa_stream_set_read_callback(new_stream.stream, PulseStream::OnStreamRequest, pa->mainloop);
|
||||
pa_stream_set_write_callback(new_stream.stream, PulseStream::OnStreamRequest, pa->mainloop);
|
||||
pa_stream_set_latency_update_callback(new_stream.stream, PulseStream::OnLatencyUpdate, pa->mainloop);
|
||||
|
||||
pa_stream_flags flags = static_cast<pa_stream_flags>(PA_STREAM_INTERPOLATE_TIMING | PA_STREAM_ADJUST_LATENCY |
|
||||
PA_STREAM_AUTO_TIMING_UPDATE);
|
||||
|
||||
// TODO: Support Playback and Recording streams
|
||||
int r = pa_stream_connect_playback(new_stream.stream, dev, attr, flags, volume, NULL);
|
||||
if (r < 0)
|
||||
{
|
||||
int error = pa_context_errno(pa->context);
|
||||
throw std::runtime_error(std::format("Failed to connect the stream: {}", error));
|
||||
}
|
||||
|
||||
for (;;)
|
||||
{
|
||||
pa_stream_state_t state;
|
||||
state = pa_stream_get_state(new_stream.stream);
|
||||
|
||||
if (state == PA_STREAM_READY)
|
||||
break;
|
||||
|
||||
if (!PA_STREAM_IS_GOOD(state))
|
||||
{
|
||||
int error = pa_context_errno(pa->context);
|
||||
throw std::runtime_error(std::format("Stream state is bad: {}", error));
|
||||
}
|
||||
|
||||
pa_threaded_mainloop_wait(pa->mainloop);
|
||||
}
|
||||
|
||||
pa_threaded_mainloop_unlock(pa->mainloop);
|
||||
|
||||
streams.insert({stream_name, new_stream});
|
||||
|
||||
return new_stream;
|
||||
}
|
||||
protected:
|
||||
private:
|
||||
static void OnCtxStateChange(pa_context* c, void* userdata)
|
||||
{
|
||||
std::cout << "context state callback: ";
|
||||
|
||||
auto *p = static_cast<pa_impl *>(userdata);
|
||||
switch(pa_context_get_state(c)) {
|
||||
case PA_CONTEXT_READY:
|
||||
std::cout << "Context Ready" << std::endl;
|
||||
pa_threaded_mainloop_signal(p->mainloop, 0);
|
||||
break;
|
||||
case PA_CONTEXT_TERMINATED:
|
||||
std::cout << "Context Terminated" << std::endl;
|
||||
pa_threaded_mainloop_signal(p->mainloop, 0);
|
||||
break;
|
||||
case PA_CONTEXT_FAILED:
|
||||
std::cout << "Context Failed" << std::endl;
|
||||
pa_threaded_mainloop_signal(p->mainloop, 0);
|
||||
break;
|
||||
case PA_CONTEXT_UNCONNECTED:
|
||||
std::cout << "Context Unconnected" << std::endl;
|
||||
break;
|
||||
case PA_CONTEXT_CONNECTING:
|
||||
std::cout << "Context Connecting" << std::endl;
|
||||
break;
|
||||
case PA_CONTEXT_AUTHORIZING:
|
||||
std::cout << "Context Authorizing" << std::endl;
|
||||
break;
|
||||
case PA_CONTEXT_SETTING_NAME:
|
||||
std::cout << "Context Setting Name" << std::endl;
|
||||
break;
|
||||
default:
|
||||
std::cerr << "The fuck?" << std::endl;
|
||||
break;
|
||||
}
|
||||
}
|
||||
static void OnCtxStateChange(pa_context* c, void* userdata);
|
||||
pa_impl* pa;
|
||||
bool ctx_connected = false;
|
||||
|
||||
|
@@ -57,10 +57,7 @@ namespace ReMixer
|
||||
|
||||
};
|
||||
|
||||
class Decibels
|
||||
{
|
||||
|
||||
};
|
||||
class Decibels { };
|
||||
|
||||
enum class SoundApi
|
||||
{
|
||||
@@ -84,6 +81,11 @@ namespace ReMixer
|
||||
class SoundSubsystem
|
||||
{
|
||||
public:
|
||||
SoundSubsystem()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
std::vector<AudioDevice> GetAudioDevices();
|
||||
std::vector<PlaybackDevice> GetPlaybackDevices();
|
||||
std::vector<RecordingDevice> GetRecordingDevices();
|
||||
|
@@ -1,3 +1,13 @@
|
||||
/// ReMixer
|
||||
/// A Public Domain C++ Audio Playback Library
|
||||
/// By william @ RedactedSoftware. Thanks to Dawsh & Maxine.
|
||||
/// (c) 2024 Redacted Software
|
||||
/// This work is explicitly dedicated to the public domain, for the hopeful betterment of the software industry.
|
||||
|
||||
/// @file sound.h
|
||||
/// @desc This class contains and manipulates sound data.
|
||||
/// @edit 2024-08-29
|
||||
|
||||
#pragma once
|
||||
#include <vector>
|
||||
#include <pulse/pulseaudio.h>
|
||||
@@ -15,6 +25,7 @@ namespace ReMixer {
|
||||
/// The sound class contains a raw audio data buffer in Pulse-Code Modulated form.
|
||||
class Sound {
|
||||
public:
|
||||
|
||||
/// The default constructor for a Sound object is intentionally left undefined.
|
||||
/// It is intended that you use the static constructors below to load Sound objects.
|
||||
Sound() = default;
|
||||
@@ -73,11 +84,6 @@ namespace ReMixer {
|
||||
char* ptr() { return audio_data.data();}
|
||||
[[nodiscard]] const char* ptr() const { return audio_data.data();}
|
||||
|
||||
|
||||
|
||||
|
||||
public:
|
||||
|
||||
private:
|
||||
uint sample_rate;
|
||||
std::vector<char> audio_data;
|
||||
|
@@ -16,23 +16,24 @@
|
||||
#include <pulse/thread-mainloop.h>
|
||||
#include <iostream>
|
||||
#include "sound.h"
|
||||
#include "SoundSubsystem.h"
|
||||
#include <ReMixer/ReMixer.h>
|
||||
|
||||
|
||||
namespace ReMixer
|
||||
{
|
||||
namespace ReMixer {
|
||||
class Stream {
|
||||
private:
|
||||
std::string name;
|
||||
std::string parent_name;
|
||||
unsigned int channel_count;
|
||||
unsigned int sample_rate;
|
||||
StreamDirection dir;
|
||||
|
||||
std::vector<char> buffer;
|
||||
|
||||
|
||||
public:
|
||||
Stream() = default;
|
||||
Stream(SoundSubsystem* parent_system);
|
||||
|
||||
uint SampleRate() const { return sample_rate;}
|
||||
|
||||
unsigned int sample_rate;
|
||||
size_t bufferSize;
|
||||
uint16_t handle;
|
||||
//Stream(const std::string& application_name, const std::string& stream_name, SampleRate sample_rate, StreamMode mode);
|
||||
@@ -41,55 +42,15 @@ namespace ReMixer
|
||||
class PulseStream : public Stream
|
||||
{
|
||||
public:
|
||||
PulseStream() = default;
|
||||
|
||||
// PulseStream(PulseAudioSubsystem* parent_system) : Stream(parent_system) { }
|
||||
|
||||
pa_stream* stream;
|
||||
|
||||
|
||||
|
||||
static void OnStreamStateChanged(pa_stream* s, void* userdata)
|
||||
{
|
||||
std::cout << "stream state callback: ";
|
||||
|
||||
auto *p = static_cast<pa_threaded_mainloop *>(userdata);
|
||||
|
||||
auto state = pa_stream_get_state(s);
|
||||
switch(state) {
|
||||
case PA_STREAM_READY:
|
||||
std::cout << "Stream Ready" << std::endl;
|
||||
pa_threaded_mainloop_signal(p, 0);
|
||||
break;
|
||||
case PA_STREAM_FAILED:
|
||||
std::cout << "Stream Failed" << std::endl;
|
||||
pa_threaded_mainloop_signal(p, 0);
|
||||
break;
|
||||
case PA_STREAM_TERMINATED:
|
||||
std::cout << "Stream Terminated" << std::endl;
|
||||
pa_threaded_mainloop_signal(p, 0);
|
||||
break;
|
||||
case PA_STREAM_UNCONNECTED:
|
||||
std::cout << "Stream Unconnected" << std::endl;
|
||||
break;
|
||||
case PA_STREAM_CREATING:
|
||||
std::cout << "Stream Creating" << std::endl;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void OnStreamRequest(pa_stream* s, size_t length, void* userdata)
|
||||
{
|
||||
std::cout << "Received stream request callback: " << length << std::endl;
|
||||
|
||||
auto *p = static_cast<pa_threaded_mainloop *>(userdata);
|
||||
|
||||
pa_threaded_mainloop_signal(p, 0);
|
||||
}
|
||||
|
||||
static void OnLatencyUpdate(pa_stream* s, void* userdata)
|
||||
{
|
||||
std::cout << "Received stream latency update callback" << std::endl;
|
||||
auto *p = static_cast<pa_threaded_mainloop *>(userdata);
|
||||
|
||||
pa_threaded_mainloop_signal(p, 0);
|
||||
}
|
||||
static void OnStreamStateChanged(pa_stream* s, void* userdata);
|
||||
static void OnStreamRequest(pa_stream* s, size_t length, void* userdata);
|
||||
static void OnLatencyUpdate(pa_stream* s, void* userdata);
|
||||
protected:
|
||||
private:
|
||||
|
||||
|
4
main.cpp
4
main.cpp
@@ -21,12 +21,14 @@
|
||||
|
||||
|
||||
[[noreturn]] int main() {
|
||||
|
||||
using namespace ReMixer;
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
uint measurement = 44.1_kHz;
|
||||
|
||||
PulseAudioSubsystem test = PulseAudioSubsystem("PulseAudio Test");
|
||||
|
||||
|
||||
PulseStream test_stream = test.CreateStream("Test Stream");
|
||||
PulseStream test_stream2 = test.CreateStream("Another Test Stream");
|
||||
|
||||
|
@@ -1 +1,195 @@
|
||||
#include <ReMixer/PulseSubsystem.h>
|
||||
#include <ReMixer/PulseSubsystem.h>
|
||||
|
||||
void ReMixer::PulseAudioSubsystem::Play(const ReMixer::PulseStream &stream, const ReMixer::Sound &sound) {
|
||||
|
||||
if (stream.SampleRate() != sound.SampleRate())
|
||||
{
|
||||
std::cerr << "There is an incongruency in sample rate between the stream and the sound file. "
|
||||
<< std::format("Stream: {}hz, meanwhile sound: {}hz", stream.SampleRate(), sound.SampleRate())
|
||||
<< std::endl;
|
||||
}
|
||||
|
||||
pa_threaded_mainloop_lock(pa->mainloop);
|
||||
|
||||
size_t length = sound.SampleCount();
|
||||
|
||||
const void* data = sound.ptr();
|
||||
|
||||
while(length > 0)
|
||||
{
|
||||
size_t l;
|
||||
int r;
|
||||
while(!(l = pa_stream_writable_size(stream.stream))) {
|
||||
pa_threaded_mainloop_wait(pa->mainloop);
|
||||
}
|
||||
|
||||
if (l > length)
|
||||
l = length;
|
||||
|
||||
r = pa_stream_write(stream.stream, data, l, nullptr, 0LL, PA_SEEK_RELATIVE);
|
||||
data = (const char*) data + l;
|
||||
length -= l;
|
||||
}
|
||||
|
||||
pa_threaded_mainloop_unlock(pa->mainloop);
|
||||
}
|
||||
|
||||
bool ReMixer::PulseAudioSubsystem::Connected() {
|
||||
return ctx_connected;
|
||||
}
|
||||
|
||||
ReMixer::PulseStream ReMixer::PulseAudioSubsystem::CreateStream(const std::string &stream_name) {
|
||||
// Assumed defaults
|
||||
// TODO: Expose to the API later
|
||||
static const pa_sample_spec ss = {
|
||||
.format = PA_SAMPLE_S16LE,
|
||||
.rate = 44100,
|
||||
.channels = 2
|
||||
};
|
||||
|
||||
const pa_cvolume* volume = NULL;
|
||||
pa_channel_map* map = NULL;
|
||||
const char* dev = NULL;
|
||||
pa_buffer_attr* attr = NULL;
|
||||
|
||||
PulseStream new_stream = PulseStream();
|
||||
new_stream.sample_rate = 44.1_kHz;
|
||||
pa_threaded_mainloop_lock(pa->mainloop);
|
||||
|
||||
if (!(new_stream.stream = pa_stream_new(pa->context, stream_name.c_str(), &ss, map)))
|
||||
{
|
||||
throw std::runtime_error("Failed to create a new PulseAudio stream.");
|
||||
}
|
||||
|
||||
pa_stream_set_state_callback(new_stream.stream, PulseStream::OnStreamStateChanged, pa->mainloop);
|
||||
pa_stream_set_read_callback(new_stream.stream, PulseStream::OnStreamRequest, pa->mainloop);
|
||||
pa_stream_set_write_callback(new_stream.stream, PulseStream::OnStreamRequest, pa->mainloop);
|
||||
pa_stream_set_latency_update_callback(new_stream.stream, PulseStream::OnLatencyUpdate, pa->mainloop);
|
||||
|
||||
pa_stream_flags flags = static_cast<pa_stream_flags>(PA_STREAM_INTERPOLATE_TIMING | PA_STREAM_ADJUST_LATENCY |
|
||||
PA_STREAM_AUTO_TIMING_UPDATE);
|
||||
|
||||
// TODO: Support Playback and Recording streams
|
||||
int r = pa_stream_connect_playback(new_stream.stream, dev, attr, flags, volume, NULL);
|
||||
if (r < 0)
|
||||
{
|
||||
int error = pa_context_errno(pa->context);
|
||||
throw std::runtime_error(std::format("Failed to connect the stream: {}", error));
|
||||
}
|
||||
|
||||
for (;;)
|
||||
{
|
||||
pa_stream_state_t state;
|
||||
state = pa_stream_get_state(new_stream.stream);
|
||||
|
||||
if (state == PA_STREAM_READY)
|
||||
break;
|
||||
|
||||
if (!PA_STREAM_IS_GOOD(state))
|
||||
{
|
||||
int error = pa_context_errno(pa->context);
|
||||
throw std::runtime_error(std::format("Stream state is bad: {}", error));
|
||||
}
|
||||
|
||||
pa_threaded_mainloop_wait(pa->mainloop);
|
||||
}
|
||||
|
||||
pa_threaded_mainloop_unlock(pa->mainloop);
|
||||
|
||||
streams.insert({stream_name, new_stream});
|
||||
|
||||
return new_stream;
|
||||
}
|
||||
|
||||
ReMixer::PulseAudioSubsystem::PulseAudioSubsystem(const std::string &context_name) : SoundSubsystem()
|
||||
{
|
||||
const char *server = NULL;
|
||||
pa = pa_xnew(pa_impl, 1);
|
||||
|
||||
int error = PA_ERR_INTERNAL;
|
||||
|
||||
if (!(pa->mainloop = pa_threaded_mainloop_new()))
|
||||
{
|
||||
throw std::runtime_error("Failed to create a PulseAudio mainloop.");
|
||||
}
|
||||
|
||||
pa->api = pa_threaded_mainloop_get_api(pa->mainloop);
|
||||
|
||||
if (!(pa->context = pa_context_new(pa->api, context_name.c_str())))
|
||||
{
|
||||
throw std::runtime_error("Failed to create a PulseAudio context.");
|
||||
}
|
||||
|
||||
pa_context_flags flags = pa_context_flags::PA_CONTEXT_NOAUTOSPAWN;
|
||||
|
||||
pa_context_set_state_callback(pa->context, OnCtxStateChange, pa);
|
||||
|
||||
|
||||
if (pa_context_connect(pa->context, server, flags, NULL) < 0)
|
||||
{
|
||||
error = pa_context_errno(pa->context);
|
||||
throw std::runtime_error(std::format("Failed to connect to context {}", error));
|
||||
} else{
|
||||
ctx_connected = true;
|
||||
}
|
||||
|
||||
pa_threaded_mainloop_lock(pa->mainloop);
|
||||
|
||||
if (pa_threaded_mainloop_start(pa->mainloop) < 0) {
|
||||
throw std::runtime_error("Failed to start thread mainloop.");
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
pa_context_state_t state;
|
||||
state = pa_context_get_state(pa->context);
|
||||
|
||||
if (state == PA_CONTEXT_READY)
|
||||
break;
|
||||
|
||||
if (!PA_CONTEXT_IS_GOOD(state)) {
|
||||
error = pa_context_errno(pa->context);
|
||||
|
||||
throw std::runtime_error(std::format("Context was not good: {}", error));
|
||||
}
|
||||
|
||||
// Wait until the context is ready.
|
||||
pa_threaded_mainloop_wait(pa->mainloop);
|
||||
}
|
||||
pa_threaded_mainloop_unlock(pa->mainloop);
|
||||
std::cout << "PulseAudio context is ready." << std::endl;
|
||||
}
|
||||
|
||||
void ReMixer::PulseAudioSubsystem::OnCtxStateChange(pa_context *c, void *userdata) {
|
||||
std::cout << "context state callback: ";
|
||||
|
||||
auto *p = static_cast<pa_impl *>(userdata);
|
||||
switch(pa_context_get_state(c)) {
|
||||
case PA_CONTEXT_READY:
|
||||
std::cout << "Context Ready" << std::endl;
|
||||
pa_threaded_mainloop_signal(p->mainloop, 0);
|
||||
break;
|
||||
case PA_CONTEXT_TERMINATED:
|
||||
std::cout << "Context Terminated" << std::endl;
|
||||
pa_threaded_mainloop_signal(p->mainloop, 0);
|
||||
break;
|
||||
case PA_CONTEXT_FAILED:
|
||||
std::cout << "Context Failed" << std::endl;
|
||||
pa_threaded_mainloop_signal(p->mainloop, 0);
|
||||
break;
|
||||
case PA_CONTEXT_UNCONNECTED:
|
||||
std::cout << "Context Unconnected" << std::endl;
|
||||
break;
|
||||
case PA_CONTEXT_CONNECTING:
|
||||
std::cout << "Context Connecting" << std::endl;
|
||||
break;
|
||||
case PA_CONTEXT_AUTHORIZING:
|
||||
std::cout << "Context Authorizing" << std::endl;
|
||||
break;
|
||||
case PA_CONTEXT_SETTING_NAME:
|
||||
std::cout << "Context Setting Name" << std::endl;
|
||||
break;
|
||||
default:
|
||||
std::cerr << "The fuck?" << std::endl;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@@ -50,4 +50,46 @@ void Stream::erase() {
|
||||
if (this == streamList[i])
|
||||
streamList.erase(streamList.begin() + i);
|
||||
}
|
||||
*/
|
||||
*/
|
||||
void ReMixer::PulseStream::OnStreamStateChanged(pa_stream *s, void *userdata) {
|
||||
std::cout << "stream state callback: ";
|
||||
|
||||
auto *p = static_cast<pa_threaded_mainloop *>(userdata);
|
||||
|
||||
auto state = pa_stream_get_state(s);
|
||||
switch(state) {
|
||||
case PA_STREAM_READY:
|
||||
std::cout << "Stream Ready" << std::endl;
|
||||
pa_threaded_mainloop_signal(p, 0);
|
||||
break;
|
||||
case PA_STREAM_FAILED:
|
||||
std::cout << "Stream Failed" << std::endl;
|
||||
pa_threaded_mainloop_signal(p, 0);
|
||||
break;
|
||||
case PA_STREAM_TERMINATED:
|
||||
std::cout << "Stream Terminated" << std::endl;
|
||||
pa_threaded_mainloop_signal(p, 0);
|
||||
break;
|
||||
case PA_STREAM_UNCONNECTED:
|
||||
std::cout << "Stream Unconnected" << std::endl;
|
||||
break;
|
||||
case PA_STREAM_CREATING:
|
||||
std::cout << "Stream Creating" << std::endl;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void ReMixer::PulseStream::OnStreamRequest(pa_stream *s, size_t length, void *userdata) {
|
||||
std::cout << "Received stream request callback: " << length << std::endl;
|
||||
|
||||
auto *p = static_cast<pa_threaded_mainloop *>(userdata);
|
||||
|
||||
pa_threaded_mainloop_signal(p, 0);
|
||||
}
|
||||
|
||||
void ReMixer::PulseStream::OnLatencyUpdate(pa_stream *s, void *userdata) {
|
||||
std::cout << "Received stream latency update callback" << std::endl;
|
||||
auto *p = static_cast<pa_threaded_mainloop *>(userdata);
|
||||
|
||||
pa_threaded_mainloop_signal(p, 0);
|
||||
}
|
||||
|
Reference in New Issue
Block a user