Commit 224357f1 authored by Josué Ortega's avatar Josué Ortega

New upstream version 1.6

parent e3c2ca42
tools/
build/
Makefile.in
aclocal.m4
autom4te.cache/
config.h.in
configure
.vscode
.idea
cmake-build-*
config.hpp
man/pamix.1
\ No newline at end of file
# Get the current working branch
execute_process(
COMMAND git rev-parse --abbrev-ref HEAD
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
OUTPUT_VARIABLE GIT_BRANCH
OUTPUT_STRIP_TRAILING_WHITESPACE
)
# Get the latest abbreviated commit hash of the working branch
execute_process(
COMMAND git log -1 --format=%h
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
OUTPUT_VARIABLE GIT_COMMIT_HASH
OUTPUT_STRIP_TRAILING_WHITESPACE
)
execute_process(
COMMAND git describe --tags
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
OUTPUT_VARIABLE GIT_TAG
RESULT_VARIABLE GIT_TAG_ERR
OUTPUT_STRIP_TRAILING_WHITESPACE
)
if (${GIT_TAG_ERR} EQUAL 0)
set(GIT_VERSION "${GIT_TAG}")
else()
set(GIT_VERSION "${GIT_BRANCH} ${GIT_COMMIT_HASH}")
endif ()
\ No newline at end of file
cmake_minimum_required(VERSION 2.8)
project(pamix)
include(CMakeGitDefines.cmake)
option(WITH_UNICODE "Compile with unicode support and symbols" ON)
set(NCURSESW_H_INCLUDE "ncursesw/ncurses.h" CACHE STRING "ncursesw include directive content")
configure_file(config.hpp.in ${CMAKE_CURRENT_SOURCE_DIR}/config.hpp )
configure_file(man/pamix.1.in ${CMAKE_CURRENT_SOURCE_DIR}/man/pamix.1)
set(CMAKE_CXX_STANDARD 11)
file(GLOB_RECURSE pamix_SRC
"include/*.h"
"src/*.cpp")
include_directories("include")
link_libraries("pulse" "pthread")
IF (WITH_UNICODE)
link_libraries("ncursesw")
add_definitions(-DFEAT_UNICODE)
ELSE ()
link_libraries("ncurses")
ENDIF ()
add_executable(pamix ${pamix_SRC})
install(FILES pamix.conf DESTINATION /etc)
install(TARGETS pamix DESTINATION bin)
install(FILES man/pamix.1 DESTINATION share/man/man1)
bin_PROGRAMS = pamix
pamix_CXXFLAGS = -I$(top_srcdir)/include -pthread $(NCURSES_CFLAGS) $(PULSEAUDIO_CFLAGS)
pamix_LDADD = $(NCURSES_LIBS) $(PULSEAUDIO_LIBS)
pamix_SOURCES = \
src/cardentry.cpp \
src/volumeutil.cpp\
src/sinkentry.cpp\
src/sourceentry.cpp\
src/pamix.cpp\
src/sourceoutputentry.cpp\
src/sinkinputentry.cpp\
src/entry.cpp\
src/configuration.cpp\
src/pamix_functions.cpp\
src/painterface.cpp
man1_MANS = man/pamix.1
pkgsysconfdir = $(sysconfdir)
dist_pkgsysconf_DATA = pamix.conf
......@@ -6,9 +6,8 @@
2. Arch
2. [**Building Manually**](#building-manually)
1. Dependencies
2. Configuration
3. Building
4. Installing
2. Building and Installing
4. Build Options
3. [**Configuration**](#configuration)
4. [**Default Keybindings**](#default-keybindings)
......@@ -23,31 +22,33 @@
# Building Manually: #
## Dependencies: #
In order for CMake to properly inject the current version into the headers and man files it has to be inside the git repository.
### Build ##
* autoconf
* autoconf-archive
* pkg-config
* make
* cmake
### Runtime ##
* PulseAudio
* Ncurses
## Building and Installing
```bash
mkdir build && cd build
cmake .. -DCMAKE_BUILD_TYPE=RELEASE -DWITH_UNICODE=1
make
sudo make install
```
## Build Options
### Unicode Support
To compile PAmix with ncurses and without unicode support pass `-DWITH_UNICODE=0` as an argument to cmake.
This will use ncurses instead of ncursesw.
## Autoconf Configuration ##
Generate configure script by running `autoreconf -i` and then run `./configure` with your preferred options
### Options ###
`--disable-unicode` depends on ncurses instead of ncursesw and replaces unicode symbols with ascii
## Building ##
Run `make`
## Installing ##
Run `make install`
### ncursesw header location
You can pass in the include location of your ncursesw header file as an argument, if you are having problems with the default setup.
So if your ncursesw header file is at /usr/include/ncw/ncurses.h you would pass `-DNCURSESW_H_INCLUDE="ncw/ncurses.h"`
---
# Configuration #
Configure pamix and set keybindings using pamix.conf (see [**Configuration**](https://github.com/patroclos/PAmix/wiki/Configuration) for detailed instructions)
......@@ -61,6 +62,7 @@ Configure pamix and set keybindings using pamix.conf (see [**Configuration**](ht
| Recording Tab | F2 |
| Output Devices | F3 |
| Input Devices | F4 |
| Cards | F5 |
| Set volume to percentage | 0-9 |
| Decrease Volume | h |
| Increase Volume | l |
......
#pragma once
#ifdef FEAT_UNICODE
#include <${NCURSESW_H_INCLUDE}>
#else
#include <ncurses.h>
#endif
#define GIT_VERSION "${GIT_VERSION}"
# -*- Autoconf -*-
# Process this file with autoconf to produce a configure script.
AC_PREREQ([2.69])
AC_INIT([pamix], [1.2], [jenschjoshua@gmail.com])
AC_CONFIG_SRCDIR([include/entry.hpp])
AC_CONFIG_AUX_DIR([tools])
AC_CONFIG_HEADERS([config.h])
AM_INIT_AUTOMAKE([-Wall -Werror foreign subdir-objects])
AC_LANG([C++])
AX_CXX_COMPILE_STDCXX_11()
# Checks for programs.
AC_PROG_CXX
# Check options
AC_MSG_CHECKING([--enable-unicode argument])
AC_ARG_ENABLE([unicode], AS_HELP_STRING([--enable-unicode], [Enable unicode support.]), [enable_unicode=$enableval], [enable_unicode="yes"])
AC_MSG_RESULT([$enable_unicode])
if test "$enable_unicode" = "yes"; then
AC_DEFINE([FEAT_UNICODE], [1], [Enable unicode support])
fi
# Checks for libraries.
AS_IF([test "$enable_unicode" = "yes"], [PKG_CHECK_MODULES([NCURSES], [ncursesw])], [PKG_CHECK_MODULES([NCURSES], [ncurses])])
AC_SEARCH_LIBS([use_default_colors], [ncurses curses],
AC_DEFINE(HAVE_USE_DEFAULT_COLORS, 1, [Define to 1 if the curses library has the function `use_default_colors`. ]))
PKG_CHECK_MODULES([PULSEAUDIO], [libpulse])
# Checks for header files.
AC_CHECK_HEADERS([locale.h])
# Checks for typedefs, structures, and compiler characteristics.
AC_CHECK_HEADER_STDBOOL
AC_C_INLINE
AC_TYPE_SIZE_T
AC_TYPE_UINT32_T
AC_TYPE_UINT8_T
# Checks for library functions.
AC_CHECK_FUNCS([memset setlocale])
AC_CONFIG_FILES([Makefile])
AC_OUTPUT
#pragma once
#include <pamix.hpp>
#include <map>
#include <memory>
#include <pamix_functions.hpp>
......@@ -9,33 +10,40 @@
#define CONFIGURATION_AUTOSPAWN_PULSE "pulseaudio_autospawn"
#define CONFIGURATION_DEFAULT_TAB "default_tab"
struct keybind_t
{
struct keybind_t {
union argument_t m_Argument;
void (*m_Function)(argument_t arg);
};
class Configuration
{
class Configuration {
private:
std::map<std::string, std::string> m_Variables;
std::map<int, std::vector<keybind_t>> m_Bindings;
static std::vector<std::pair<int, const char *>> m_Keynames;
static int getKeycode(const std::string &name);
public:
bool has(const std::string &key);
std::string getString(const std::string &key);
int getInt(const std::string &key);
bool getBool(const std::string &key);
bool pressKey(int code);
void set(const std::string &key, const std::string &value);
void unset(const std::string &key);
void bind(const std::string &key, const std::string &cmd, const std::string &arg = "");
void unbind(const std::string &key);
void unbindall();
static bool loadFile(Configuration *config, const std::string &path);
......
......@@ -4,12 +4,17 @@
#include <pulse/pulseaudio.h>
#include <string>
#include <vector>
#include <map>
#include <volumeutil.hpp>
#include <memory>
struct Entry;
typedef std::map<uint32_t, std::unique_ptr<Entry>>::iterator pamix_entry_iter_t;
class PAInterface;
enum entry_type
{
enum entry_type {
ENTRY_SINK,
ENTRY_SOURCE,
ENTRY_SINKINPUT,
......@@ -18,168 +23,203 @@ enum entry_type
ENTRY_COUNT
};
struct Entry
{
PAInterface * interface;
std::string m_Name;
uint32_t m_Index;
double m_Peak = 0;
pa_stream * m_Monitor = nullptr;
uint32_t m_MonitorIndex;
bool m_Mute;
pa_cvolume m_PAVolume;
static std::map<entry_type, const char *> entryTypeNames = {
{ENTRY_SINK, "Output Devices"},
{ENTRY_SINKINPUT, "Playback"},
{ENTRY_SOURCE, "Input Devices"},
{ENTRY_SOURCEOUTPUT, "Recording"},
{ENTRY_CARDS, "Cards"}
};
struct Entry {
PAInterface *interface;
std::string m_Name;
uint32_t m_Index;
double m_Peak = 0;
pa_stream *m_Monitor = nullptr;
uint32_t m_MonitorIndex;
bool m_Mute;
pa_cvolume m_PAVolume;
pa_channel_map m_PAChannelMap;
bool m_Lock = true;
bool m_Kill;
bool m_Meter = true;
bool m_Lock = true;
bool m_Kill;
bool m_Meter = true;
Entry(PAInterface *iface);
~Entry();
// general methods
virtual void setVolume(const int channel, const pa_volume_t volume) = 0;
virtual void setMute(bool mute) = 0;
virtual void addVolume(const int channel, const double deltaPct);
virtual void cycleSwitch(bool increment) = 0;
virtual void update(const pa_sink_info *info) {}
virtual void update(const pa_source_info *info) {}
virtual void update(const pa_sink_input_info *info) {}
virtual void update(const pa_source_output_info *info) {}
virtual void update(const pa_card_info *info) {}
// device methods
virtual void suspend() {}
virtual void setPort(const char *port) {}
// stream methods
virtual void move(uint32_t idx) {}
virtual void kill() {}
virtual void kill() {}
};
struct DeviceEntry : public Entry
{
int m_Port;
std::vector<std::string> m_Ports;
struct DeviceEntry : public Entry {
struct DeviceProfile {
std::string name;
std::string description;
DeviceProfile(std::string name, std::string description) : name(name), description(description) {}
};
int m_Port;
std::vector<DeviceProfile> m_Ports;
DeviceEntry(PAInterface *iface)
: Entry(iface){};
DeviceEntry(PAInterface *paInterface)
: Entry(paInterface) {};
// general methods
virtual void setVolume(const int channel, const pa_volume_t volume) = 0;
virtual void setMute(bool mute) = 0;
virtual void cycleSwitch(bool increment) = 0;
virtual std::string getPort() { return m_Port > -1 ? m_Ports[m_Port] : ""; }
virtual const DeviceProfile *getPortProfile() const { return m_Port > -1 ? &m_Ports[m_Port] : nullptr; }
virtual void setPort(const char *port) = 0;
};
struct StreamEntry : public Entry
{
struct StreamEntry : public Entry {
uint32_t m_Device;
StreamEntry(PAInterface *iface)
: Entry(iface){};
: Entry(iface) {};
// general methods
virtual void setVolume(const int channel, const pa_volume_t volume) = 0;
virtual void setMute(bool mute) = 0;
virtual void cycleSwitch(bool increment) = 0;
virtual void move(uint32_t idx) = 0;
virtual void kill() = 0;
};
struct SinkEntry : public DeviceEntry
{
struct SinkEntry : public DeviceEntry {
pa_sink_state_t m_State;
SinkEntry(PAInterface *iface)
: DeviceEntry(iface) {}
: DeviceEntry(iface) {}
void update(const pa_sink_info *info);
// general methods
virtual void setVolume(const int channel, const pa_volume_t volume);
virtual void setMute(bool mute);
virtual void cycleSwitch(bool increment);
virtual void setPort(const char *port);
};
struct SourceEntry : public DeviceEntry
{
struct SourceEntry : public DeviceEntry {
pa_source_state_t m_State;
SourceEntry(PAInterface *iface)
: DeviceEntry(iface) {}
: DeviceEntry(iface) {}
void update(const pa_source_info *info);
// general methods
virtual void setVolume(const int channel, const pa_volume_t volume);
virtual void setMute(bool mute);
virtual void cycleSwitch(bool increment);
virtual void setPort(const char *port);
};
struct SinkInputEntry : public StreamEntry
{
struct SinkInputEntry : public StreamEntry {
void update(const pa_sink_input_info *info);
SinkInputEntry(PAInterface *iface)
: StreamEntry(iface) {}
: StreamEntry(iface) {}
// general methods
virtual void setVolume(const int channel, const pa_volume_t volume);
virtual void setMute(bool mute);
virtual void cycleSwitch(bool increment);
virtual void move(uint32_t idx);
virtual void kill();
};
struct SourceOutputEntry : public StreamEntry
{
struct SourceOutputEntry : public StreamEntry {
void update(const pa_source_output_info *info);
SourceOutputEntry(PAInterface *iface)
: StreamEntry(iface) {}
: StreamEntry(iface) {}
// general methods
virtual void setVolume(const int channel, const pa_volume_t volume);
virtual void setMute(bool mute);
virtual void cycleSwitch(bool increment);
virtual void move(uint32_t idx);
virtual void kill();
};
struct CardEntry : public Entry
{
struct CardProfile
{
struct CardEntry : public Entry {
struct CardProfile {
std::string name;
std::string description;
CardProfile(pa_card_profile_info2 *profile)
: name(profile->name)
, description(profile->description) {};
: name(profile->name), description(profile->description) {};
};
int m_Profile;
int m_Profile;
std::vector<CardProfile> m_Profiles;
void update(const pa_card_info *info);
CardEntry(PAInterface *iface)
: Entry(iface) {}
: Entry(iface) {}
virtual void cycleSwitch(bool increment);
virtual void setVolume(const int channel, const pa_volume_t volume) {}
virtual void setMute(bool mute) {}
virtual void move(uint32_t idx) {}
virtual void kill() {}
};
......@@ -10,35 +10,36 @@
#include <thread>
#include <vector>
struct mainloop_lockguard
{
struct mainloop_lockguard {
pa_threaded_mainloop *m;
mainloop_lockguard(pa_threaded_mainloop *m);
~mainloop_lockguard();
};
class PAInterface;
struct Entry;
//define subscription masks
#define PAI_SUBSCRIPTION_MASK_PEAK 0x1U
#define PAI_SUBSCRIPTION_MASK_INFO 0x2U
#define PAI_SUBSCRIPTION_MASK_OTHER 0x4U
#define PAI_SUBSCRIPTION_MASK_CONNECTION_STATUS 0x128
typedef uint32_t pai_subscription_type_t;
typedef void (*pai_subscription_cb)(PAInterface *, const pai_subscription_type_t);
typedef std::map<uint32_t, std::unique_ptr<Entry>>::iterator iter_entry_t;
class PAInterface
{
class PAInterface {
private:
bool m_Autospawn;
const char * m_ContextName;
const char *m_ContextName;
pa_threaded_mainloop *m_Mainloop;
pa_mainloop_api * m_MainloopApi;
pa_context * m_Context;
pa_mainloop_api *m_MainloopApi;
pa_context *m_Context;
std::map<uint32_t, std::unique_ptr<Entry>> m_Sinks;
std::map<uint32_t, std::unique_ptr<Entry>> m_Sources;
......@@ -52,62 +53,92 @@ private:
static void signal_mainloop(void *interface);
static void _updateSinks(PAInterface *interface);
static void _updateSources(PAInterface *interface);
static void _updateInputs(PAInterface *interface);
static void _updateOutputs(PAInterface *interface);
static void _updateCards(PAInterface *interface);
static void _updatethread(pai_subscription_type_t paisubtype, pa_subscription_event_type_t type, PAInterface *interface);
static void
_updatethread(pai_subscription_type_t paisubtype, pa_subscription_event_type_t type, PAInterface *interface);
//member methods
void updateSinks() { _updateSinks(this); }
void updateSources() { _updateSources(this); }
void updateInputs() { _updateInputs(this); }
void updateOutputs() { _updateOutputs(this); }
void updateCards() { _updateCards(this); }
void notifySubscription(const pai_subscription_type_t);
bool tryCreateConnection();
void cleanupPulseObjects();
public:
PAInterface(const char *context_name);
~PAInterface();
inline pa_threaded_mainloop *getPAMainloop() { return m_Mainloop; }
inline pa_context * getPAContext() { return m_Context; }
inline pa_context *getPAContext() { return m_Context; }
bool connect();
bool isConnected();
void setAutospawn(bool as) { m_Autospawn = as; }
bool getAutospawn() { return m_Autospawn; }
bool getAutospawn() { return m_Autospawn; }
void subscribe(pai_subscription_cb callback);
std::mutex m_ModifyMutex;
std::map<uint32_t, std::unique_ptr<Entry>> &getSinks() { return m_Sinks; }
std::map<uint32_t, std::unique_ptr<Entry>> &getSources() { return m_Sources; }
std::map<uint32_t, std::unique_ptr<Entry>> &getSinkInputs() { return m_SinkInputs; }
std::map<uint32_t, std::unique_ptr<Entry>> &getSourceOutputs() { return m_SourceOutputs; }
std::map<uint32_t, std::unique_ptr<Entry>> &getCards() { return m_Cards; }
std::vector<std::unique_ptr<std::pair<PAInterface *, Entry *>>> m_IEPairs;
void createMonitorStreamForEntry(Entry *entry, int type);
//PulseAudio API Callbacks
//userptr points to current PAInterface instance
static void cb_context_state(pa_context *context, void *interface);
static void cb_context_drain_complete(pa_context *context, void *null);
static void cb_success(pa_context *context, int success, void *interface);
static void cb_subscription_event(pa_context *context, pa_subscription_event_type_t type, uint32_t idx, void *interface);
static void
cb_subscription_event(pa_context *context, pa_subscription_event_type_t type, uint32_t idx, void *interface);
static void cb_sink_info(pa_context *context, const pa_sink_info *info, int eol, void *interface);
static void cb_source_info(pa_context *context, const pa_source_info *info, int eol, void *interface);
static void cb_sink_input_info(pa_context *context, const pa_sink_input_info *info, int eol, void *interface);
static void cb_source_output_info(pa_context *context, const pa_source_output_info *info, int eol, void *interface);
static void cb_card_info(pa_context *context, const pa_card_info *info, int eol, void *interface);
static void cb_read(pa_stream *stream, size_t nbytes, void *iepair);
static void cb_stream_state(pa_stream *stream, void *entry);
};
#pragma once
#include <../config.hpp>
#include <painterface.hpp>
#include "pamix_ui.hpp"
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
struct UpdateData
{
struct UpdateData {
bool redrawAll;
UpdateData() = default;
UpdateData(bool redrawAll) { this->redrawAll = redrawAll; }
explicit UpdateData(bool redrawAll) { this->redrawAll = redrawAll; }
};
#define DECAY_STEP 0.04
......@@ -35,20 +34,23 @@ struct UpdateData
#endif
void quit();
void signal_update(bool all);
void selectEntries(PAInterface *interfae, entry_type type);
void signal_update(bool all, bool threaded = false);
void set_volume(PAInterface *interface, double pct);
void add_volume(PAInterface *interface, double pct);
void set_volume(pamix_ui *ui, double pct);
void cycle_switch(PAInterface *interface, bool inc);
void add_volume(pamix_ui *ui, double pct);
void set_mute(PAInterface *interface, bool mute);
void toggle_mute(PAInterface *interface);
void cycle_switch(pamix_ui *ui, bool inc);
void set_lock(PAInterface *interface, bool lock);
void toggle_lock(PAInterface *interface);
void set_mute(pamix_ui *ui, bool mute);
void toggle_mute(pamix_ui *ui);
void set_lock(pamix_ui *ui, bool lock);
void toggle_lock(pamix_ui *ui);
void select_next(PAInterface *interface, bool precise);
void select_previous(PAInterface *interface, bool precise);
......@@ -2,6 +2,7 @@
#include <pamix.hpp>
#include <string>
#include "pamix_ui.hpp"
union argument_t {
double d;
......@@ -9,17 +10,28 @@ union argument_t {
bool b;
};
void pamix_set_interface(