shairport: add AirPort Express emulation software
authorFlorian Fainelli <florian@openwrt.org>
Fri, 22 Feb 2013 14:52:38 +0000 (14:52 +0000)
committerFlorian Fainelli <florian@openwrt.org>
Fri, 22 Feb 2013 14:52:38 +0000 (14:52 +0000)
Signed-off-by: Florian Fainelli <florian@openwrt.org>
SVN-Revision: 35746

multimedia/shairport/Makefile [new file with mode: 0644]
multimedia/shairport/files/shairport.config [new file with mode: 0644]
multimedia/shairport/files/shairport.init [new file with mode: 0644]
multimedia/shairport/patches/001-fix_ipv6_fallback.patch [new file with mode: 0644]

diff --git a/multimedia/shairport/Makefile b/multimedia/shairport/Makefile
new file mode 100644 (file)
index 0000000..332c41a
--- /dev/null
@@ -0,0 +1,56 @@
+#
+# Copyright (C) 2013 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=shairport
+PKG_VERSION:=2012-10-20
+PKG_RELEASE:=$(PKG_SOURCE_VERSION)
+
+PKG_SOURCE_PROTO:=git
+PKG_SOURCE_URL:=git://github.com/albertz/shairport.git
+PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION)
+PKG_SOURCE_VERSION:=4746bb11395d171ee800f074f489c42020a84932
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION)-$(PKG_SOURCE_VERSION).tar.gz
+
+include $(INCLUDE_DIR)/package.mk
+
+define Package/shairport
+  SECTION:=multimedia
+  CATEGORY:=Multimedia
+  DEPENDS:=+libpthread +avahi-utils +libopenssl +libao
+  TITLE:=ShairPort AirPort Express emulator
+endef
+
+define Package/shairport/description
+  This program emulates an AirPort Express for the purpose of streaming
+  music from iTunes and compatible iPods. It implements a server for the
+  Apple RAOP protocol.
+  ShairPort does not support AirPlay v2 (video and photo streaming).
+
+  It supports multiple simultaneous streams, if your audio output chain
+  (as detected by libao) does so.
+endef
+
+TARGET_CFLAGS += $(FPIC)
+
+LIBS:=-lao -lm -lcrypto -lpthread
+
+MAKE_FLAGS += \
+       CFLAGS="$(TARGET_CFLAGS) $(TARGET_CPPFLAGS)" \
+       LDFLAGS="$(TARGET_LDFLAGS) $(LIBS)"
+
+define Package/shairport/install
+       $(INSTALL_DIR) $(1)/usr/sbin
+       $(INSTALL_BIN) $(PKG_BUILD_DIR)/shairport $(1)/usr/sbin/
+       $(INSTALL_DIR) $(1)/etc/init.d/
+       $(INSTALL_BIN) files/shairport.init $(1)/etc/init.d/shairport
+       $(INSTALL_DIR) $(1)/etc/config
+       $(INSTALL_DATA) files/shairport.config $(1)/etc/config/shairport
+endef
+
+$(eval $(call BuildPackage,shairport))
diff --git a/multimedia/shairport/files/shairport.config b/multimedia/shairport/files/shairport.config
new file mode 100644 (file)
index 0000000..83ba692
--- /dev/null
@@ -0,0 +1,3 @@
+config shairport
+       option name     'AirPort'
+       option buffer   '256'
diff --git a/multimedia/shairport/files/shairport.init b/multimedia/shairport/files/shairport.init
new file mode 100644 (file)
index 0000000..f3aa75f
--- /dev/null
@@ -0,0 +1,36 @@
+#!/bin/sh /etc/rc.common
+START=80
+
+DAEMON="/usr/sbin/shairport"
+
+config_shairport() {
+       local cfg="$1"
+       local args=""
+
+       config_get name "$cfg" name
+       config_get password "$cfg" password
+       config_get port "$cfg" port
+       config_get buffer "$cfg" buffer
+
+       [ -z $name ] && name="AirPort"
+       args="$args -a $name"
+
+       [ ! -z "$password" ] && args="$args -p $password"
+       [ ! -z "$port" ] && args="$args -o $port"
+
+       [ -z $buffer ] && buffer="256"
+       args="$args -b $buffer"
+
+       args="$args -d"
+
+       service_start $DAEMON $args
+}
+
+start() {
+       config_load shairport
+       config_foreach config_shairport shairport
+}
+
+stop() {
+       service_stop $DAEMON
+}
diff --git a/multimedia/shairport/patches/001-fix_ipv6_fallback.patch b/multimedia/shairport/patches/001-fix_ipv6_fallback.patch
new file mode 100644 (file)
index 0000000..070742b
--- /dev/null
@@ -0,0 +1,108 @@
+diff --git a/socketlib.c b/socketlib.c
+index 9efdf22..eb44bcf 100644
+--- a/socketlib.c
++++ b/socketlib.c
+@@ -39,9 +39,11 @@
+ #include <openssl/bio.h>
+ #include <openssl/buffer.h>
+-int common_setup(struct addrinfo *pAddrInfo)
+-{  
++int common_setup(struct addrinfo **ppAddrInfo, int pPort)
++{
+   int tSock;
++  struct addrinfo *pAddrInfo = *ppAddrInfo;
++
+   //printAddrs(pAddrInfo);
+   tSock = socket(pAddrInfo->ai_family, pAddrInfo->ai_socktype, 0);
+ #ifdef AF_INET6
+@@ -49,7 +51,17 @@ int common_setup(struct addrinfo *pAddrInfo)
+   {
+     //Fallback to ipv4
+     perror("Failed to create ipv6 socket. Trying ipv4");
+-    pAddrInfo->ai_family = AF_INET;
++    (*ppAddrInfo)->ai_family = AF_INET;
++    if (pPort != -1)
++    {
++       char tService[SERVLEN];
++       sprintf(tService, "%d", pPort); // copies port to string
++       int tFamily = AF_INET;
++       if(getAddr(NULL, tService, tFamily, SOCK_STREAM, ppAddrInfo))
++       {
++           return ERROR; // getAddr prints out error message
++       }
++    }
+     tSock = socket(pAddrInfo->ai_family, pAddrInfo->ai_socktype, 0);
+   }
+ #endif
+@@ -63,7 +75,7 @@ int setup_client(struct addrinfo *server_host)
+   while(tIdx++ < RETRY_COUNT)
+   {
+-    tSockDesc = common_setup(server_host);
++    tSockDesc = common_setup(&server_host, -1);
+     if (tSockDesc < 0 && tIdx >= RETRY_COUNT)
+     {
+       perror("Error: Could not create socket");
+@@ -107,9 +119,23 @@ int getAddr(char *pHostname, char *pService, int pFamily, int pSockType, struct
+   return tError;
+ }
+-int setup_server(struct addrinfo *server_addr)
++int setup_server(struct addrinfo *server_addr, int pPort)
+ {
+-  int tSock = common_setup(server_addr);
++  char tService[SERVLEN];
++  sprintf(tService, "%d", pPort); // copies port to string
++  int tFamily = AF_INET;
++  #ifdef AF_INET6
++  //printf("Listening on IPv6 Socket\n");
++  tFamily = AF_INET6;
++  #else
++  //printf("Listening on IPv4 Socket");
++  #endif
++  if(getAddr(NULL, tService, tFamily, SOCK_STREAM, &server_addr))
++  {
++     return ERROR; // getAddr prints out error message
++  }
++
++  int tSock = common_setup(&server_addr, pPort);
+   if (tSock < 0)
+   {
+     perror("Error: Could not create server socket");
+@@ -154,21 +180,7 @@ int acceptClient(int pSock, struct addrinfo *server_addr)
+ int setupListenServer(struct addrinfo **pAddrInfo, int pPort)
+ {
+-    char tService[SERVLEN];
+-    sprintf(tService, "%d", pPort); // copies port to string
+-    int tFamily = AF_INET;
+-    #ifdef AF_INET6
+-    //printf("Listening on IPv6 Socket\n");
+-    tFamily = AF_INET6;
+-    #else
+-    //printf("Listening on IPv4 Socket");
+-    #endif
+-    if(getAddr(NULL, tService, tFamily, SOCK_STREAM, pAddrInfo))
+-    {
+-      return ERROR; // getAddr prints out error message
+-    }
+-
+-    int tSocketDescriptor = setup_server(*pAddrInfo);
++    int tSocketDescriptor = setup_server(*pAddrInfo, pPort);
+     char tAddr[INET6_ADDRSTRLEN];
+     socklen_t tSize = INET6_ADDRSTRLEN;
+     inet_ntop((*pAddrInfo)->ai_family, (*pAddrInfo)->ai_addr, tAddr, tSize);
+diff --git a/socketlib.h b/socketlib.h
+index 6d501f3..5cb1bf0 100644
+--- a/socketlib.h
++++ b/socketlib.h
+@@ -24,7 +24,7 @@
+ #define DEFAULT_UNIX "/unix"
+ int setup_client(struct addrinfo *server_info);
+-int setup_server(struct addrinfo *server_address);
++int setup_server(struct addrinfo *server_address, int pPort);
+ int setupListenServer(struct addrinfo **pAddrInfo, int pPort);
+ int acceptClient(int pSock, struct addrinfo *server_addr);
+ void delay(long pMillisecs, struct timeval *pRes);