remove Haiku support
Haiku support has been unmaintained for many years, and this issue has
been open for more than 5 years, but apparently the Haiku people have
lost interest:
https://github.com/MusicPlayerDaemon/MPD/pull/183
Haiku support was therefore deprecated by this commit 4 years ago:
7de8fd04a4
- but in those 4 years, nobody stepped up to adopt
maintainership.
I don't have any computer (or VM) with Haiku and there is no CI with
Haiku support, so I'm unable to adapt the Haiku specific code to API
changes.
Closes https://github.com/MusicPlayerDaemon/MPD/issues/182
Closes https://github.com/MusicPlayerDaemon/MPD/issues/185
This commit is contained in:
parent
45071607aa
commit
52eff41379
1
NEWS
1
NEWS
|
@ -14,6 +14,7 @@ ver 0.24 (not yet released)
|
|||
- new tag "Mood"
|
||||
* switch to C++20
|
||||
- GCC 10 or clang 11 (or newer) recommended
|
||||
* remove Haiku support
|
||||
|
||||
ver 0.23.9 (not yet released)
|
||||
|
||||
|
|
|
@ -923,14 +923,6 @@ The fifo plugin writes raw PCM data to a FIFO (First In, First Out) file. The da
|
|||
* - **path P**
|
||||
- This specifies the path of the FIFO to write to. Must be an absolute path. If the path does not exist, it will be created when MPD is started, and removed when MPD is stopped. The FIFO will be created with the same user and group as MPD is running as. Default permissions can be modified by using the builtin shell command umask. If a FIFO already exists at the specified path it will be reused, and will not be removed when MPD is stopped. You can use the "mkfifo" command to create this, and then you may modify the permissions to your liking.
|
||||
|
||||
haiku
|
||||
-----
|
||||
|
||||
Use the SoundPlayer API on the Haiku operating system.
|
||||
|
||||
This plugin is unmaintained and contains known bugs. It will be
|
||||
removed soon, unless there is a new maintainer.
|
||||
|
||||
|
||||
jack
|
||||
----
|
||||
|
|
22
meson.build
22
meson.build
|
@ -158,7 +158,6 @@ is_linux = host_machine.system() == 'linux'
|
|||
is_android = get_option('android_ndk') != ''
|
||||
is_darwin = host_machine.system() == 'darwin'
|
||||
is_windows = host_machine.system() == 'windows'
|
||||
is_haiku = host_machine.system() == 'haiku'
|
||||
|
||||
if is_android
|
||||
common_cppflags += '-DANDROID'
|
||||
|
@ -516,13 +515,6 @@ if is_android
|
|||
declare_dependency(sources: [classes_jar]),
|
||||
java_dep,
|
||||
]
|
||||
elif is_haiku
|
||||
target_type = 'executable'
|
||||
target_name = 'mpd.nores'
|
||||
link_args += [
|
||||
'-lnetwork',
|
||||
'-lbe',
|
||||
]
|
||||
else
|
||||
target_type = 'executable'
|
||||
target_name = 'mpd'
|
||||
|
@ -562,25 +554,13 @@ mpd = build_target(
|
|||
],
|
||||
link_args: link_args,
|
||||
build_by_default: not get_option('fuzzer'),
|
||||
install: not is_android and not is_haiku,
|
||||
install: not is_android
|
||||
)
|
||||
|
||||
if is_android
|
||||
subdir('android/apk')
|
||||
endif
|
||||
|
||||
if is_haiku
|
||||
subdir('src/haiku')
|
||||
custom_target(
|
||||
'mpd',
|
||||
output: 'mpd',
|
||||
input: [mpd, rsrc],
|
||||
command: [addres, '@OUTPUT@', '@INPUT0@', '@INPUT1@'],
|
||||
install: true,
|
||||
install_dir: get_option('bindir'),
|
||||
)
|
||||
endif
|
||||
|
||||
configure_file(output: 'config.h', configuration: conf)
|
||||
|
||||
if systemd_dep.found()
|
||||
|
|
Binary file not shown.
|
@ -1,3 +0,0 @@
|
|||
#!/bin/sh
|
||||
|
||||
cp "$2" "$1" && xres -o "$1" -- "$3" && mimeset -f "$1" || (rm -f "$1"; exit 1)
|
|
@ -1,26 +0,0 @@
|
|||
haiku_conf = configuration_data()
|
||||
haiku_conf.set('VERSION', meson.project_version())
|
||||
|
||||
splitted_version = meson.project_version().split('~')[0].split('.')
|
||||
haiku_conf.set('VERSION_MAJOR', splitted_version[0])
|
||||
haiku_conf.set('VERSION_MINOR', splitted_version.get(1, '0'))
|
||||
haiku_conf.set('VERSION_REVISION', splitted_version.get(2, '0'))
|
||||
haiku_conf.set('VERSION_EXTRA', splitted_version.get(3, '0'))
|
||||
|
||||
mpd_rdef = configure_file(
|
||||
input: 'mpd.rdef.in',
|
||||
output: 'mpd.rdef',
|
||||
configuration: haiku_conf,
|
||||
)
|
||||
|
||||
rc = find_program('rc')
|
||||
xres = find_program('xres')
|
||||
|
||||
rsrc = custom_target(
|
||||
'mpd.rsrc',
|
||||
output: 'mpd.rsrc',
|
||||
input: mpd_rdef,
|
||||
command: [rc, '-o', '@OUTPUT@', '@INPUT@'],
|
||||
)
|
||||
|
||||
addres = files('add_resources.sh')
|
|
@ -1,77 +0,0 @@
|
|||
resource app_signature "application/x-vnd.MusicPD";
|
||||
|
||||
resource app_flags B_BACKGROUND_APP;
|
||||
|
||||
resource app_version {
|
||||
major = @VERSION_MAJOR@,
|
||||
middle = @VERSION_MINOR@,
|
||||
minor = @VERSION_REVISION@,
|
||||
variety = B_APPV_ALPHA,
|
||||
internal = @VERSION_EXTRA@,
|
||||
short_info = "Music Player Daemon @VERSION@",
|
||||
long_info = "Music Player Daemon @VERSION@ ©The Music Player Daemon Project"
|
||||
};
|
||||
|
||||
resource vector_icon {
|
||||
$"6E6369661F050102031604BEE29BBEC5403EC540BEE29B4A10004A10000001C6"
|
||||
$"70D073FFFF020116033EB0000000000000003EB000482000482000BE4B0084FF"
|
||||
$"32020316023CAF103CF749BCF7493CAF104A07A44A1DB7A143FFFF02031602BC"
|
||||
$"AB8FBCFA713CFA71BCAB8F4A05E34A004BAB08FFFF03010000020016023CC7EE"
|
||||
$"389BC0BA16573E39B04977C842ADC700FFFFD3020006023C529D3753A2B8966F"
|
||||
$"3D9D084B6044496AAF00474747FFA5A0A002001602BC4E76BC411B3C90DABCA0"
|
||||
$"0D47587D4ABA850090FFD40200160238313C3B5CF0BFCD963C7AAC4C13943FCA"
|
||||
$"F901ECFFC3054B04017E020106023E1C1538010FB7C32B3DF5E649B8BE48DD4A"
|
||||
$"000593DCFF00337F020006023879063B8224BE2CC83B10DB4A1F6F49B894FF9A"
|
||||
$"9A9A00242222020006033C69A60000000000003E186148800049800058F3F3F3"
|
||||
$"00D4CECEFFD9D9D9038DFF06050002001602B2E4F7386B91BA78F7B4F4FD49FB"
|
||||
$"A94AE12500CEFF6603010000020006023C55B638309FBA16573E39B049E9FF43"
|
||||
$"840A008B8787FF161515020016023C57B5364381B785863DA4F54B27C349B7BB"
|
||||
$"0010FF4C02001602BC4E76BC411B3C90DABCA00D47587D4ABA850060FF500200"
|
||||
$"160238313C3B5CF0BFCD963C7AAC4C13943FCAF90174FF22055C04017E020016"
|
||||
$"023879063B8224BE2CC83B10DB4A1F6F49B894FF59001E020016033C3DA60000"
|
||||
$"000000003E186148AC0049800058AD0076FA800333C805020106023A40000000"
|
||||
$"000000003980004A300048400000767676FC403E3E020106023E1C1538010FB7"
|
||||
$"C32B3DF5E649B8BE48DD4A000593DCFF00337F05002102044022C65922B92622"
|
||||
$"224022B92622C659405EB9265EC6595E5E405EC6595EB9260A062E262E4B4C5A"
|
||||
$"5650562C38220A064C5C545C604FCA1BC4875C4A58480A042E264C32562C3822"
|
||||
$"0A044C324C5A5650562C0A042E262E4B4C5A4C320A044934494E3043302A0A04"
|
||||
$"BA29C0283043302ABA31B7540A04494B494E304332C0270A044934494B3241BA"
|
||||
$"31B7540A043E25432252264D2A08043E2543225226522C0A034D2A5226522C08"
|
||||
$"02464F47C5ED0A043246324A4453444E0A04344834494250424E08025436503A"
|
||||
$"0A06262E264C485E5252523430280A04262E483C523430280A04483C485E5252"
|
||||
$"52340A04262E264C485E483C0A04443D4456284928320A04B6F9C28C28492832"
|
||||
$"B701BA840A044454445728492AC28B0A04443D44542A47B701BA840A04382B3D"
|
||||
$"284E2D49310804382B3D284E2D4E330A0349304E2C4E320802425843C9830A06"
|
||||
$"486054606052CA1BC5B95C4D524802044530C2D730C0A430403540BAB540BC06"
|
||||
$"4538C0A438C2D7384A354ABC064ABAB50803452145335B250A044934494B3241"
|
||||
$"BA31B754240A0B0102023EF45B0000000000003EF45B487749B685270A05010B"
|
||||
$"1A3EF45B0000000000003EF45B487749B6852715FF01178400040A09010A0A3E"
|
||||
$"F45B0000000000003EF45B487749B6852715FF0A0A010C023EF45B0000000000"
|
||||
$"003EF45B487749B685270A050101123EF45B0000000000003EF45B487749B685"
|
||||
$"2701178400040A060103023EF45B0000000000003EF45B487749B685270A0701"
|
||||
$"04023EF45B0000000000003EF45B487749B685270A08020506023EF45B000000"
|
||||
$"0000003EF45B487749B685270A0C0109023EF45B0000000000003EF45B487749"
|
||||
$"B685270A0D01070A3EF45B0000000000003EF45B487749B6852715FF0A0E0108"
|
||||
$"0A3EF45B0000000000003EF45B487749B6852715FF0A0F010D1A3EF45B000000"
|
||||
$"0000003EF45B487749B6852715FF01178220040A0A010E0A3EF45B0000000000"
|
||||
$"003EF45B487749B6852715FF0A11010F0A3EF45B0000000000003EF45B487749"
|
||||
$"B6852715FF0A0B01000A3D43F93C2B26BD304E3DF9DE48FCA544AB2E15FF0A00"
|
||||
$"0100123CF8FE3C832FBCE7163E4DA3480D86C5C7B501178400040A010100023C"
|
||||
$"F8FE3C832FBCE7163E4DA3480D86C5C7B50A020100023AC6433A584EBAB58C3C"
|
||||
$"265448124D45D0400A0301001A3CB1A73C46E3BCA16C3E165C480E5DC4720015"
|
||||
$"FF01178200040A0401001A3C808E3C1D64BC71B33DE0FC480EF2C30DBC15FF01"
|
||||
$"178200040A18011D023EAAAA0000000000003EAAAA47155548B0480A12011A1A"
|
||||
$"3EAAAA0000000000003EAAAA47155548B04815FF01178400040A1601190A3EAA"
|
||||
$"AA0000000000003EAAAA47155548B04815FF0A17011B0A3EAAAA000000000000"
|
||||
$"3EAAAA47155548B04815FF0A120111123EAAAA0000000000003EAAAA47155548"
|
||||
$"B04801178400040A130112023EAAAA0000000000003EAAAA47155548B0480A14"
|
||||
$"0113023EAAAA0000000000003EAAAA47155548B0480A15021415023EAAAA0000"
|
||||
$"000000003EAAAA47155548B0480A1D01180A3EAAAA0000000000003EAAAA4715"
|
||||
$"5548B04815FF0A1D01180A3EAAAA0000000000003EAAAA47155548B04800150A"
|
||||
$"1901160A3EAAAA0000000000003EAAAA47155548B04815FF0A1A01170A3EAAAA"
|
||||
$"0000000000003EAAAA47155548B04815FF0A1B011C1A3EAAAA0000000000003E"
|
||||
$"AAAA47155548B04815FF01178220040A1C011E023EAAAA0000000000003EAAAA"
|
||||
$"47155548B0480A12011F1A3EAAAA0000000000003EAAAA47155548B04815FF01"
|
||||
$"178222040A12011F1A3EAAAA0000000000003EAAAA47155548B0480015011784"
|
||||
$"2204"
|
||||
};
|
|
@ -31,7 +31,6 @@ extern const MixerPlugin null_mixer_plugin;
|
|||
extern const MixerPlugin software_mixer_plugin;
|
||||
extern const MixerPlugin android_mixer_plugin;
|
||||
extern const MixerPlugin alsa_mixer_plugin;
|
||||
extern const MixerPlugin haiku_mixer_plugin;
|
||||
extern const MixerPlugin oss_mixer_plugin;
|
||||
extern const MixerPlugin osx_mixer_plugin;
|
||||
extern const MixerPlugin pulse_mixer_plugin;
|
||||
|
|
|
@ -1,72 +0,0 @@
|
|||
/*
|
||||
* Copyright 2003-2021 The Music Player Daemon Project
|
||||
* Copyright (C) 2010-2011 Philipp 'ph3-der-loewe' Schafft
|
||||
* Copyright (C) 2010-2011 Hans-Kristian 'maister' Arntzen
|
||||
* Copyright (C) 2014-2015 François 'mmu_man' Revol
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
|
||||
#include "mixer/MixerInternal.hxx"
|
||||
#include "output/plugins/HaikuOutputPlugin.hxx"
|
||||
#include "util/Compiler.h"
|
||||
|
||||
#include "util/RuntimeError.hxx"
|
||||
|
||||
class HaikuMixer final : public Mixer {
|
||||
/** the base mixer class */
|
||||
HaikuOutput &self;
|
||||
|
||||
public:
|
||||
HaikuMixer(HaikuOutput &_output, MixerListener &_listener)
|
||||
:Mixer(haiku_mixer_plugin, _listener),
|
||||
self(_output) {}
|
||||
|
||||
/* virtual methods from class Mixer */
|
||||
void Open() override {
|
||||
}
|
||||
|
||||
void Close() noexcept override {
|
||||
}
|
||||
|
||||
int GetVolume() override;
|
||||
void SetVolume(unsigned volume) override;
|
||||
};
|
||||
|
||||
static Mixer *
|
||||
haiku_mixer_init([[maybe_unused]] EventLoop &event_loop, AudioOutput &ao,
|
||||
MixerListener &listener,
|
||||
[[maybe_unused]] const ConfigBlock &block)
|
||||
{
|
||||
return new HaikuMixer((HaikuOutput &)ao, listener);
|
||||
}
|
||||
|
||||
int
|
||||
HaikuMixer::GetVolume()
|
||||
{
|
||||
return haiku_output_get_volume(self);
|
||||
}
|
||||
|
||||
void
|
||||
HaikuMixer::SetVolume(unsigned volume)
|
||||
{
|
||||
haiku_output_set_volume(self, volume);
|
||||
}
|
||||
|
||||
const MixerPlugin haiku_mixer_plugin = {
|
||||
haiku_mixer_init,
|
||||
false,
|
||||
};
|
|
@ -10,10 +10,6 @@ if alsa_dep.found()
|
|||
]
|
||||
endif
|
||||
|
||||
if is_haiku
|
||||
mixer_plugins_sources += 'HaikuMixerPlugin.cxx'
|
||||
endif
|
||||
|
||||
if enable_oss
|
||||
mixer_plugins_sources += 'OssMixerPlugin.cxx'
|
||||
endif
|
||||
|
|
|
@ -27,7 +27,6 @@
|
|||
#include "plugins/SndioOutputPlugin.hxx"
|
||||
#include "plugins/snapcast/SnapcastOutputPlugin.hxx"
|
||||
#include "plugins/httpd/HttpdOutputPlugin.hxx"
|
||||
#include "plugins/HaikuOutputPlugin.hxx"
|
||||
#include "plugins/JackOutputPlugin.hxx"
|
||||
#include "plugins/NullOutputPlugin.hxx"
|
||||
#include "plugins/OpenALOutputPlugin.hxx"
|
||||
|
@ -62,9 +61,6 @@ constexpr const AudioOutputPlugin *audio_output_plugins[] = {
|
|||
#ifdef ENABLE_SNDIO
|
||||
&sndio_output_plugin,
|
||||
#endif
|
||||
#ifdef ENABLE_HAIKU
|
||||
&haiku_output_plugin,
|
||||
#endif
|
||||
#ifdef ENABLE_PIPE_OUTPUT
|
||||
&pipe_output_plugin,
|
||||
#endif
|
||||
|
|
|
@ -1,458 +0,0 @@
|
|||
/*
|
||||
* Copyright 2003-2021 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
* Copyright (C) 2014-2015 François 'mmu_man' Revol
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "HaikuOutputPlugin.hxx"
|
||||
#include "../OutputAPI.hxx"
|
||||
#include "mixer/MixerList.hxx"
|
||||
#include "util/Domain.hxx"
|
||||
#include "util/Math.hxx"
|
||||
#include "system/Error.hxx"
|
||||
#include "Log.hxx"
|
||||
|
||||
#include <AppFileInfo.h>
|
||||
#include <Application.h>
|
||||
#include <Bitmap.h>
|
||||
#include <IconUtils.h>
|
||||
#include <MediaDefs.h>
|
||||
#include <MediaRoster.h>
|
||||
#include <Notification.h>
|
||||
#include <OS.h>
|
||||
#include <Resources.h>
|
||||
#include <StringList.h>
|
||||
#include <SoundPlayer.h>
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#define UTF8_PLAY "\xE2\x96\xB6"
|
||||
|
||||
class HaikuOutput final: AudioOutput {
|
||||
friend int haiku_output_get_volume(HaikuOutput &haiku);
|
||||
friend bool haiku_output_set_volume(HaikuOutput &haiku, unsigned volume);
|
||||
|
||||
size_t write_size;
|
||||
|
||||
media_raw_audio_format format;
|
||||
BSoundPlayer* sound_player;
|
||||
|
||||
sem_id new_buffer;
|
||||
sem_id buffer_done;
|
||||
|
||||
uint8* buffer;
|
||||
size_t buffer_size;
|
||||
size_t buffer_filled;
|
||||
|
||||
unsigned buffer_delay;
|
||||
|
||||
public:
|
||||
HaikuOutput(const ConfigBlock &block)
|
||||
:AudioOutput(0),
|
||||
/* XXX: by default we should let the MediaKit propose the buffer size */
|
||||
write_size(block.GetPositiveValue("write_size", 4096u)) {}
|
||||
|
||||
~HaikuOutput();
|
||||
|
||||
static AudioOutput *Create(EventLoop &event_loop,
|
||||
const ConfigBlock &block);
|
||||
|
||||
private:
|
||||
void Open(AudioFormat &audio_format) override;
|
||||
void Close() noexcept override;
|
||||
|
||||
std::size_t Play(std::span<const std::byte> src) override;
|
||||
|
||||
std::chrono::steady_clock::duration Delay() const noexcept override;
|
||||
|
||||
static void _FillBuffer(void* cookie, void* _buffer, size_t size,
|
||||
[[maybe_unused]] const media_raw_audio_format& _format);
|
||||
void FillBuffer(void* _buffer, size_t size,
|
||||
[[maybe_unused]] const media_raw_audio_format& _format);
|
||||
|
||||
void SendTag(const Tag &tag) override;
|
||||
};
|
||||
|
||||
static constexpr Domain haiku_output_domain("haiku_output");
|
||||
|
||||
static void
|
||||
initialize_application()
|
||||
{
|
||||
// required to send the notification with a bitmap
|
||||
// TODO: actually Run() it and handle B_QUIT_REQUESTED
|
||||
// TODO: use some locking?
|
||||
if (be_app == NULL) {
|
||||
LogDebug(haiku_output_domain, "creating be_app");
|
||||
new BApplication("application/x-vnd.MusicPD");
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
finalize_application()
|
||||
{
|
||||
// TODO: use some locking?
|
||||
delete be_app;
|
||||
be_app = NULL;
|
||||
LogDebug(haiku_output_domain, "deleting be_app");
|
||||
}
|
||||
|
||||
static bool
|
||||
haiku_test_default_device(void)
|
||||
{
|
||||
BSoundPlayer testPlayer;
|
||||
return testPlayer.InitCheck() == B_OK;
|
||||
|
||||
}
|
||||
|
||||
inline AudioOutput *
|
||||
HaikuOutput::Create(EventLoop &, const ConfigBlock &block)
|
||||
{
|
||||
initialize_application();
|
||||
|
||||
return new HaikuOutput(block);
|
||||
}
|
||||
|
||||
void
|
||||
HaikuOutput::Close() noexcept
|
||||
{
|
||||
sound_player->SetHasData(false);
|
||||
delete_sem(new_buffer);
|
||||
delete_sem(buffer_done);
|
||||
sound_player->Stop();
|
||||
delete sound_player;
|
||||
sound_player = nullptr;
|
||||
}
|
||||
|
||||
HaikuOutput::~HaikuOutput()
|
||||
{
|
||||
finalize_application();
|
||||
}
|
||||
|
||||
void
|
||||
HaikuOutput::_FillBuffer(void* cookie, void* buffer, size_t size,
|
||||
const media_raw_audio_format& format)
|
||||
{
|
||||
HaikuOutput *ad = (HaikuOutput *)cookie;
|
||||
ad->FillBuffer(buffer, size, format);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
HaikuOutput::FillBuffer(void* _buffer, size_t size,
|
||||
[[maybe_unused]] const media_raw_audio_format& _format)
|
||||
{
|
||||
|
||||
buffer = (uint8*)_buffer;
|
||||
buffer_size = size;
|
||||
buffer_filled = 0;
|
||||
bigtime_t start = system_time();
|
||||
release_sem(new_buffer);
|
||||
acquire_sem(buffer_done);
|
||||
bigtime_t w = system_time() - start;
|
||||
|
||||
if (w > 5000LL) {
|
||||
FmtDebug(haiku_output_domain,
|
||||
"haiku:fill_buffer waited {}us", w);
|
||||
}
|
||||
|
||||
if (buffer_filled < buffer_size) {
|
||||
memset(buffer + buffer_filled, 0,
|
||||
buffer_size - buffer_filled);
|
||||
FmtDebug(haiku_output_domain,
|
||||
"haiku:fill_buffer filled {} size {} clearing remainder",
|
||||
buffer_filled, buffer_size);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
HaikuOutput::Open(AudioFormat &audio_format)
|
||||
{
|
||||
status_t err;
|
||||
format = media_multi_audio_format::wildcard;
|
||||
|
||||
switch (audio_format.format) {
|
||||
case SampleFormat::S8:
|
||||
format.format = media_raw_audio_format::B_AUDIO_CHAR;
|
||||
break;
|
||||
|
||||
case SampleFormat::S16:
|
||||
format.format = media_raw_audio_format::B_AUDIO_SHORT;
|
||||
break;
|
||||
|
||||
case SampleFormat::S32:
|
||||
format.format = media_raw_audio_format::B_AUDIO_INT;
|
||||
break;
|
||||
|
||||
case SampleFormat::FLOAT:
|
||||
format.format = media_raw_audio_format::B_AUDIO_FLOAT;
|
||||
break;
|
||||
|
||||
default:
|
||||
/* fall back to float */
|
||||
audio_format.format = SampleFormat::FLOAT;
|
||||
format.format = media_raw_audio_format::B_AUDIO_FLOAT;
|
||||
break;
|
||||
}
|
||||
|
||||
format.frame_rate = audio_format.sample_rate;
|
||||
format.byte_order = B_MEDIA_HOST_ENDIAN;
|
||||
format.channel_count = audio_format.channels;
|
||||
|
||||
buffer_size = 0;
|
||||
|
||||
if (write_size)
|
||||
format.buffer_size = write_size;
|
||||
else
|
||||
format.buffer_size = BMediaRoster::Roster()->AudioBufferSizeFor(
|
||||
format.channel_count, format.format,
|
||||
format.frame_rate, B_UNKNOWN_BUS) * 2;
|
||||
|
||||
FmtDebug(haiku_output_domain,
|
||||
"using haiku driver ad: bs: {} ws: {} "
|
||||
"channels {} rate {} fmt {:08x} bs {}",
|
||||
buffer_size, write_size,
|
||||
format.channel_count, format.frame_rate,
|
||||
format.format, format.buffer_size);
|
||||
|
||||
sound_player = new BSoundPlayer(&format, "MPD Output",
|
||||
HaikuOutput::_FillBuffer, NULL, this);
|
||||
|
||||
err = sound_player->InitCheck();
|
||||
if (err != B_OK) {
|
||||
delete sound_player;
|
||||
sound_player = NULL;
|
||||
throw MakeErrno(err, "BSoundPlayer::InitCheck() failed");
|
||||
}
|
||||
|
||||
// calculate the allowable delay for the buffer (ms)
|
||||
buffer_delay = format.buffer_size;
|
||||
buffer_delay /= (format.format &
|
||||
media_raw_audio_format::B_AUDIO_SIZE_MASK);
|
||||
buffer_delay /= format.channel_count;
|
||||
buffer_delay *= 1000 / format.frame_rate;
|
||||
// half of the total buffer play time
|
||||
buffer_delay /= 2;
|
||||
FmtDebug(haiku_output_domain, "buffer delay: {} ms", buffer_delay);
|
||||
|
||||
new_buffer = create_sem(0, "New buffer request");
|
||||
buffer_done = create_sem(0, "Buffer done");
|
||||
|
||||
sound_player->SetVolume(1.0);
|
||||
sound_player->Start();
|
||||
sound_player->SetHasData(false);
|
||||
}
|
||||
|
||||
std::size_t
|
||||
HaikuOutput::Play(std::span<const std::byte> src)
|
||||
{
|
||||
BSoundPlayer* const soundPlayer = sound_player;
|
||||
const uint8 *data = (const uint8 *)src.data();
|
||||
|
||||
if (!soundPlayer->HasData())
|
||||
soundPlayer->SetHasData(true);
|
||||
acquire_sem(new_buffer);
|
||||
|
||||
size_t bytesLeft = src.size();
|
||||
while (bytesLeft > 0) {
|
||||
if (buffer_filled == buffer_size) {
|
||||
// Request another buffer from BSoundPlayer
|
||||
release_sem(buffer_done);
|
||||
acquire_sem(new_buffer);
|
||||
}
|
||||
|
||||
const size_t copyBytes = std::min(bytesLeft, buffer_size
|
||||
- buffer_filled);
|
||||
memcpy(buffer + buffer_filled, data,
|
||||
copyBytes);
|
||||
buffer_filled += copyBytes;
|
||||
data += copyBytes;
|
||||
bytesLeft -= copyBytes;
|
||||
}
|
||||
|
||||
|
||||
if (buffer_filled < buffer_size) {
|
||||
// Continue filling this buffer the next time this function is called
|
||||
release_sem(new_buffer);
|
||||
} else {
|
||||
// Buffer is full
|
||||
release_sem(buffer_done);
|
||||
//soundPlayer->SetHasData(false);
|
||||
}
|
||||
|
||||
return src.size();
|
||||
}
|
||||
|
||||
inline std::chrono::steady_clock::duration
|
||||
HaikuOutput::Delay() const noexcept
|
||||
{
|
||||
unsigned delay = buffer_filled ? 0 : buffer_delay;
|
||||
|
||||
//FmtDebug(haiku_output_domain,
|
||||
// "delay={}", delay / 2);
|
||||
// XXX: doesn't work
|
||||
//return (delay / 2) ? 1 : 0;
|
||||
(void)delay;
|
||||
|
||||
return std::chrono::steady_clock::duration::zero();
|
||||
}
|
||||
|
||||
void
|
||||
HaikuOutput::SendTag(const Tag &tag)
|
||||
{
|
||||
status_t err;
|
||||
|
||||
/* lazily initialized */
|
||||
static BBitmap *icon = NULL;
|
||||
|
||||
if (icon == NULL) {
|
||||
BAppFileInfo info;
|
||||
BResources resources;
|
||||
err = resources.SetToImage((const void *)&HaikuOutput::SendTag);
|
||||
BFile file(resources.File());
|
||||
err = info.SetTo(&file);
|
||||
icon = new BBitmap(BRect(0, 0, (float)B_LARGE_ICON - 1,
|
||||
(float)B_LARGE_ICON - 1), B_BITMAP_NO_SERVER_LINK, B_RGBA32);
|
||||
err = info.GetIcon(icon, B_LARGE_ICON);
|
||||
if (err != B_OK) {
|
||||
delete icon;
|
||||
icon = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
BNotification notification(B_INFORMATION_NOTIFICATION);
|
||||
|
||||
BString messageId("mpd_");
|
||||
messageId << find_thread(NULL);
|
||||
notification.SetMessageID(messageId);
|
||||
|
||||
notification.SetGroup("Music Player Daemon");
|
||||
|
||||
char timebuf[16];
|
||||
unsigned seconds = 0;
|
||||
if (!tag.duration.IsNegative()) {
|
||||
seconds = tag.duration.ToS();
|
||||
snprintf(timebuf, sizeof(timebuf), "%02u:%02u:%02u",
|
||||
seconds / 3600, (seconds % 3600) / 60, seconds % 60);
|
||||
}
|
||||
|
||||
BString artist;
|
||||
BString album;
|
||||
BString title;
|
||||
BString track;
|
||||
BString name;
|
||||
|
||||
for (const auto &item : tag)
|
||||
{
|
||||
switch (item.type) {
|
||||
case TAG_ARTIST:
|
||||
case TAG_ALBUM_ARTIST:
|
||||
if (artist.Length() == 0)
|
||||
artist << item.value;
|
||||
break;
|
||||
case TAG_ALBUM:
|
||||
if (album.Length() == 0)
|
||||
album << item.value;
|
||||
break;
|
||||
case TAG_TITLE:
|
||||
if (title.Length() == 0)
|
||||
title << item.value;
|
||||
break;
|
||||
case TAG_TRACK:
|
||||
if (track.Length() == 0)
|
||||
track << item.value;
|
||||
break;
|
||||
case TAG_NAME:
|
||||
if (name.Length() == 0)
|
||||
name << item.value;
|
||||
break;
|
||||
case TAG_GENRE:
|
||||
case TAG_DATE:
|
||||
case TAG_ORIGINAL_DATE:
|
||||
case TAG_PERFORMER:
|
||||
case TAG_COMMENT:
|
||||
case TAG_DISC:
|
||||
case TAG_COMPOSER:
|
||||
case TAG_MUSICBRAINZ_ARTISTID:
|
||||
case TAG_MUSICBRAINZ_ALBUMID:
|
||||
case TAG_MUSICBRAINZ_ALBUMARTISTID:
|
||||
case TAG_MUSICBRAINZ_TRACKID:
|
||||
default:
|
||||
FmtDebug(haiku_output_domain,
|
||||
"tag item: type {} value '{}'\n",
|
||||
item.type, item.value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
notification.SetTitle(UTF8_PLAY " Now Playing:");
|
||||
|
||||
BStringList content;
|
||||
if (name.Length())
|
||||
content.Add(name);
|
||||
if (artist.Length())
|
||||
content.Add(artist);
|
||||
if (album.Length())
|
||||
content.Add(album);
|
||||
if (track.Length())
|
||||
content.Add(track);
|
||||
if (title.Length())
|
||||
content.Add(title);
|
||||
|
||||
if (content.CountStrings() == 0)
|
||||
content.Add("(Unknown)");
|
||||
|
||||
BString full = content.Join(" " B_UTF8_BULLET " ");
|
||||
|
||||
if (seconds > 0)
|
||||
full << " (" << timebuf << ")";
|
||||
|
||||
notification.SetContent(full);
|
||||
|
||||
err = notification.SetIcon(icon);
|
||||
|
||||
notification.Send();
|
||||
}
|
||||
|
||||
int
|
||||
haiku_output_get_volume(HaikuOutput &haiku)
|
||||
{
|
||||
BSoundPlayer* const soundPlayer = haiku.sound_player;
|
||||
|
||||
if (soundPlayer == NULL || soundPlayer->InitCheck() != B_OK)
|
||||
return 0;
|
||||
|
||||
return lround(soundPlayer->Volume() * 100);
|
||||
}
|
||||
|
||||
bool
|
||||
haiku_output_set_volume(HaikuOutput &haiku, unsigned volume)
|
||||
{
|
||||
BSoundPlayer* const soundPlayer = haiku.sound_player;
|
||||
|
||||
if (soundPlayer == NULL || soundPlayer->InitCheck() != B_OK)
|
||||
return false;
|
||||
|
||||
soundPlayer->SetVolume((float)volume / 100);
|
||||
return true;
|
||||
}
|
||||
|
||||
const struct AudioOutputPlugin haiku_output_plugin = {
|
||||
"haiku",
|
||||
haiku_test_default_device,
|
||||
&HaikuOutput::Create,
|
||||
&haiku_mixer_plugin,
|
||||
};
|
|
@ -1,34 +0,0 @@
|
|||
/*
|
||||
* Copyright 2003-2021 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
* Copyright (C) 2014-2015 François 'mmu_man' Revol
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#ifndef MPD_HAIKU_OUTPUT_PLUGIN_HXX
|
||||
#define MPD_HAIKU_OUTPUT_PLUGIN_HXX
|
||||
|
||||
class HaikuOutput;
|
||||
|
||||
extern const struct AudioOutputPlugin haiku_output_plugin;
|
||||
|
||||
int
|
||||
haiku_output_get_volume(HaikuOutput &haiku);
|
||||
|
||||
bool
|
||||
haiku_output_set_volume(HaikuOutput &haiku, unsigned volume);
|
||||
|
||||
#endif
|
|
@ -29,10 +29,6 @@ if enable_fifo_output
|
|||
output_plugins_sources += 'FifoOutputPlugin.cxx'
|
||||
endif
|
||||
|
||||
if is_haiku
|
||||
output_plugins_sources += 'HaikuOutputPlugin.cxx'
|
||||
endif
|
||||
|
||||
output_features.set('ENABLE_HTTPD_OUTPUT', get_option('httpd'))
|
||||
if get_option('httpd')
|
||||
output_plugins_sources += [
|
||||
|
|
Loading…
Reference in New Issue