2006-04-14 23:47:33 +00:00
/***
2006-06-19 21:53:48 +00:00
This file is part of PulseAudio .
2007-02-13 15:35:19 +00:00
Copyright 2006 Lennart Poettering
2007-05-29 17:24:48 +00:00
2006-06-19 21:53:48 +00:00
PulseAudio is free software ; you can redistribute it and / or modify
2006-04-14 23:47:33 +00:00
it under the terms of the GNU Lesser General Public License as published
2009-03-03 20:23:02 +00:00
by the Free Software Foundation ; either version 2.1 of the License ,
2006-04-14 23:47:33 +00:00
or ( at your option ) any later version .
2007-05-29 17:24:48 +00:00
2006-06-19 21:53:48 +00:00
PulseAudio is distributed in the hope that it will be useful , but
2006-04-14 23:47:33 +00:00
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 .
2007-05-29 17:24:48 +00:00
2006-04-14 23:47:33 +00:00
You should have received a copy of the GNU Lesser General Public License
2006-06-19 21:53:48 +00:00
along with PulseAudio ; if not , write to the Free Software
2006-04-14 23:47:33 +00:00
Foundation , Inc . , 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307
USA .
* * */
# ifdef HAVE_CONFIG_H
# include <config.h>
# endif
# include <stdio.h>
# include <sys/socket.h>
# include <netinet/in.h>
# include <errno.h>
# include <unistd.h>
2009-04-05 02:13:43 +03:00
# include <pulse/rtclock.h>
2006-06-19 21:53:48 +00:00
# include <pulse/timeval.h>
# include <pulse/util.h>
# include <pulse/xmalloc.h>
2006-05-17 16:34:18 +00:00
2006-06-19 21:53:48 +00:00
# include <pulsecore/core-error.h>
# include <pulsecore/module.h>
# include <pulsecore/source.h>
# include <pulsecore/source-output.h>
# include <pulsecore/memblockq.h>
# include <pulsecore/log.h>
# include <pulsecore/core-util.h>
# include <pulsecore/modargs.h>
# include <pulsecore/namereg.h>
2007-10-28 19:13:50 +00:00
# include <pulsecore/sample-util.h>
# include <pulsecore/macro.h>
# include <pulsecore/socket-util.h>
2011-03-01 16:06:19 +01:00
# include <pulsecore/arpa-inet.h>
2006-04-14 23:47:33 +00:00
2006-04-16 10:56:45 +00:00
# include "module-rtp-send-symdef.h"
2006-04-14 23:47:33 +00:00
# include "rtp.h"
# include "sdp.h"
# include "sap.h"
2007-11-09 18:25:40 +00:00
PA_MODULE_AUTHOR ( " Lennart Poettering " ) ;
PA_MODULE_DESCRIPTION ( " Read data from source and send it to the network via RTP/SAP/SDP " ) ;
PA_MODULE_VERSION ( PACKAGE_VERSION ) ;
2013-06-27 19:28:09 +02:00
PA_MODULE_LOAD_ONCE ( false ) ;
2006-04-14 23:47:33 +00:00
PA_MODULE_USAGE (
2006-04-16 00:16:53 +00:00
" source=<name of the source> "
2006-04-14 23:47:33 +00:00
" format=<sample format> "
" channels=<number of channels> "
" rate=<sample rate> "
2012-11-17 23:31:17 +00:00
" destination_ip=<destination IP address> "
2012-11-17 23:31:18 +00:00
" source_ip=<source IP address> "
2006-04-14 23:47:33 +00:00
" port=<port number> "
" mtu=<maximum transfer unit> "
2008-08-15 14:40:08 +02:00
" loop=<loopback to local host?> "
" ttl=<ttl value> "
2007-11-09 18:25:40 +00:00
) ;
2006-04-14 23:47:33 +00:00
2006-04-16 09:14:55 +00:00
# define DEFAULT_PORT 46000
2008-08-15 14:40:08 +02:00
# define DEFAULT_TTL 1
2006-04-14 23:47:33 +00:00
# define SAP_PORT 9875
2012-11-17 23:31:18 +00:00
# define DEFAULT_SOURCE_IP "0.0.0.0"
2012-11-17 23:31:17 +00:00
# define DEFAULT_DESTINATION_IP "224.0.0.56"
2006-04-14 23:47:33 +00:00
# define MEMBLOCKQ_MAXLENGTH (1024*170)
2006-04-16 09:14:55 +00:00
# define DEFAULT_MTU 1280
2009-04-05 02:13:43 +03:00
# define SAP_INTERVAL (5*PA_USEC_PER_SEC)
2006-04-14 23:47:33 +00:00
static const char * const valid_modargs [ ] = {
" source " ,
" format " ,
" channels " ,
" rate " ,
2012-11-17 23:31:17 +00:00
" destination " , /* Compatbility */
" destination_ip " ,
2012-11-17 23:31:18 +00:00
" source_ip " ,
2006-04-14 23:47:33 +00:00
" port " ,
2006-08-23 22:28:53 +00:00
" mtu " ,
2006-04-16 00:16:53 +00:00
" loop " ,
2008-08-15 14:40:08 +02:00
" ttl " ,
2006-04-14 23:47:33 +00:00
NULL
} ;
struct userdata {
pa_module * module ;
pa_source_output * source_output ;
pa_memblockq * memblockq ;
pa_rtp_context rtp_context ;
pa_sap_context sap_context ;
size_t mtu ;
pa_time_event * sap_event ;
} ;
2007-10-28 19:13:50 +00:00
/* Called from I/O thread context */
static int source_output_process_msg ( pa_msgobject * o , int code , void * data , int64_t offset , pa_memchunk * chunk ) {
struct userdata * u ;
pa_assert_se ( u = PA_SOURCE_OUTPUT ( o ) - > userdata ) ;
switch ( code ) {
case PA_SOURCE_OUTPUT_MESSAGE_GET_LATENCY :
* ( ( pa_usec_t * ) data ) = pa_bytes_to_usec ( pa_memblockq_get_length ( u - > memblockq ) , & u - > source_output - > sample_spec ) ;
/* Fall through, the default handler will add in the extra
* latency added by the resampler */
break ;
}
return pa_source_output_process_msg ( o , code , data , offset , chunk ) ;
}
/* Called from I/O thread context */
2006-04-14 23:47:33 +00:00
static void source_output_push ( pa_source_output * o , const pa_memchunk * chunk ) {
struct userdata * u ;
2007-10-28 19:13:50 +00:00
pa_source_output_assert_ref ( o ) ;
pa_assert_se ( u = o - > userdata ) ;
2006-04-14 23:47:33 +00:00
if ( pa_memblockq_push ( u - > memblockq , chunk ) < 0 ) {
2007-10-28 19:13:50 +00:00
pa_log_warn ( " Failed to push chunk into memblockq. " ) ;
2006-04-14 23:47:33 +00:00
return ;
}
2007-05-29 17:24:48 +00:00
2006-04-14 23:47:33 +00:00
pa_rtp_send ( & u - > rtp_context , u - > mtu , u - > memblockq ) ;
}
2007-10-28 19:13:50 +00:00
/* Called from main context */
2006-04-14 23:47:33 +00:00
static void source_output_kill ( pa_source_output * o ) {
struct userdata * u ;
2007-10-28 19:13:50 +00:00
pa_source_output_assert_ref ( o ) ;
pa_assert_se ( u = o - > userdata ) ;
2006-04-14 23:47:33 +00:00
2013-06-27 19:28:09 +02:00
pa_module_unload_request ( u - > module , true ) ;
2006-04-14 23:47:33 +00:00
2007-10-28 19:13:50 +00:00
pa_source_output_unlink ( u - > source_output ) ;
2006-04-14 23:47:33 +00:00
pa_source_output_unref ( u - > source_output ) ;
u - > source_output = NULL ;
}
2006-04-16 00:16:53 +00:00
static void sap_event_cb ( pa_mainloop_api * m , pa_time_event * t , const struct timeval * tv , void * userdata ) {
2006-04-14 23:47:33 +00:00
struct userdata * u = userdata ;
2007-05-29 17:24:48 +00:00
2007-10-28 19:13:50 +00:00
pa_assert ( m ) ;
pa_assert ( t ) ;
pa_assert ( u ) ;
2006-04-14 23:47:33 +00:00
pa_sap_send ( & u - > sap_context , 0 ) ;
2009-04-05 02:13:43 +03:00
pa_core_rttime_restart ( u - > module - > core , t , pa_rtclock_now ( ) + SAP_INTERVAL ) ;
2006-04-14 23:47:33 +00:00
}
2007-10-28 19:13:50 +00:00
int pa__init ( pa_module * m ) {
2006-04-14 23:47:33 +00:00
struct userdata * u ;
pa_modargs * ma = NULL ;
2012-11-17 23:31:16 +00:00
const char * dst_addr ;
2012-11-17 23:31:18 +00:00
const char * src_addr ;
2006-04-14 23:47:33 +00:00
uint32_t port = DEFAULT_PORT , mtu ;
2008-08-18 17:36:59 +02:00
uint32_t ttl = DEFAULT_TTL ;
2008-08-19 22:39:54 +02:00
sa_family_t af ;
int fd = - 1 , sap_fd = - 1 ;
2006-04-14 23:47:33 +00:00
pa_source * s ;
pa_sample_spec ss ;
pa_channel_map cm ;
2012-11-17 23:31:18 +00:00
struct sockaddr_in dst_sa4 , dst_sap_sa4 , src_sa4 , src_sap_sa4 ;
2009-02-13 21:58:09 +01:00
# ifdef HAVE_IPV6
2012-11-17 23:31:18 +00:00
struct sockaddr_in6 dst_sa6 , dst_sap_sa6 , src_sa6 , src_sap_sa6 ;
2009-02-13 21:58:09 +01:00
# endif
2006-04-14 23:47:33 +00:00
struct sockaddr_storage sa_dst ;
pa_source_output * o = NULL ;
uint8_t payload ;
char * p ;
2007-11-13 17:37:44 +00:00
int r , j ;
2006-04-14 23:47:33 +00:00
socklen_t k ;
2006-04-16 00:16:53 +00:00
char hn [ 128 ] , * n ;
2013-06-27 19:28:09 +02:00
bool loop = false ;
2006-08-13 19:55:17 +00:00
pa_source_output_new_data data ;
2007-05-29 17:24:48 +00:00
2007-10-28 19:13:50 +00:00
pa_assert ( m ) ;
2006-04-14 23:47:33 +00:00
if ( ! ( ma = pa_modargs_new ( m - > argument , valid_modargs ) ) ) {
2007-10-28 19:13:50 +00:00
pa_log ( " Failed to parse module arguments " ) ;
2006-04-14 23:47:33 +00:00
goto fail ;
}
2009-01-15 20:07:13 +01:00
if ( ! ( s = pa_namereg_get ( m - > core , pa_modargs_get_value ( ma , " source " , NULL ) , PA_NAMEREG_SOURCE ) ) ) {
2007-10-28 19:13:50 +00:00
pa_log ( " Source does not exist. " ) ;
2006-04-14 23:47:33 +00:00
goto fail ;
}
2006-04-16 00:16:53 +00:00
if ( pa_modargs_get_value_boolean ( ma , " loop " , & loop ) < 0 ) {
2007-10-28 19:13:50 +00:00
pa_log ( " Failed to parse \" loop \" parameter. " ) ;
2006-04-16 00:16:53 +00:00
goto fail ;
}
2006-04-14 23:47:33 +00:00
ss = s - > sample_spec ;
pa_rtp_sample_spec_fixup ( & ss ) ;
cm = s - > channel_map ;
if ( pa_modargs_get_sample_spec ( ma , & ss ) < 0 ) {
2007-10-28 19:13:50 +00:00
pa_log ( " Failed to parse sample specification " ) ;
2006-04-14 23:47:33 +00:00
goto fail ;
}
if ( ! pa_rtp_sample_spec_valid ( & ss ) ) {
2007-10-28 19:13:50 +00:00
pa_log ( " Specified sample type not compatible with RTP " ) ;
2006-04-14 23:47:33 +00:00
goto fail ;
}
if ( ss . channels ! = cm . channels )
2006-05-16 23:47:38 +00:00
pa_channel_map_init_auto ( & cm , ss . channels , PA_CHANNEL_MAP_AIFF ) ;
2006-04-14 23:47:33 +00:00
2006-04-16 00:16:53 +00:00
payload = pa_rtp_payload_from_sample_spec ( & ss ) ;
2006-04-14 23:47:33 +00:00
2008-08-19 22:39:54 +02:00
mtu = ( uint32_t ) pa_frame_align ( DEFAULT_MTU , & ss ) ;
2007-05-29 17:24:48 +00:00
2006-04-14 23:47:33 +00:00
if ( pa_modargs_get_value_u32 ( ma , " mtu " , & mtu ) < 0 | | mtu < 1 | | mtu % pa_frame_size ( & ss ) ! = 0 ) {
2007-10-28 19:13:50 +00:00
pa_log ( " Invalid MTU. " ) ;
2006-04-14 23:47:33 +00:00
goto fail ;
}
2006-04-16 09:14:55 +00:00
2008-08-19 22:39:54 +02:00
port = DEFAULT_PORT + ( ( uint32_t ) ( rand ( ) % 512 ) < < 1 ) ;
2006-04-14 23:47:33 +00:00
if ( pa_modargs_get_value_u32 ( ma , " port " , & port ) < 0 | | port < 1 | | port > 0xFFFF ) {
2006-08-18 21:38:40 +00:00
pa_log ( " port= expects a numerical argument between 1 and 65535. " ) ;
2006-04-14 23:47:33 +00:00
goto fail ;
}
2006-04-16 10:53:27 +00:00
if ( port & 1 )
2007-10-28 19:13:50 +00:00
pa_log_warn ( " Port number not even as suggested in RFC3550! " ) ;
2006-04-16 10:53:27 +00:00
2008-08-15 14:40:08 +02:00
if ( pa_modargs_get_value_u32 ( ma , " ttl " , & ttl ) < 0 | | ttl < 1 | | ttl > 0xFF ) {
pa_log ( " ttl= expects a numerical argument between 1 and 255. " ) ;
goto fail ;
}
2012-11-17 23:31:18 +00:00
src_addr = pa_modargs_get_value ( ma , " source_ip " , DEFAULT_SOURCE_IP ) ;
if ( inet_pton ( AF_INET , src_addr , & src_sa4 . sin_addr ) > 0 ) {
src_sa4 . sin_family = af = AF_INET ;
src_sa4 . sin_port = htons ( 0 ) ;
2013-12-16 17:22:10 +01:00
memset ( & src_sa4 . sin_zero , 0 , sizeof ( src_sa4 . sin_zero ) ) ;
2012-11-17 23:31:18 +00:00
src_sap_sa4 = src_sa4 ;
# ifdef HAVE_IPV6
} else if ( inet_pton ( AF_INET6 , src_addr , & src_sa6 . sin6_addr ) > 0 ) {
src_sa6 . sin6_family = af = AF_INET6 ;
src_sa6 . sin6_port = htons ( 0 ) ;
2013-12-16 17:22:10 +01:00
src_sa6 . sin6_flowinfo = 0 ;
src_sa6 . sin6_scope_id = 0 ;
2012-11-17 23:31:18 +00:00
src_sap_sa6 = src_sa6 ;
# endif
} else {
pa_log ( " Invalid source address '%s' " , src_addr ) ;
goto fail ;
}
2012-11-17 23:31:17 +00:00
dst_addr = pa_modargs_get_value ( ma , " destination " , NULL ) ;
if ( dst_addr = = NULL )
dst_addr = pa_modargs_get_value ( ma , " destination_ip " , DEFAULT_DESTINATION_IP ) ;
2006-04-16 00:16:53 +00:00
2012-11-17 23:31:16 +00:00
if ( inet_pton ( AF_INET , dst_addr , & dst_sa4 . sin_addr ) > 0 ) {
dst_sa4 . sin_family = af = AF_INET ;
dst_sa4 . sin_port = htons ( ( uint16_t ) port ) ;
2013-12-16 17:22:10 +01:00
memset ( & dst_sa4 . sin_zero , 0 , sizeof ( dst_sa4 . sin_zero ) ) ;
2012-11-17 23:31:16 +00:00
dst_sap_sa4 = dst_sa4 ;
dst_sap_sa4 . sin_port = htons ( SAP_PORT ) ;
2009-02-13 21:58:09 +01:00
# ifdef HAVE_IPV6
2012-11-17 23:31:16 +00:00
} else if ( inet_pton ( AF_INET6 , dst_addr , & dst_sa6 . sin6_addr ) > 0 ) {
dst_sa6 . sin6_family = af = AF_INET6 ;
dst_sa6 . sin6_port = htons ( ( uint16_t ) port ) ;
2013-12-16 17:22:10 +01:00
dst_sa6 . sin6_flowinfo = 0 ;
src_sa6 . sin6_scope_id = 0 ;
2012-11-17 23:31:16 +00:00
dst_sap_sa6 = dst_sa6 ;
dst_sap_sa6 . sin6_port = htons ( SAP_PORT ) ;
2009-02-13 21:58:09 +01:00
# endif
2006-04-16 00:16:53 +00:00
} else {
2012-11-17 23:31:16 +00:00
pa_log ( " Invalid destination '%s' " , dst_addr ) ;
2006-04-16 00:16:53 +00:00
goto fail ;
2006-04-14 23:47:33 +00:00
}
2007-05-29 17:24:48 +00:00
2009-10-30 03:32:38 +01:00
if ( ( fd = pa_socket_cloexec ( af , SOCK_DGRAM , 0 ) ) < 0 ) {
2006-08-18 21:38:40 +00:00
pa_log ( " socket() failed: %s " , pa_cstrerror ( errno ) ) ;
2006-04-14 23:47:33 +00:00
goto fail ;
}
2012-11-17 23:31:18 +00:00
if ( af = = AF_INET & & bind ( fd , ( struct sockaddr * ) & src_sa4 , sizeof ( src_sa4 ) ) < 0 ) {
pa_log ( " bind() failed: %s " , pa_cstrerror ( errno ) ) ;
goto fail ;
# ifdef HAVE_IPV6
} else if ( af = = AF_INET6 & & bind ( fd , ( struct sockaddr * ) & src_sa6 , sizeof ( src_sa6 ) ) < 0 ) {
pa_log ( " bind() failed: %s " , pa_cstrerror ( errno ) ) ;
goto fail ;
# endif
}
2012-11-17 23:31:16 +00:00
if ( af = = AF_INET & & connect ( fd , ( struct sockaddr * ) & dst_sa4 , sizeof ( dst_sa4 ) ) < 0 ) {
2006-08-18 21:38:40 +00:00
pa_log ( " connect() failed: %s " , pa_cstrerror ( errno ) ) ;
2006-04-14 23:47:33 +00:00
goto fail ;
2009-02-13 21:58:09 +01:00
# ifdef HAVE_IPV6
2012-11-17 23:31:16 +00:00
} else if ( af = = AF_INET6 & & connect ( fd , ( struct sockaddr * ) & dst_sa6 , sizeof ( dst_sa6 ) ) < 0 ) {
2009-02-13 21:58:09 +01:00
pa_log ( " connect() failed: %s " , pa_cstrerror ( errno ) ) ;
goto fail ;
# endif
2006-04-14 23:47:33 +00:00
}
2009-10-30 03:32:38 +01:00
if ( ( sap_fd = pa_socket_cloexec ( af , SOCK_DGRAM , 0 ) ) < 0 ) {
2006-08-18 21:38:40 +00:00
pa_log ( " socket() failed: %s " , pa_cstrerror ( errno ) ) ;
2006-04-14 23:47:33 +00:00
goto fail ;
}
2012-11-17 23:31:18 +00:00
if ( af = = AF_INET & & bind ( sap_fd , ( struct sockaddr * ) & src_sap_sa4 , sizeof ( src_sap_sa4 ) ) < 0 ) {
pa_log ( " bind() failed: %s " , pa_cstrerror ( errno ) ) ;
goto fail ;
# ifdef HAVE_IPV6
} else if ( af = = AF_INET6 & & bind ( sap_fd , ( struct sockaddr * ) & src_sap_sa6 , sizeof ( src_sap_sa6 ) ) < 0 ) {
pa_log ( " bind() failed: %s " , pa_cstrerror ( errno ) ) ;
goto fail ;
# endif
}
2012-11-17 23:31:16 +00:00
if ( af = = AF_INET & & connect ( sap_fd , ( struct sockaddr * ) & dst_sap_sa4 , sizeof ( dst_sap_sa4 ) ) < 0 ) {
2009-02-13 21:58:09 +01:00
pa_log ( " connect() failed: %s " , pa_cstrerror ( errno ) ) ;
goto fail ;
# ifdef HAVE_IPV6
2012-11-17 23:31:16 +00:00
} else if ( af = = AF_INET6 & & connect ( sap_fd , ( struct sockaddr * ) & dst_sap_sa6 , sizeof ( dst_sap_sa6 ) ) < 0 ) {
2006-08-18 21:38:40 +00:00
pa_log ( " connect() failed: %s " , pa_cstrerror ( errno ) ) ;
2006-04-14 23:47:33 +00:00
goto fail ;
2009-02-13 21:58:09 +01:00
# endif
2006-04-14 23:47:33 +00:00
}
2007-11-13 17:37:44 +00:00
j = ! ! loop ;
if ( setsockopt ( fd , IPPROTO_IP , IP_MULTICAST_LOOP , & j , sizeof ( j ) ) < 0 | |
setsockopt ( sap_fd , IPPROTO_IP , IP_MULTICAST_LOOP , & j , sizeof ( j ) ) < 0 ) {
2006-08-18 21:38:40 +00:00
pa_log ( " IP_MULTICAST_LOOP failed: %s " , pa_cstrerror ( errno ) ) ;
2006-04-16 00:16:53 +00:00
goto fail ;
}
2006-08-13 19:55:17 +00:00
2008-08-18 17:36:59 +02:00
if ( ttl ! = DEFAULT_TTL ) {
int _ttl = ( int ) ttl ;
if ( setsockopt ( fd , IPPROTO_IP , IP_MULTICAST_TTL , & _ttl , sizeof ( _ttl ) ) < 0 ) {
pa_log ( " IP_MULTICAST_TTL failed: %s " , pa_cstrerror ( errno ) ) ;
goto fail ;
}
2008-12-20 23:44:09 +02:00
if ( setsockopt ( sap_fd , IPPROTO_IP , IP_MULTICAST_TTL , & _ttl , sizeof ( _ttl ) ) < 0 ) {
pa_log ( " IP_MULTICAST_TTL (sap) failed: %s " , pa_cstrerror ( errno ) ) ;
goto fail ;
}
2008-08-15 14:40:08 +02:00
}
2007-10-28 19:13:50 +00:00
/* If the socket queue is full, let's drop packets */
pa_make_fd_nonblock ( fd ) ;
pa_make_udp_socket_low_delay ( fd ) ;
2006-08-13 19:55:17 +00:00
pa_source_output_new_data_init ( & data ) ;
2008-05-15 23:34:41 +00:00
pa_proplist_sets ( data . proplist , PA_PROP_MEDIA_NAME , " RTP Monitor Stream " ) ;
2012-11-17 23:31:18 +00:00
pa_proplist_sets ( data . proplist , " rtp.source " , src_addr ) ;
2012-11-17 23:31:16 +00:00
pa_proplist_sets ( data . proplist , " rtp.destination " , dst_addr ) ;
2008-05-15 23:34:41 +00:00
pa_proplist_setf ( data . proplist , " rtp.mtu " , " %lu " , ( unsigned long ) mtu ) ;
pa_proplist_setf ( data . proplist , " rtp.port " , " %lu " , ( unsigned long ) port ) ;
2008-08-15 14:40:08 +02:00
pa_proplist_setf ( data . proplist , " rtp.ttl " , " %lu " , ( unsigned long ) ttl ) ;
2006-08-13 19:55:17 +00:00
data . driver = __FILE__ ;
data . module = m ;
2013-06-27 19:28:09 +02:00
pa_source_output_new_data_set_source ( & data , s , false ) ;
2006-08-13 19:55:17 +00:00
pa_source_output_new_data_set_sample_spec ( & data , & ss ) ;
pa_source_output_new_data_set_channel_map ( & data , & cm ) ;
2009-08-28 23:24:09 +02:00
data . flags = PA_SOURCE_OUTPUT_DONT_INHIBIT_AUTO_SUSPEND ;
2007-05-29 17:24:48 +00:00
2009-08-28 23:24:09 +02:00
pa_source_output_new ( & o , m - > core , & data ) ;
2008-05-15 23:34:41 +00:00
pa_source_output_new_data_done ( & data ) ;
if ( ! o ) {
2006-08-18 21:38:40 +00:00
pa_log ( " failed to create source output. " ) ;
2006-04-14 23:47:33 +00:00
goto fail ;
}
2007-10-28 19:13:50 +00:00
o - > parent . process_msg = source_output_process_msg ;
2006-04-14 23:47:33 +00:00
o - > push = source_output_push ;
o - > kill = source_output_kill ;
2007-05-29 17:24:48 +00:00
2009-06-05 19:25:15 +02:00
pa_log_info ( " Configured source latency of %llu ms. " ,
( unsigned long long ) pa_source_output_set_requested_latency ( o , pa_bytes_to_usec ( mtu , & o - > sample_spec ) ) / PA_USEC_PER_MSEC ) ;
2006-04-14 23:47:33 +00:00
2009-04-07 00:47:13 +02:00
m - > userdata = o - > userdata = u = pa_xnew ( struct userdata , 1 ) ;
2006-04-14 23:47:33 +00:00
u - > module = m ;
u - > source_output = o ;
2007-05-29 17:24:48 +00:00
2006-04-14 23:47:33 +00:00
u - > memblockq = pa_memblockq_new (
2011-09-29 18:54:03 +03:00
" module-rtp-send memblockq " ,
2006-04-14 23:47:33 +00:00
0 ,
MEMBLOCKQ_MAXLENGTH ,
MEMBLOCKQ_MAXLENGTH ,
2011-09-29 18:54:03 +03:00
& ss ,
2006-04-14 23:47:33 +00:00
1 ,
0 ,
2008-05-15 23:34:41 +00:00
0 ,
2006-08-18 19:55:18 +00:00
NULL ) ;
2006-04-14 23:47:33 +00:00
u - > mtu = mtu ;
2007-05-29 17:24:48 +00:00
2006-04-14 23:47:33 +00:00
k = sizeof ( sa_dst ) ;
2007-10-28 19:13:50 +00:00
pa_assert_se ( ( r = getsockname ( fd , ( struct sockaddr * ) & sa_dst , & k ) ) > = 0 ) ;
2006-04-16 00:16:53 +00:00
2006-06-20 13:02:34 +00:00
n = pa_sprintf_malloc ( " PulseAudio RTP Stream on %s " , pa_get_fqdn ( hn , sizeof ( hn ) ) ) ;
2007-05-29 17:24:48 +00:00
2009-02-13 21:58:09 +01:00
if ( af = = AF_INET ) {
p = pa_sdp_build ( af ,
( void * ) & ( ( struct sockaddr_in * ) & sa_dst ) - > sin_addr ,
2012-11-17 23:31:16 +00:00
( void * ) & dst_sa4 . sin_addr ,
2009-02-13 21:58:09 +01:00
n , ( uint16_t ) port , payload , & ss ) ;
# ifdef HAVE_IPV6
} else {
p = pa_sdp_build ( af ,
( void * ) & ( ( struct sockaddr_in6 * ) & sa_dst ) - > sin6_addr ,
2012-11-17 23:31:16 +00:00
( void * ) & dst_sa6 . sin6_addr ,
2008-08-19 22:39:54 +02:00
n , ( uint16_t ) port , payload , & ss ) ;
2009-02-13 21:58:09 +01:00
# endif
}
2006-04-16 00:16:53 +00:00
pa_xfree ( n ) ;
2007-05-29 17:24:48 +00:00
2007-10-28 19:13:50 +00:00
pa_rtp_context_init_send ( & u - > rtp_context , fd , m - > core - > cookie , payload , pa_frame_size ( & ss ) ) ;
2006-04-14 23:47:33 +00:00
pa_sap_context_init_send ( & u - > sap_context , sap_fd , p ) ;
2012-11-17 23:31:18 +00:00
pa_log_info ( " RTP stream initialized with mtu %u on %s:%u from %s ttl=%u, SSRC=0x%08x, payload=%u, initial sequence #%u " , mtu , dst_addr , port , src_addr , ttl , u - > rtp_context . ssrc , payload , u - > rtp_context . sequence ) ;
2007-10-28 19:13:50 +00:00
pa_log_info ( " SDP-Data: \n %s \n EOF " , p ) ;
2006-04-16 00:16:53 +00:00
2006-04-14 23:47:33 +00:00
pa_sap_send ( & u - > sap_context , 0 ) ;
2009-04-05 02:13:43 +03:00
u - > sap_event = pa_core_rttime_new ( m - > core , pa_rtclock_now ( ) + SAP_INTERVAL , sap_event_cb , u ) ;
2007-10-28 19:13:50 +00:00
pa_source_output_put ( u - > source_output ) ;
2006-04-14 23:47:33 +00:00
pa_modargs_free ( ma ) ;
return 0 ;
fail :
if ( ma )
pa_modargs_free ( ma ) ;
if ( fd > = 0 )
2007-10-28 19:13:50 +00:00
pa_close ( fd ) ;
2007-05-29 17:24:48 +00:00
2006-04-14 23:47:33 +00:00
if ( sap_fd > = 0 )
2007-10-28 19:13:50 +00:00
pa_close ( sap_fd ) ;
2006-04-14 23:47:33 +00:00
if ( o ) {
2007-10-28 19:13:50 +00:00
pa_source_output_unlink ( o ) ;
2006-04-14 23:47:33 +00:00
pa_source_output_unref ( o ) ;
}
2007-05-29 17:24:48 +00:00
2006-04-14 23:47:33 +00:00
return - 1 ;
}
2007-10-28 19:13:50 +00:00
void pa__done ( pa_module * m ) {
2006-04-14 23:47:33 +00:00
struct userdata * u ;
2007-10-28 19:13:50 +00:00
pa_assert ( m ) ;
2006-04-14 23:47:33 +00:00
if ( ! ( u = m - > userdata ) )
return ;
2007-10-28 19:13:50 +00:00
if ( u - > sap_event )
m - > core - > mainloop - > time_free ( u - > sap_event ) ;
2007-05-29 17:24:48 +00:00
2006-04-14 23:47:33 +00:00
if ( u - > source_output ) {
2007-10-28 19:13:50 +00:00
pa_source_output_unlink ( u - > source_output ) ;
2006-04-14 23:47:33 +00:00
pa_source_output_unref ( u - > source_output ) ;
}
pa_rtp_context_destroy ( & u - > rtp_context ) ;
pa_sap_send ( & u - > sap_context , 1 ) ;
pa_sap_context_destroy ( & u - > sap_context ) ;
2007-10-28 19:13:50 +00:00
if ( u - > memblockq )
pa_memblockq_free ( u - > memblockq ) ;
2007-05-29 17:24:48 +00:00
2006-04-14 23:47:33 +00:00
pa_xfree ( u ) ;
}