Added an alternate method for setting volume in PulseOut.

This commit is contained in:
casey langen 2017-03-11 01:25:37 +00:00
parent b8a220e1dd
commit 9c30e0e7f6
7 changed files with 128 additions and 6 deletions

View File

@ -8,7 +8,7 @@ cmake_minimum_required(VERSION 3.0)
project(musikbox)
set (musikbox_VERSION_MAJOR 0)
set (musikbox_VERSION_MINOR 9)
set (musikbox_VERSION_PATCH 3)
set (musikbox_VERSION_PATCH 4)
set (musikbox_VERSION "${musikbox_VERSION_MAJOR}.${musikbox_VERSION_MINOR}.${musikbox_VERSION_PATCH}")
include(ExternalProject)

View File

@ -34,12 +34,20 @@
#include "PulseOut.h"
#include <core/sdk/constants.h>
#include <core/sdk/IPreferences.h>
#include <pulse/volume.h>
#include <math.h>
using namespace musik::core::sdk;
typedef std::unique_lock<std::recursive_mutex> Lock;
static musik::core::sdk::IPreferences* prefs = nullptr;
extern "C" void SetPreferences(musik::core::sdk::IPreferences* prefs) {
::prefs = prefs;
prefs->GetBool("force_sw_volume", false);
prefs->Save();
}
PulseOut::PulseOut() {
std::cerr << "PulseOut::PulseOut() called" << std::endl;
@ -49,6 +57,7 @@ PulseOut::PulseOut() {
this->volumeUpdated = false;
this->channels = 0;
this->rate = 0;
this->hwVolume = false;
}
PulseOut::~PulseOut() {
@ -105,10 +114,16 @@ void PulseOut::OpenDevice(musik::core::sdk::IBuffer* buffer) {
0);
if (this->audioConnection) {
this->SetVolume(this->volume);
this->rate = buffer->SampleRate();
this->channels = buffer->Channels();
this->state = StatePlaying;
this->hwVolume = pa_blocking_has_hw_volume(this->audioConnection, 0);
if (::prefs && ::prefs->GetBool("force_sw_volume", false)) {
this->hwVolume = false;
}
this->SetVolume(this->volume);
}
}
}
@ -148,9 +163,17 @@ void PulseOut::SetVolume(double volume) {
this->volume = volume;
this->volumeUpdated = false;
if (this->audioConnection) {
int normalized = (int) round((double) PA_VOLUME_NORM * volume);
int normalized;
if (this->hwVolume) {
//std::cerr << "PulseOut: hw volume!\n";
normalized = (int) round((double) PA_VOLUME_NORM * volume);
}
else {
//std::cerr << "PulseOut: sw volume!\n";
normalized = (int) pa_sw_volume_from_linear(this->volume);
}
this->volumeUpdated = pa_blocking_set_volume(this->audioConnection, normalized, 0) == 0;
std::cerr << "PulseOut: volumeUpdated = " << this->volumeUpdated << "\n";
//std::cerr << "PulseOut: volumeUpdated = " << this->volumeUpdated << ", value = " << normalized << "\n";
}
}

View File

@ -77,4 +77,5 @@ class PulseOut : public musik::core::sdk::IOutput {
int channels, rate;
double volume;
bool volumeUpdated;
bool hwVolume;
};

View File

@ -42,6 +42,8 @@ struct pa_blocking {
const void *read_data;
size_t read_index, read_length;
size_t channels;
int sink_id;
int hw_volume;
int operation_success;
};
@ -165,6 +167,8 @@ pa_blocking* pa_blocking_new(
p = pa_xnew0(pa_blocking, 1);
p->direction = dir;
p->channels = ss->channels;
p->sink_id = -1;
p->hw_volume = -1;
if (!(p->mainloop = pa_threaded_mainloop_new()))
goto fail;
@ -551,3 +555,94 @@ unlock_and_fail:
pa_threaded_mainloop_unlock(p->mainloop);
return -1;
}
static void sink_info_cb(pa_context* c, const pa_sink_info* info, int eol, void* userdata) {
pa_blocking* p = (pa_blocking*) userdata;
if (info) {
p->hw_volume = (info->flags & PA_SINK_HW_VOLUME_CTRL) != 0;
p->operation_success = 1;
pa_threaded_mainloop_signal(p->mainloop, 0);
}
}
static void sink_input_info_cb(pa_context* c, const pa_sink_input_info* info, int eol, void* userdata) {
pa_blocking* p = (pa_blocking*) userdata;
if (info) {
p->sink_id = info->sink;
p->operation_success = 1;
pa_threaded_mainloop_signal(p->mainloop, 0);
}
}
int pa_blocking_has_hw_volume(pa_blocking *p, int *rerror) {
pa_operation *o = NULL;
pa_stream *s = NULL;
uint32_t idx;
int result = -1;
int sink = -1;
assert(p);
if (p->hw_volume != -1) {
return p->hw_volume;
}
CHECK_VALIDITY_RETURN_ANY(rerror, p->direction == PA_STREAM_PLAYBACK, PA_ERR_BADSTATE, -1);
pa_threaded_mainloop_lock(p->mainloop);
CHECK_DEAD_GOTO(p, rerror, unlock_and_fail);
CHECK_SUCCESS_GOTO(p, rerror, ((idx = pa_stream_get_index (p->stream)) != PA_INVALID_INDEX), unlock_and_fail);
s = p->stream;
assert(s);
/* determine the sink id */
if (p->sink_id == -1) {
o = pa_context_get_sink_input_info(p->context, idx, sink_input_info_cb, p);
CHECK_SUCCESS_GOTO(p, rerror, o, unlock_and_fail);
p->operation_success = 0;
while (pa_operation_get_state(o) == PA_OPERATION_RUNNING) {
pa_threaded_mainloop_wait(p->mainloop);
CHECK_DEAD_GOTO(p, rerror, unlock_and_fail);
}
CHECK_SUCCESS_GOTO(p, rerror, p->operation_success, unlock_and_fail);
pa_operation_unref(o);
}
//fprintf(stderr, "success getting sink_id=%d\n", p->sink_id);
if (p->sink_id != -1) {
/* once we have the sink id, query it for hw volume info */
o = pa_context_get_sink_info_by_index(p->context, p->sink_id, sink_info_cb, p);
CHECK_SUCCESS_GOTO(p, rerror, o, unlock_and_fail);
p->operation_success = 0;
while (pa_operation_get_state(o) == PA_OPERATION_RUNNING) {
pa_threaded_mainloop_wait(p->mainloop);
CHECK_DEAD_GOTO(p, rerror, unlock_and_fail);
}
CHECK_SUCCESS_GOTO(p, rerror, p->operation_success, unlock_and_fail);
pa_operation_unref(o);
}
//fprintf(stderr, "success getting hw_volume=%d\n", p->hw_volume);
pa_threaded_mainloop_unlock(p->mainloop);
return p->hw_volume == -1 ? 0 : p->hw_volume;
unlock_and_fail:
if (o) {
pa_operation_cancel(o);
pa_operation_unref(o);
}
pa_threaded_mainloop_unlock(p->mainloop);
return 0;
}

View File

@ -78,5 +78,8 @@ int pa_blocking_flush(pa_blocking *s, int *error);
/** Set the output volume of the stream. */
int pa_blocking_set_volume(pa_blocking *p, int volume, int *rerror);
/** returns 1 if the stream has hardware volume, false otherwise */
int pa_blocking_has_hw_volume(pa_blocking *p, int *rerror);
PA_C_DECL_END

View File

@ -44,7 +44,7 @@ class PulsePlugin : public musik::core::sdk::IPlugin {
public:
virtual void Destroy() { delete this; }
virtual const char* Name() { return "PulseAudio IOutput"; }
virtual const char* Version() { return "0.3"; }
virtual const char* Version() { return "0.4.0"; }
virtual const char* Author() { return "clangen"; }
virtual int SdkVersion() { return musik::core::sdk::SdkVersion; }
};

View File

@ -1,3 +1,3 @@
#pragma once
#define VERSION "0.9.3"
#define VERSION "0.9.4"