aboutsummaryrefslogtreecommitdiffstats
path: root/multimedia/kodi
diff options
context:
space:
mode:
authortobik <tobik@FreeBSD.org>2017-10-14 01:42:53 +0800
committertobik <tobik@FreeBSD.org>2017-10-14 01:42:53 +0800
commitce16d8cdd342f71ffcb7a905ce75fab49a07a7fb (patch)
tree01a9a1f44cbef6b36a5f526d0498dbf5c6fdcc88 /multimedia/kodi
parent98811ae3a822518575ab1c02eafb62ad997e79e2 (diff)
downloadfreebsd-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/Makefile6
-rw-r--r--multimedia/kodi/files/extra-patch-sndio542
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