mirror of
https://github.com/yann64/haikuports.git
synced 2026-04-09 05:10:05 +02:00
916 lines
26 KiB
Plaintext
916 lines
26 KiB
Plaintext
From b600c27b3dbeb7664035766a03f4574adefd7e2a Mon Sep 17 00:00:00 2001
|
|
From: Gerasim Troeglazov <3dEyes@gmail.com>
|
|
Date: Wed, 24 Feb 2021 14:13:58 +1000
|
|
Subject: Add Haiku backend
|
|
|
|
|
|
diff --git a/CMakeLists.txt b/CMakeLists.txt
|
|
index 0cf0613..47280e7 100644
|
|
--- a/CMakeLists.txt
|
|
+++ b/CMakeLists.txt
|
|
@@ -790,6 +790,7 @@ set(HAVE_OPENSL 0)
|
|
set(HAVE_OBOE 0)
|
|
set(HAVE_WAVE 0)
|
|
set(HAVE_SDL2 0)
|
|
+set(HAVE_HAIKU 0)
|
|
|
|
if(WIN32 OR HAVE_DLFCN_H)
|
|
set(IS_LINKED "")
|
|
@@ -865,6 +866,22 @@ if(ALSOFT_REQUIRE_SOLARIS AND NOT HAVE_SOLARIS)
|
|
message(FATAL_ERROR "Failed to enabled required Solaris backend")
|
|
endif()
|
|
|
|
+# Check Haiku backend
|
|
+option(ALSOFT_REQUIRE_HAIKU "Require Haiku backend" OFF)
|
|
+if(HAIKU)
|
|
+ option(ALSOFT_BACKEND_HAIKU "Enable Haiku backend" ON)
|
|
+ if(ALSOFT_BACKEND_HAIKU)
|
|
+ SET(HAVE_HAIKU 1)
|
|
+ SET(BACKENDS "${BACKENDS} Haiku,")
|
|
+ SET(ALC_OBJS ${ALC_OBJS} alc/backends/haiku.cpp alc/backends/haiku.h)
|
|
+ SET(EXTRA_LIBS be ${EXTRA_LIBS})
|
|
+ SET(EXTRA_LIBS media ${EXTRA_LIBS})
|
|
+ endif()
|
|
+endif()
|
|
+if(ALSOFT_REQUIRE_HAIKU AND NOT HAVE_HAIKU)
|
|
+ MESSAGE(FATAL_ERROR "Failed to enabled required Haiku backend")
|
|
+endif()
|
|
+
|
|
# Check SndIO backend
|
|
option(ALSOFT_REQUIRE_SNDIO "Require SndIO backend" OFF)
|
|
find_package(SoundIO)
|
|
diff --git a/alc/alc.cpp b/alc/alc.cpp
|
|
index a755e67..fd23820 100644
|
|
--- a/alc/alc.cpp
|
|
+++ b/alc/alc.cpp
|
|
@@ -149,6 +149,9 @@
|
|
#ifdef HAVE_SDL2
|
|
#include "backends/sdl2.h"
|
|
#endif
|
|
+#ifdef HAVE_HAIKU
|
|
+#include "backends/haiku.h"
|
|
+#endif
|
|
#ifdef HAVE_WAVE
|
|
#include "backends/wave.h"
|
|
#endif
|
|
@@ -214,7 +217,9 @@ BackendInfo BackendList[] = {
|
|
#ifdef HAVE_SDL2
|
|
{ "sdl2", SDL2BackendFactory::getFactory },
|
|
#endif
|
|
-
|
|
+#ifdef HAVE_HAIKU
|
|
+ { "haiku", HaikuBackendFactory::getFactory },
|
|
+#endif
|
|
{ "null", NullBackendFactory::getFactory },
|
|
#ifdef HAVE_WAVE
|
|
{ "wave", WaveBackendFactory::getFactory },
|
|
diff --git a/alc/backends/haiku.cpp b/alc/backends/haiku.cpp
|
|
new file mode 100644
|
|
index 0000000..0052a64
|
|
--- /dev/null
|
|
+++ b/alc/backends/haiku.cpp
|
|
@@ -0,0 +1,453 @@
|
|
+/**
|
|
+ * OpenAL cross platform audio library
|
|
+ * Copyright (C) 2020-2021 by Gerasim Troeglazov
|
|
+ * This library is free software; you can redistribute it and/or
|
|
+ * modify it under the terms of the GNU Library General Public
|
|
+ * License as published by the Free Software Foundation; either
|
|
+ * version 2 of the License, or (at your option) any later version.
|
|
+ *
|
|
+ * This library is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
+ * Library General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU Library General Public
|
|
+ * License along with this library; if not, write to the
|
|
+ * Free Software Foundation, Inc.,
|
|
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
+ * Or go to http://www.gnu.org/copyleft/lgpl.html
|
|
+ */
|
|
+
|
|
+#include "config.h"
|
|
+
|
|
+#include "backends/haiku.h"
|
|
+
|
|
+#include <exception>
|
|
+#include <atomic>
|
|
+#include <chrono>
|
|
+#include <cstdint>
|
|
+#include <cstring>
|
|
+#include <functional>
|
|
+#include <thread>
|
|
+
|
|
+#include "alcmain.h"
|
|
+#include "almalloc.h"
|
|
+#include "alu.h"
|
|
+#include "threads.h"
|
|
+#include "ringbuffer.h"
|
|
+#include "converter.h"
|
|
+
|
|
+#include <OS.h>
|
|
+#include <Path.h>
|
|
+#include <Roster.h>
|
|
+#include <Application.h>
|
|
+#include <SoundPlayer.h>
|
|
+#include <MediaAddOn.h>
|
|
+#include <MediaFile.h>
|
|
+#include <MediaNode.h>
|
|
+#include <MediaRecorder.h>
|
|
+#include <MediaRoster.h>
|
|
+#include <MediaTrack.h>
|
|
+#include <TimeSource.h>
|
|
+#include <NodeInfo.h>
|
|
+
|
|
+namespace {
|
|
+
|
|
+constexpr char defaultDeviceName[] = "Haiku Default";
|
|
+constexpr char defualtProcessName[] = "OpenAL";
|
|
+
|
|
+struct HaikuPlayback final : public BackendBase {
|
|
+ HaikuPlayback(ALCdevice *device) noexcept : BackendBase{device} { }
|
|
+ ~HaikuPlayback() override;
|
|
+
|
|
+ void audioCallback(void *stream, size_t len) noexcept;
|
|
+ static void audioCallbackC(void *cookie, void *buffer, size_t len, const media_raw_audio_format &) noexcept
|
|
+ {
|
|
+ static_cast<HaikuPlayback*>(cookie)->audioCallback(buffer, len);
|
|
+ }
|
|
+
|
|
+ void open(const char *name) override;
|
|
+ bool reset() override;
|
|
+ void start() override;
|
|
+ void stop() override;
|
|
+
|
|
+ BSoundPlayer *haikuSoundPlayer{0u};
|
|
+
|
|
+ DEF_NEWDEL(HaikuPlayback)
|
|
+};
|
|
+
|
|
+HaikuPlayback::~HaikuPlayback()
|
|
+{
|
|
+ if(haikuSoundPlayer) {
|
|
+ haikuSoundPlayer->SetHasData(false);
|
|
+ haikuSoundPlayer->Stop();
|
|
+ delete haikuSoundPlayer;
|
|
+ }
|
|
+ haikuSoundPlayer = 0;
|
|
+}
|
|
+
|
|
+void HaikuPlayback::audioCallback(void *stream, size_t len) noexcept
|
|
+{
|
|
+ const auto ulen = static_cast<unsigned int>(len);
|
|
+ mDevice->renderSamples(stream, ulen / mDevice->frameSizeFromFmt(), mDevice->channelsFromFmt());
|
|
+}
|
|
+
|
|
+void HaikuPlayback::open(const char *name)
|
|
+{
|
|
+ if(!name)
|
|
+ name = defaultDeviceName;
|
|
+ else if(strcmp(name, defaultDeviceName) != 0) {
|
|
+ throw al::backend_exception{al::backend_error::NoDevice, "Device name \"%s\" not found",
|
|
+ name};
|
|
+ }
|
|
+
|
|
+ media_raw_audio_format format = {
|
|
+ static_cast<float>(mDevice->Frequency),
|
|
+ mDevice->channelsFromFmt(),
|
|
+ media_raw_audio_format::B_AUDIO_SHORT,
|
|
+ B_MEDIA_LITTLE_ENDIAN,
|
|
+ mDevice->UpdateSize * sizeof(short)
|
|
+ };
|
|
+
|
|
+ switch(mDevice->FmtType)
|
|
+ {
|
|
+ case DevFmtUByte:
|
|
+ format.format = media_raw_audio_format::B_AUDIO_UCHAR;
|
|
+ break;
|
|
+ case DevFmtByte:
|
|
+ format.format = media_raw_audio_format::B_AUDIO_CHAR;
|
|
+ break;
|
|
+ case DevFmtUShort:
|
|
+ mDevice->FmtType = DevFmtShort;
|
|
+ format.format = media_raw_audio_format::B_AUDIO_SHORT;
|
|
+ break;
|
|
+ case DevFmtShort:
|
|
+ format.format = media_raw_audio_format::B_AUDIO_SHORT;
|
|
+ break;
|
|
+ case DevFmtUInt:
|
|
+ mDevice->FmtType = DevFmtInt;
|
|
+ format.format = media_raw_audio_format::B_AUDIO_INT;
|
|
+ break;
|
|
+ case DevFmtInt:
|
|
+ format.format = media_raw_audio_format::B_AUDIO_INT;
|
|
+ break;
|
|
+ case DevFmtFloat:
|
|
+ format.format = media_raw_audio_format::B_AUDIO_FLOAT;
|
|
+ break;
|
|
+ default:
|
|
+ mDevice->FmtType = DevFmtShort;
|
|
+ format.format = media_raw_audio_format::B_AUDIO_SHORT;
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ format.buffer_size = mDevice->UpdateSize * mDevice->frameSizeFromFmt();
|
|
+
|
|
+ BString processName(defualtProcessName);
|
|
+ app_info appInfo;
|
|
+ if (be_app->GetAppInfo(&appInfo) == B_OK) {
|
|
+ BPath path(&appInfo.ref);
|
|
+ processName.SetTo(path.Leaf());
|
|
+ }
|
|
+
|
|
+ haikuSoundPlayer = new BSoundPlayer(&format, processName.String(), audioCallbackC, NULL, static_cast<void*>(this));
|
|
+ if(haikuSoundPlayer->InitCheck() != B_OK)
|
|
+ throw al::backend_exception{al::backend_error::NoDevice, "Failed to create BSoundPlayer"};
|
|
+
|
|
+ mDevice->DeviceName = name;
|
|
+}
|
|
+
|
|
+bool HaikuPlayback::reset()
|
|
+{
|
|
+ setDefaultWFXChannelOrder();
|
|
+ return true;
|
|
+}
|
|
+
|
|
+void HaikuPlayback::start()
|
|
+{
|
|
+ if(haikuSoundPlayer) {
|
|
+ haikuSoundPlayer->Start();
|
|
+ haikuSoundPlayer->SetHasData(true);
|
|
+ }
|
|
+}
|
|
+
|
|
+void HaikuPlayback::stop()
|
|
+{
|
|
+ if(haikuSoundPlayer) {
|
|
+ haikuSoundPlayer->SetHasData(false);
|
|
+ haikuSoundPlayer->Stop();
|
|
+ }
|
|
+}
|
|
+
|
|
+struct HaikuCapture final : public BackendBase {
|
|
+ HaikuCapture(ALCdevice *device) noexcept : BackendBase{device} { }
|
|
+ ~HaikuCapture() override;
|
|
+
|
|
+ void readCallback(void* data, size_t size, const media_format &format) noexcept;
|
|
+ static void readCallbackC(void* cookie, bigtime_t, void* data, size_t size, const media_format &format) noexcept
|
|
+ {
|
|
+ return static_cast<HaikuCapture*>(cookie)->readCallback(data, size, format);
|
|
+ }
|
|
+
|
|
+ static void notifyCallbackC(void * cookie, BMediaRecorder::notification code, ...)
|
|
+ {
|
|
+ HaikuCapture *haikuCapture = static_cast<HaikuCapture*>(cookie);
|
|
+ if (code == BMediaRecorder::B_WILL_STOP) {
|
|
+ if (haikuCapture->isRecording) {
|
|
+ haikuCapture->fRecorder->Stop();
|
|
+ haikuCapture->isRecording = false;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ void open(const char *name) override;
|
|
+ void start() override;
|
|
+ void stop() override;
|
|
+ void captureSamples(al::byte *buffer, uint samples) override;
|
|
+ uint availableSamples() override;
|
|
+
|
|
+ RingBufferPtr mRing{nullptr};
|
|
+ ChannelConverter mChannelConv{};
|
|
+ SampleConverterPtr mSampleConv;
|
|
+
|
|
+ bool isRecording{false};
|
|
+
|
|
+ BMediaRoster *fRoster{0u};
|
|
+ BMediaRecorder *fRecorder{0u};
|
|
+ media_format fRecordFormat;
|
|
+ media_node fAudioInputNode;
|
|
+ media_node fAudioMixerNode;
|
|
+
|
|
+ DEF_NEWDEL(HaikuCapture)
|
|
+};
|
|
+
|
|
+HaikuCapture::~HaikuCapture()
|
|
+{
|
|
+ if (fRecorder) {
|
|
+ if (fRecorder->InitCheck() == B_OK) {
|
|
+ if (fRecorder->IsConnected())
|
|
+ fRecorder->Disconnect();
|
|
+ }
|
|
+ delete fRecorder;
|
|
+ fRecorder = NULL;
|
|
+ }
|
|
+}
|
|
+
|
|
+void HaikuCapture::readCallback(void* data, size_t size, const media_format &format) noexcept
|
|
+{
|
|
+ uint numsamples = static_cast<uint>(size) / format.AudioFrameSize();
|
|
+ void *rdata = data;
|
|
+
|
|
+ al::vector<float> samples;
|
|
+ if (mChannelConv.is_active()) {
|
|
+ samples.resize(numsamples*2);
|
|
+ mChannelConv.convert(rdata, samples.data(), numsamples);
|
|
+ rdata = reinterpret_cast<void*>(samples.data());
|
|
+ }
|
|
+
|
|
+ auto dstdata = mRing->getWriteVector();
|
|
+ size_t dstframes;
|
|
+ if (mSampleConv) {
|
|
+ const void *srcdata{rdata};
|
|
+ uint srcframes{numsamples};
|
|
+ dstframes = mSampleConv->convert(&srcdata, &srcframes, dstdata.first.buf,
|
|
+ static_cast<uint>(minz(dstdata.first.len, INT_MAX)));
|
|
+ } else {
|
|
+ const uint framesize{mDevice->frameSizeFromFmt()};
|
|
+ size_t len1{minz(dstdata.first.len, numsamples)};
|
|
+ size_t len2{minz(dstdata.second.len, numsamples - len1)};
|
|
+ memcpy(dstdata.first.buf, rdata, len1 * framesize);
|
|
+ if(len2 > 0)
|
|
+ memcpy(dstdata.second.buf, static_cast<unsigned char*>(rdata) + len1 * framesize, len2 * framesize);
|
|
+ dstframes = len1 + len2;
|
|
+ }
|
|
+
|
|
+ mRing->writeAdvance(dstframes);
|
|
+}
|
|
+
|
|
+void HaikuCapture::open(const char *name)
|
|
+{
|
|
+ if(!name)
|
|
+ name = defaultDeviceName;
|
|
+ else if(strcmp(name, defaultDeviceName) != 0) {
|
|
+ throw al::backend_exception{al::backend_error::NoDevice, "Device name \"%s\" not found",
|
|
+ name};
|
|
+ }
|
|
+
|
|
+ status_t error;
|
|
+
|
|
+ fRoster = BMediaRoster::Roster(&error);
|
|
+ if (!fRoster)
|
|
+ throw al::backend_exception{al::backend_error::NoDevice, "Failed to open BMediaRoster"};
|
|
+
|
|
+ error = fRoster->GetAudioInput(&fAudioInputNode);
|
|
+ if (error < B_OK)
|
|
+ throw al::backend_exception{al::backend_error::NoDevice, "Failed to get audio input node"};
|
|
+
|
|
+ error = fRoster->GetAudioMixer(&fAudioMixerNode);
|
|
+ if (error < B_OK)
|
|
+ throw al::backend_exception{al::backend_error::NoDevice, "Failed to open audio mixer"};
|
|
+
|
|
+ fRecorder = new BMediaRecorder(defualtProcessName, B_MEDIA_RAW_AUDIO);
|
|
+ if (fRecorder->InitCheck() < B_OK)
|
|
+ throw al::backend_exception{al::backend_error::NoDevice, "Failed to create BMediaRecorder"};
|
|
+
|
|
+ media_format output_format;
|
|
+ output_format.type = B_MEDIA_RAW_AUDIO;
|
|
+ output_format.u.raw_audio = media_raw_audio_format::wildcard;
|
|
+ output_format.u.raw_audio.channel_count = static_cast<int>(mDevice->channelsFromFmt());
|
|
+ fRecorder->SetAcceptedFormat(output_format);
|
|
+
|
|
+ const int maxInputCount = 64;
|
|
+ dormant_node_info dni[maxInputCount];
|
|
+
|
|
+ int32 real_count = maxInputCount;
|
|
+
|
|
+ error = fRoster->GetDormantNodes(dni, &real_count, 0, &output_format, 0, B_BUFFER_PRODUCER | B_PHYSICAL_INPUT);
|
|
+ if (real_count > maxInputCount)
|
|
+ real_count = maxInputCount;
|
|
+ char selected_name[B_MEDIA_NAME_LENGTH] = "Default input";
|
|
+
|
|
+ for (int i = 0; i < real_count; i++) {
|
|
+ media_node_id ni[12];
|
|
+ int32 ni_count = 12;
|
|
+ error = fRoster->GetInstancesFor(dni[i].addon, dni[i].flavor_id, ni, &ni_count);
|
|
+ if (error == B_OK) {
|
|
+ for (int j = 0; j < ni_count; j++) {
|
|
+ if (ni[j] == fAudioInputNode.node) {
|
|
+ strcpy(selected_name, dni[i].name);
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ media_output audioOutput;
|
|
+ if (!fRecorder->IsConnected()) {
|
|
+ int32 count = 0;
|
|
+ error = fRoster->GetFreeOutputsFor(fAudioInputNode, &audioOutput, 1, &count, B_MEDIA_RAW_AUDIO);
|
|
+ if (error < B_OK || count < 1)
|
|
+ throw al::backend_exception{al::backend_error::NoDevice, "Failed to get free outputs"};
|
|
+
|
|
+ fRecordFormat.u.raw_audio = audioOutput.format.u.raw_audio;
|
|
+ } else {
|
|
+ fRecordFormat.u.raw_audio = fRecorder->AcceptedFormat().u.raw_audio;
|
|
+ }
|
|
+
|
|
+ fRecordFormat.type = B_MEDIA_RAW_AUDIO;
|
|
+
|
|
+ error = fRecorder->SetHooks(readCallbackC, notifyCallbackC, this);
|
|
+ if (error < B_OK)
|
|
+ throw al::backend_exception{al::backend_error::NoDevice, "Failed to set recorder hooks"};
|
|
+
|
|
+ if (!fRecorder->IsConnected()) {
|
|
+ error = fRecorder->Connect(fAudioInputNode, &audioOutput, &fRecordFormat);
|
|
+ if (error < B_OK) {
|
|
+ fRecorder->SetHooks(NULL, NULL, NULL);
|
|
+ throw al::backend_exception{al::backend_error::NoDevice, "Failed connection to BMediaRecorder"};
|
|
+ }
|
|
+ }
|
|
+
|
|
+ mRing = RingBuffer::Create(mDevice->BufferSize, mDevice->frameSizeFromFmt(), false);
|
|
+
|
|
+ DevFmtType srcType{};
|
|
+ switch(fRecordFormat.u.raw_audio.format) {
|
|
+ case media_raw_audio_format::B_AUDIO_UCHAR:
|
|
+ srcType = DevFmtUByte;
|
|
+ break;
|
|
+ case media_raw_audio_format::B_AUDIO_CHAR:
|
|
+ srcType = DevFmtByte;
|
|
+ break;
|
|
+ case media_raw_audio_format::B_AUDIO_SHORT:
|
|
+ srcType = DevFmtShort;
|
|
+ break;
|
|
+ case media_raw_audio_format::B_AUDIO_INT:
|
|
+ srcType = DevFmtInt;
|
|
+ break;
|
|
+ case media_raw_audio_format::B_AUDIO_FLOAT:
|
|
+ srcType = DevFmtFloat;
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ mSampleConv = nullptr;
|
|
+ mChannelConv = {};
|
|
+
|
|
+ if(mDevice->FmtChans == DevFmtMono && fRecordFormat.u.raw_audio.channel_count != 1) {
|
|
+ uint chanmask{(1u<<fRecordFormat.u.raw_audio.channel_count) - 1u};
|
|
+ mChannelConv = ChannelConverter{srcType, fRecordFormat.u.raw_audio.channel_count, chanmask, mDevice->FmtChans};
|
|
+ srcType = DevFmtFloat;
|
|
+ } else if(mDevice->FmtChans == DevFmtStereo && fRecordFormat.u.raw_audio.channel_count == 1) {
|
|
+ mChannelConv = ChannelConverter{srcType, 1, 0x1, mDevice->FmtChans};
|
|
+ srcType = DevFmtFloat;
|
|
+ }
|
|
+
|
|
+ if(static_cast<uint>(fRecordFormat.u.raw_audio.frame_rate) != mDevice->Frequency || mDevice->FmtType != srcType) {
|
|
+ mSampleConv = CreateSampleConverter(srcType, mDevice->FmtType,
|
|
+ mDevice->channelsFromFmt(), static_cast<int>(fRecordFormat.u.raw_audio.frame_rate),
|
|
+ mDevice->Frequency, Resampler::FastBSinc24);
|
|
+ }
|
|
+
|
|
+ mDevice->DeviceName = name;
|
|
+}
|
|
+
|
|
+void HaikuCapture::start()
|
|
+{
|
|
+ isRecording = true;
|
|
+ fRecorder->Start();
|
|
+}
|
|
+
|
|
+void HaikuCapture::stop()
|
|
+{
|
|
+ isRecording = false;
|
|
+ fRecorder->Stop();
|
|
+}
|
|
+
|
|
+uint HaikuCapture::availableSamples()
|
|
+{
|
|
+ return static_cast<uint>(mRing->readSpace());
|
|
+}
|
|
+
|
|
+void HaikuCapture::captureSamples(al::byte *buffer, uint samples)
|
|
+{
|
|
+ mRing->read(buffer, samples);
|
|
+}
|
|
+
|
|
+} // namespace
|
|
+
|
|
+
|
|
+bool HaikuBackendFactory::init()
|
|
+{
|
|
+ return true;
|
|
+}
|
|
+
|
|
+bool HaikuBackendFactory::querySupport(BackendType type)
|
|
+{
|
|
+ return (type == BackendType::Playback || type == BackendType::Capture);
|
|
+}
|
|
+
|
|
+std::string HaikuBackendFactory::probe(BackendType type)
|
|
+{
|
|
+ std::string outnames;
|
|
+ switch(type)
|
|
+ {
|
|
+ case BackendType::Playback:
|
|
+ case BackendType::Capture:
|
|
+ outnames.append(defaultDeviceName, sizeof(defaultDeviceName));
|
|
+ break;
|
|
+ }
|
|
+ return outnames;
|
|
+}
|
|
+
|
|
+BackendPtr HaikuBackendFactory::createBackend(ALCdevice *device, BackendType type)
|
|
+{
|
|
+ if(type == BackendType::Playback)
|
|
+ return BackendPtr{new HaikuPlayback{device}};
|
|
+ if(type == BackendType::Capture)
|
|
+ return BackendPtr{new HaikuCapture{device}};
|
|
+ return nullptr;
|
|
+}
|
|
+
|
|
+BackendFactory &HaikuBackendFactory::getFactory()
|
|
+{
|
|
+ static HaikuBackendFactory factory{};
|
|
+ return factory;
|
|
+}
|
|
diff --git a/alc/backends/haiku.h b/alc/backends/haiku.h
|
|
new file mode 100644
|
|
index 0000000..3e20db8
|
|
--- /dev/null
|
|
+++ b/alc/backends/haiku.h
|
|
@@ -0,0 +1,19 @@
|
|
+#ifndef BACKENDS_HAIKU_H
|
|
+#define BACKENDS_HAIKU_H
|
|
+
|
|
+#include "backends/base.h"
|
|
+
|
|
+struct HaikuBackendFactory final : public BackendFactory {
|
|
+public:
|
|
+ bool init() override;
|
|
+
|
|
+ bool querySupport(BackendType type) override;
|
|
+
|
|
+ std::string probe(BackendType type) override;
|
|
+
|
|
+ BackendPtr createBackend(ALCdevice *device, BackendType type) override;
|
|
+
|
|
+ static BackendFactory &getFactory();
|
|
+};
|
|
+
|
|
+#endif /* BACKENDS_HAIKU_H */
|
|
diff --git a/config.h.in b/config.h.in
|
|
index a28204e..c37065c 100644
|
|
--- a/config.h.in
|
|
+++ b/config.h.in
|
|
@@ -71,6 +71,9 @@
|
|
/* Define if we have the SDL2 backend */
|
|
#cmakedefine HAVE_SDL2
|
|
|
|
+/* Define if we have the Haiku backend */
|
|
+#cmakedefine HAVE_HAIKU
|
|
+
|
|
/* Define if we have dlfcn.h */
|
|
#cmakedefine HAVE_DLFCN_H
|
|
|
|
--
|
|
2.30.2
|
|
|
|
|
|
From 4d275ab94a2d3de13f28a496759a8e224b81d596 Mon Sep 17 00:00:00 2001
|
|
From: Gerasim Troeglazov <3dEyes@gmail.com>
|
|
Date: Wed, 24 Feb 2021 17:06:13 +1000
|
|
Subject: Move config file to settings dir
|
|
|
|
|
|
diff --git a/alc/alconfig.cpp b/alc/alconfig.cpp
|
|
index 634679a..e6eba16 100644
|
|
--- a/alc/alconfig.cpp
|
|
+++ b/alc/alconfig.cpp
|
|
@@ -32,6 +32,9 @@
|
|
#ifdef __APPLE__
|
|
#include <CoreFoundation/CoreFoundation.h>
|
|
#endif
|
|
+#ifdef __HAIKU__
|
|
+#include <FindDirectory.h>
|
|
+#endif
|
|
|
|
#include <algorithm>
|
|
#include <cstdio>
|
|
@@ -314,6 +317,27 @@ void ReadALConfig()
|
|
}
|
|
}
|
|
|
|
+#elif defined(__HAIKU__)
|
|
+void ReadALConfig()
|
|
+{
|
|
+ char confpath[PATH_MAX] = "";
|
|
+ if (find_directory(B_USER_SETTINGS_DIRECTORY, -1, false, confpath, sizeof(confpath)) == B_OK) {
|
|
+ std::string confname{confpath};
|
|
+ confname += "/alsoft.conf";
|
|
+
|
|
+ TRACE("Loading config %s...\n", confname.c_str());
|
|
+ al::ifstream f{confname};
|
|
+ if(f.is_open())
|
|
+ LoadConfigFromFile(f);
|
|
+ }
|
|
+ if(auto confname = al::getenv("ALSOFT_CONF"))
|
|
+ {
|
|
+ TRACE("Loading config %s...\n", confname->c_str());
|
|
+ al::ifstream f{*confname};
|
|
+ if(f.is_open())
|
|
+ LoadConfigFromFile(f);
|
|
+ }
|
|
+}
|
|
#else
|
|
|
|
void ReadALConfig()
|
|
diff --git a/utils/alsoft-config/mainwindow.cpp b/utils/alsoft-config/mainwindow.cpp
|
|
index 8e6c7be..5454a3f 100644
|
|
--- a/utils/alsoft-config/mainwindow.cpp
|
|
+++ b/utils/alsoft-config/mainwindow.cpp
|
|
@@ -19,6 +19,10 @@
|
|
#include <shlobj.h>
|
|
#endif
|
|
|
|
+#ifdef __HAIKU__
|
|
+#include <FindDirectory.h>
|
|
+#endif
|
|
+
|
|
namespace {
|
|
|
|
static const struct {
|
|
@@ -64,6 +68,9 @@ static const struct {
|
|
#ifdef HAVE_OPENSL
|
|
{ "opensl", "OpenSL" },
|
|
#endif
|
|
+#ifdef HAVE_HAIKU
|
|
+ { "haiku", "Haiku" },
|
|
+#endif
|
|
|
|
{ "null", "Null Output" },
|
|
#ifdef HAVE_WAVE
|
|
@@ -152,6 +159,12 @@ static QString getDefaultConfigName()
|
|
return QString();
|
|
};
|
|
QString base = get_appdata_path();
|
|
+#elif defined(Q_OS_HAIKU)
|
|
+ static const char fname[] = "alsoft.conf";
|
|
+ QString base;
|
|
+ char confpath[PATH_MAX] = "";
|
|
+ if (find_directory(B_USER_SETTINGS_DIRECTORY, -1, false, confpath, sizeof(confpath)) == B_OK)
|
|
+ base = QString::fromUtf8(confpath);
|
|
#else
|
|
static const char fname[] = "alsoft.conf";
|
|
QByteArray base = qgetenv("XDG_CONFIG_HOME");
|
|
@@ -178,6 +191,11 @@ static QString getBaseDataPath()
|
|
return QString();
|
|
};
|
|
QString base = get_appdata_path();
|
|
+#elif defined(Q_OS_HAIKU)
|
|
+ QString base;
|
|
+ char datapath[PATH_MAX] = "";
|
|
+ if (find_directory(B_SYSTEM_DATA_DIRECTORY, -1, false, datapath, sizeof(datapath)) == B_OK)
|
|
+ base = QString::fromUtf8(datapath);
|
|
#else
|
|
QByteArray base = qgetenv("XDG_DATA_HOME");
|
|
if(base.isEmpty())
|
|
--
|
|
2.30.2
|
|
|
|
|
|
From 7a3ec72da52e2341a90a8c08a2e7f793a84aa1a5 Mon Sep 17 00:00:00 2001
|
|
From: Gerasim Troeglazov <3dEyes@gmail.com>
|
|
Date: Wed, 24 Feb 2021 18:14:20 +1000
|
|
Subject: Add missing include
|
|
|
|
|
|
diff --git a/alc/backends/haiku.cpp b/alc/backends/haiku.cpp
|
|
index 0052a64..0159c0e 100644
|
|
--- a/alc/backends/haiku.cpp
|
|
+++ b/alc/backends/haiku.cpp
|
|
@@ -40,6 +40,7 @@
|
|
#include <OS.h>
|
|
#include <Path.h>
|
|
#include <Roster.h>
|
|
+#include <String.h>
|
|
#include <Application.h>
|
|
#include <SoundPlayer.h>
|
|
#include <MediaAddOn.h>
|
|
--
|
|
2.30.2
|
|
|
|
|
|
From 2f213bfd3f3c470ad768fe05453fc900ff49690b Mon Sep 17 00:00:00 2001
|
|
From: Gerasim Troeglazov <3dEyes@gmail.com>
|
|
Date: Sat, 27 Feb 2021 23:49:01 +1000
|
|
Subject: Move create/delete BSoundPlayer to play()/stop() funcs
|
|
|
|
|
|
diff --git a/alc/backends/haiku.cpp b/alc/backends/haiku.cpp
|
|
index 0159c0e..08ebf48 100644
|
|
--- a/alc/backends/haiku.cpp
|
|
+++ b/alc/backends/haiku.cpp
|
|
@@ -73,18 +73,15 @@ struct HaikuPlayback final : public BackendBase {
|
|
void stop() override;
|
|
|
|
BSoundPlayer *haikuSoundPlayer{0u};
|
|
+ BString processName;
|
|
+ media_raw_audio_format format;
|
|
|
|
DEF_NEWDEL(HaikuPlayback)
|
|
};
|
|
|
|
HaikuPlayback::~HaikuPlayback()
|
|
{
|
|
- if(haikuSoundPlayer) {
|
|
- haikuSoundPlayer->SetHasData(false);
|
|
- haikuSoundPlayer->Stop();
|
|
- delete haikuSoundPlayer;
|
|
- }
|
|
- haikuSoundPlayer = 0;
|
|
+ stop();
|
|
}
|
|
|
|
void HaikuPlayback::audioCallback(void *stream, size_t len) noexcept
|
|
@@ -102,7 +99,14 @@ void HaikuPlayback::open(const char *name)
|
|
name};
|
|
}
|
|
|
|
- media_raw_audio_format format = {
|
|
+ processName.SetTo(defualtProcessName);
|
|
+ app_info appInfo;
|
|
+ if (be_app->GetAppInfo(&appInfo) == B_OK) {
|
|
+ BPath path(&appInfo.ref);
|
|
+ processName.SetTo(path.Leaf());
|
|
+ }
|
|
+
|
|
+ format = {
|
|
static_cast<float>(mDevice->Frequency),
|
|
mDevice->channelsFromFmt(),
|
|
media_raw_audio_format::B_AUDIO_SHORT,
|
|
@@ -143,17 +147,6 @@ void HaikuPlayback::open(const char *name)
|
|
|
|
format.buffer_size = mDevice->UpdateSize * mDevice->frameSizeFromFmt();
|
|
|
|
- BString processName(defualtProcessName);
|
|
- app_info appInfo;
|
|
- if (be_app->GetAppInfo(&appInfo) == B_OK) {
|
|
- BPath path(&appInfo.ref);
|
|
- processName.SetTo(path.Leaf());
|
|
- }
|
|
-
|
|
- haikuSoundPlayer = new BSoundPlayer(&format, processName.String(), audioCallbackC, NULL, static_cast<void*>(this));
|
|
- if(haikuSoundPlayer->InitCheck() != B_OK)
|
|
- throw al::backend_exception{al::backend_error::NoDevice, "Failed to create BSoundPlayer"};
|
|
-
|
|
mDevice->DeviceName = name;
|
|
}
|
|
|
|
@@ -165,10 +158,15 @@ bool HaikuPlayback::reset()
|
|
|
|
void HaikuPlayback::start()
|
|
{
|
|
- if(haikuSoundPlayer) {
|
|
- haikuSoundPlayer->Start();
|
|
- haikuSoundPlayer->SetHasData(true);
|
|
- }
|
|
+ if (haikuSoundPlayer)
|
|
+ stop();
|
|
+
|
|
+ haikuSoundPlayer = new BSoundPlayer(&format, processName.String(), audioCallbackC, NULL, static_cast<void*>(this));
|
|
+ if(haikuSoundPlayer->InitCheck() != B_OK)
|
|
+ throw al::backend_exception{al::backend_error::NoDevice, "Failed to create BSoundPlayer"};
|
|
+
|
|
+ haikuSoundPlayer->Start();
|
|
+ haikuSoundPlayer->SetHasData(true);
|
|
}
|
|
|
|
void HaikuPlayback::stop()
|
|
@@ -176,7 +174,9 @@ void HaikuPlayback::stop()
|
|
if(haikuSoundPlayer) {
|
|
haikuSoundPlayer->SetHasData(false);
|
|
haikuSoundPlayer->Stop();
|
|
+ delete haikuSoundPlayer;
|
|
}
|
|
+ haikuSoundPlayer = 0;
|
|
}
|
|
|
|
struct HaikuCapture final : public BackendBase {
|
|
@@ -212,6 +212,7 @@ struct HaikuCapture final : public BackendBase {
|
|
|
|
bool isRecording{false};
|
|
|
|
+ BString processName;
|
|
BMediaRoster *fRoster{0u};
|
|
BMediaRecorder *fRecorder{0u};
|
|
media_format fRecordFormat;
|
|
@@ -274,6 +275,13 @@ void HaikuCapture::open(const char *name)
|
|
name};
|
|
}
|
|
|
|
+ processName.SetTo(defualtProcessName);
|
|
+ app_info appInfo;
|
|
+ if (be_app->GetAppInfo(&appInfo) == B_OK) {
|
|
+ BPath path(&appInfo.ref);
|
|
+ processName.SetTo(path.Leaf());
|
|
+ }
|
|
+
|
|
status_t error;
|
|
|
|
fRoster = BMediaRoster::Roster(&error);
|
|
@@ -288,7 +296,7 @@ void HaikuCapture::open(const char *name)
|
|
if (error < B_OK)
|
|
throw al::backend_exception{al::backend_error::NoDevice, "Failed to open audio mixer"};
|
|
|
|
- fRecorder = new BMediaRecorder(defualtProcessName, B_MEDIA_RAW_AUDIO);
|
|
+ fRecorder = new BMediaRecorder(processName, B_MEDIA_RAW_AUDIO);
|
|
if (fRecorder->InitCheck() < B_OK)
|
|
throw al::backend_exception{al::backend_error::NoDevice, "Failed to create BMediaRecorder"};
|
|
|
|
--
|
|
2.30.2
|
|
|
|
|
|
From c7c83004d39f8e446f2bbdcd44ea6d65c0e71a96 Mon Sep 17 00:00:00 2001
|
|
From: Anonymous Maarten <madebr@users.noreply.github.com>
|
|
Date: Tue, 6 Jul 2021 09:34:40 +0200
|
|
Subject: Make OpenALConfig.cmake compatible with CMake's FindOpenAL.cmake
|
|
(#581)
|
|
|
|
* Make OpenALConfig.cmake compatible with CMake's FindOpenAL.cmake
|
|
|
|
* Create and install OpenALConfigVersion.cmake
|
|
|
|
* cmake: drop creating of OpenALConfigVersion.cmake
|
|
|
|
diff --git a/CMakeLists.txt b/CMakeLists.txt
|
|
index 47280e7..f2c7414 100644
|
|
--- a/CMakeLists.txt
|
|
+++ b/CMakeLists.txt
|
|
@@ -69,6 +69,7 @@ include(CheckCXXCompilerFlag)
|
|
include(CheckCSourceCompiles)
|
|
include(CheckCXXSourceCompiles)
|
|
include(CheckStructHasMember)
|
|
+include(CMakePackageConfigHelpers)
|
|
include(GNUInstallDirs)
|
|
|
|
|
|
@@ -1255,7 +1256,7 @@ else()
|
|
target_include_directories(OpenAL
|
|
PUBLIC
|
|
$<BUILD_INTERFACE:${OpenAL_SOURCE_DIR}/include>
|
|
- $<INSTALL_INTERFACE:include>
|
|
+ $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
|
|
PRIVATE
|
|
${OpenAL_SOURCE_DIR}/common
|
|
${OpenAL_BINARY_DIR}
|
|
@@ -1320,7 +1321,10 @@ endif()
|
|
target_include_directories(${IMPL_TARGET}
|
|
PUBLIC
|
|
$<BUILD_INTERFACE:${OpenAL_SOURCE_DIR}/include>
|
|
- $<INSTALL_INTERFACE:include>
|
|
+ INTERFACE
|
|
+ $<BUILD_INTERFACE:${OpenAL_SOURCE_DIR}/include/AL>
|
|
+ $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
|
|
+ $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}/AL>
|
|
PRIVATE
|
|
${INC_PATHS}
|
|
${OpenAL_BINARY_DIR}
|
|
@@ -1387,6 +1391,8 @@ endif()
|
|
|
|
# Install main library
|
|
if(ALSOFT_INSTALL)
|
|
+ configure_package_config_file(OpenALConfig.cmake.in OpenALConfig.cmake
|
|
+ INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/OpenAL)
|
|
install(TARGETS OpenAL EXPORT OpenAL
|
|
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
|
|
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
|
@@ -1395,15 +1401,17 @@ if(ALSOFT_INSTALL)
|
|
INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} ${CMAKE_INSTALL_INCLUDEDIR}/AL)
|
|
export(TARGETS OpenAL
|
|
NAMESPACE OpenAL::
|
|
- FILE OpenALConfig.cmake)
|
|
+ FILE OpenALTargets.cmake)
|
|
install(EXPORT OpenAL
|
|
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/OpenAL
|
|
NAMESPACE OpenAL::
|
|
- FILE OpenALConfig.cmake)
|
|
+ FILE OpenALTargets.cmake)
|
|
install(DIRECTORY include/AL
|
|
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
|
|
install(FILES "${OpenAL_BINARY_DIR}/openal.pc"
|
|
DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig")
|
|
+ install(FILES "${OpenAL_BINARY_DIR}/OpenALConfig.cmake"
|
|
+ DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/OpenAL")
|
|
if(TARGET soft_oal)
|
|
install(TARGETS soft_oal
|
|
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
|
|
diff --git a/OpenALConfig.cmake.in b/OpenALConfig.cmake.in
|
|
new file mode 100644
|
|
index 0000000..128c1a4
|
|
--- /dev/null
|
|
+++ b/OpenALConfig.cmake.in
|
|
@@ -0,0 +1,9 @@
|
|
+cmake_minimum_required(VERSION 3.1)
|
|
+
|
|
+include("${CMAKE_CURRENT_LIST_DIR}/OpenALTargets.cmake")
|
|
+
|
|
+set(OPENAL_FOUND ON)
|
|
+set(OPENAL_INCLUDE_DIR $<TARGET_PROPERTY:OpenAL::OpenAL,INTERFACE_INCLUDE_DIRECTORIES>)
|
|
+set(OPENAL_LIBRARY $<LINK_ONLY:OpenAL::OpenAL>)
|
|
+set(OPENAL_DEFINITIONS $<TARGET_PROPERTY:OpenAL::OpenAL,INTERFACE_COMPILE_DEFINITIONS>)
|
|
+set(OPENAL_VERSION_STRING @PACKAGE_VERSION@)
|
|
--
|
|
2.30.2
|
|
|