mirror of
				https://gitlab.freedesktop.org/pulseaudio/pulseaudio.git
				synced 2025-11-03 09:01:50 -05:00 
			
		
		
		
	Start the raop sink. It's based on pipe sink and isn't anywhere near finished. It does however compile.
git-svn-id: file:///home/lennart/svn/public/pulseaudio/branches/coling@2335 fefdeb5f-60dc-0310-8127-8f9354f1896f
This commit is contained in:
		
							parent
							
								
									fef102e35a
								
							
						
					
					
						commit
						6570620cc3
					
				
					 2 changed files with 430 additions and 1 deletions
				
			
		| 
						 | 
					@ -1004,7 +1004,13 @@ libsocket_util_la_SOURCES = \
 | 
				
			||||||
libsocket_util_la_LDFLAGS = -avoid-version
 | 
					libsocket_util_la_LDFLAGS = -avoid-version
 | 
				
			||||||
libsocket_util_la_LIBADD = $(AM_LIBADD) $(WINSOCK_LIBS) libpulsecore.la
 | 
					libsocket_util_la_LIBADD = $(AM_LIBADD) $(WINSOCK_LIBS) libpulsecore.la
 | 
				
			||||||
 | 
					
 | 
				
			||||||
librtp_la_SOURCES = modules/rtp/rtp.c modules/rtp/rtp.h modules/rtp/sdp.c modules/rtp/sdp.h modules/rtp/sap.c modules/rtp/sap.h
 | 
					librtp_la_SOURCES = \
 | 
				
			||||||
 | 
							modules/rtp/rtp.c modules/rtp/rtp.h \
 | 
				
			||||||
 | 
							modules/rtp/sdp.c modules/rtp/sdp.h \
 | 
				
			||||||
 | 
							modules/rtp/sap.c modules/rtp/sap.h \
 | 
				
			||||||
 | 
							modules/rtp/rtsp.c modules/rtp/rtsp.h \
 | 
				
			||||||
 | 
							modules/rtp/headerlist.c modules/rtp/headerlist.h \
 | 
				
			||||||
 | 
							modules/rtp/base64.c modules/rtp/base64.h
 | 
				
			||||||
librtp_la_LDFLAGS = -avoid-version
 | 
					librtp_la_LDFLAGS = -avoid-version
 | 
				
			||||||
librtp_la_LIBADD = $(AM_LIBADD) libpulsecore.la
 | 
					librtp_la_LIBADD = $(AM_LIBADD) libpulsecore.la
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1053,6 +1059,7 @@ modlibexec_LTLIBRARIES += \
 | 
				
			||||||
		module-remap-sink.la \
 | 
							module-remap-sink.la \
 | 
				
			||||||
		module-ladspa-sink.la \
 | 
							module-ladspa-sink.la \
 | 
				
			||||||
		module-esound-sink.la \
 | 
							module-esound-sink.la \
 | 
				
			||||||
 | 
							module-raop-sink.la \
 | 
				
			||||||
		module-tunnel-sink.la \
 | 
							module-tunnel-sink.la \
 | 
				
			||||||
		module-tunnel-source.la \
 | 
							module-tunnel-source.la \
 | 
				
			||||||
		module-position-event-sounds.la
 | 
							module-position-event-sounds.la
 | 
				
			||||||
| 
						 | 
					@ -1199,6 +1206,7 @@ SYMDEF_FILES = \
 | 
				
			||||||
		modules/module-esound-compat-spawnfd-symdef.h \
 | 
							modules/module-esound-compat-spawnfd-symdef.h \
 | 
				
			||||||
		modules/module-esound-compat-spawnpid-symdef.h \
 | 
							modules/module-esound-compat-spawnpid-symdef.h \
 | 
				
			||||||
		modules/module-match-symdef.h \
 | 
							modules/module-match-symdef.h \
 | 
				
			||||||
 | 
							modules/module-raop-sink-symdef.h \
 | 
				
			||||||
		modules/module-tunnel-sink-symdef.h \
 | 
							modules/module-tunnel-sink-symdef.h \
 | 
				
			||||||
		modules/module-tunnel-source-symdef.h \
 | 
							modules/module-tunnel-source-symdef.h \
 | 
				
			||||||
		modules/module-null-sink-symdef.h \
 | 
							modules/module-null-sink-symdef.h \
 | 
				
			||||||
| 
						 | 
					@ -1367,6 +1375,10 @@ module_match_la_SOURCES = modules/module-match.c
 | 
				
			||||||
module_match_la_LDFLAGS = -module -avoid-version
 | 
					module_match_la_LDFLAGS = -module -avoid-version
 | 
				
			||||||
module_match_la_LIBADD = $(AM_LIBADD) libpulsecore.la
 | 
					module_match_la_LIBADD = $(AM_LIBADD) libpulsecore.la
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module_raop_sink_la_SOURCES = modules/module-raop-sink.c
 | 
				
			||||||
 | 
					module_raop_sink_la_LDFLAGS = -module -avoid-version
 | 
				
			||||||
 | 
					module_raop_sink_la_LIBADD = $(AM_LIBADD) libpulsecore.la libiochannel.la librtp.la
 | 
				
			||||||
 | 
					
 | 
				
			||||||
module_tunnel_sink_la_SOURCES = modules/module-tunnel.c
 | 
					module_tunnel_sink_la_SOURCES = modules/module-tunnel.c
 | 
				
			||||||
module_tunnel_sink_la_CFLAGS = -DTUNNEL_SINK=1 $(AM_CFLAGS)
 | 
					module_tunnel_sink_la_CFLAGS = -DTUNNEL_SINK=1 $(AM_CFLAGS)
 | 
				
			||||||
module_tunnel_sink_la_LDFLAGS = -module -avoid-version
 | 
					module_tunnel_sink_la_LDFLAGS = -module -avoid-version
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										417
									
								
								src/modules/module-raop-sink.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										417
									
								
								src/modules/module-raop-sink.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,417 @@
 | 
				
			||||||
 | 
					/* $Id$ */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/***
 | 
				
			||||||
 | 
					  This file is part of PulseAudio.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  Copyright 2004-2006 Lennart Poettering
 | 
				
			||||||
 | 
					  Copyright 2008      Colin Guthrie
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  PulseAudio is free software; you can redistribute it and/or modify
 | 
				
			||||||
 | 
					  it under the terms of the GNU Lesser General Public License as published
 | 
				
			||||||
 | 
					  by the Free Software Foundation; either version 2 of the License,
 | 
				
			||||||
 | 
					  or (at your option) any later version.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  PulseAudio 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 Lesser General Public License
 | 
				
			||||||
 | 
					  along with PulseAudio; if not, write to the Free Software
 | 
				
			||||||
 | 
					  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
 | 
				
			||||||
 | 
					  USA.
 | 
				
			||||||
 | 
					***/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef HAVE_CONFIG_H
 | 
				
			||||||
 | 
					#include <config.h>
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <stdlib.h>
 | 
				
			||||||
 | 
					#include <sys/stat.h>
 | 
				
			||||||
 | 
					#include <stdio.h>
 | 
				
			||||||
 | 
					#include <errno.h>
 | 
				
			||||||
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					#include <fcntl.h>
 | 
				
			||||||
 | 
					#include <unistd.h>
 | 
				
			||||||
 | 
					#include <limits.h>
 | 
				
			||||||
 | 
					#include <sys/ioctl.h>
 | 
				
			||||||
 | 
					#include <poll.h>
 | 
				
			||||||
 | 
					#include <openssl/err.h>
 | 
				
			||||||
 | 
					#include <openssl/rand.h>
 | 
				
			||||||
 | 
					#include <openssl/aes.h>
 | 
				
			||||||
 | 
					#include <openssl/rsa.h>
 | 
				
			||||||
 | 
					#include <openssl/engine.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <pulse/xmalloc.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <pulsecore/core-error.h>
 | 
				
			||||||
 | 
					#include <pulsecore/sink.h>
 | 
				
			||||||
 | 
					#include <pulsecore/module.h>
 | 
				
			||||||
 | 
					#include <pulsecore/core-util.h>
 | 
				
			||||||
 | 
					#include <pulsecore/modargs.h>
 | 
				
			||||||
 | 
					#include <pulsecore/log.h>
 | 
				
			||||||
 | 
					#include <pulsecore/thread.h>
 | 
				
			||||||
 | 
					#include <pulsecore/thread-mq.h>
 | 
				
			||||||
 | 
					#include <pulsecore/random.h>
 | 
				
			||||||
 | 
					#include <pulsecore/rtpoll.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "rtp.h"
 | 
				
			||||||
 | 
					#include "sdp.h"
 | 
				
			||||||
 | 
					#include "sap.h"
 | 
				
			||||||
 | 
					#include "rtsp.h"
 | 
				
			||||||
 | 
					#include "base64.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "module-raop-sink-symdef.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define JACK_STATUS_DISCONNECTED 0
 | 
				
			||||||
 | 
					#define JACK_STATUS_CONNECTED 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define JACK_TYPE_ANALOG 0
 | 
				
			||||||
 | 
					#define JACK_TYPE_DIGITAL 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define VOLUME_DEF -30
 | 
				
			||||||
 | 
					#define VOLUME_MIN -144
 | 
				
			||||||
 | 
					#define VOLUME_MAX 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					PA_MODULE_AUTHOR("Colin Guthrie");
 | 
				
			||||||
 | 
					PA_MODULE_DESCRIPTION("RAOP Sink (Apple Airport)");
 | 
				
			||||||
 | 
					PA_MODULE_VERSION(PACKAGE_VERSION);
 | 
				
			||||||
 | 
					PA_MODULE_LOAD_ONCE(FALSE);
 | 
				
			||||||
 | 
					PA_MODULE_USAGE(
 | 
				
			||||||
 | 
					        "server=<address> "
 | 
				
			||||||
 | 
					        "sink_name=<name for the sink> "
 | 
				
			||||||
 | 
					        "format=<sample format> "
 | 
				
			||||||
 | 
					        "channels=<number of channels> "
 | 
				
			||||||
 | 
					        "rate=<sample rate>"
 | 
				
			||||||
 | 
					        "channel_map=<channel map>");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define DEFAULT_SINK_NAME "airtunes"
 | 
				
			||||||
 | 
					#define AES_CHUNKSIZE 16
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct userdata {
 | 
				
			||||||
 | 
					    pa_core *core;
 | 
				
			||||||
 | 
					    pa_module *module;
 | 
				
			||||||
 | 
					    pa_sink *sink;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pa_thread *thread;
 | 
				
			||||||
 | 
					    pa_thread_mq thread_mq;
 | 
				
			||||||
 | 
					    pa_rtpoll *rtpoll;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    char *server_name;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Encryption Related bits
 | 
				
			||||||
 | 
					    AES_KEY aes;
 | 
				
			||||||
 | 
					    uint8_t aes_iv[AES_CHUNKSIZE]; // initialization vector for aes-cbc
 | 
				
			||||||
 | 
					    uint8_t aes_nv[AES_CHUNKSIZE]; // next vector for aes-cbc
 | 
				
			||||||
 | 
					    uint8_t aes_key[AES_CHUNKSIZE]; // key for aes-cbc
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pa_rtsp_context *rtsp;
 | 
				
			||||||
 | 
					    //pa_socket_client *client;
 | 
				
			||||||
 | 
					    pa_memchunk memchunk;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pa_rtpoll_item *rtpoll_item;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const char* const valid_modargs[] = {
 | 
				
			||||||
 | 
					    "server",
 | 
				
			||||||
 | 
					    "rate",
 | 
				
			||||||
 | 
					    "format",
 | 
				
			||||||
 | 
					    "channels",
 | 
				
			||||||
 | 
					    "sink_name",
 | 
				
			||||||
 | 
					    "channel_map",
 | 
				
			||||||
 | 
					    NULL
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int rsa_encrypt(uint8_t *text, int len, uint8_t *res) {
 | 
				
			||||||
 | 
					    char n[] =
 | 
				
			||||||
 | 
					        "59dE8qLieItsH1WgjrcFRKj6eUWqi+bGLOX1HL3U3GhC/j0Qg90u3sG/1CUtwC"
 | 
				
			||||||
 | 
					        "5vOYvfDmFI6oSFXi5ELabWJmT2dKHzBJKa3k9ok+8t9ucRqMd6DZHJ2YCCLlDR"
 | 
				
			||||||
 | 
					        "KSKv6kDqnw4UwPdpOMXziC/AMj3Z/lUVX1G7WSHCAWKf1zNS1eLvqr+boEjXuB"
 | 
				
			||||||
 | 
					        "OitnZ/bDzPHrTOZz0Dew0uowxf/+sG+NCK3eQJVxqcaJ/vEHKIVd2M+5qL71yJ"
 | 
				
			||||||
 | 
					        "Q+87X6oV3eaYvt3zWZYD6z5vYTcrtij2VZ9Zmni/UAaHqn9JdsBWLUEpVviYnh"
 | 
				
			||||||
 | 
					        "imNVvYFZeCXg/IdTQ+x4IRdiXNv5hEew==";
 | 
				
			||||||
 | 
					    char e[] = "AQAB";
 | 
				
			||||||
 | 
					    uint8_t modules[256];
 | 
				
			||||||
 | 
					    uint8_t exponent[8];
 | 
				
			||||||
 | 
					    int size;
 | 
				
			||||||
 | 
					    RSA *rsa;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    rsa = RSA_new();
 | 
				
			||||||
 | 
					    size = pa_base64_decode(n, modules);
 | 
				
			||||||
 | 
					    rsa->n = BN_bin2bn(modules, size, NULL);
 | 
				
			||||||
 | 
					    size = pa_base64_decode(e, exponent);
 | 
				
			||||||
 | 
					    rsa->e = BN_bin2bn(exponent, size, NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    size = RSA_public_encrypt(len, text, res, rsa, RSA_PKCS1_OAEP_PADDING);
 | 
				
			||||||
 | 
					    RSA_free(rsa);
 | 
				
			||||||
 | 
					    return size;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int aes_encrypt(struct userdata *u, uint8_t *data, int size)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    uint8_t *buf;
 | 
				
			||||||
 | 
					    int i=0, j;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pa_assert(u);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    memcpy(u->aes_nv, u->aes_iv, AES_CHUNKSIZE);
 | 
				
			||||||
 | 
					    while (i+AES_CHUNKSIZE <= size) {
 | 
				
			||||||
 | 
					        buf = data + i;
 | 
				
			||||||
 | 
					        for (j=0; j<AES_CHUNKSIZE; ++j)
 | 
				
			||||||
 | 
					            buf[j] ^= u->aes_nv[j];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        AES_encrypt(buf, buf, &u->aes);
 | 
				
			||||||
 | 
					        memcpy(u->aes_nv, buf, AES_CHUNKSIZE);
 | 
				
			||||||
 | 
					        i += AES_CHUNKSIZE;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return i;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int sink_process_msg(pa_msgobject *o, int code, void *data, int64_t offset, pa_memchunk *chunk) {
 | 
				
			||||||
 | 
					    struct userdata *u = PA_SINK(o)->userdata;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    switch (code) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        case PA_SINK_MESSAGE_GET_LATENCY: {
 | 
				
			||||||
 | 
					            size_t n = 0;
 | 
				
			||||||
 | 
					            //int l;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef TIOCINQ
 | 
				
			||||||
 | 
					            /*
 | 
				
			||||||
 | 
					            if (ioctl(u->fd, TIOCINQ, &l) >= 0 && l > 0)
 | 
				
			||||||
 | 
					                n = (size_t) l;
 | 
				
			||||||
 | 
					            */
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            n += u->memchunk.length;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            *((pa_usec_t*) data) = pa_bytes_to_usec(n, &u->sink->sample_spec);
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return pa_sink_process_msg(o, code, data, offset, chunk);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void thread_func(void *userdata) {
 | 
				
			||||||
 | 
					    struct userdata *u = userdata;
 | 
				
			||||||
 | 
					    //int write_type = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pa_assert(u);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pa_log_debug("Thread starting up");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pa_thread_mq_install(&u->thread_mq);
 | 
				
			||||||
 | 
					    pa_rtpoll_install(u->rtpoll);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (;;) {
 | 
				
			||||||
 | 
					        struct pollfd *pollfd;
 | 
				
			||||||
 | 
					        int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        pollfd = pa_rtpoll_item_get_pollfd(u->rtpoll_item, NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /* Render some data and write it to the fifo */
 | 
				
			||||||
 | 
					        if (u->sink->thread_info.state == PA_SINK_RUNNING && pollfd->revents) {
 | 
				
			||||||
 | 
					            ssize_t l;
 | 
				
			||||||
 | 
					            void *p;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (u->memchunk.length <= 0)
 | 
				
			||||||
 | 
					                pa_sink_render(u->sink, PIPE_BUF, &u->memchunk);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            pa_assert(u->memchunk.length > 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            p = pa_memblock_acquire(u->memchunk.memblock);
 | 
				
			||||||
 | 
					            //l = pa_write(u->fd, (uint8_t*) p + u->memchunk.index, u->memchunk.length, &write_type);
 | 
				
			||||||
 | 
					            // Fake the length of the "write".
 | 
				
			||||||
 | 
					            l = u->memchunk.length;
 | 
				
			||||||
 | 
					            pa_memblock_release(u->memchunk.memblock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            pa_assert(l != 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (l < 0) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if (errno == EINTR)
 | 
				
			||||||
 | 
					                    continue;
 | 
				
			||||||
 | 
					                else if (errno != EAGAIN) {
 | 
				
			||||||
 | 
					                    pa_log("Failed to write data to FIFO: %s", pa_cstrerror(errno));
 | 
				
			||||||
 | 
					                    goto fail;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                u->memchunk.index += l;
 | 
				
			||||||
 | 
					                u->memchunk.length -= l;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if (u->memchunk.length <= 0) {
 | 
				
			||||||
 | 
					                    pa_memblock_unref(u->memchunk.memblock);
 | 
				
			||||||
 | 
					                    pa_memchunk_reset(&u->memchunk);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                pollfd->revents = 0;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /* Hmm, nothing to do. Let's sleep */
 | 
				
			||||||
 | 
					        pollfd->events = u->sink->thread_info.state == PA_SINK_RUNNING ? POLLOUT : 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if ((ret = pa_rtpoll_run(u->rtpoll, TRUE)) < 0)
 | 
				
			||||||
 | 
					            goto fail;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (ret == 0)
 | 
				
			||||||
 | 
					            goto finish;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        pollfd = pa_rtpoll_item_get_pollfd(u->rtpoll_item, NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (pollfd->revents & ~POLLOUT) {
 | 
				
			||||||
 | 
					            pa_log("FIFO shutdown.");
 | 
				
			||||||
 | 
					            goto fail;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fail:
 | 
				
			||||||
 | 
					    /* If this was no regular exit from the loop we have to continue
 | 
				
			||||||
 | 
					     * processing messages until we received PA_MESSAGE_SHUTDOWN */
 | 
				
			||||||
 | 
					    pa_asyncmsgq_post(u->thread_mq.outq, PA_MSGOBJECT(u->core), PA_CORE_MESSAGE_UNLOAD_MODULE, u->module, 0, NULL, NULL);
 | 
				
			||||||
 | 
					    pa_asyncmsgq_wait_for(u->thread_mq.inq, PA_MESSAGE_SHUTDOWN);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					finish:
 | 
				
			||||||
 | 
					    pa_log_debug("Thread shutting down");
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int pa__init(pa_module*m) {
 | 
				
			||||||
 | 
					    struct userdata *u;
 | 
				
			||||||
 | 
					    //struct stat st;
 | 
				
			||||||
 | 
					    pa_sample_spec ss;
 | 
				
			||||||
 | 
					    pa_channel_map map;
 | 
				
			||||||
 | 
					    pa_modargs *ma;
 | 
				
			||||||
 | 
					    char *t;
 | 
				
			||||||
 | 
					    struct pollfd *pollfd;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pa_assert(m);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!(ma = pa_modargs_new(m->argument, valid_modargs))) {
 | 
				
			||||||
 | 
					        pa_log("Failed to parse module arguments.");
 | 
				
			||||||
 | 
					        goto fail;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ss = m->core->default_sample_spec;
 | 
				
			||||||
 | 
					    if (pa_modargs_get_sample_spec_and_channel_map(ma, &ss, &map, PA_CHANNEL_MAP_DEFAULT) < 0) {
 | 
				
			||||||
 | 
					        pa_log("Invalid sample format specification or channel map");
 | 
				
			||||||
 | 
					        goto fail;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    u = pa_xnew0(struct userdata, 1);
 | 
				
			||||||
 | 
					    u->core = m->core;
 | 
				
			||||||
 | 
					    u->module = m;
 | 
				
			||||||
 | 
					    m->userdata = u;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Initialise the AES encryption system
 | 
				
			||||||
 | 
					    pa_random_seed();
 | 
				
			||||||
 | 
					    pa_random(u->aes_iv, sizeof(u->aes_iv));
 | 
				
			||||||
 | 
					    pa_random(u->aes_key, sizeof(u->aes_key));
 | 
				
			||||||
 | 
					    memcpy(u->aes_nv, u->aes_iv, sizeof(u->aes_nv));
 | 
				
			||||||
 | 
					    AES_set_encrypt_key(u->aes_key, 128, &u->aes);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pa_memchunk_reset(&u->memchunk);
 | 
				
			||||||
 | 
					    pa_thread_mq_init(&u->thread_mq, m->core->mainloop);
 | 
				
			||||||
 | 
					    u->rtpoll = pa_rtpoll_new();
 | 
				
			||||||
 | 
					    pa_rtpoll_item_new_asyncmsgq(u->rtpoll, PA_RTPOLL_EARLY, u->thread_mq.inq);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    u->server_name = pa_xstrdup(pa_modargs_get_value(ma, "server", NULL));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Open a connection to the server... this is just to connect and test....
 | 
				
			||||||
 | 
					    /*
 | 
				
			||||||
 | 
					    mkfifo(u->filename, 0666);
 | 
				
			||||||
 | 
					    if ((u->fd = open(u->filename, O_RDWR|O_NOCTTY)) < 0) {
 | 
				
			||||||
 | 
					        pa_log("open('%s'): %s", u->filename, pa_cstrerror(errno));
 | 
				
			||||||
 | 
					        goto fail;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pa_make_fd_cloexec(u->fd);
 | 
				
			||||||
 | 
					    pa_make_fd_nonblock(u->fd);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (fstat(u->fd, &st) < 0) {
 | 
				
			||||||
 | 
					        pa_log("fstat('%s'): %s", u->filename, pa_cstrerror(errno));
 | 
				
			||||||
 | 
					        goto fail;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!S_ISFIFO(st.st_mode)) {
 | 
				
			||||||
 | 
					        pa_log("'%s' is not a FIFO.", u->filename);
 | 
				
			||||||
 | 
					        goto fail;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    */
 | 
				
			||||||
 | 
					    if (!(u->sink = pa_sink_new(m->core, __FILE__, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME), 0, &ss, &map))) {
 | 
				
			||||||
 | 
					        pa_log("Failed to create sink.");
 | 
				
			||||||
 | 
					        goto fail;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    u->sink->parent.process_msg = sink_process_msg;
 | 
				
			||||||
 | 
					    u->sink->userdata = u;
 | 
				
			||||||
 | 
					    u->sink->flags = PA_SINK_LATENCY;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pa_sink_set_module(u->sink, m);
 | 
				
			||||||
 | 
					    pa_sink_set_asyncmsgq(u->sink, u->thread_mq.inq);
 | 
				
			||||||
 | 
					    pa_sink_set_rtpoll(u->sink, u->rtpoll);
 | 
				
			||||||
 | 
					    pa_sink_set_description(u->sink, t = pa_sprintf_malloc("Airtunes sink '%s'", u->server_name));
 | 
				
			||||||
 | 
					    pa_xfree(t);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    u->rtpoll_item = pa_rtpoll_item_new(u->rtpoll, PA_RTPOLL_NEVER, 1);
 | 
				
			||||||
 | 
					    pollfd = pa_rtpoll_item_get_pollfd(u->rtpoll_item, NULL);
 | 
				
			||||||
 | 
					    //pollfd->fd = u->fd;
 | 
				
			||||||
 | 
					    pollfd->events = pollfd->revents = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!(u->thread = pa_thread_new(thread_func, u))) {
 | 
				
			||||||
 | 
					        pa_log("Failed to create thread.");
 | 
				
			||||||
 | 
					        goto fail;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pa_sink_put(u->sink);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pa_modargs_free(ma);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fail:
 | 
				
			||||||
 | 
					    if (ma)
 | 
				
			||||||
 | 
					        pa_modargs_free(ma);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pa__done(m);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return -1;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void pa__done(pa_module*m) {
 | 
				
			||||||
 | 
					    struct userdata *u;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pa_assert(m);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!(u = m->userdata))
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (u->sink)
 | 
				
			||||||
 | 
					        pa_sink_unlink(u->sink);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (u->thread) {
 | 
				
			||||||
 | 
					        pa_asyncmsgq_send(u->thread_mq.inq, NULL, PA_MESSAGE_SHUTDOWN, NULL, 0, NULL);
 | 
				
			||||||
 | 
					        pa_thread_free(u->thread);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pa_thread_mq_done(&u->thread_mq);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (u->sink)
 | 
				
			||||||
 | 
					        pa_sink_unref(u->sink);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (u->memchunk.memblock)
 | 
				
			||||||
 | 
					       pa_memblock_unref(u->memchunk.memblock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (u->rtpoll_item)
 | 
				
			||||||
 | 
					        pa_rtpoll_item_free(u->rtpoll_item);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (u->rtpoll)
 | 
				
			||||||
 | 
					        pa_rtpoll_free(u->rtpoll);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pa_xfree(u->server_name);
 | 
				
			||||||
 | 
					    pa_xfree(u);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue