Backup.
This commit is contained in:
parent
6afa08df82
commit
25762b0c29
@ -19,7 +19,7 @@ jobs:
|
|||||||
- name: Building/Compiling/Installing Project
|
- name: Building/Compiling/Installing Project
|
||||||
run: |
|
run: |
|
||||||
cd ${{ gitea.workspace }}
|
cd ${{ gitea.workspace }}
|
||||||
cmake -A x64 -DCMAKE_BUILD_TYPE=Release --preset=default .
|
cmake -A x64 -DCMAKE_BUILD_TYPE=Release .
|
||||||
cd build
|
cd build
|
||||||
cmake --build . --config Release
|
cmake --build . --config Release
|
||||||
cmake --install .
|
cmake --install .
|
||||||
|
@ -252,6 +252,12 @@ target_include_directories(EHS_Dyn PUBLIC ${PROJECT_SOURCE_DIR}/include)
|
|||||||
if (IS_OS_LINUX)
|
if (IS_OS_LINUX)
|
||||||
set(CMAKE_INSTALL_PREFIX "${USER_HOME_DIRECTORY}/.local")
|
set(CMAKE_INSTALL_PREFIX "${USER_HOME_DIRECTORY}/.local")
|
||||||
install(TARGETS EHS_Dyn LIBRARY DESTINATION "bin")
|
install(TARGETS EHS_Dyn LIBRARY DESTINATION "bin")
|
||||||
|
|
||||||
|
find_package(PkgConfig REQUIRED)
|
||||||
|
pkg_check_modules(PIPEWIRE REQUIRED libpipewire-0.3)
|
||||||
|
|
||||||
|
target_include_directories(EHS_Stc PRIVATE ${PIPEWIRE_INCLUDE_DIRS})
|
||||||
|
target_include_directories(EHS_Dyn PRIVATE ${PIPEWIRE_INCLUDE_DIRS})
|
||||||
elseif (IS_OS_WINDOWS)
|
elseif (IS_OS_WINDOWS)
|
||||||
set(CMAKE_INSTALL_PREFIX "${USER_HOME_DIRECTORY}/EHS")
|
set(CMAKE_INSTALL_PREFIX "${USER_HOME_DIRECTORY}/EHS")
|
||||||
install(TARGETS EHS_Dyn LIBRARY DESTINATION "lib")
|
install(TARGETS EHS_Dyn LIBRARY DESTINATION "lib")
|
||||||
@ -295,6 +301,6 @@ elseif (IS_OS_LINUX)
|
|||||||
target_link_libraries(StrToHash xcb xcb-cursor xcb-xfixes xcb-xinput)
|
target_link_libraries(StrToHash xcb xcb-cursor xcb-xfixes xcb-xinput)
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
target_link_libraries(EHS_Dyn z asound)
|
target_link_libraries(EHS_Dyn z asound pipewire-0.3)
|
||||||
target_link_libraries(StrToHash z asound EHS_Stc)
|
target_link_libraries(StrToHash z asound EHS_Stc)
|
||||||
endif ()
|
endif ()
|
@ -1879,6 +1879,9 @@ namespace ehs
|
|||||||
/// @returns The character count.
|
/// @returns The character count.
|
||||||
static N Len(const T* const str)
|
static N Len(const T* const str)
|
||||||
{
|
{
|
||||||
|
if (!str)
|
||||||
|
return 0;
|
||||||
|
|
||||||
N count = 0;
|
N count = 0;
|
||||||
while (str[count])
|
while (str[count])
|
||||||
++count;
|
++count;
|
||||||
|
@ -3,14 +3,32 @@
|
|||||||
#include "ehs/EHS.h"
|
#include "ehs/EHS.h"
|
||||||
#include "BaseAudioDevice.h"
|
#include "BaseAudioDevice.h"
|
||||||
|
|
||||||
#include <alsa/asoundlib.h>
|
#include <spa/param/audio/format-utils.h>
|
||||||
|
#include <pipewire/pipewire.h>
|
||||||
|
#include <pipewire/loop.h>
|
||||||
|
#include <pipewire/context.h>
|
||||||
|
#include <pipewire/stream.h>
|
||||||
|
#include <pipewire/keys.h>
|
||||||
|
|
||||||
namespace ehs
|
namespace ehs
|
||||||
{
|
{
|
||||||
class EHS_LIB_IO AudioDevice : public BaseAudioDevice
|
class EHS_LIB_IO AudioDevice : public BaseAudioDevice
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
snd_pcm_t* hdl;
|
static Array<AudioDevice> devices;
|
||||||
|
static AudioDevice defOut;
|
||||||
|
static AudioDevice defIn;
|
||||||
|
|
||||||
|
UInt_32 id;
|
||||||
|
Str_8 name;
|
||||||
|
pw_loop *loop;
|
||||||
|
pw_context *context;
|
||||||
|
pw_core *core;
|
||||||
|
pw_stream *stream;
|
||||||
|
|
||||||
|
static void RegistryEventGlobal(void *user_data, UInt_32 id, UInt_32 permissions, const char *type, UInt_32 version, const spa_dict *props);
|
||||||
|
|
||||||
|
static void RegistryEventGlobalRemove(void *user_data, UInt_32 id);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
~AudioDevice() override;
|
~AudioDevice() override;
|
||||||
@ -31,16 +49,12 @@ namespace ehs
|
|||||||
|
|
||||||
void CloseStream() override;
|
void CloseStream() override;
|
||||||
|
|
||||||
UInt_64 GetAvailFrames() const override;
|
UInt_64 SendStream(void *data, UInt_64 size) override;
|
||||||
|
|
||||||
Byte* Map(UInt_64* offset, UInt_64* frames) override;
|
|
||||||
|
|
||||||
void UnMap(const UInt_64 offset, const UInt_64 frames) override;
|
|
||||||
|
|
||||||
bool IsValid() const override;
|
bool IsValid() const override;
|
||||||
|
|
||||||
static AudioDevice GetDefault(const AudioDeviceType type);
|
static AudioDevice GetDefault(AudioDeviceType type);
|
||||||
|
|
||||||
static Array<AudioDevice> Get(const AudioDeviceType type, const AudioDeviceState state);
|
static Array<AudioDevice> Get(AudioDeviceType type, AudioDeviceState state);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -51,15 +51,17 @@ namespace ehs
|
|||||||
|
|
||||||
virtual void CloseStream();
|
virtual void CloseStream();
|
||||||
|
|
||||||
|
virtual UInt_64 SendStream(void *data, UInt_64 size);
|
||||||
|
|
||||||
virtual UInt_64 GetAvailFrames() const;
|
virtual UInt_64 GetAvailFrames() const;
|
||||||
|
|
||||||
virtual Byte* Map(UInt_64* offset, UInt_64* frames);
|
virtual Byte* Map(UInt_64* offset, UInt_64* frames);
|
||||||
|
|
||||||
virtual void UnMap(const UInt_64 offset, const UInt_64 frames);
|
virtual void UnMap(UInt_64 offset, UInt_64 frames);
|
||||||
|
|
||||||
AudioDeviceType GetType() const;
|
AudioDeviceType GetType() const;
|
||||||
|
|
||||||
void SetDataType(const DataType newDataType);
|
void SetDataType(DataType newDataType);
|
||||||
|
|
||||||
DataType GetDataType() const;
|
DataType GetDataType() const;
|
||||||
|
|
||||||
@ -67,21 +69,21 @@ namespace ehs
|
|||||||
|
|
||||||
UInt_16 GetBitDepth() const;
|
UInt_16 GetBitDepth() const;
|
||||||
|
|
||||||
void SetSampleRate(const UInt_32 newSampleRate);
|
void SetSampleRate(UInt_32 newSampleRate);
|
||||||
|
|
||||||
UInt_32 GetSampleRate() const;
|
UInt_32 GetSampleRate() const;
|
||||||
|
|
||||||
void SetChannels(const UInt_32 newChannels);
|
void SetChannels(UInt_32 newChannels);
|
||||||
|
|
||||||
UInt_16 GetChannels() const;
|
UInt_16 GetChannels() const;
|
||||||
|
|
||||||
UInt_32 GetFrameSize() const;
|
UInt_32 GetFrameSize() const;
|
||||||
|
|
||||||
void SetPeriod(const UInt_32 newPeriod);
|
void SetPeriod(UInt_32 newPeriod);
|
||||||
|
|
||||||
UInt_32 GetPeriod() const;
|
UInt_32 GetPeriod() const;
|
||||||
|
|
||||||
void SetLatency(const UInt_32 newLatency);
|
void SetLatency(UInt_32 newLatency);
|
||||||
|
|
||||||
UInt_32 GetLatency() const;
|
UInt_32 GetLatency() const;
|
||||||
|
|
||||||
@ -94,12 +96,12 @@ namespace ehs
|
|||||||
/// Retrieves the default audio input/output device.
|
/// Retrieves the default audio input/output device.
|
||||||
/// @param [in] type The audio device type to retrieve.
|
/// @param [in] type The audio device type to retrieve.
|
||||||
/// @param [out] device The default audio device.
|
/// @param [out] device The default audio device.
|
||||||
static BaseAudioDevice GetDefault(const AudioDeviceType type);
|
static BaseAudioDevice GetDefault(AudioDeviceType type);
|
||||||
|
|
||||||
/// Retrieves a list of audio input/output devices.
|
/// Retrieves a list of audio input/output devices.
|
||||||
/// @param [in] type The audio device type to retrieve.
|
/// @param [in] type The audio device type to retrieve.
|
||||||
/// @param [in] state The audio device state to retrieve.
|
/// @param [in] state The audio device state to retrieve.
|
||||||
/// @param [out] devices The list of audio devices.
|
/// @param [out] devices The list of audio devices.
|
||||||
static Array<BaseAudioDevice> Get(const AudioDeviceType type, const AudioDeviceState state);
|
static Array<BaseAudioDevice> Get(AudioDeviceType type, AudioDeviceState state);
|
||||||
};
|
};
|
||||||
}
|
}
|
@ -1,32 +1,61 @@
|
|||||||
#include "ehs/io/audio/AudioDevice_ALSA.h"
|
#include "ehs/io/audio/AudioDevice_ALSA.h"
|
||||||
#include "ehs/EHS.h"
|
#include "ehs/EHS.h"
|
||||||
#include "ehs/Log.h"
|
#include "ehs/Log.h"
|
||||||
#include "ehs/io/Console.h"
|
#include "ehs/system/Semaphore.h"
|
||||||
|
|
||||||
|
#include <spa/utils/list.h>
|
||||||
|
#include <spa/utils/result.h>
|
||||||
|
#include <spa/utils/dict.h>
|
||||||
|
|
||||||
|
#include "ehs/io/audio/AudioDevice.h"
|
||||||
|
|
||||||
namespace ehs
|
namespace ehs
|
||||||
{
|
{
|
||||||
|
Array<AudioDevice> AudioDevice::devices;
|
||||||
|
|
||||||
|
void AudioDevice::RegistryEventGlobal(void *user_data, UInt_32 id, UInt_32 permissions, const char *type, UInt_32 version, const spa_dict *props)
|
||||||
|
{
|
||||||
|
const Str_8 mediaClass = spa_dict_lookup(props, PW_KEY_MEDIA_CLASS);
|
||||||
|
|
||||||
|
if (mediaClass.Size() && (mediaClass == "Audio/Sink" || mediaClass == "Audio/Source"))
|
||||||
|
{
|
||||||
|
AudioDevice device;
|
||||||
|
|
||||||
|
if (mediaClass == "Audio/Sink")
|
||||||
|
device.type = AudioDeviceType::OUTPUT;
|
||||||
|
else if (mediaClass == "Audio/Source")
|
||||||
|
device.type = AudioDeviceType::INPUT;
|
||||||
|
|
||||||
|
device.id = id;
|
||||||
|
device.name = spa_dict_lookup(props, PW_KEY_NODE_NAME);
|
||||||
|
|
||||||
|
EHS_LOG_INT(LogType::INFO, 1, "\nDevice Name: " + device.name + "\nId: " + Str_8::FromNum(device.id));
|
||||||
|
|
||||||
|
const pw_metadata *metadata = pw_core_get_metadata();
|
||||||
|
|
||||||
|
devices.Push(device);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AudioDevice::RegistryEventGlobalRemove(void *user_data, UInt_32 id)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
AudioDevice::~AudioDevice()
|
AudioDevice::~AudioDevice()
|
||||||
{
|
{
|
||||||
if (!hdl)
|
|
||||||
return;
|
|
||||||
|
|
||||||
snd_pcm_drain(hdl);
|
|
||||||
snd_pcm_close(hdl);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
AudioDevice::AudioDevice()
|
AudioDevice::AudioDevice()
|
||||||
: hdl(nullptr)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
AudioDevice::AudioDevice(AudioDevice&& device) noexcept
|
AudioDevice::AudioDevice(AudioDevice&& device) noexcept
|
||||||
: BaseAudioDevice(device), hdl(device.hdl)
|
: BaseAudioDevice(device)
|
||||||
{
|
{
|
||||||
device.hdl = nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
AudioDevice::AudioDevice(const AudioDevice& device)
|
AudioDevice::AudioDevice(const AudioDevice& device)
|
||||||
: BaseAudioDevice(device), hdl(nullptr)
|
: BaseAudioDevice(device)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -37,10 +66,6 @@ namespace ehs
|
|||||||
|
|
||||||
BaseAudioDevice::operator=(device);
|
BaseAudioDevice::operator=(device);
|
||||||
|
|
||||||
hdl = device.hdl;
|
|
||||||
|
|
||||||
device.hdl = nullptr;
|
|
||||||
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -51,8 +76,6 @@ namespace ehs
|
|||||||
|
|
||||||
BaseAudioDevice::operator=(device);
|
BaseAudioDevice::operator=(device);
|
||||||
|
|
||||||
hdl = nullptr;
|
|
||||||
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -60,10 +83,6 @@ namespace ehs
|
|||||||
{
|
{
|
||||||
if (!IsValid())
|
if (!IsValid())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
snd_pcm_drain(hdl);
|
|
||||||
snd_pcm_close(hdl);
|
|
||||||
hdl = nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioDevice::OpenStream()
|
void AudioDevice::OpenStream()
|
||||||
@ -71,198 +90,50 @@ namespace ehs
|
|||||||
if (streaming)
|
if (streaming)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
snd_pcm_hw_params_t* params;
|
pw_init(nullptr, nullptr);
|
||||||
snd_pcm_hw_params_alloca(¶ms);
|
|
||||||
|
|
||||||
snd_pcm_hw_params_any(hdl, params);
|
loop = pw_loop_new(nullptr);
|
||||||
|
context = pw_context_new(loop, nullptr, 0);
|
||||||
|
core = pw_context_connect(context, nullptr, 0);
|
||||||
|
|
||||||
if (snd_pcm_hw_params_set_access(hdl, params, SND_PCM_ACCESS_MMAP_INTERLEAVED) < 0)
|
spa_audio_info_raw info = {
|
||||||
{
|
.format = SPA_AUDIO_FORMAT_F32,
|
||||||
EHS_LOG_INT(LogType::ERR, 0, "Failed to set access.");
|
.rate = 48000,
|
||||||
return;
|
.channels = 2,
|
||||||
|
.position = {
|
||||||
|
SPA_AUDIO_CHANNEL_FL,
|
||||||
|
SPA_AUDIO_CHANNEL_FR,
|
||||||
|
SPA_AUDIO_CHANNEL_FC,
|
||||||
|
SPA_AUDIO_CHANNEL_LFE,
|
||||||
|
SPA_AUDIO_CHANNEL_SL,
|
||||||
|
SPA_AUDIO_CHANNEL_SR,
|
||||||
|
SPA_AUDIO_CHANNEL_RL,
|
||||||
|
SPA_AUDIO_CHANNEL_RR
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
if (bitDepth)
|
pw_properties *props = pw_properties_new(
|
||||||
{
|
PW_KEY_MEDIA_TYPE, "Audio",
|
||||||
snd_pcm_format_t format;
|
PW_KEY_MEDIA_CATEGORY, "Playback",
|
||||||
switch (dataType)
|
PW_KEY_MEDIA_ROLE, "Game",
|
||||||
{
|
nullptr
|
||||||
case DataType::FLOAT:
|
);
|
||||||
{
|
|
||||||
format = SND_PCM_FORMAT_FLOAT;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case DataType::SINT_32:
|
|
||||||
{
|
|
||||||
format = SND_PCM_FORMAT_S32;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case DataType::SINT_24:
|
|
||||||
{
|
|
||||||
format = SND_PCM_FORMAT_S24;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case DataType::SINT_16:
|
|
||||||
{
|
|
||||||
format = SND_PCM_FORMAT_S16;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case DataType::SINT_8:
|
|
||||||
{
|
|
||||||
format = SND_PCM_FORMAT_S8;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
{
|
|
||||||
EHS_LOG_INT(LogType::ERR, 0, "Invalid data type.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
snd_pcm_hw_params_set_format(hdl, params, format);
|
spa_pod_builder b = {};
|
||||||
}
|
Byte buffer[1024];
|
||||||
|
|
||||||
if (channels)
|
spa_pod_builder_init(&b, buffer, sizeof(buffer));
|
||||||
{
|
|
||||||
if (snd_pcm_hw_params_set_channels_near(hdl, params, &channels) < 0)
|
|
||||||
{
|
|
||||||
EHS_LOG_INT(LogType::ERR, 1, "Failed to set channels.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sampleRate)
|
const spa_pod *pod[] = {spa_format_audio_raw_build(&b, SPA_PARAM_EnumFormat, &info)};
|
||||||
{
|
|
||||||
if (snd_pcm_hw_params_set_rate_near(hdl, params, &sampleRate, nullptr) < 0)
|
|
||||||
{
|
|
||||||
EHS_LOG_INT(LogType::ERR, 2, "Failed to set sample rate.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (snd_pcm_hw_params_set_period_time_near(hdl, params, &period, nullptr) < 0)
|
pw_stream_connect(
|
||||||
{
|
stream,
|
||||||
EHS_LOG_INT(LogType::ERR, 3, "Failed to set period.");
|
PW_DIRECTION_OUTPUT,
|
||||||
return;
|
PW_ID_ANY,
|
||||||
}
|
(pw_stream_flags)(PW_STREAM_FLAG_AUTOCONNECT | PW_STREAM_FLAG_MAP_BUFFERS),
|
||||||
|
pod,
|
||||||
if (snd_pcm_hw_params_set_buffer_time_near(hdl, params, &latency, nullptr) < 0)
|
1
|
||||||
{
|
);
|
||||||
EHS_LOG_INT(LogType::ERR, 4, "Failed to set latency.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (snd_pcm_hw_params(hdl, params) < 0)
|
|
||||||
{
|
|
||||||
EHS_LOG_INT(LogType::ERR, 5, "Failed to apply hardware parameters.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!bitDepth)
|
|
||||||
{
|
|
||||||
snd_pcm_format_t format;
|
|
||||||
if (snd_pcm_hw_params_get_format(params, &format) < 0)
|
|
||||||
{
|
|
||||||
EHS_LOG_INT(LogType::ERR, 6, "Failed to retrieve audio device properties.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (format)
|
|
||||||
{
|
|
||||||
case SND_PCM_FORMAT_FLOAT:
|
|
||||||
{
|
|
||||||
dataType = DataType::FLOAT;
|
|
||||||
bitDepth = 32;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case SND_PCM_FORMAT_S32:
|
|
||||||
{
|
|
||||||
dataType = DataType::SINT_32;
|
|
||||||
bitDepth = 32;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case SND_PCM_FORMAT_S24:
|
|
||||||
{
|
|
||||||
dataType = DataType::SINT_24;
|
|
||||||
bitDepth = 24;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case SND_PCM_FORMAT_S16:
|
|
||||||
{
|
|
||||||
dataType = DataType::SINT_16;
|
|
||||||
bitDepth = 16;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case SND_PCM_FORMAT_S8:
|
|
||||||
{
|
|
||||||
dataType = DataType::SINT_8;
|
|
||||||
bitDepth = 8;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
{
|
|
||||||
EHS_LOG_INT(LogType::ERR, 7, "Format unsupported.");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!channels)
|
|
||||||
{
|
|
||||||
if (snd_pcm_hw_params_get_channels(params, &channels) < 0)
|
|
||||||
{
|
|
||||||
EHS_LOG_INT(LogType::ERR, 8, "Failed to retrieve channel count.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!sampleRate)
|
|
||||||
{
|
|
||||||
int dir;
|
|
||||||
if (snd_pcm_hw_params_get_rate(params, &sampleRate, &dir) < 0)
|
|
||||||
{
|
|
||||||
EHS_LOG_INT(LogType::ERR, 9, "Failed to retrieve sample rate.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (snd_pcm_hw_params_get_buffer_size(params, &maxFrames) < 0)
|
|
||||||
{
|
|
||||||
EHS_LOG_INT(LogType::ERR, 10, "Failed to retrieve buffer size.");
|
|
||||||
}
|
|
||||||
|
|
||||||
snd_pcm_sw_params_t* swParams = nullptr;
|
|
||||||
snd_pcm_sw_params_alloca(&swParams);
|
|
||||||
|
|
||||||
if (snd_pcm_sw_params_current(hdl, swParams) < 0)
|
|
||||||
{
|
|
||||||
EHS_LOG_INT(LogType::ERR, 11, "Failed to retrieve software parameters.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (snd_pcm_sw_params_set_silence_threshold(hdl, swParams, maxFrames) < 0)
|
|
||||||
{
|
|
||||||
EHS_LOG_INT(LogType::ERR, 12, "Failed to set silence threshold.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (snd_pcm_sw_params_set_silence_size(hdl, swParams, maxFrames) < 0)
|
|
||||||
{
|
|
||||||
EHS_LOG_INT(LogType::ERR, 12, "Failed to set silence size.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (snd_pcm_sw_params(hdl, swParams) < 0)
|
|
||||||
{
|
|
||||||
EHS_LOG_INT(LogType::ERR, 13, "Failed to set software parameters.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (snd_pcm_prepare(hdl) < 0)
|
|
||||||
{
|
|
||||||
EHS_LOG_INT(LogType::ERR, 14, "Failed to prepare audio stream.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
streaming = true;
|
streaming = true;
|
||||||
}
|
}
|
||||||
@ -272,119 +143,72 @@ namespace ehs
|
|||||||
if (!streaming)
|
if (!streaming)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
snd_pcm_drain(hdl);
|
pw_stream_destroy(stream);
|
||||||
|
pw_core_disconnect(core);
|
||||||
|
pw_context_destroy(context);
|
||||||
|
pw_loop_destroy(loop);
|
||||||
|
pw_deinit();
|
||||||
|
|
||||||
streaming = false;
|
streaming = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
UInt_64 AudioDevice::GetAvailFrames() const
|
UInt_64 AudioDevice::SendStream(void *data, const UInt_64 size)
|
||||||
{
|
{
|
||||||
snd_pcm_state_t state = snd_pcm_state(hdl);
|
while (pw_loop_iterate(loop, 0));
|
||||||
if (state == SND_PCM_STATE_XRUN)
|
|
||||||
{
|
|
||||||
EHS_LOG_INT(LogType::WARN, 0, "Buffer overrun/underrun occurred.");
|
|
||||||
if (snd_pcm_recover(hdl, -EPIPE, 0) < 0)
|
|
||||||
{
|
|
||||||
EHS_LOG_INT(LogType::ERR, 1, "Failed to recover from buffer overrun/underrun.");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return GetAvailFrames();
|
|
||||||
}
|
|
||||||
else if (state == SND_PCM_STATE_PREPARED)
|
|
||||||
{
|
|
||||||
if (snd_pcm_start(hdl) < 0)
|
|
||||||
{
|
|
||||||
EHS_LOG_INT(LogType::ERR, 2, "Failed to start audio stream.");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return GetAvailFrames();
|
if (pw_stream_get_state(stream, nullptr) != PW_STREAM_STATE_STREAMING)
|
||||||
}
|
|
||||||
|
|
||||||
snd_pcm_sframes_t frames = snd_pcm_avail_update(hdl);
|
|
||||||
if (frames < 0)
|
|
||||||
{
|
|
||||||
if (frames == -EPIPE)
|
|
||||||
{
|
|
||||||
EHS_LOG_INT(LogType::WARN, 3, "Buffer overrun/underrun occurred.");
|
|
||||||
if (snd_pcm_recover(hdl, -EPIPE, 1) < 0)
|
|
||||||
{
|
|
||||||
EHS_LOG_INT(LogType::ERR, 4, "Failed to recover from buffer overrun/underrun.");
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
|
||||||
|
|
||||||
return GetAvailFrames();
|
pw_buffer *buf = pw_stream_dequeue_buffer(stream);
|
||||||
}
|
if (!buf)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
UInt_64 out = 0;
|
||||||
|
|
||||||
|
spa_data &result = buf->buffer->datas[0];
|
||||||
|
|
||||||
|
if (size > result.maxsize)
|
||||||
|
out = result.maxsize;
|
||||||
else
|
else
|
||||||
{
|
out = size;
|
||||||
EHS_LOG_INT(LogType::ERR, 5, "Failed to retrieve available frames with error #" + Str_8::FromNum(frames) + ".");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return frames;
|
Util::Copy(result.data, data, out);
|
||||||
}
|
|
||||||
|
|
||||||
Byte* AudioDevice::Map(UInt_64* offset, UInt_64* frames)
|
pw_stream_queue_buffer(stream, buf);
|
||||||
{
|
|
||||||
const snd_pcm_channel_area_t* areas;
|
|
||||||
if (snd_pcm_mmap_begin(hdl, &areas, offset, frames) < 0)
|
|
||||||
{
|
|
||||||
EHS_LOG_INT(LogType::ERR, 0, "Failed to map audio buffer.");
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (Byte*)areas->addr + areas->first / 8;
|
return out;
|
||||||
}
|
|
||||||
|
|
||||||
void AudioDevice::UnMap(const UInt_64 offset, const UInt_64 frames)
|
|
||||||
{
|
|
||||||
snd_pcm_sframes_t committed = snd_pcm_mmap_commit(hdl, offset, frames);
|
|
||||||
if (committed < 0)
|
|
||||||
{
|
|
||||||
EHS_LOG_INT(LogType::ERR, 0, "Failed to commit mapped audio buffer.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AudioDevice::IsValid() const
|
bool AudioDevice::IsValid() const
|
||||||
{
|
{
|
||||||
return hdl;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
AudioDevice AudioDevice::GetDefault(const AudioDeviceType type)
|
AudioDevice AudioDevice::GetDefault(const AudioDeviceType type)
|
||||||
{
|
{
|
||||||
AudioDevice result;
|
pw_init(nullptr, nullptr);
|
||||||
|
|
||||||
|
pw_loop *loop = pw_loop_new(nullptr);
|
||||||
|
pw_context *context = pw_context_new(loop, nullptr, 0);
|
||||||
|
pw_core *core = pw_context_connect(context, nullptr, 0);
|
||||||
|
pw_registry *registry = pw_core_get_registry(core, PW_VERSION_REGISTRY, 0);
|
||||||
|
spa_hook listener = {};
|
||||||
|
|
||||||
|
constexpr pw_registry_events events = {
|
||||||
|
.version = PW_VERSION_REGISTRY_EVENTS,
|
||||||
|
.global = RegistryEventGlobal,
|
||||||
|
.global_remove = RegistryEventGlobalRemove
|
||||||
|
};
|
||||||
|
|
||||||
|
pw_registry_add_listener(registry, &listener, &events, nullptr);
|
||||||
|
|
||||||
|
while (pw_loop_iterate(loop, 10));
|
||||||
|
|
||||||
|
constexpr pw_metadata_events
|
||||||
|
|
||||||
snd_pcm_stream_t rType;
|
|
||||||
if (type == AudioDeviceType::INPUT)
|
|
||||||
{
|
|
||||||
rType = SND_PCM_STREAM_CAPTURE;
|
|
||||||
}
|
|
||||||
else if (type == AudioDeviceType::OUTPUT)
|
|
||||||
{
|
|
||||||
rType = SND_PCM_STREAM_PLAYBACK;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
EHS_LOG_INT(LogType::ERR, 1, "Wrong value for the audio device type.");
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
int err = snd_pcm_open(&result.hdl, "default", rType, SND_PCM_NONBLOCK);
|
|
||||||
if (err < 0)
|
|
||||||
{
|
|
||||||
EHS_LOG_INT(LogType::ERR, 2, "Failed to retrieve default audio device with error #" + Str_8::FromNum(err) + ".");
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
result.type = AudioDeviceType::OUTPUT;
|
|
||||||
|
|
||||||
EHS_LOG_SUCCESS();
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
Array<AudioDevice> AudioDevice::Get(const AudioDeviceType type, const AudioDeviceState state)
|
Array<AudioDevice> AudioDevice::Get(const AudioDeviceType type, const AudioDeviceState state)
|
||||||
{
|
{
|
||||||
return {};
|
return {};
|
||||||
|
@ -44,6 +44,11 @@ namespace ehs
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UInt_64 BaseAudioDevice::SendStream(void *data, UInt_64 size)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
UInt_64 BaseAudioDevice::GetAvailFrames() const
|
UInt_64 BaseAudioDevice::GetAvailFrames() const
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
|
Loading…
Reference in New Issue
Block a user