static int ref(void) { if (n_ref > 0) { pa_assert(pipe_fd[0] >= 0); pa_assert(pipe_fd[1] >= 0); pa_assert(lock_fd_mutex); n_ref++; return 0; } pa_assert(!lock_fd_mutex); pa_assert(state == STATE_IDLE); pa_assert(lock_fd < 0); pa_assert(!thread); pa_assert(pipe_fd[0] < 0); pa_assert(pipe_fd[1] < 0); if (pa_pipe_cloexec(pipe_fd) < 0) return -1; pa_make_fd_nonblock(pipe_fd[1]); pa_make_fd_nonblock(pipe_fd[0]); lock_fd_mutex = pa_mutex_new(FALSE, FALSE); n_ref = 1; return 0; }
/* Initializes CPU load limiter */ int pa_cpu_limit_init(pa_mainloop_api *m) { struct sigaction sa; pa_assert(m); pa_assert(!api); pa_assert(!io_event); pa_assert(the_pipe[0] == -1); pa_assert(the_pipe[1] == -1); pa_assert(!installed); time(&last_time); /* Prepare the main loop pipe */ if (pipe(the_pipe) < 0) { pa_log("pipe() failed: %s", pa_cstrerror(errno)); return -1; } pa_make_fd_nonblock(the_pipe[0]); pa_make_fd_nonblock(the_pipe[1]); pa_make_fd_cloexec(the_pipe[0]); pa_make_fd_cloexec(the_pipe[1]); api = m; io_event = api->io_new(m, the_pipe[0], PA_IO_EVENT_INPUT, callback, NULL); phase = PHASE_IDLE; /* Install signal handler for SIGXCPU */ memset(&sa, 0, sizeof(sa)); sa.sa_handler = signal_handler; sigemptyset(&sa.sa_mask); sa.sa_flags = SA_RESTART; if (sigaction(SIGXCPU, &sa, &sigaction_prev) < 0) { pa_cpu_limit_done(); return -1; } installed = 1; reset_cpu_time(CPUTIME_INTERVAL_SOFT); return 0; }
pa_iochannel* pa_iochannel_new(pa_mainloop_api*m, int ifd, int ofd) { pa_iochannel *io; pa_assert(m); pa_assert(ifd >= 0 || ofd >= 0); io = pa_xnew0(pa_iochannel, 1); io->ifd = ifd; io->ofd = ofd; io->mainloop = m; if (io->ifd >= 0) pa_make_fd_nonblock(io->ifd); if (io->ofd >= 0 && io->ofd != io->ifd) pa_make_fd_nonblock(io->ofd); enable_events(io); return io; }
int pa__init(pa_module *m) { struct userdata *u; struct stat st; pa_sample_spec ss; pa_channel_map map; pa_modargs *ma; struct pollfd *pollfd; pa_source_new_data data; 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; map = m->core->default_channel_map; 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; } m->userdata = u = pa_xnew0(struct userdata, 1); u->core = m->core; u->module = m; pa_memchunk_reset(&u->memchunk); u->rtpoll = pa_rtpoll_new(); if (pa_thread_mq_init(&u->thread_mq, m->core->mainloop, u->rtpoll) < 0) { pa_log("pa_thread_mq_init() failed."); goto fail; } u->filename = pa_runtime_path(pa_modargs_get_value(ma, "file", DEFAULT_FILE_NAME)); if (mkfifo(u->filename, 0666) < 0) { pa_log("mkfifo('%s'): %s", u->filename, pa_cstrerror(errno)); goto fail; } if ((u->fd = pa_open_cloexec(u->filename, O_RDWR, 0)) < 0) { pa_log("open('%s'): %s", u->filename, pa_cstrerror(errno)); goto fail; } 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; } pa_source_new_data_init(&data); data.driver = __FILE__; data.module = m; pa_source_new_data_set_name(&data, pa_modargs_get_value(ma, "source_name", DEFAULT_SOURCE_NAME)); pa_proplist_sets(data.proplist, PA_PROP_DEVICE_STRING, u->filename); pa_proplist_setf(data.proplist, PA_PROP_DEVICE_DESCRIPTION, "Unix FIFO source %s", u->filename); pa_source_new_data_set_sample_spec(&data, &ss); pa_source_new_data_set_channel_map(&data, &map); if (pa_modargs_get_proplist(ma, "source_properties", data.proplist, PA_UPDATE_REPLACE) < 0) { pa_log("Invalid properties"); pa_source_new_data_done(&data); goto fail; } u->source = pa_source_new(m->core, &data, PA_SOURCE_LATENCY); pa_source_new_data_done(&data); if (!u->source) { pa_log("Failed to create source."); goto fail; } u->source->parent.process_msg = source_process_msg; u->source->userdata = u; pa_source_set_asyncmsgq(u->source, u->thread_mq.inq); pa_source_set_rtpoll(u->source, u->rtpoll); pa_source_set_fixed_latency(u->source, pa_bytes_to_usec(pa_pipe_buf(u->fd), &u->source->sample_spec)); 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("pipe-source", thread_func, u))) { pa_log("Failed to create thread."); goto fail; } pa_source_put(u->source); pa_modargs_free(ma); return 0; fail: if (ma) pa_modargs_free(ma); pa__done(m); return -1; }
int pa__init(pa_module*m) { struct userdata *u; pa_modargs *ma = NULL; const char *dst_addr; const char *src_addr; uint32_t port = DEFAULT_PORT, mtu; uint32_t ttl = DEFAULT_TTL; sa_family_t af; int fd = -1, sap_fd = -1; pa_source *s; pa_sample_spec ss; pa_channel_map cm; struct sockaddr_in dst_sa4, dst_sap_sa4, src_sa4, src_sap_sa4; #ifdef HAVE_IPV6 struct sockaddr_in6 dst_sa6, dst_sap_sa6, src_sa6, src_sap_sa6; #endif struct sockaddr_storage sa_dst; pa_source_output *o = NULL; uint8_t payload; char *p; int r, j; socklen_t k; char hn[128], *n; bool loop = false; enum inhibit_auto_suspend inhibit_auto_suspend = INHIBIT_AUTO_SUSPEND_ONLY_WITH_NON_MONITOR_SOURCES; const char *inhibit_auto_suspend_str; pa_source_output_new_data data; pa_assert(m); if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { pa_log("Failed to parse module arguments"); goto fail; } if (!(s = pa_namereg_get(m->core, pa_modargs_get_value(ma, "source", NULL), PA_NAMEREG_SOURCE))) { pa_log("Source does not exist."); goto fail; } if (pa_modargs_get_value_boolean(ma, "loop", &loop) < 0) { pa_log("Failed to parse \"loop\" parameter."); goto fail; } if ((inhibit_auto_suspend_str = pa_modargs_get_value(ma, "inhibit_auto_suspend", NULL))) { if (pa_streq(inhibit_auto_suspend_str, "always")) inhibit_auto_suspend = INHIBIT_AUTO_SUSPEND_ALWAYS; else if (pa_streq(inhibit_auto_suspend_str, "never")) inhibit_auto_suspend = INHIBIT_AUTO_SUSPEND_NEVER; else if (pa_streq(inhibit_auto_suspend_str, "only_with_non_monitor_sources")) inhibit_auto_suspend = INHIBIT_AUTO_SUSPEND_ONLY_WITH_NON_MONITOR_SOURCES; else { pa_log("Failed to parse the \"inhibit_auto_suspend\" parameter."); goto fail; } } ss = s->sample_spec; pa_rtp_sample_spec_fixup(&ss); cm = s->channel_map; if (pa_modargs_get_sample_spec(ma, &ss) < 0) { pa_log("Failed to parse sample specification"); goto fail; } if (!pa_rtp_sample_spec_valid(&ss)) { pa_log("Specified sample type not compatible with RTP"); goto fail; } if (ss.channels != cm.channels) pa_channel_map_init_auto(&cm, ss.channels, PA_CHANNEL_MAP_AIFF); payload = pa_rtp_payload_from_sample_spec(&ss); mtu = (uint32_t) pa_frame_align(DEFAULT_MTU, &ss); if (pa_modargs_get_value_u32(ma, "mtu", &mtu) < 0 || mtu < 1 || mtu % pa_frame_size(&ss) != 0) { pa_log("Invalid MTU."); goto fail; } port = DEFAULT_PORT + ((uint32_t) (rand() % 512) << 1); if (pa_modargs_get_value_u32(ma, "port", &port) < 0 || port < 1 || port > 0xFFFF) { pa_log("port= expects a numerical argument between 1 and 65535."); goto fail; } if (port & 1) pa_log_warn("Port number not even as suggested in RFC3550!"); 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; } 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); memset(&src_sa4.sin_zero, 0, sizeof(src_sa4.sin_zero)); 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); src_sa6.sin6_flowinfo = 0; src_sa6.sin6_scope_id = 0; src_sap_sa6 = src_sa6; #endif } else { pa_log("Invalid source address '%s'", src_addr); goto fail; } 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); 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); memset(&dst_sa4.sin_zero, 0, sizeof(dst_sa4.sin_zero)); dst_sap_sa4 = dst_sa4; dst_sap_sa4.sin_port = htons(SAP_PORT); #ifdef HAVE_IPV6 } 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); dst_sa6.sin6_flowinfo = 0; dst_sa6.sin6_scope_id = 0; dst_sap_sa6 = dst_sa6; dst_sap_sa6.sin6_port = htons(SAP_PORT); #endif } else { pa_log("Invalid destination '%s'", dst_addr); goto fail; } if ((fd = pa_socket_cloexec(af, SOCK_DGRAM, 0)) < 0) { pa_log("socket() failed: %s", pa_cstrerror(errno)); goto fail; } 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 } if (af == AF_INET && connect(fd, (struct sockaddr*) &dst_sa4, sizeof(dst_sa4)) < 0) { pa_log("connect() failed: %s", pa_cstrerror(errno)); goto fail; #ifdef HAVE_IPV6 } else if (af == AF_INET6 && connect(fd, (struct sockaddr*) &dst_sa6, sizeof(dst_sa6)) < 0) { pa_log("connect() failed: %s", pa_cstrerror(errno)); goto fail; #endif } if ((sap_fd = pa_socket_cloexec(af, SOCK_DGRAM, 0)) < 0) { pa_log("socket() failed: %s", pa_cstrerror(errno)); goto fail; } 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 } if (af == AF_INET && connect(sap_fd, (struct sockaddr*) &dst_sap_sa4, sizeof(dst_sap_sa4)) < 0) { pa_log("connect() failed: %s", pa_cstrerror(errno)); goto fail; #ifdef HAVE_IPV6 } else if (af == AF_INET6 && connect(sap_fd, (struct sockaddr*) &dst_sap_sa6, sizeof(dst_sap_sa6)) < 0) { pa_log("connect() failed: %s", pa_cstrerror(errno)); goto fail; #endif } 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) { pa_log("IP_MULTICAST_LOOP failed: %s", pa_cstrerror(errno)); goto fail; } 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; } 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; } } /* If the socket queue is full, let's drop packets */ pa_make_fd_nonblock(fd); pa_make_udp_socket_low_delay(fd); pa_source_output_new_data_init(&data); pa_proplist_sets(data.proplist, PA_PROP_MEDIA_NAME, "RTP Monitor Stream"); pa_proplist_sets(data.proplist, "rtp.source", src_addr); pa_proplist_sets(data.proplist, "rtp.destination", dst_addr); pa_proplist_setf(data.proplist, "rtp.mtu", "%lu", (unsigned long) mtu); pa_proplist_setf(data.proplist, "rtp.port", "%lu", (unsigned long) port); pa_proplist_setf(data.proplist, "rtp.ttl", "%lu", (unsigned long) ttl); data.driver = __FILE__; data.module = m; pa_source_output_new_data_set_source(&data, s, false, true); pa_source_output_new_data_set_sample_spec(&data, &ss); pa_source_output_new_data_set_channel_map(&data, &cm); data.flags |= get_dont_inhibit_auto_suspend_flag(s, inhibit_auto_suspend); pa_source_output_new(&o, m->core, &data); pa_source_output_new_data_done(&data); if (!o) { pa_log("failed to create source output."); goto fail; } o->parent.process_msg = source_output_process_msg; o->push = source_output_push_cb; o->moving = source_output_moving_cb; o->kill = source_output_kill_cb; 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); m->userdata = o->userdata = u = pa_xnew(struct userdata, 1); u->module = m; u->source_output = o; u->memblockq = pa_memblockq_new( "module-rtp-send memblockq", 0, MEMBLOCKQ_MAXLENGTH, MEMBLOCKQ_MAXLENGTH, &ss, 1, 0, 0, NULL); u->mtu = mtu; k = sizeof(sa_dst); pa_assert_se((r = getsockname(fd, (struct sockaddr*) &sa_dst, &k)) >= 0); n = pa_xstrdup(pa_modargs_get_value(ma, "stream_name", NULL)); if (n == NULL) n = pa_sprintf_malloc("PulseAudio RTP Stream on %s", pa_get_fqdn(hn, sizeof(hn))); if (af == AF_INET) { p = pa_sdp_build(af, (void*) &((struct sockaddr_in*) &sa_dst)->sin_addr, (void*) &dst_sa4.sin_addr, n, (uint16_t) port, payload, &ss); #ifdef HAVE_IPV6 } else { p = pa_sdp_build(af, (void*) &((struct sockaddr_in6*) &sa_dst)->sin6_addr, (void*) &dst_sa6.sin6_addr, n, (uint16_t) port, payload, &ss); #endif } pa_xfree(n); pa_rtp_context_init_send(&u->rtp_context, fd, m->core->cookie, payload, pa_frame_size(&ss)); pa_sap_context_init_send(&u->sap_context, sap_fd, p); 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); pa_log_info("SDP-Data:\n%s\nEOF", p); pa_sap_send(&u->sap_context, 0); u->sap_event = pa_core_rttime_new(m->core, pa_rtclock_now() + SAP_INTERVAL, sap_event_cb, u); u->inhibit_auto_suspend = inhibit_auto_suspend; pa_source_output_put(u->source_output); pa_modargs_free(ma); return 0; fail: if (ma) pa_modargs_free(ma); if (fd >= 0) pa_close(fd); if (sap_fd >= 0) pa_close(sap_fd); return -1; }