diff --git a/packages/mediacenter/xbmc/patches/xbmc-999.80.010-PR4414.patch b/packages/mediacenter/xbmc/patches/xbmc-999.80.010-PR4414.patch new file mode 100644 index 0000000000..3fbe818f34 --- /dev/null +++ b/packages/mediacenter/xbmc/patches/xbmc-999.80.010-PR4414.patch @@ -0,0 +1,390 @@ +From 794ebc00947bc208e6b377e5d69be6cfa85cf382 Mon Sep 17 00:00:00 2001 +From: Memphiz +Date: Tue, 11 Mar 2014 20:30:19 +0100 +Subject: [PATCH 1/3] [airplay] - ensure to announce airtunes before airplay + via zeroconf (makes it more likely that ios7 clients detect us correctly at + the first shot) + +--- + xbmc/network/NetworkServices.cpp | 14 +++++++------- + 1 file changed, 7 insertions(+), 7 deletions(-) + +diff --git a/xbmc/network/NetworkServices.cpp b/xbmc/network/NetworkServices.cpp +index f1b82d7..66316b4 100644 +--- a/xbmc/network/NetworkServices.cpp ++++ b/xbmc/network/NetworkServices.cpp +@@ -210,12 +210,6 @@ bool CNetworkServices::OnSettingChanging(const CSetting *setting) + } + #endif //HAS_ZEROCONF + +- if (!StartAirPlayServer()) +- { +- CGUIDialogOK::ShowAndGetInput(g_localizeStrings.Get(1273), "", g_localizeStrings.Get(33100), ""); +- return false; +- } +- + #ifdef HAS_AIRTUNES + if (!StartAirTunesServer()) + { +@@ -223,6 +217,12 @@ bool CNetworkServices::OnSettingChanging(const CSetting *setting) + return false; + } + #endif //HAS_AIRTUNES ++ ++ if (!StartAirPlayServer()) ++ { ++ CGUIDialogOK::ShowAndGetInput(g_localizeStrings.Get(1273), "", g_localizeStrings.Get(33100), ""); ++ return false; ++ } + } + else + { +@@ -402,8 +402,8 @@ void CNetworkServices::Start() + CGUIDialogKaiToast::QueueNotification(CGUIDialogKaiToast::Warning, g_localizeStrings.Get(33102), g_localizeStrings.Get(33100)); + if (CSettings::Get().GetBool("services.esenabled") && !StartJSONRPCServer()) + CGUIDialogKaiToast::QueueNotification(CGUIDialogKaiToast::Warning, g_localizeStrings.Get(33103), g_localizeStrings.Get(33100)); +- StartAirPlayServer(); + StartAirTunesServer(); ++ StartAirPlayServer(); + StartRss(); + } + +-- +1.8.5.5 + + +From 9cfabede54d59aafff8aece7e4270f32422d03b3 Mon Sep 17 00:00:00 2001 +From: Memphiz +Date: Tue, 11 Mar 2014 20:31:58 +0100 +Subject: [PATCH 2/3] [zeroconf] - add method to reannounce already published + services + +--- + xbmc/network/Zeroconf.cpp | 11 +++++++++++ + xbmc/network/Zeroconf.h | 15 ++++++++++++++- + xbmc/network/linux/ZeroconfAvahi.cpp | 20 ++++++++++++++++++++ + xbmc/network/linux/ZeroconfAvahi.h | 1 + + xbmc/network/mdns/ZeroconfMDNS.cpp | 36 +++++++++++++++++++++++++++++++----- + xbmc/network/mdns/ZeroconfMDNS.h | 9 ++++++++- + xbmc/network/osx/ZeroconfOSX.cpp | 26 ++++++++++++++++++++++++++ + xbmc/network/osx/ZeroconfOSX.h | 2 ++ + 8 files changed, 113 insertions(+), 7 deletions(-) + +diff --git a/xbmc/network/Zeroconf.cpp b/xbmc/network/Zeroconf.cpp +index ac13ac4..1569ec4 100644 +--- a/xbmc/network/Zeroconf.cpp ++++ b/xbmc/network/Zeroconf.cpp +@@ -45,6 +45,8 @@ class CZeroconfDummy : public CZeroconf + { + return false; + } ++ ++ virtual bool doForceReAnnounceService(const std::string&){return false;} + virtual bool doRemoveService(const std::string& fcr_ident){return false;} + virtual void doStop(){} + }; +@@ -93,6 +95,15 @@ bool CZeroconf::RemoveService(const std::string& fcr_identifier) + return true; + } + ++bool CZeroconf::ForceReAnnounceService(const std::string& fcr_identifier) ++{ ++ if (HasService(fcr_identifier) && m_started) ++ { ++ return doForceReAnnounceService(fcr_identifier); ++ } ++ return false; ++} ++ + bool CZeroconf::HasService(const std::string& fcr_identifier) const + { + return (m_service_map.find(fcr_identifier) != m_service_map.end()); +diff --git a/xbmc/network/Zeroconf.h b/xbmc/network/Zeroconf.h +index 441c0c1..d87e34c 100644 +--- a/xbmc/network/Zeroconf.h ++++ b/xbmc/network/Zeroconf.h +@@ -40,7 +40,7 @@ class CZeroconf + public: + + //tries to publish this service via zeroconf +- //fcr_identifier can be used to stop this service later ++ //fcr_identifier can be used to stop or reannounce this service later + //fcr_type is the zeroconf service type to publish (e.g. _http._tcp for webserver) + //fcr_name is the name of the service to publish. The hostname is currently automatically appended + // and used for name collisions. e.g. XBMC would get published as fcr_name@Martn or, after collision fcr_name@Martn-2 +@@ -51,6 +51,14 @@ class CZeroconf + const std::string& fcr_name, + unsigned int f_port, + std::vector > txt /*= std::vector >()*/); ++ ++ //tries to rebroadcast that service on the network without removing/readding ++ //this can be achieved by changing a fake txt record. Implementations should ++ //implement it by doing so. ++ // ++ //fcr_identifier - the identifier of the already published service which should be reannounced ++ // returns true on successfull reannonuce - false if this service isn't published yet ++ bool ForceReAnnounceService(const std::string& fcr_identifier); + + ///removes the specified service + ///returns false if fcr_identifier does not exist +@@ -90,6 +98,11 @@ class CZeroconf + const std::string& fcr_name, + unsigned int f_port, + const std::vector >& txt) = 0; ++ ++ //methods to implement for concrete implementations ++ //update this service ++ virtual bool doForceReAnnounceService(const std::string& fcr_identifier) = 0; ++ + //removes the service if published + virtual bool doRemoveService(const std::string& fcr_ident) = 0; + +diff --git a/xbmc/network/linux/ZeroconfAvahi.cpp b/xbmc/network/linux/ZeroconfAvahi.cpp +index 355b7ce..e9199b9 100644 +--- a/xbmc/network/linux/ZeroconfAvahi.cpp ++++ b/xbmc/network/linux/ZeroconfAvahi.cpp +@@ -167,6 +167,26 @@ bool CZeroconfAvahi::doPublishService(const std::string& fcr_identifier, + return true; + } + ++bool CZeroconfAvahi::doForceReAnnounceService(const std::string& fcr_identifier) ++{ ++ bool ret = false; ++ ScopedEventLoopBlock l_block(mp_poll); ++ tServiceMap::iterator it = m_services.find(fcr_identifier); ++ if (it != m_services.end()) ++ { ++ // to force a reannounce on avahi its enough to reverse the txtrecord list ++ it->second->mp_txt = avahi_string_list_reverse(it->second->mp_txt); ++ ++ // this will trigger the reannouncement ++ if ((avahi_entry_group_update_service_txt_strlst(it->second->mp_group, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, AvahiPublishFlags(0), ++ it->second->m_name.c_str(), ++ it->second->m_type.c_str(), NULL, it->second->mp_txt)) >= 0) ++ ret = true; ++ } ++ ++ return ret; ++} ++ + bool CZeroconfAvahi::doRemoveService(const std::string& fcr_ident) + { + CLog::Log(LOGDEBUG, "CZeroconfAvahi::doRemoveService named: %s", fcr_ident.c_str()); +diff --git a/xbmc/network/linux/ZeroconfAvahi.h b/xbmc/network/linux/ZeroconfAvahi.h +index 281dc21..e0b46b5 100644 +--- a/xbmc/network/linux/ZeroconfAvahi.h ++++ b/xbmc/network/linux/ZeroconfAvahi.h +@@ -50,6 +50,7 @@ class CZeroconfAvahi : public CZeroconf + unsigned int f_port, + const std::vector >& txt); + ++ virtual bool doForceReAnnounceService(const std::string& fcr_identifier); + virtual bool doRemoveService(const std::string& fcr_ident); + + virtual void doStop(); +diff --git a/xbmc/network/mdns/ZeroconfMDNS.cpp b/xbmc/network/mdns/ZeroconfMDNS.cpp +index b81ea11..00d02c5 100644 +--- a/xbmc/network/mdns/ZeroconfMDNS.cpp ++++ b/xbmc/network/mdns/ZeroconfMDNS.cpp +@@ -144,21 +144,46 @@ bool CZeroconfMDNS::doPublishService(const std::string& fcr_identifier, + else + { + CSingleLock lock(m_data_guard); +- m_services.insert(make_pair(fcr_identifier, netService)); ++ struct tServiceRef newService; ++ newService.serviceRef = netService; ++ newService.txtRecordRef = txtRecord; ++ newService.updateNumber = 0; ++ m_services.insert(make_pair(fcr_identifier, newService)); + } + +- TXTRecordDeallocate(&txtRecord); +- + return err == kDNSServiceErr_NoError; + } + ++bool CZeroconfMDNS::doForceReAnnounceService(const std::string& fcr_identifier) ++{ ++ bool ret = false; ++ CSingleLock lock(m_data_guard); ++ tServiceMap::iterator it = m_services.find(fcr_identifier); ++ if(it != m_services.end()) ++ { ++ // for force announcing a service with mdns we need ++ // to change a txt record - so we diddle between ++ // even and odd dummy records here ++ if ( (it->second.updateNumber % 2) == 0) ++ TXTRecordSetValue(&it->second.txtRecordRef, "xbmcdummy", strlen("evendummy"), "evendummy"); ++ else ++ TXTRecordSetValue(&it->second.txtRecordRef, "xbmcdummy", strlen("odddummy"), "odddummy"); ++ it->second.updateNumber++; ++ ++ if (DNSServiceUpdateRecord(it->second.serviceRef, NULL, 0, TXTRecordGetLength(&it->second.txtRecordRef), TXTRecordGetBytesPtr(&it->second.txtRecordRef), 0) == kDNSServiceErr_NoError) ++ ret = true; ++ } ++ return ret; ++} ++ + bool CZeroconfMDNS::doRemoveService(const std::string& fcr_ident) + { + CSingleLock lock(m_data_guard); + tServiceMap::iterator it = m_services.find(fcr_ident); + if(it != m_services.end()) + { +- DNSServiceRefDeallocate(it->second); ++ DNSServiceRefDeallocate(it->second.serviceRef); ++ TXTRecordDeallocate(&it->second.txtRecordRef); + m_services.erase(it); + CLog::Log(LOGDEBUG, "ZeroconfMDNS: Removed service %s", fcr_ident.c_str()); + return true; +@@ -174,7 +199,8 @@ void CZeroconfMDNS::doStop() + CLog::Log(LOGDEBUG, "ZeroconfMDNS: Shutdown services"); + for(tServiceMap::iterator it = m_services.begin(); it != m_services.end(); ++it) + { +- DNSServiceRefDeallocate(it->second); ++ DNSServiceRefDeallocate(it->second.serviceRef); ++ TXTRecordDeallocate(&it->second.txtRecordRef); + CLog::Log(LOGDEBUG, "ZeroconfMDNS: Removed service %s", it->first.c_str()); + } + m_services.clear(); +diff --git a/xbmc/network/mdns/ZeroconfMDNS.h b/xbmc/network/mdns/ZeroconfMDNS.h +index 075c22e..0156691 100644 +--- a/xbmc/network/mdns/ZeroconfMDNS.h ++++ b/xbmc/network/mdns/ZeroconfMDNS.h +@@ -44,6 +44,7 @@ class CZeroconfMDNS : public CZeroconf,public CThread + unsigned int f_port, + const std::vector >& txt); + ++ bool doForceReAnnounceService(const std::string& fcr_identifier); + bool doRemoveService(const std::string& fcr_ident); + + virtual void doStop(); +@@ -65,7 +66,13 @@ class CZeroconfMDNS : public CZeroconf,public CThread + + //lock + data (accessed from runloop(main thread) + the rest) + CCriticalSection m_data_guard; +- typedef std::map tServiceMap; ++ struct tServiceRef ++ { ++ DNSServiceRef serviceRef; ++ TXTRecordRef txtRecordRef; ++ int updateNumber; ++ }; ++ typedef std::map tServiceMap; + tServiceMap m_services; + DNSServiceRef m_service; + }; +diff --git a/xbmc/network/osx/ZeroconfOSX.cpp b/xbmc/network/osx/ZeroconfOSX.cpp +index 298dea4..24ad68c 100644 +--- a/xbmc/network/osx/ZeroconfOSX.cpp ++++ b/xbmc/network/osx/ZeroconfOSX.cpp +@@ -125,6 +125,32 @@ bool CZeroconfOSX::doPublishService(const std::string& fcr_identifier, + return result; + } + ++bool CZeroconfOSX::doForceReAnnounceService(const std::string& fcr_identifier) ++{ ++ bool ret = false; ++ CSingleLock lock(m_data_guard); ++ tServiceMap::iterator it = m_services.find(fcr_identifier); ++ if(it != m_services.end()) ++ { ++ CFNetServiceRef service = it->second; ++ ++ CFDataRef txtData = CFNetServiceGetTXTData(service); ++ // convert the txtdata back and forth is enough to trigger a reannounce later ++ CFDictionaryRef txtDict = CFNetServiceCreateDictionaryWithTXTData(NULL, txtData); ++ CFMutableDictionaryRef txtDictMutable =CFDictionaryCreateMutableCopy(NULL, 0, txtDict); ++ txtData = CFNetServiceCreateTXTDataWithDictionary(NULL, txtDictMutable); ++ ++ // this triggers the reannounce ++ ret = CFNetServiceSetTXTData(service, txtData); ++ ++ CFRelease(txtDictMutable); ++ CFRelease(txtDict); ++ CFRelease(txtData); ++ } ++ return ret; ++} ++ ++ + bool CZeroconfOSX::doRemoveService(const std::string& fcr_ident) + { + CSingleLock lock(m_data_guard); +diff --git a/xbmc/network/osx/ZeroconfOSX.h b/xbmc/network/osx/ZeroconfOSX.h +index 368c2d4..8952a96 100644 +--- a/xbmc/network/osx/ZeroconfOSX.h ++++ b/xbmc/network/osx/ZeroconfOSX.h +@@ -45,6 +45,8 @@ class CZeroconfOSX : public CZeroconf + unsigned int f_port, + const std::vector >& txt); + ++ bool doForceReAnnounceService(const std::string& fcr_identifier); ++ + bool doRemoveService(const std::string& fcr_ident); + + virtual void doStop(); +-- +1.8.5.5 + + +From 16d31f8914520d89de53ae19ce7b4d5eb8f4fa29 Mon Sep 17 00:00:00 2001 +From: Memphiz +Date: Tue, 11 Mar 2014 20:32:22 +0100 +Subject: [PATCH 3/3] [airplay] - reannounce airplay service every 10 secs + (fixes ios7 clients not detecting us when their wlan was asleep or they saw + the airplay announcement before the airtunes annoncement) + +--- + xbmc/network/AirPlayServer.cpp | 21 +++++++++++++++++++++ + 1 file changed, 21 insertions(+) + +diff --git a/xbmc/network/AirPlayServer.cpp b/xbmc/network/AirPlayServer.cpp +index 7db6754..4c93368 100644 +--- a/xbmc/network/AirPlayServer.cpp ++++ b/xbmc/network/AirPlayServer.cpp +@@ -43,6 +43,9 @@ + #include "URL.h" + #include "cores/IPlayer.h" + #include "interfaces/AnnouncementManager.h" ++#ifdef HAS_ZEROCONF ++#include "network/Zeroconf.h" ++#endif // HAS_ZEROCONF + + using namespace ANNOUNCEMENT; + +@@ -277,6 +280,18 @@ void CAirPlayServer::AnnounceToClients(int state) + CAnnouncementManager::RemoveAnnouncer(this); + } + ++void handleZeroconfAnnouncement() ++{ ++#if defined(HAS_ZEROCONF) ++ static XbmcThreads::EndTime timeout(10000); ++ if(timeout.IsTimePast()) ++ { ++ CZeroconf::GetInstance()->ForceReAnnounceService("servers.airplay"); ++ timeout.Set(10000); ++ } ++#endif ++} ++ + void CAirPlayServer::Process() + { + m_bStop = false; +@@ -357,6 +372,12 @@ void CAirPlayServer::Process() + } + } + } ++ ++ // by reannouncing the zeroconf service ++ // we fix issues where xbmc is detected ++ // as audio-only target on devices with ++ // ios7 and later ++ handleZeroconfAnnouncement(); + } + + Deinitialize(); +-- +1.8.5.5 +