diff options
author | tobik <tobik@FreeBSD.org> | 2017-10-14 01:42:53 +0800 |
---|---|---|
committer | tobik <tobik@FreeBSD.org> | 2017-10-14 01:42:53 +0800 |
commit | ce16d8cdd342f71ffcb7a905ce75fab49a07a7fb (patch) | |
tree | 01a9a1f44cbef6b36a5f526d0498dbf5c6fdcc88 /multimedia/kodi | |
parent | 98811ae3a822518575ab1c02eafb62ad997e79e2 (diff) | |
download | freebsd-ports-gnome-ce16d8cdd342f71ffcb7a905ce75fab49a07a7fb.tar.gz freebsd-ports-gnome-ce16d8cdd342f71ffcb7a905ce75fab49a07a7fb.tar.zst freebsd-ports-gnome-ce16d8cdd342f71ffcb7a905ce75fab49a07a7fb.zip |
multimedia/kodi: Add sndio backend
This is essentially a backport of [1] which was already merged and
will hopefully be part of the next Kodi release.
[1] https://github.com/xbmc/xbmc/pull/11962
PR: 220231
Approved by: mickael.maillot@gmail.com (maintainer timeout, 3 months)
Diffstat (limited to 'multimedia/kodi')
-rw-r--r-- | multimedia/kodi/Makefile | 6 | ||||
-rw-r--r-- | multimedia/kodi/files/extra-patch-sndio | 542 |
2 files changed, 547 insertions, 1 deletions
diff --git a/multimedia/kodi/Makefile b/multimedia/kodi/Makefile index fe1c2695075a..b731701fe164 100644 --- a/multimedia/kodi/Makefile +++ b/multimedia/kodi/Makefile @@ -94,7 +94,7 @@ PLIST_SUB= ARCH=${KODI_ARCH_${ARCH}} OPTIONS_SUB= yes OPTIONS_DEFINE= AIRPLAY AIRTUNES AVAHI CEC DOCS \ LIBBLURAY LIRC MYSQL NFS NONFREE PULSEAUDIO RTMP \ - SFTP SMB VAAPI VDPAU WEBSERVER + SFTP SNDIO SMB VAAPI VDPAU WEBSERVER OPTIONS_SINGLE= RPI OPTIONS_SINGLE_RPI= RPI1 RPI2 @@ -153,6 +153,10 @@ RPI2_CONFIGURE_ON= --with-platform=raspberry-pi2 RTMP_LIB_DEPENDS= librtmp.so:multimedia/librtmp RTMP_CONFIGURE_ENABLE= rtmp +SNDIO_LIB_DEPENDS= libsndio.so:audio/sndio +SNDIO_CONFIGURE_ENABLE= sndio +SNDIO_EXTRA_PATCHES= ${PATCHDIR}/extra-patch-sndio + SMB_USES= samba:lib SMB_CONFIGURE_ENABLE= samba diff --git a/multimedia/kodi/files/extra-patch-sndio b/multimedia/kodi/files/extra-patch-sndio new file mode 100644 index 000000000000..2c6909509b75 --- /dev/null +++ b/multimedia/kodi/files/extra-patch-sndio @@ -0,0 +1,542 @@ +diff --git configure.ac configure.ac +index 47eb1d9e33..c61564bb0e 100644 +--- configure.ac ++++ configure.ac +@@ -315,6 +315,12 @@ AC_ARG_ENABLE([pulse], + [use_pulse=$enableval], + [use_pulse=auto]) + ++AC_ARG_ENABLE([sndio], ++ [AS_HELP_STRING([--enable-sndio], ++ [enable sndio support (default is auto)])], ++ [use_sndio=$enableval], ++ [use_sndio=auto]) ++ + AC_ARG_ENABLE([ssh], + [AS_HELP_STRING([--disable-ssh], + [disable SSH SFTP support (default is enabled)])], +@@ -1210,6 +1216,22 @@ else + USE_PULSE=0 + fi + ++# sndio ++if test "x$use_sndio" != "xno"; then ++ USE_SNDIO=0 ++ AC_CHECK_HEADER(sndio.h, HAVE_SNDIO="yes", HAVE_SNDIO="no") ++ if test "x$HAVE_SNDIO" = "xyes"; then ++ AC_CHECK_LIB(sndio, sio_open, HAVE_SNDIO="yes", HAVE_SNDIO="no", []) ++ if test "x$HAVE_SNDIO" = "xyes"; then ++ LIBS="$LIBS -lsndio" ++ USE_SNDIO=1 ++ AC_DEFINE([HAVE_SNDIO],[1],[sndio enabled]) ++ fi ++ fi ++else ++ USE_SNDIO=0 ++fi ++ + # avahi + if test "$use_avahi" = "yes"; then + AC_CHECK_LIB([avahi-common], [main],, +@@ -1924,6 +1946,12 @@ else + final_message="$final_message\n PulseAudio:\tNo" + fi + ++if test "$use_sndio" = "yes"; then ++ final_message="$final_message\n Sndio Support:\tYes" ++else ++ final_message="$final_message\n Sndio Support:\tNo" ++fi ++ + # Google Test Framework + if test "$configure_gtest" = "yes"; then + AC_MSG_NOTICE($gtest_enabled) +@@ -2247,6 +2275,8 @@ AC_SUBST(USE_AIRPLAY) + AC_SUBST(USE_OPENMAX) + AC_SUBST(USE_PULSE) + AC_SUBST(HAVE_LIBPULSE) ++AC_SUBST(USE_SNDIO) ++AC_SUBST(HAVE_SNDIO) + AC_SUBST(USE_ALSA) + AC_SUBST(USE_TEXTUREPACKER) + AC_SUBST(TEXTUREPACKER) +diff --git xbmc/cores/AudioEngine/AESinkFactory.cpp xbmc/cores/AudioEngine/AESinkFactory.cpp +index d7b05cdbfe..617b5dba83 100644 +--- xbmc/cores/AudioEngine/AESinkFactory.cpp ++++ xbmc/cores/AudioEngine/AESinkFactory.cpp +@@ -36,6 +36,9 @@ + #if defined(HAS_ALSA) + #include "Sinks/AESinkALSA.h" + #endif ++ #if defined(HAS_SNDIO) ++ #include "Sinks/AESinkSNDIO.h" ++ #endif + #if defined(TARGET_FREEBSD) + #include "Sinks/AESinkOSS.h" + #endif +@@ -77,6 +80,9 @@ + #if defined(HAS_ALSA) + driver == "ALSA" || + #endif ++ #if defined(HAS_SNDIO) ++ driver == "SNDIO" || ++ #endif + #if defined(TARGET_FREEBSD) + driver == "OSS" || + #endif +@@ -116,11 +122,15 @@ IAESink *CAESinkFactory::TrySink(std::string &driver, std::string &device, AEAud + sink = new CAESinkDARWINIOS(); + #elif defined(TARGET_DARWIN_OSX) + sink = new CAESinkDARWINOSX(); +-#elif defined(TARGET_LINUX) || defined(TARGET_FREEBSD) ++#elif defined(TARGET_LINUX) || defined(TARGET_FREEBSD) || defined(TARGET_OPENBSD) + #if defined(HAS_PULSEAUDIO) + if (driver == "PULSE") + sink = new CAESinkPULSE(); + #endif ++ #if defined(HAS_SNDIO) ++ if (driver == "SNDIO") ++ sink = new CAESinkSNDIO(); ++ #endif + #if defined(HAS_ALSA) + if (driver == "ALSA") + sink = new CAESinkALSA(); +@@ -236,6 +246,10 @@ void CAESinkFactory::EnumerateEx(AESinkInfoList &list, bool force) + if (envSink == "PULSE") + CAESinkPULSE::EnumerateDevicesEx(info.m_deviceInfoList, force); + #endif ++ #if defined(HAS_SNDIO) ++ if (envSink == "SNDIO") ++ CAESinkSNDIO::EnumerateDevicesEx(info.m_deviceInfoList, force); ++ #endif + #if defined(HAS_ALSA) + if (envSink == "ALSA") + CAESinkALSA::EnumerateDevicesEx(info.m_deviceInfoList, force); +@@ -264,6 +278,17 @@ void CAESinkFactory::EnumerateEx(AESinkInfoList &list, bool force) + } + #endif + ++ #if defined(HAS_SNDIO) ++ info.m_deviceInfoList.clear(); ++ info.m_sinkName = "SNDIO"; ++ CAESinkSNDIO::EnumerateDevicesEx(info.m_deviceInfoList, force); ++ if(!info.m_deviceInfoList.empty()) ++ { ++ list.push_back(info); ++ return; ++ } ++ #endif ++ + #if defined(HAS_ALSA) + info.m_deviceInfoList.clear(); + info.m_sinkName = "ALSA"; +diff --git xbmc/cores/AudioEngine/Makefile.in xbmc/cores/AudioEngine/Makefile.in +index 7aab111f81..788786e2d1 100644 +--- xbmc/cores/AudioEngine/Makefile.in ++++ xbmc/cores/AudioEngine/Makefile.in +@@ -55,6 +55,9 @@ SRCS += Sinks/AESinkOSS.cpp + ifeq (@USE_PULSE@,1) + SRCS += Sinks/AESinkPULSE.cpp + endif ++ifeq (@USE_SNDIO@,1) ++SRCS += Sinks/AESinkSNDIO.cpp ++endif + endif + + SRCS += DSPAddons/ActiveAEDSP.cpp +diff --git xbmc/cores/AudioEngine/Sinks/AESinkSNDIO.cpp xbmc/cores/AudioEngine/Sinks/AESinkSNDIO.cpp +new file mode 100644 +index 0000000000..879b9a90a3 +--- /dev/null ++++ xbmc/cores/AudioEngine/Sinks/AESinkSNDIO.cpp +@@ -0,0 +1,313 @@ ++/* -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*- */ ++/* ++ * Copyright (C) 2010-2013 Team XBMC ++ * http://xbmc.org ++ * ++ * 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, 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 XBMC; see the file COPYING. If not, see ++ * <http://www.gnu.org/licenses/>. ++ * ++ */ ++ ++#include "system.h" ++#ifdef HAS_SNDIO ++#include "AESinkSNDIO.h" ++#include "cores/AudioEngine/Utils/AEUtil.h" ++#include "utils/log.h" ++ ++#include <sys/param.h> ++ ++#ifndef nitems ++#define nitems(x) (sizeof((x))/sizeof((x)[0])) ++#endif ++ ++static enum AEChannel channelMap[] = ++{ ++ AE_CH_FL, ++ AE_CH_FR, ++ AE_CH_BL, ++ AE_CH_BR, ++ AE_CH_FC, ++ AE_CH_LFE, ++ AE_CH_SL, ++ AE_CH_SR, ++}; ++ ++struct sndio_formats ++{ ++ AEDataFormat fmt; ++ unsigned int bits; ++ unsigned int bps; ++ unsigned int sig; ++ unsigned int le; ++ unsigned int msb; ++}; ++ ++static struct sndio_formats formats[] = ++{ ++ { AE_FMT_S32LE, 32, 4, 1, 1, 1 }, ++ { AE_FMT_S32BE, 32, 4, 1, 0, 1 }, ++ ++ { AE_FMT_S24LE4, 24, 4, 1, 1, 0 }, ++ { AE_FMT_S24BE4, 24, 4, 1, 0, 0 }, ++ { AE_FMT_S24LE4, 24, 4, 1, 1, 1 }, ++ { AE_FMT_S24BE4, 24, 4, 1, 0, 1 }, ++ ++ { AE_FMT_S24LE3, 24, 3, 1, 1, 0 }, ++ { AE_FMT_S24BE3, 24, 3, 1, 0, 0 }, ++ { AE_FMT_S24LE3, 24, 3, 1, 1, 1 }, ++ { AE_FMT_S24BE3, 24, 3, 1, 0, 1 }, ++ ++ { AE_FMT_S16LE, 16, 2, 1, 1, 1 }, ++ { AE_FMT_S16LE, 16, 2, 1, 1, 0 }, ++ { AE_FMT_S16BE, 16, 2, 1, 0, 1 }, ++ { AE_FMT_S16BE, 16, 2, 1, 0, 0 }, ++ ++ { AE_FMT_U8, 8, 1, 0, 0, 0 }, ++ { AE_FMT_U8, 8, 1, 0, 0, 1 }, ++ { AE_FMT_U8, 8, 1, 0, 1, 0 }, ++ { AE_FMT_U8, 8, 1, 0, 1, 1 }, ++}; ++ ++static AEDataFormat lookupDataFormat(int bits, int bps, int sig, int le, int msb) ++{ ++ for (size_t i = 0; i < nitems(formats); i++) ++ { ++ if (bits == formats[i].bits && ++ bps == formats[i].bps && ++ sig == formats[i].sig && ++ le == formats[i].le && ++ msb == formats[i].msb) ++ { ++ return formats[i].fmt; ++ } ++ } ++ return AE_FMT_INVALID; ++} ++ ++void CAESinkSNDIO::AudioFormatToPar(AEAudioFormat& format) ++{ ++ sio_initpar(&par); ++ ++ par.rate = format.m_sampleRate; ++ par.xrun = SIO_IGNORE; ++ par.pchan = format.m_channelLayout.Count(); ++ ++ for (size_t i = 0; i < nitems(formats); i++) ++ { ++ if (formats[i].fmt == format.m_dataFormat) ++ { ++ par.bits = formats[i].bits; ++ par.sig = formats[i].sig; ++ par.le = formats[i].le; ++ par.msb = formats[i].msb; ++ par.bps = formats[i].bps; ++ return; ++ } ++ } ++ ++ /* Default to AE_FMT_S16LE */ ++ par.bits = 16; ++ par.bps = SIO_BPS(16); ++ par.sig = 1; ++ par.le = 1; ++ par.msb = 0; ++} ++ ++bool CAESinkSNDIO::ParToAudioFormat(AEAudioFormat& format) ++{ ++ AEDataFormat dataFormat = lookupDataFormat(par.bits, par.bps, par.sig, par.le, par.msb); ++ if (dataFormat == AE_FMT_INVALID) ++ { ++ CLog::Log(LOGERROR, "CAESinkSNDIO::ParToAudioFormat - invalid data format"); ++ return false; ++ } ++ ++ if (par.pchan > nitems(channelMap)) ++ { ++ CLog::Log(LOGERROR, "CAESinkSNDIO::ParToAudioFormat - too many channels: %d", par.pchan); ++ return false; ++ } ++ ++ CAEChannelInfo info; ++ for (unsigned int i = 0; i < par.pchan; i++) ++ info += channelMap[i]; ++ format.m_channelLayout = info; ++ format.m_dataFormat = dataFormat; ++ format.m_sampleRate = par.rate; ++ format.m_frameSize = par.bps * par.pchan; ++ format.m_frames = par.bufsz / format.m_frameSize; ++ ++ return true; ++} ++ ++CAESinkSNDIO::CAESinkSNDIO() ++{ ++ m_hdl = nullptr; ++} ++ ++CAESinkSNDIO::~CAESinkSNDIO() ++{ ++ Deinitialize(); ++} ++ ++bool CAESinkSNDIO::Initialize(AEAudioFormat &format, std::string &device) ++{ ++ if ((m_hdl = sio_open(SIO_DEVANY, SIO_PLAY, 0)) == nullptr) ++ { ++ CLog::Log(LOGERROR, "CAESinkSNDIO::Initialize - Failed to open device"); ++ return false; ++ } ++ ++ AudioFormatToPar(format); ++ if (!sio_setpar(m_hdl, &par) || ++ !sio_getpar(m_hdl, &par) || ++ !ParToAudioFormat(format)) ++ { ++ CLog::Log(LOGERROR, "CAESinkSNDIO::Initialize - could not negotiate parameters"); ++ return false; ++ } ++ ++ played = written = 0; ++ ++ sio_onmove(m_hdl, CAESinkSNDIO::OnmoveCb, this); ++ ++ if (!sio_start(m_hdl)) ++ { ++ CLog::Log(LOGERROR, "CAESinkSNDIO::Initialize - sio_start failed"); ++ return false; ++ } ++ ++ return true; ++} ++ ++void CAESinkSNDIO::Deinitialize() ++{ ++ if (m_hdl != nullptr) ++ { ++ sio_close(m_hdl); ++ m_hdl = nullptr; ++ } ++} ++ ++void CAESinkSNDIO::Stop() ++{ ++ if (!m_hdl) ++ return; ++ ++ if (!sio_stop(m_hdl)) ++ CLog::Log(LOGERROR, "CAESinkSNDIO::Stop - Failed"); ++ ++ written = played = 0; ++} ++ ++void CAESinkSNDIO::OnmoveCb(void *arg, int delta) { ++ CAESinkSNDIO* self = static_cast<CAESinkSNDIO*>(arg); ++ self->played += delta; ++} ++ ++void CAESinkSNDIO::GetDelay(AEDelayStatus& status) ++{ ++ unsigned int frameSize = par.bps * par.pchan; ++ double delay = 1.0 * ((written / frameSize) - played) / par.rate; ++ status.SetDelay(delay); ++} ++ ++unsigned int CAESinkSNDIO::AddPackets(uint8_t **data, unsigned int frames, unsigned int offset) ++{ ++ if (!m_hdl) ++ return INT_MAX; ++ ++ unsigned int frameSize = par.bps * par.pchan; ++ size_t size = frames * frameSize; ++ void *buffer = data[0] + offset * frameSize; ++ size_t wrote = sio_write(m_hdl, buffer, size); ++ written += wrote; ++ return wrote / frameSize; ++} ++ ++void CAESinkSNDIO::Drain() ++{ ++ if(!m_hdl) ++ return; ++ ++ if (!sio_stop(m_hdl) || !sio_start(m_hdl)) ++ CLog::Log(LOGERROR, "CAESinkSNDIO::Drain - failed"); ++ ++ written = played = 0; ++} ++ ++void CAESinkSNDIO::EnumerateDevicesEx(AEDeviceInfoList &list, bool force) ++{ ++ struct sio_hdl *hdl; ++ struct sio_cap cap; ++ ++ if ((hdl = sio_open(SIO_DEVANY, SIO_PLAY, 0)) == nullptr) ++ { ++ CLog::Log(LOGERROR, "CAESinkSNDIO::EnumerateDevicesEx - sio_open"); ++ return; ++ } ++ ++ if (!sio_getcap(hdl, &cap)) ++ { ++ CLog::Log(LOGERROR, "CAESinkSNDIO::EnumerateDevicesEx - sio_getcap"); ++ return; ++ } ++ ++ sio_close(hdl); ++ hdl = nullptr; ++ ++ for (unsigned int i = 0; i < cap.nconf; i++) ++ { ++ CAEDeviceInfo info; ++ sio_cap::sio_conf conf = cap.confs[i]; ++ ++ info.m_deviceName = SIO_DEVANY; ++ info.m_displayName = "sndio"; ++ info.m_displayNameExtra = "#" + std::to_string(i); ++ info.m_deviceType = AE_DEVTYPE_PCM; ++ ++ unsigned int maxchan = 0; ++ for (unsigned int j = 0; j < SIO_NCHAN; j++) ++ { ++ if (conf.pchan & (1 << j)) ++ maxchan = MAX(maxchan, cap.pchan[j]); ++ } ++ ++ maxchan = MIN(maxchan, nitems(channelMap)); ++ for (unsigned int j = 0; j < maxchan; j++) ++ info.m_channels += channelMap[j]; ++ ++ for (unsigned int j = 0; j < SIO_NRATE; j++) ++ { ++ if (conf.rate & (1 << j)) ++ { ++ info.m_sampleRates.push_back(cap.rate[j]); ++ } ++ } ++ ++ for (unsigned int j = 0; j < SIO_NENC; j++) ++ { ++ if (conf.enc & (1 << j)) ++ { ++ AEDataFormat format = lookupDataFormat(cap.enc[j].bits, cap.enc[j].bps, cap.enc[j].sig, cap.enc[j].le, cap.enc[j].msb); ++ if (format != AE_FMT_INVALID) ++ info.m_dataFormats.push_back(format); ++ } ++ } ++ ++ list.push_back(info); ++ } ++} ++ ++#endif +diff --git xbmc/cores/AudioEngine/Sinks/AESinkSNDIO.h xbmc/cores/AudioEngine/Sinks/AESinkSNDIO.h +new file mode 100644 +index 0000000000..55719cd305 +--- /dev/null ++++ xbmc/cores/AudioEngine/Sinks/AESinkSNDIO.h +@@ -0,0 +1,57 @@ ++/* -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*- */ ++#pragma once ++/* ++ * Copyright (C) 2010-2013 Team XBMC ++ * http://xbmc.org ++ * ++ * 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, 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 XBMC; see the file COPYING. If not, see ++ * <http://www.gnu.org/licenses/>. ++ * ++ */ ++ ++#include "cores/AudioEngine/Interfaces/AESink.h" ++#include "cores/AudioEngine/Utils/AEDeviceInfo.h" ++#include <stdint.h> ++#include <sndio.h> ++ ++#include "threads/CriticalSection.h" ++ ++class CAESinkSNDIO : public IAESink ++{ ++public: ++ virtual const char *GetName() { return "sndio"; } ++ ++ CAESinkSNDIO(); ++ virtual ~CAESinkSNDIO(); ++ ++ virtual bool Initialize(AEAudioFormat &format, std::string &device); ++ virtual void Deinitialize(); ++ ++ virtual void Stop(); ++ virtual void GetDelay(AEDelayStatus& status); ++ virtual double GetCacheTotal() { return 0.0; } ++ virtual unsigned int AddPackets(uint8_t **data, unsigned int frames, unsigned int offset); ++ virtual void Drain(); ++ static void EnumerateDevicesEx(AEDeviceInfoList &list, bool force = false); ++private: ++ void AudioFormatToPar(AEAudioFormat& format); ++ bool ParToAudioFormat(AEAudioFormat& format); ++ static void OnmoveCb(void *arg, int delta); ++ ++ struct sio_hdl *m_hdl; ++ struct sio_par par; ++ ssize_t played; ++ ssize_t written; ++}; ++ +diff --git xbmc/system.h xbmc/system.h +index d426ade093..ed01ab53fd 100644 +--- xbmc/system.h ++++ xbmc/system.h +@@ -172,6 +172,9 @@ + #ifdef HAVE_LIBPULSE + #define HAS_PULSEAUDIO + #endif ++#ifdef HAVE_SNDIO ++#define HAS_SNDIO ++#endif + #ifdef HAVE_ALSA + #define HAS_ALSA + #endif |