mirror of
https://github.com/LibreELEC/LibreELEC.tv.git
synced 2025-07-29 13:46:49 +00:00
xbmc: add some more upstream patches
Signed-off-by: Stephan Raue <stephan@openelec.tv>
This commit is contained in:
parent
efdcefdcf9
commit
23e7cebd1e
@ -0,0 +1,527 @@
|
||||
From b73018af2ae69c7cfad0a4461d169a49c7d0dfbf Mon Sep 17 00:00:00 2001
|
||||
From: Memphiz <memphis@machzwo.de>
|
||||
Date: Tue, 15 May 2012 19:12:07 +0200
|
||||
Subject: [PATCH] [airtunes] - implementation for windows using libshairplay
|
||||
|
||||
---
|
||||
xbmc/network/AirTunesServer.cpp | 330 +++++++++++++++++++++++++++++++++++++--
|
||||
xbmc/network/AirTunesServer.h | 23 +++
|
||||
2 files changed, 343 insertions(+), 10 deletions(-)
|
||||
|
||||
diff --git a/xbmc/network/AirTunesServer.cpp b/xbmc/network/AirTunesServer.cpp
|
||||
index a60ad09..e14da90 100644
|
||||
--- a/xbmc/network/AirTunesServer.cpp
|
||||
+++ b/xbmc/network/AirTunesServer.cpp
|
||||
@@ -17,7 +17,9 @@
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
+#if !defined(TARGET_WINDOWS)
|
||||
#pragma GCC diagnostic ignored "-Wwrite-strings"
|
||||
+#endif
|
||||
|
||||
#include "AirTunesServer.h"
|
||||
|
||||
@@ -37,15 +39,243 @@
|
||||
#include "music/tags/MusicInfoTag.h"
|
||||
#include "FileItem.h"
|
||||
#include "GUIInfoManager.h"
|
||||
+#include "guilib/GUIWindowManager.h"
|
||||
#include "utils/Variant.h"
|
||||
#include "settings/AdvancedSettings.h"
|
||||
+#include "utils/EndianSwap.h"
|
||||
+
|
||||
+#include <map>
|
||||
+#include <string>
|
||||
+
|
||||
|
||||
using namespace XFILE;
|
||||
|
||||
+#if defined(TARGET_WINDOWS)
|
||||
+DllLibShairplay *CAirTunesServer::m_pLibShairplay = NULL;
|
||||
+#else
|
||||
DllLibShairport *CAirTunesServer::m_pLibShairport = NULL;
|
||||
+#endif
|
||||
CAirTunesServer *CAirTunesServer::ServerInstance = NULL;
|
||||
CStdString CAirTunesServer::m_macAddress;
|
||||
|
||||
+//parse daap metadata - thx to project MythTV
|
||||
+std::map<std::string, std::string> decodeDMAP(const char *buffer, unsigned int size)
|
||||
+{
|
||||
+ std::map<std::string, std::string> result;
|
||||
+ unsigned int offset = 8;
|
||||
+ while (offset < size)
|
||||
+ {
|
||||
+ std::string tag;
|
||||
+ tag.append(buffer + offset, 4);
|
||||
+ offset += 4;
|
||||
+ uint32_t length = Endian_SwapBE32(*(uint32_t *)(buffer + offset));
|
||||
+ offset += sizeof(uint32_t);
|
||||
+ std::string content;
|
||||
+ content.append(buffer + offset, length);//possible fixme - utf8?
|
||||
+ offset += length;
|
||||
+ result[tag] = content;
|
||||
+ }
|
||||
+ return result;
|
||||
+}
|
||||
+
|
||||
+void CAirTunesServer::SetMetadataFromBuffer(const char *buffer, unsigned int size)
|
||||
+{
|
||||
+ MUSIC_INFO::CMusicInfoTag tag;
|
||||
+ std::map<std::string, std::string> metadata = decodeDMAP(buffer, size);
|
||||
+ if(metadata["asal"].length())
|
||||
+ tag.SetAlbum(metadata["asal"]);//album
|
||||
+ if(metadata["minm"].length())
|
||||
+ tag.SetTitle(metadata["minm"]);//title
|
||||
+ if(metadata["asar"].length())
|
||||
+ tag.SetArtist(metadata["asar"]);//artist
|
||||
+ g_infoManager.SetCurrentSongTag(tag);
|
||||
+}
|
||||
+
|
||||
+void CAirTunesServer::SetCoverArtFromBuffer(const char *buffer, unsigned int size)
|
||||
+{
|
||||
+ XFILE::CFile tmpFile;
|
||||
+ const char *tmpFileName = "special://temp/airtunes_album_thumb.jpg";
|
||||
+
|
||||
+ if(!size)
|
||||
+ return;
|
||||
+
|
||||
+ if (tmpFile.OpenForWrite(tmpFileName, true))
|
||||
+ {
|
||||
+ int writtenBytes=0;
|
||||
+ writtenBytes = tmpFile.Write(buffer, size);
|
||||
+ tmpFile.Close();
|
||||
+
|
||||
+ if(writtenBytes)
|
||||
+ {
|
||||
+ //reset to empty before setting the new one
|
||||
+ //else it won't get refreshed because the name didn't change
|
||||
+ g_infoManager.SetCurrentAlbumThumb("");
|
||||
+ g_infoManager.SetCurrentAlbumThumb(tmpFileName);
|
||||
+ //update the ui
|
||||
+ CGUIMessage msg(GUI_MSG_NOTIFY_ALL,0,0,GUI_MSG_REFRESH_THUMBS);
|
||||
+ g_windowManager.SendThreadMessage(msg);
|
||||
+ }
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+#if defined(TARGET_WINDOWS)
|
||||
+#define RSA_KEY " \
|
||||
+-----BEGIN RSA PRIVATE KEY-----\
|
||||
+MIIEpQIBAAKCAQEA59dE8qLieItsH1WgjrcFRKj6eUWqi+bGLOX1HL3U3GhC/j0Qg90u3sG/1CUt\
|
||||
+wC5vOYvfDmFI6oSFXi5ELabWJmT2dKHzBJKa3k9ok+8t9ucRqMd6DZHJ2YCCLlDRKSKv6kDqnw4U\
|
||||
+wPdpOMXziC/AMj3Z/lUVX1G7WSHCAWKf1zNS1eLvqr+boEjXuBOitnZ/bDzPHrTOZz0Dew0uowxf\
|
||||
+/+sG+NCK3eQJVxqcaJ/vEHKIVd2M+5qL71yJQ+87X6oV3eaYvt3zWZYD6z5vYTcrtij2VZ9Zmni/\
|
||||
+UAaHqn9JdsBWLUEpVviYnhimNVvYFZeCXg/IdTQ+x4IRdiXNv5hEewIDAQABAoIBAQDl8Axy9XfW\
|
||||
+BLmkzkEiqoSwF0PsmVrPzH9KsnwLGH+QZlvjWd8SWYGN7u1507HvhF5N3drJoVU3O14nDY4TFQAa\
|
||||
+LlJ9VM35AApXaLyY1ERrN7u9ALKd2LUwYhM7Km539O4yUFYikE2nIPscEsA5ltpxOgUGCY7b7ez5\
|
||||
+NtD6nL1ZKauw7aNXmVAvmJTcuPxWmoktF3gDJKK2wxZuNGcJE0uFQEG4Z3BrWP7yoNuSK3dii2jm\
|
||||
+lpPHr0O/KnPQtzI3eguhe0TwUem/eYSdyzMyVx/YpwkzwtYL3sR5k0o9rKQLtvLzfAqdBxBurciz\
|
||||
+aaA/L0HIgAmOit1GJA2saMxTVPNhAoGBAPfgv1oeZxgxmotiCcMXFEQEWflzhWYTsXrhUIuz5jFu\
|
||||
+a39GLS99ZEErhLdrwj8rDDViRVJ5skOp9zFvlYAHs0xh92ji1E7V/ysnKBfsMrPkk5KSKPrnjndM\
|
||||
+oPdevWnVkgJ5jxFuNgxkOLMuG9i53B4yMvDTCRiIPMQ++N2iLDaRAoGBAO9v//mU8eVkQaoANf0Z\
|
||||
+oMjW8CN4xwWA2cSEIHkd9AfFkftuv8oyLDCG3ZAf0vrhrrtkrfa7ef+AUb69DNggq4mHQAYBp7L+\
|
||||
+k5DKzJrKuO0r+R0YbY9pZD1+/g9dVt91d6LQNepUE/yY2PP5CNoFmjedpLHMOPFdVgqDzDFxU8hL\
|
||||
+AoGBANDrr7xAJbqBjHVwIzQ4To9pb4BNeqDndk5Qe7fT3+/H1njGaC0/rXE0Qb7q5ySgnsCb3DvA\
|
||||
+cJyRM9SJ7OKlGt0FMSdJD5KG0XPIpAVNwgpXXH5MDJg09KHeh0kXo+QA6viFBi21y340NonnEfdf\
|
||||
+54PX4ZGS/Xac1UK+pLkBB+zRAoGAf0AY3H3qKS2lMEI4bzEFoHeK3G895pDaK3TFBVmD7fV0Zhov\
|
||||
+17fegFPMwOII8MisYm9ZfT2Z0s5Ro3s5rkt+nvLAdfC/PYPKzTLalpGSwomSNYJcB9HNMlmhkGzc\
|
||||
+1JnLYT4iyUyx6pcZBmCd8bD0iwY/FzcgNDaUmbX9+XDvRA0CgYEAkE7pIPlE71qvfJQgoA9em0gI\
|
||||
+LAuE4Pu13aKiJnfft7hIjbK+5kyb3TysZvoyDnb3HOKvInK7vXbKuU4ISgxB2bB3HcYzQMGsz1qJ\
|
||||
+2gG0N5hvJpzwwhbhXqFKA4zaaSrw622wDniAK5MlIE0tIAKKP4yxNGjoD2QYjhBGuhvkWKY=\
|
||||
+-----END RSA PRIVATE KEY-----"
|
||||
+
|
||||
+void CAirTunesServer::AudioOutputFunctions::audio_set_metadata(void *cls, void *session, const void *buffer, int buflen)
|
||||
+{
|
||||
+ CAirTunesServer::SetMetadataFromBuffer((char *)buffer, buflen);
|
||||
+}
|
||||
+
|
||||
+void CAirTunesServer::AudioOutputFunctions::audio_set_coverart(void *cls, void *session, const void *buffer, int buflen)
|
||||
+{
|
||||
+ CAirTunesServer::SetCoverArtFromBuffer((char *)buffer, buflen);
|
||||
+}
|
||||
+
|
||||
+void* CAirTunesServer::AudioOutputFunctions::audio_init(void *cls, int bits, int channels, int samplerate)
|
||||
+{
|
||||
+ XFILE::CPipeFile *pipe=(XFILE::CPipeFile *)cls;
|
||||
+ pipe->OpenForWrite(XFILE::PipesManager::GetInstance().GetUniquePipeName());
|
||||
+ pipe->SetOpenThreashold(300);
|
||||
+
|
||||
+ BXA_FmtHeader header;
|
||||
+ strncpy(header.fourcc, "BXA ", 4);
|
||||
+ header.type = BXA_PACKET_TYPE_FMT;
|
||||
+ header.bitsPerSample = bits;
|
||||
+ header.channels = channels;
|
||||
+ header.sampleRate = samplerate;
|
||||
+ header.durationMs = 0;
|
||||
+
|
||||
+ if (pipe->Write(&header, sizeof(header)) == 0)
|
||||
+ return 0;
|
||||
+
|
||||
+ ThreadMessage tMsg = { TMSG_MEDIA_STOP };
|
||||
+ g_application.getApplicationMessenger().SendMessage(tMsg, true);
|
||||
+
|
||||
+ CFileItem item;
|
||||
+ item.SetPath(pipe->GetName());
|
||||
+ item.SetMimeType("audio/x-xbmc-pcm");
|
||||
+
|
||||
+ ThreadMessage tMsg2 = { TMSG_GUI_ACTIVATE_WINDOW, WINDOW_VISUALISATION, 0 };
|
||||
+ g_application.getApplicationMessenger().SendMessage(tMsg2, true);
|
||||
+
|
||||
+ g_application.getApplicationMessenger().PlayFile(item);
|
||||
+
|
||||
+ return "XBMC-AirTunes";//session
|
||||
+}
|
||||
+
|
||||
+void CAirTunesServer::AudioOutputFunctions::audio_set_volume(void *cls, void *session, float volume)
|
||||
+{
|
||||
+ //volume from -144 - 0
|
||||
+ float volPercent = 1 - volume/-144;
|
||||
+ g_application.SetVolume(volPercent, false);//non-percent volume 0.0-1.0
|
||||
+}
|
||||
+
|
||||
+void CAirTunesServer::AudioOutputFunctions::audio_process(void *cls, void *session, const void *buffer, int buflen)
|
||||
+{
|
||||
+ #define NUM_OF_BYTES 64
|
||||
+ XFILE::CPipeFile *pipe=(XFILE::CPipeFile *)cls;
|
||||
+ int sentBytes = 0;
|
||||
+ unsigned char buf[NUM_OF_BYTES];
|
||||
+
|
||||
+ while (sentBytes < buflen)
|
||||
+ {
|
||||
+ int n = (buflen - sentBytes < NUM_OF_BYTES ? buflen - sentBytes : NUM_OF_BYTES);
|
||||
+ memcpy(buf, (char*) buffer + sentBytes, n);
|
||||
+
|
||||
+ if (pipe->Write(buf, n) == 0)
|
||||
+ return;
|
||||
+
|
||||
+ sentBytes += n;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+void CAirTunesServer::AudioOutputFunctions::audio_flush(void *cls, void *session)
|
||||
+{
|
||||
+ XFILE::CPipeFile *pipe=(XFILE::CPipeFile *)cls;
|
||||
+ pipe->Flush();
|
||||
+}
|
||||
+
|
||||
+void CAirTunesServer::AudioOutputFunctions::audio_destroy(void *cls, void *session)
|
||||
+{
|
||||
+ XFILE::CPipeFile *pipe=(XFILE::CPipeFile *)cls;
|
||||
+ pipe->SetEof();
|
||||
+ pipe->Close();
|
||||
+
|
||||
+ //fix airplay video for ios5 devices
|
||||
+ //on ios5 when airplaying video
|
||||
+ //the client first opens an airtunes stream
|
||||
+ //while the movie is loading
|
||||
+ //in that case we don't want to stop the player here
|
||||
+ //because this would stop the airplaying video
|
||||
+#ifdef HAS_AIRPLAY
|
||||
+ if (!CAirPlayServer::IsPlaying())
|
||||
+#endif
|
||||
+ {
|
||||
+ ThreadMessage tMsg = { TMSG_MEDIA_STOP };
|
||||
+ g_application.getApplicationMessenger().SendMessage(tMsg, true);
|
||||
+ CLog::Log(LOGDEBUG, "AIRTUNES: AirPlay not running - stopping player");
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+void shairplay_log(int level, const char *msg)
|
||||
+{
|
||||
+ int xbmcLevel = LOGINFO;
|
||||
+
|
||||
+ switch(level)
|
||||
+ {
|
||||
+ case RAOP_LOG_EMERG: // system is unusable
|
||||
+ xbmcLevel = LOGFATAL;
|
||||
+ break;
|
||||
+ case RAOP_LOG_ALERT: // action must be taken immediately
|
||||
+ case RAOP_LOG_CRIT: // critical conditions
|
||||
+ xbmcLevel = LOGSEVERE;
|
||||
+ break;
|
||||
+ case RAOP_LOG_ERR: // error conditions
|
||||
+ xbmcLevel = LOGERROR;
|
||||
+ break;
|
||||
+ case RAOP_LOG_WARNING: // warning conditions
|
||||
+ xbmcLevel = LOGWARNING;
|
||||
+ break;
|
||||
+ case RAOP_LOG_NOTICE: // normal but significant condition
|
||||
+ xbmcLevel = LOGNOTICE;
|
||||
+ break;
|
||||
+ case RAOP_LOG_INFO: // informational
|
||||
+ xbmcLevel = LOGINFO;
|
||||
+ break;
|
||||
+ case RAOP_LOG_DEBUG: // debug-level messages
|
||||
+ xbmcLevel = LOGDEBUG;
|
||||
+ break;
|
||||
+ default:
|
||||
+ break;
|
||||
+ }
|
||||
+ CLog::Log(xbmcLevel, "AIRTUNES: %s", msg);
|
||||
+}
|
||||
+
|
||||
+#else
|
||||
+
|
||||
struct ao_device_xbmc
|
||||
{
|
||||
XFILE::CPipeFile *pipe;
|
||||
@@ -214,6 +444,17 @@ char* CAirTunesServer::AudioOutputFunctions::ao_get_option(ao_option *options, c
|
||||
return NULL;
|
||||
}
|
||||
|
||||
+int shairport_log(const char* msg, size_t msgSize)
|
||||
+{
|
||||
+ if( g_advancedSettings.m_logEnableAirtunes)
|
||||
+ {
|
||||
+ CLog::Log(LOGDEBUG, "AIRTUNES: %s", msg);
|
||||
+ }
|
||||
+ return 1;
|
||||
+}
|
||||
+
|
||||
+#endif
|
||||
+
|
||||
bool CAirTunesServer::StartServer(int port, bool nonlocal, bool usePassword, const CStdString &password/*=""*/)
|
||||
{
|
||||
bool success = false;
|
||||
@@ -243,7 +484,9 @@ bool CAirTunesServer::StartServer(int port, bool nonlocal, bool usePassword, con
|
||||
ServerInstance = new CAirTunesServer(port, nonlocal);
|
||||
if (ServerInstance->Initialize(password))
|
||||
{
|
||||
+#ifndef TARGET_WINDOWS
|
||||
ServerInstance->Create();
|
||||
+#endif
|
||||
success = true;
|
||||
}
|
||||
|
||||
@@ -264,6 +507,9 @@ bool CAirTunesServer::StartServer(int port, bool nonlocal, bool usePassword, con
|
||||
txt["sr"] = "44100";
|
||||
txt["pw"] = "false";
|
||||
txt["vn"] = "3";
|
||||
+ txt["da"] = "true";
|
||||
+ txt["vs"] = "130.14";
|
||||
+ txt["md"] = "0,1,2";
|
||||
txt["txtvers"] = "1";
|
||||
|
||||
CZeroconf::GetInstance()->PublishService("servers.airtunes", "_raop._tcp", appName, port, txt);
|
||||
@@ -276,10 +522,12 @@ void CAirTunesServer::StopServer(bool bWait)
|
||||
{
|
||||
if (ServerInstance)
|
||||
{
|
||||
+#if !defined(TARGET_WINDOWS)
|
||||
if (m_pLibShairport->IsLoaded())
|
||||
{
|
||||
m_pLibShairport->shairport_exit();
|
||||
}
|
||||
+#endif
|
||||
ServerInstance->StopThread(bWait);
|
||||
ServerInstance->Deinitialize();
|
||||
if (bWait)
|
||||
@@ -295,47 +543,98 @@ void CAirTunesServer::StopServer(bool bWait)
|
||||
CAirTunesServer::CAirTunesServer(int port, bool nonlocal) : CThread("AirTunesServer")
|
||||
{
|
||||
m_port = port;
|
||||
+#if defined(TARGET_WINDOWS)
|
||||
+ m_pLibShairplay = new DllLibShairplay();
|
||||
+ m_pPipe = new XFILE::CPipeFile;
|
||||
+#else
|
||||
m_pLibShairport = new DllLibShairport();
|
||||
+#endif
|
||||
}
|
||||
|
||||
CAirTunesServer::~CAirTunesServer()
|
||||
{
|
||||
+#if defined(TARGET_WINDOWS)
|
||||
+ if (m_pLibShairplay->IsLoaded())
|
||||
+ {
|
||||
+ m_pLibShairplay->Unload();
|
||||
+ }
|
||||
+ delete m_pLibShairplay;
|
||||
+ delete m_pPipe;
|
||||
+#else
|
||||
if (m_pLibShairport->IsLoaded())
|
||||
{
|
||||
m_pLibShairport->Unload();
|
||||
}
|
||||
delete m_pLibShairport;
|
||||
+#endif
|
||||
}
|
||||
|
||||
void CAirTunesServer::Process()
|
||||
{
|
||||
m_bStop = false;
|
||||
|
||||
+#if !defined(TARGET_WINDOWS)
|
||||
while (!m_bStop && m_pLibShairport->shairport_is_running())
|
||||
{
|
||||
m_pLibShairport->shairport_loop();
|
||||
}
|
||||
+#endif
|
||||
}
|
||||
|
||||
-int shairport_log(const char* msg, size_t msgSize)
|
||||
+bool CAirTunesServer::Initialize(const CStdString &password)
|
||||
{
|
||||
- if( g_advancedSettings.m_logEnableAirtunes)
|
||||
+ bool ret = false;
|
||||
+
|
||||
+ Deinitialize();
|
||||
+
|
||||
+#if defined(TARGET_WINDOWS)
|
||||
+ if (m_pLibShairplay->Load())
|
||||
{
|
||||
- CLog::Log(LOGDEBUG, "AIRTUNES: %s", msg);
|
||||
+
|
||||
+ raop_callbacks_t ao;
|
||||
+ ao.cls = m_pPipe;
|
||||
+ ao.audio_init = AudioOutputFunctions::audio_init;
|
||||
+ ao.audio_set_volume = AudioOutputFunctions::audio_set_volume;
|
||||
+ ao.audio_set_metadata = AudioOutputFunctions::audio_set_metadata;
|
||||
+ ao.audio_set_coverart = AudioOutputFunctions::audio_set_coverart;
|
||||
+ ao.audio_process = AudioOutputFunctions::audio_process;
|
||||
+ ao.audio_flush = AudioOutputFunctions::audio_flush;
|
||||
+ ao.audio_destroy = AudioOutputFunctions::audio_destroy;
|
||||
+ m_pLibShairplay->EnableDelayedUnload(false);
|
||||
+ m_pRaop = m_pLibShairplay->raop_init(1, &ao, RSA_KEY);//1 - we handle one client at a time max
|
||||
+ ret = m_pRaop != NULL;
|
||||
+
|
||||
+ if(ret)
|
||||
+ {
|
||||
+ char macAdr[6];
|
||||
+ unsigned short port = (unsigned short)m_port;
|
||||
+
|
||||
+ m_pLibShairplay->raop_set_log_level(m_pRaop, RAOP_LOG_WARNING);
|
||||
+ if(g_advancedSettings.m_logEnableAirtunes)
|
||||
+ {
|
||||
+ m_pLibShairplay->raop_set_log_level(m_pRaop, RAOP_LOG_DEBUG);
|
||||
+ }
|
||||
+
|
||||
+ m_pLibShairplay->raop_set_log_callback(m_pRaop, shairplay_log);
|
||||
+
|
||||
+ CNetworkInterface *net = g_application.getNetwork().GetFirstConnectedInterface();
|
||||
+
|
||||
+ if (net)
|
||||
+ {
|
||||
+ net->GetMacAddressRaw(macAdr);
|
||||
+ }
|
||||
+
|
||||
+ ret = m_pLibShairplay->raop_start(m_pRaop, &port, macAdr, 6, password.c_str()) >= 0;
|
||||
+ }
|
||||
}
|
||||
- return 1;
|
||||
-}
|
||||
|
||||
-bool CAirTunesServer::Initialize(const CStdString &password)
|
||||
-{
|
||||
- bool ret = false;
|
||||
+#else
|
||||
+
|
||||
int numArgs = 3;
|
||||
CStdString hwStr;
|
||||
CStdString pwStr;
|
||||
CStdString portStr;
|
||||
|
||||
- Deinitialize();
|
||||
-
|
||||
hwStr.Format("--mac=%s", m_macAddress.c_str());
|
||||
pwStr.Format("--password=%s",password.c_str());
|
||||
portStr.Format("--server_port=%d",m_port);
|
||||
@@ -368,16 +667,27 @@ bool CAirTunesServer::Initialize(const CStdString &password)
|
||||
m_pLibShairport->shairport_main(numArgs, argv);
|
||||
ret = true;
|
||||
}
|
||||
+#endif
|
||||
return ret;
|
||||
}
|
||||
|
||||
void CAirTunesServer::Deinitialize()
|
||||
{
|
||||
+#if defined(TARGET_WINDOWS)
|
||||
+ if (m_pLibShairplay && m_pLibShairplay->IsLoaded())
|
||||
+ {
|
||||
+ m_pLibShairplay->raop_stop(m_pRaop);
|
||||
+ m_pLibShairplay->raop_destroy(m_pRaop);
|
||||
+ m_pLibShairplay->Unload();
|
||||
+ }
|
||||
+#else
|
||||
if (m_pLibShairport && m_pLibShairport->IsLoaded())
|
||||
{
|
||||
m_pLibShairport->shairport_exit();
|
||||
m_pLibShairport->Unload();
|
||||
}
|
||||
+#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
+
|
||||
diff --git a/xbmc/network/AirTunesServer.h b/xbmc/network/AirTunesServer.h
|
||||
index da893df..4a30e0a 100644
|
||||
--- a/xbmc/network/AirTunesServer.h
|
||||
+++ b/xbmc/network/AirTunesServer.h
|
||||
@@ -26,7 +26,11 @@
|
||||
|
||||
#ifdef HAS_AIRTUNES
|
||||
|
||||
+#if defined(TARGET_WINDOWS)
|
||||
+#include "DllLibShairplay.h"
|
||||
+#else
|
||||
#include "DllLibShairport.h"
|
||||
+#endif
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
@@ -41,11 +45,14 @@
|
||||
|
||||
class DllLibShairport;
|
||||
|
||||
+
|
||||
class CAirTunesServer : public CThread
|
||||
{
|
||||
public:
|
||||
static bool StartServer(int port, bool nonlocal, bool usePassword, const CStdString &password="");
|
||||
static void StopServer(bool bWait);
|
||||
+ static void SetMetadataFromBuffer(const char *buffer, unsigned int size);
|
||||
+ static void SetCoverArtFromBuffer(const char *buffer, unsigned int size);
|
||||
|
||||
protected:
|
||||
void Process();
|
||||
@@ -57,13 +64,28 @@ class CAirTunesServer : public CThread
|
||||
void Deinitialize();
|
||||
|
||||
int m_port;
|
||||
+#if defined(TARGET_WINDOWS)
|
||||
+ static DllLibShairplay *m_pLibShairplay;//the lib
|
||||
+ raop_t *m_pRaop;
|
||||
+ XFILE::CPipeFile *m_pPipe;
|
||||
+#else
|
||||
static DllLibShairport *m_pLibShairport;//the lib
|
||||
+#endif
|
||||
static CAirTunesServer *ServerInstance;
|
||||
static CStdString m_macAddress;
|
||||
|
||||
class AudioOutputFunctions
|
||||
{
|
||||
public:
|
||||
+#if defined(TARGET_WINDOWS)
|
||||
+ static void* audio_init(void *cls, int bits, int channels, int samplerate);
|
||||
+ static void audio_set_volume(void *cls, void *session, float volume);
|
||||
+ static void audio_set_metadata(void *cls, void *session, const void *buffer, int buflen);
|
||||
+ static void audio_set_coverart(void *cls, void *session, const void *buffer, int buflen);
|
||||
+ static void audio_process(void *cls, void *session, const void *buffer, int buflen);
|
||||
+ static void audio_flush(void *cls, void *session);
|
||||
+ static void audio_destroy(void *cls, void *session);
|
||||
+#else
|
||||
static void ao_initialize(void);
|
||||
static int ao_play(ao_device *device, char *output_samples, uint32_t num_bytes);
|
||||
static int ao_default_driver_id(void);
|
||||
@@ -74,6 +96,7 @@ class CAirTunesServer : public CThread
|
||||
static int ao_append_option(ao_option **options, const char *key, const char *value);
|
||||
static void ao_free_options(ao_option *options);
|
||||
static char* ao_get_option(ao_option *options, const char* key);
|
||||
+#endif
|
||||
};
|
||||
};
|
||||
|
||||
--
|
||||
1.7.10
|
||||
|
@ -0,0 +1,64 @@
|
||||
From b7fb4615609c684a98dc1cc27906aaa0f117837f Mon Sep 17 00:00:00 2001
|
||||
From: Memphiz <memphis@machzwo.de>
|
||||
Date: Wed, 9 May 2012 18:53:45 +0200
|
||||
Subject: [PATCH] [airtunes] - add dmap metadata parsing
|
||||
|
||||
---
|
||||
xbmc/network/AirTunesServer.cpp | 13 ++++++++++++-
|
||||
xbmc/network/AirTunesServer.h | 2 ++
|
||||
2 files changed, 14 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/xbmc/network/AirTunesServer.cpp b/xbmc/network/AirTunesServer.cpp
|
||||
index e14da90..2ad097e 100644
|
||||
--- a/xbmc/network/AirTunesServer.cpp
|
||||
+++ b/xbmc/network/AirTunesServer.cpp
|
||||
@@ -47,7 +47,6 @@
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
-
|
||||
using namespace XFILE;
|
||||
|
||||
#if defined(TARGET_WINDOWS)
|
||||
@@ -390,6 +389,16 @@ int CAirTunesServer::AudioOutputFunctions::ao_close(ao_device *device)
|
||||
return 0;
|
||||
}
|
||||
|
||||
+void CAirTunesServer::AudioOutputFunctions::ao_set_metadata(const char *buffer, unsigned int size)
|
||||
+{
|
||||
+ CAirTunesServer::SetMetadataFromBuffer(buffer, size);
|
||||
+}
|
||||
+
|
||||
+void CAirTunesServer::AudioOutputFunctions::ao_set_metadata_coverart(const char *buffer, unsigned int size)
|
||||
+{
|
||||
+ CAirTunesServer::SetCoverArtFromBuffer(buffer, size);
|
||||
+}
|
||||
+
|
||||
/* -- Device Setup/Playback/Teardown -- */
|
||||
int CAirTunesServer::AudioOutputFunctions::ao_append_option(ao_option **options, const char *key, const char *value)
|
||||
{
|
||||
@@ -658,6 +667,8 @@ bool CAirTunesServer::Initialize(const CStdString &password)
|
||||
ao.ao_append_option = AudioOutputFunctions::ao_append_option;
|
||||
ao.ao_free_options = AudioOutputFunctions::ao_free_options;
|
||||
ao.ao_get_option = AudioOutputFunctions::ao_get_option;
|
||||
+ ao.ao_set_metadata = AudioOutputFunctions::ao_set_metadata;
|
||||
+ ao.ao_set_metadata_coverart = AudioOutputFunctions::ao_set_metadata_coverart;
|
||||
struct printfPtr funcPtr;
|
||||
funcPtr.extprintf = shairport_log;
|
||||
|
||||
diff --git a/xbmc/network/AirTunesServer.h b/xbmc/network/AirTunesServer.h
|
||||
index 4a30e0a..0a4ce5a 100644
|
||||
--- a/xbmc/network/AirTunesServer.h
|
||||
+++ b/xbmc/network/AirTunesServer.h
|
||||
@@ -96,6 +96,8 @@ class CAirTunesServer : public CThread
|
||||
static int ao_append_option(ao_option **options, const char *key, const char *value);
|
||||
static void ao_free_options(ao_option *options);
|
||||
static char* ao_get_option(ao_option *options, const char* key);
|
||||
+ static void ao_set_metadata(const char *buffer, unsigned int size);
|
||||
+ static void ao_set_metadata_coverart(const char *buffer, unsigned int size);
|
||||
#endif
|
||||
};
|
||||
};
|
||||
--
|
||||
1.7.10
|
||||
|
@ -0,0 +1,31 @@
|
||||
From ab175ba28508445f6aff57386a8ce04b58a86f60 Mon Sep 17 00:00:00 2001
|
||||
From: Memphiz <memphis@machzwo.de>
|
||||
Date: Fri, 11 May 2012 19:56:37 +0200
|
||||
Subject: [PATCH] [fix] - reapply fix for airtunes with AE which was lost
|
||||
during merge
|
||||
|
||||
---
|
||||
xbmc/network/AirTunesServer.cpp | 4 ++--
|
||||
1 file changed, 2 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/xbmc/network/AirTunesServer.cpp b/xbmc/network/AirTunesServer.cpp
|
||||
index 285a0a6..a60ad09 100644
|
||||
--- a/xbmc/network/AirTunesServer.cpp
|
||||
+++ b/xbmc/network/AirTunesServer.cpp
|
||||
@@ -125,11 +125,11 @@ ao_device* CAirTunesServer::AudioOutputFunctions::ao_open_live(int driver_id, ao
|
||||
if (ao_get_option(option, "name"))
|
||||
item.GetMusicInfoTag()->SetTitle(ao_get_option(option, "name"));
|
||||
|
||||
- g_application.getApplicationMessenger().PlayFile(item);
|
||||
-
|
||||
ThreadMessage tMsg2 = { TMSG_GUI_ACTIVATE_WINDOW, WINDOW_VISUALISATION, 0 };
|
||||
g_application.getApplicationMessenger().SendMessage(tMsg2, true);
|
||||
|
||||
+ g_application.getApplicationMessenger().PlayFile(item);
|
||||
+
|
||||
return (ao_device*) device;
|
||||
}
|
||||
|
||||
--
|
||||
1.7.10
|
||||
|
@ -0,0 +1,527 @@
|
||||
From b73018af2ae69c7cfad0a4461d169a49c7d0dfbf Mon Sep 17 00:00:00 2001
|
||||
From: Memphiz <memphis@machzwo.de>
|
||||
Date: Tue, 15 May 2012 19:12:07 +0200
|
||||
Subject: [PATCH] [airtunes] - implementation for windows using libshairplay
|
||||
|
||||
---
|
||||
xbmc/network/AirTunesServer.cpp | 330 +++++++++++++++++++++++++++++++++++++--
|
||||
xbmc/network/AirTunesServer.h | 23 +++
|
||||
2 files changed, 343 insertions(+), 10 deletions(-)
|
||||
|
||||
diff --git a/xbmc/network/AirTunesServer.cpp b/xbmc/network/AirTunesServer.cpp
|
||||
index a60ad09..e14da90 100644
|
||||
--- a/xbmc/network/AirTunesServer.cpp
|
||||
+++ b/xbmc/network/AirTunesServer.cpp
|
||||
@@ -17,7 +17,9 @@
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
+#if !defined(TARGET_WINDOWS)
|
||||
#pragma GCC diagnostic ignored "-Wwrite-strings"
|
||||
+#endif
|
||||
|
||||
#include "AirTunesServer.h"
|
||||
|
||||
@@ -37,15 +39,243 @@
|
||||
#include "music/tags/MusicInfoTag.h"
|
||||
#include "FileItem.h"
|
||||
#include "GUIInfoManager.h"
|
||||
+#include "guilib/GUIWindowManager.h"
|
||||
#include "utils/Variant.h"
|
||||
#include "settings/AdvancedSettings.h"
|
||||
+#include "utils/EndianSwap.h"
|
||||
+
|
||||
+#include <map>
|
||||
+#include <string>
|
||||
+
|
||||
|
||||
using namespace XFILE;
|
||||
|
||||
+#if defined(TARGET_WINDOWS)
|
||||
+DllLibShairplay *CAirTunesServer::m_pLibShairplay = NULL;
|
||||
+#else
|
||||
DllLibShairport *CAirTunesServer::m_pLibShairport = NULL;
|
||||
+#endif
|
||||
CAirTunesServer *CAirTunesServer::ServerInstance = NULL;
|
||||
CStdString CAirTunesServer::m_macAddress;
|
||||
|
||||
+//parse daap metadata - thx to project MythTV
|
||||
+std::map<std::string, std::string> decodeDMAP(const char *buffer, unsigned int size)
|
||||
+{
|
||||
+ std::map<std::string, std::string> result;
|
||||
+ unsigned int offset = 8;
|
||||
+ while (offset < size)
|
||||
+ {
|
||||
+ std::string tag;
|
||||
+ tag.append(buffer + offset, 4);
|
||||
+ offset += 4;
|
||||
+ uint32_t length = Endian_SwapBE32(*(uint32_t *)(buffer + offset));
|
||||
+ offset += sizeof(uint32_t);
|
||||
+ std::string content;
|
||||
+ content.append(buffer + offset, length);//possible fixme - utf8?
|
||||
+ offset += length;
|
||||
+ result[tag] = content;
|
||||
+ }
|
||||
+ return result;
|
||||
+}
|
||||
+
|
||||
+void CAirTunesServer::SetMetadataFromBuffer(const char *buffer, unsigned int size)
|
||||
+{
|
||||
+ MUSIC_INFO::CMusicInfoTag tag;
|
||||
+ std::map<std::string, std::string> metadata = decodeDMAP(buffer, size);
|
||||
+ if(metadata["asal"].length())
|
||||
+ tag.SetAlbum(metadata["asal"]);//album
|
||||
+ if(metadata["minm"].length())
|
||||
+ tag.SetTitle(metadata["minm"]);//title
|
||||
+ if(metadata["asar"].length())
|
||||
+ tag.SetArtist(metadata["asar"]);//artist
|
||||
+ g_infoManager.SetCurrentSongTag(tag);
|
||||
+}
|
||||
+
|
||||
+void CAirTunesServer::SetCoverArtFromBuffer(const char *buffer, unsigned int size)
|
||||
+{
|
||||
+ XFILE::CFile tmpFile;
|
||||
+ const char *tmpFileName = "special://temp/airtunes_album_thumb.jpg";
|
||||
+
|
||||
+ if(!size)
|
||||
+ return;
|
||||
+
|
||||
+ if (tmpFile.OpenForWrite(tmpFileName, true))
|
||||
+ {
|
||||
+ int writtenBytes=0;
|
||||
+ writtenBytes = tmpFile.Write(buffer, size);
|
||||
+ tmpFile.Close();
|
||||
+
|
||||
+ if(writtenBytes)
|
||||
+ {
|
||||
+ //reset to empty before setting the new one
|
||||
+ //else it won't get refreshed because the name didn't change
|
||||
+ g_infoManager.SetCurrentAlbumThumb("");
|
||||
+ g_infoManager.SetCurrentAlbumThumb(tmpFileName);
|
||||
+ //update the ui
|
||||
+ CGUIMessage msg(GUI_MSG_NOTIFY_ALL,0,0,GUI_MSG_REFRESH_THUMBS);
|
||||
+ g_windowManager.SendThreadMessage(msg);
|
||||
+ }
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+#if defined(TARGET_WINDOWS)
|
||||
+#define RSA_KEY " \
|
||||
+-----BEGIN RSA PRIVATE KEY-----\
|
||||
+MIIEpQIBAAKCAQEA59dE8qLieItsH1WgjrcFRKj6eUWqi+bGLOX1HL3U3GhC/j0Qg90u3sG/1CUt\
|
||||
+wC5vOYvfDmFI6oSFXi5ELabWJmT2dKHzBJKa3k9ok+8t9ucRqMd6DZHJ2YCCLlDRKSKv6kDqnw4U\
|
||||
+wPdpOMXziC/AMj3Z/lUVX1G7WSHCAWKf1zNS1eLvqr+boEjXuBOitnZ/bDzPHrTOZz0Dew0uowxf\
|
||||
+/+sG+NCK3eQJVxqcaJ/vEHKIVd2M+5qL71yJQ+87X6oV3eaYvt3zWZYD6z5vYTcrtij2VZ9Zmni/\
|
||||
+UAaHqn9JdsBWLUEpVviYnhimNVvYFZeCXg/IdTQ+x4IRdiXNv5hEewIDAQABAoIBAQDl8Axy9XfW\
|
||||
+BLmkzkEiqoSwF0PsmVrPzH9KsnwLGH+QZlvjWd8SWYGN7u1507HvhF5N3drJoVU3O14nDY4TFQAa\
|
||||
+LlJ9VM35AApXaLyY1ERrN7u9ALKd2LUwYhM7Km539O4yUFYikE2nIPscEsA5ltpxOgUGCY7b7ez5\
|
||||
+NtD6nL1ZKauw7aNXmVAvmJTcuPxWmoktF3gDJKK2wxZuNGcJE0uFQEG4Z3BrWP7yoNuSK3dii2jm\
|
||||
+lpPHr0O/KnPQtzI3eguhe0TwUem/eYSdyzMyVx/YpwkzwtYL3sR5k0o9rKQLtvLzfAqdBxBurciz\
|
||||
+aaA/L0HIgAmOit1GJA2saMxTVPNhAoGBAPfgv1oeZxgxmotiCcMXFEQEWflzhWYTsXrhUIuz5jFu\
|
||||
+a39GLS99ZEErhLdrwj8rDDViRVJ5skOp9zFvlYAHs0xh92ji1E7V/ysnKBfsMrPkk5KSKPrnjndM\
|
||||
+oPdevWnVkgJ5jxFuNgxkOLMuG9i53B4yMvDTCRiIPMQ++N2iLDaRAoGBAO9v//mU8eVkQaoANf0Z\
|
||||
+oMjW8CN4xwWA2cSEIHkd9AfFkftuv8oyLDCG3ZAf0vrhrrtkrfa7ef+AUb69DNggq4mHQAYBp7L+\
|
||||
+k5DKzJrKuO0r+R0YbY9pZD1+/g9dVt91d6LQNepUE/yY2PP5CNoFmjedpLHMOPFdVgqDzDFxU8hL\
|
||||
+AoGBANDrr7xAJbqBjHVwIzQ4To9pb4BNeqDndk5Qe7fT3+/H1njGaC0/rXE0Qb7q5ySgnsCb3DvA\
|
||||
+cJyRM9SJ7OKlGt0FMSdJD5KG0XPIpAVNwgpXXH5MDJg09KHeh0kXo+QA6viFBi21y340NonnEfdf\
|
||||
+54PX4ZGS/Xac1UK+pLkBB+zRAoGAf0AY3H3qKS2lMEI4bzEFoHeK3G895pDaK3TFBVmD7fV0Zhov\
|
||||
+17fegFPMwOII8MisYm9ZfT2Z0s5Ro3s5rkt+nvLAdfC/PYPKzTLalpGSwomSNYJcB9HNMlmhkGzc\
|
||||
+1JnLYT4iyUyx6pcZBmCd8bD0iwY/FzcgNDaUmbX9+XDvRA0CgYEAkE7pIPlE71qvfJQgoA9em0gI\
|
||||
+LAuE4Pu13aKiJnfft7hIjbK+5kyb3TysZvoyDnb3HOKvInK7vXbKuU4ISgxB2bB3HcYzQMGsz1qJ\
|
||||
+2gG0N5hvJpzwwhbhXqFKA4zaaSrw622wDniAK5MlIE0tIAKKP4yxNGjoD2QYjhBGuhvkWKY=\
|
||||
+-----END RSA PRIVATE KEY-----"
|
||||
+
|
||||
+void CAirTunesServer::AudioOutputFunctions::audio_set_metadata(void *cls, void *session, const void *buffer, int buflen)
|
||||
+{
|
||||
+ CAirTunesServer::SetMetadataFromBuffer((char *)buffer, buflen);
|
||||
+}
|
||||
+
|
||||
+void CAirTunesServer::AudioOutputFunctions::audio_set_coverart(void *cls, void *session, const void *buffer, int buflen)
|
||||
+{
|
||||
+ CAirTunesServer::SetCoverArtFromBuffer((char *)buffer, buflen);
|
||||
+}
|
||||
+
|
||||
+void* CAirTunesServer::AudioOutputFunctions::audio_init(void *cls, int bits, int channels, int samplerate)
|
||||
+{
|
||||
+ XFILE::CPipeFile *pipe=(XFILE::CPipeFile *)cls;
|
||||
+ pipe->OpenForWrite(XFILE::PipesManager::GetInstance().GetUniquePipeName());
|
||||
+ pipe->SetOpenThreashold(300);
|
||||
+
|
||||
+ BXA_FmtHeader header;
|
||||
+ strncpy(header.fourcc, "BXA ", 4);
|
||||
+ header.type = BXA_PACKET_TYPE_FMT;
|
||||
+ header.bitsPerSample = bits;
|
||||
+ header.channels = channels;
|
||||
+ header.sampleRate = samplerate;
|
||||
+ header.durationMs = 0;
|
||||
+
|
||||
+ if (pipe->Write(&header, sizeof(header)) == 0)
|
||||
+ return 0;
|
||||
+
|
||||
+ ThreadMessage tMsg = { TMSG_MEDIA_STOP };
|
||||
+ g_application.getApplicationMessenger().SendMessage(tMsg, true);
|
||||
+
|
||||
+ CFileItem item;
|
||||
+ item.SetPath(pipe->GetName());
|
||||
+ item.SetMimeType("audio/x-xbmc-pcm");
|
||||
+
|
||||
+ ThreadMessage tMsg2 = { TMSG_GUI_ACTIVATE_WINDOW, WINDOW_VISUALISATION, 0 };
|
||||
+ g_application.getApplicationMessenger().SendMessage(tMsg2, true);
|
||||
+
|
||||
+ g_application.getApplicationMessenger().PlayFile(item);
|
||||
+
|
||||
+ return "XBMC-AirTunes";//session
|
||||
+}
|
||||
+
|
||||
+void CAirTunesServer::AudioOutputFunctions::audio_set_volume(void *cls, void *session, float volume)
|
||||
+{
|
||||
+ //volume from -144 - 0
|
||||
+ float volPercent = 1 - volume/-144;
|
||||
+ g_application.SetVolume(volPercent, false);//non-percent volume 0.0-1.0
|
||||
+}
|
||||
+
|
||||
+void CAirTunesServer::AudioOutputFunctions::audio_process(void *cls, void *session, const void *buffer, int buflen)
|
||||
+{
|
||||
+ #define NUM_OF_BYTES 64
|
||||
+ XFILE::CPipeFile *pipe=(XFILE::CPipeFile *)cls;
|
||||
+ int sentBytes = 0;
|
||||
+ unsigned char buf[NUM_OF_BYTES];
|
||||
+
|
||||
+ while (sentBytes < buflen)
|
||||
+ {
|
||||
+ int n = (buflen - sentBytes < NUM_OF_BYTES ? buflen - sentBytes : NUM_OF_BYTES);
|
||||
+ memcpy(buf, (char*) buffer + sentBytes, n);
|
||||
+
|
||||
+ if (pipe->Write(buf, n) == 0)
|
||||
+ return;
|
||||
+
|
||||
+ sentBytes += n;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+void CAirTunesServer::AudioOutputFunctions::audio_flush(void *cls, void *session)
|
||||
+{
|
||||
+ XFILE::CPipeFile *pipe=(XFILE::CPipeFile *)cls;
|
||||
+ pipe->Flush();
|
||||
+}
|
||||
+
|
||||
+void CAirTunesServer::AudioOutputFunctions::audio_destroy(void *cls, void *session)
|
||||
+{
|
||||
+ XFILE::CPipeFile *pipe=(XFILE::CPipeFile *)cls;
|
||||
+ pipe->SetEof();
|
||||
+ pipe->Close();
|
||||
+
|
||||
+ //fix airplay video for ios5 devices
|
||||
+ //on ios5 when airplaying video
|
||||
+ //the client first opens an airtunes stream
|
||||
+ //while the movie is loading
|
||||
+ //in that case we don't want to stop the player here
|
||||
+ //because this would stop the airplaying video
|
||||
+#ifdef HAS_AIRPLAY
|
||||
+ if (!CAirPlayServer::IsPlaying())
|
||||
+#endif
|
||||
+ {
|
||||
+ ThreadMessage tMsg = { TMSG_MEDIA_STOP };
|
||||
+ g_application.getApplicationMessenger().SendMessage(tMsg, true);
|
||||
+ CLog::Log(LOGDEBUG, "AIRTUNES: AirPlay not running - stopping player");
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+void shairplay_log(int level, const char *msg)
|
||||
+{
|
||||
+ int xbmcLevel = LOGINFO;
|
||||
+
|
||||
+ switch(level)
|
||||
+ {
|
||||
+ case RAOP_LOG_EMERG: // system is unusable
|
||||
+ xbmcLevel = LOGFATAL;
|
||||
+ break;
|
||||
+ case RAOP_LOG_ALERT: // action must be taken immediately
|
||||
+ case RAOP_LOG_CRIT: // critical conditions
|
||||
+ xbmcLevel = LOGSEVERE;
|
||||
+ break;
|
||||
+ case RAOP_LOG_ERR: // error conditions
|
||||
+ xbmcLevel = LOGERROR;
|
||||
+ break;
|
||||
+ case RAOP_LOG_WARNING: // warning conditions
|
||||
+ xbmcLevel = LOGWARNING;
|
||||
+ break;
|
||||
+ case RAOP_LOG_NOTICE: // normal but significant condition
|
||||
+ xbmcLevel = LOGNOTICE;
|
||||
+ break;
|
||||
+ case RAOP_LOG_INFO: // informational
|
||||
+ xbmcLevel = LOGINFO;
|
||||
+ break;
|
||||
+ case RAOP_LOG_DEBUG: // debug-level messages
|
||||
+ xbmcLevel = LOGDEBUG;
|
||||
+ break;
|
||||
+ default:
|
||||
+ break;
|
||||
+ }
|
||||
+ CLog::Log(xbmcLevel, "AIRTUNES: %s", msg);
|
||||
+}
|
||||
+
|
||||
+#else
|
||||
+
|
||||
struct ao_device_xbmc
|
||||
{
|
||||
XFILE::CPipeFile *pipe;
|
||||
@@ -214,6 +444,17 @@ char* CAirTunesServer::AudioOutputFunctions::ao_get_option(ao_option *options, c
|
||||
return NULL;
|
||||
}
|
||||
|
||||
+int shairport_log(const char* msg, size_t msgSize)
|
||||
+{
|
||||
+ if( g_advancedSettings.m_logEnableAirtunes)
|
||||
+ {
|
||||
+ CLog::Log(LOGDEBUG, "AIRTUNES: %s", msg);
|
||||
+ }
|
||||
+ return 1;
|
||||
+}
|
||||
+
|
||||
+#endif
|
||||
+
|
||||
bool CAirTunesServer::StartServer(int port, bool nonlocal, bool usePassword, const CStdString &password/*=""*/)
|
||||
{
|
||||
bool success = false;
|
||||
@@ -243,7 +484,9 @@ bool CAirTunesServer::StartServer(int port, bool nonlocal, bool usePassword, con
|
||||
ServerInstance = new CAirTunesServer(port, nonlocal);
|
||||
if (ServerInstance->Initialize(password))
|
||||
{
|
||||
+#ifndef TARGET_WINDOWS
|
||||
ServerInstance->Create();
|
||||
+#endif
|
||||
success = true;
|
||||
}
|
||||
|
||||
@@ -264,6 +507,9 @@ bool CAirTunesServer::StartServer(int port, bool nonlocal, bool usePassword, con
|
||||
txt["sr"] = "44100";
|
||||
txt["pw"] = "false";
|
||||
txt["vn"] = "3";
|
||||
+ txt["da"] = "true";
|
||||
+ txt["vs"] = "130.14";
|
||||
+ txt["md"] = "0,1,2";
|
||||
txt["txtvers"] = "1";
|
||||
|
||||
CZeroconf::GetInstance()->PublishService("servers.airtunes", "_raop._tcp", appName, port, txt);
|
||||
@@ -276,10 +522,12 @@ void CAirTunesServer::StopServer(bool bWait)
|
||||
{
|
||||
if (ServerInstance)
|
||||
{
|
||||
+#if !defined(TARGET_WINDOWS)
|
||||
if (m_pLibShairport->IsLoaded())
|
||||
{
|
||||
m_pLibShairport->shairport_exit();
|
||||
}
|
||||
+#endif
|
||||
ServerInstance->StopThread(bWait);
|
||||
ServerInstance->Deinitialize();
|
||||
if (bWait)
|
||||
@@ -295,47 +543,98 @@ void CAirTunesServer::StopServer(bool bWait)
|
||||
CAirTunesServer::CAirTunesServer(int port, bool nonlocal) : CThread("AirTunesServer")
|
||||
{
|
||||
m_port = port;
|
||||
+#if defined(TARGET_WINDOWS)
|
||||
+ m_pLibShairplay = new DllLibShairplay();
|
||||
+ m_pPipe = new XFILE::CPipeFile;
|
||||
+#else
|
||||
m_pLibShairport = new DllLibShairport();
|
||||
+#endif
|
||||
}
|
||||
|
||||
CAirTunesServer::~CAirTunesServer()
|
||||
{
|
||||
+#if defined(TARGET_WINDOWS)
|
||||
+ if (m_pLibShairplay->IsLoaded())
|
||||
+ {
|
||||
+ m_pLibShairplay->Unload();
|
||||
+ }
|
||||
+ delete m_pLibShairplay;
|
||||
+ delete m_pPipe;
|
||||
+#else
|
||||
if (m_pLibShairport->IsLoaded())
|
||||
{
|
||||
m_pLibShairport->Unload();
|
||||
}
|
||||
delete m_pLibShairport;
|
||||
+#endif
|
||||
}
|
||||
|
||||
void CAirTunesServer::Process()
|
||||
{
|
||||
m_bStop = false;
|
||||
|
||||
+#if !defined(TARGET_WINDOWS)
|
||||
while (!m_bStop && m_pLibShairport->shairport_is_running())
|
||||
{
|
||||
m_pLibShairport->shairport_loop();
|
||||
}
|
||||
+#endif
|
||||
}
|
||||
|
||||
-int shairport_log(const char* msg, size_t msgSize)
|
||||
+bool CAirTunesServer::Initialize(const CStdString &password)
|
||||
{
|
||||
- if( g_advancedSettings.m_logEnableAirtunes)
|
||||
+ bool ret = false;
|
||||
+
|
||||
+ Deinitialize();
|
||||
+
|
||||
+#if defined(TARGET_WINDOWS)
|
||||
+ if (m_pLibShairplay->Load())
|
||||
{
|
||||
- CLog::Log(LOGDEBUG, "AIRTUNES: %s", msg);
|
||||
+
|
||||
+ raop_callbacks_t ao;
|
||||
+ ao.cls = m_pPipe;
|
||||
+ ao.audio_init = AudioOutputFunctions::audio_init;
|
||||
+ ao.audio_set_volume = AudioOutputFunctions::audio_set_volume;
|
||||
+ ao.audio_set_metadata = AudioOutputFunctions::audio_set_metadata;
|
||||
+ ao.audio_set_coverart = AudioOutputFunctions::audio_set_coverart;
|
||||
+ ao.audio_process = AudioOutputFunctions::audio_process;
|
||||
+ ao.audio_flush = AudioOutputFunctions::audio_flush;
|
||||
+ ao.audio_destroy = AudioOutputFunctions::audio_destroy;
|
||||
+ m_pLibShairplay->EnableDelayedUnload(false);
|
||||
+ m_pRaop = m_pLibShairplay->raop_init(1, &ao, RSA_KEY);//1 - we handle one client at a time max
|
||||
+ ret = m_pRaop != NULL;
|
||||
+
|
||||
+ if(ret)
|
||||
+ {
|
||||
+ char macAdr[6];
|
||||
+ unsigned short port = (unsigned short)m_port;
|
||||
+
|
||||
+ m_pLibShairplay->raop_set_log_level(m_pRaop, RAOP_LOG_WARNING);
|
||||
+ if(g_advancedSettings.m_logEnableAirtunes)
|
||||
+ {
|
||||
+ m_pLibShairplay->raop_set_log_level(m_pRaop, RAOP_LOG_DEBUG);
|
||||
+ }
|
||||
+
|
||||
+ m_pLibShairplay->raop_set_log_callback(m_pRaop, shairplay_log);
|
||||
+
|
||||
+ CNetworkInterface *net = g_application.getNetwork().GetFirstConnectedInterface();
|
||||
+
|
||||
+ if (net)
|
||||
+ {
|
||||
+ net->GetMacAddressRaw(macAdr);
|
||||
+ }
|
||||
+
|
||||
+ ret = m_pLibShairplay->raop_start(m_pRaop, &port, macAdr, 6, password.c_str()) >= 0;
|
||||
+ }
|
||||
}
|
||||
- return 1;
|
||||
-}
|
||||
|
||||
-bool CAirTunesServer::Initialize(const CStdString &password)
|
||||
-{
|
||||
- bool ret = false;
|
||||
+#else
|
||||
+
|
||||
int numArgs = 3;
|
||||
CStdString hwStr;
|
||||
CStdString pwStr;
|
||||
CStdString portStr;
|
||||
|
||||
- Deinitialize();
|
||||
-
|
||||
hwStr.Format("--mac=%s", m_macAddress.c_str());
|
||||
pwStr.Format("--password=%s",password.c_str());
|
||||
portStr.Format("--server_port=%d",m_port);
|
||||
@@ -368,16 +667,27 @@ bool CAirTunesServer::Initialize(const CStdString &password)
|
||||
m_pLibShairport->shairport_main(numArgs, argv);
|
||||
ret = true;
|
||||
}
|
||||
+#endif
|
||||
return ret;
|
||||
}
|
||||
|
||||
void CAirTunesServer::Deinitialize()
|
||||
{
|
||||
+#if defined(TARGET_WINDOWS)
|
||||
+ if (m_pLibShairplay && m_pLibShairplay->IsLoaded())
|
||||
+ {
|
||||
+ m_pLibShairplay->raop_stop(m_pRaop);
|
||||
+ m_pLibShairplay->raop_destroy(m_pRaop);
|
||||
+ m_pLibShairplay->Unload();
|
||||
+ }
|
||||
+#else
|
||||
if (m_pLibShairport && m_pLibShairport->IsLoaded())
|
||||
{
|
||||
m_pLibShairport->shairport_exit();
|
||||
m_pLibShairport->Unload();
|
||||
}
|
||||
+#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
+
|
||||
diff --git a/xbmc/network/AirTunesServer.h b/xbmc/network/AirTunesServer.h
|
||||
index da893df..4a30e0a 100644
|
||||
--- a/xbmc/network/AirTunesServer.h
|
||||
+++ b/xbmc/network/AirTunesServer.h
|
||||
@@ -26,7 +26,11 @@
|
||||
|
||||
#ifdef HAS_AIRTUNES
|
||||
|
||||
+#if defined(TARGET_WINDOWS)
|
||||
+#include "DllLibShairplay.h"
|
||||
+#else
|
||||
#include "DllLibShairport.h"
|
||||
+#endif
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
@@ -41,11 +45,14 @@
|
||||
|
||||
class DllLibShairport;
|
||||
|
||||
+
|
||||
class CAirTunesServer : public CThread
|
||||
{
|
||||
public:
|
||||
static bool StartServer(int port, bool nonlocal, bool usePassword, const CStdString &password="");
|
||||
static void StopServer(bool bWait);
|
||||
+ static void SetMetadataFromBuffer(const char *buffer, unsigned int size);
|
||||
+ static void SetCoverArtFromBuffer(const char *buffer, unsigned int size);
|
||||
|
||||
protected:
|
||||
void Process();
|
||||
@@ -57,13 +64,28 @@ class CAirTunesServer : public CThread
|
||||
void Deinitialize();
|
||||
|
||||
int m_port;
|
||||
+#if defined(TARGET_WINDOWS)
|
||||
+ static DllLibShairplay *m_pLibShairplay;//the lib
|
||||
+ raop_t *m_pRaop;
|
||||
+ XFILE::CPipeFile *m_pPipe;
|
||||
+#else
|
||||
static DllLibShairport *m_pLibShairport;//the lib
|
||||
+#endif
|
||||
static CAirTunesServer *ServerInstance;
|
||||
static CStdString m_macAddress;
|
||||
|
||||
class AudioOutputFunctions
|
||||
{
|
||||
public:
|
||||
+#if defined(TARGET_WINDOWS)
|
||||
+ static void* audio_init(void *cls, int bits, int channels, int samplerate);
|
||||
+ static void audio_set_volume(void *cls, void *session, float volume);
|
||||
+ static void audio_set_metadata(void *cls, void *session, const void *buffer, int buflen);
|
||||
+ static void audio_set_coverart(void *cls, void *session, const void *buffer, int buflen);
|
||||
+ static void audio_process(void *cls, void *session, const void *buffer, int buflen);
|
||||
+ static void audio_flush(void *cls, void *session);
|
||||
+ static void audio_destroy(void *cls, void *session);
|
||||
+#else
|
||||
static void ao_initialize(void);
|
||||
static int ao_play(ao_device *device, char *output_samples, uint32_t num_bytes);
|
||||
static int ao_default_driver_id(void);
|
||||
@@ -74,6 +96,7 @@ class CAirTunesServer : public CThread
|
||||
static int ao_append_option(ao_option **options, const char *key, const char *value);
|
||||
static void ao_free_options(ao_option *options);
|
||||
static char* ao_get_option(ao_option *options, const char* key);
|
||||
+#endif
|
||||
};
|
||||
};
|
||||
|
||||
--
|
||||
1.7.10
|
||||
|
Loading…
x
Reference in New Issue
Block a user