summaryrefslogtreecommitdiffstats
path: root/src/modules/rtp
diff options
context:
space:
mode:
Diffstat (limited to 'src/modules/rtp')
-rw-r--r--src/modules/rtp/module-rtp-recv.c533
-rw-r--r--src/modules/rtp/module-rtp-send.c189
-rw-r--r--src/modules/rtp/rtp.c173
-rw-r--r--src/modules/rtp/rtp.h12
-rw-r--r--src/modules/rtp/sap.c79
-rw-r--r--src/modules/rtp/sap.h14
-rw-r--r--src/modules/rtp/sdp.c78
-rw-r--r--src/modules/rtp/sdp.h10
8 files changed, 669 insertions, 419 deletions
diff --git a/src/modules/rtp/module-rtp-recv.c b/src/modules/rtp/module-rtp-recv.c
index 338d57cf..cff5cf8b 100644
--- a/src/modules/rtp/module-rtp-recv.c
+++ b/src/modules/rtp/module-rtp-recv.c
@@ -1,17 +1,19 @@
/***
This file is part of PulseAudio.
-
+
+ Copyright 2006 Lennart Poettering
+
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
@@ -22,7 +24,6 @@
#include <config.h>
#endif
-#include <assert.h>
#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
@@ -30,6 +31,7 @@
#include <errno.h>
#include <string.h>
#include <unistd.h>
+#include <poll.h>
#include <pulse/timeval.h>
#include <pulse/xmalloc.h>
@@ -45,6 +47,11 @@
#include <pulsecore/modargs.h>
#include <pulsecore/namereg.h>
#include <pulsecore/sample-util.h>
+#include <pulsecore/macro.h>
+#include <pulsecore/atomic.h>
+#include <pulsecore/rtclock.h>
+#include <pulsecore/atomic.h>
+#include <pulsecore/time-smoother.h>
#include "module-rtp-recv-symdef.h"
@@ -52,19 +59,22 @@
#include "sdp.h"
#include "sap.h"
-PA_MODULE_AUTHOR("Lennart Poettering")
-PA_MODULE_DESCRIPTION("Recieve data from a network via RTP/SAP/SDP")
-PA_MODULE_VERSION(PACKAGE_VERSION)
+PA_MODULE_AUTHOR("Lennart Poettering");
+PA_MODULE_DESCRIPTION("Recieve data from a network via RTP/SAP/SDP");
+PA_MODULE_VERSION(PACKAGE_VERSION);
+PA_MODULE_LOAD_ONCE(FALSE);
PA_MODULE_USAGE(
"sink=<name of the sink> "
"sap_address=<multicast address to listen on> "
-)
+);
#define SAP_PORT 9875
#define DEFAULT_SAP_ADDRESS "224.0.0.56"
-#define MEMBLOCKQ_MAXLENGTH (1024*170)
+#define MEMBLOCKQ_MAXLENGTH (1024*1024*40)
#define MAX_SESSIONS 16
-#define DEATH_TIMEOUT 20000000
+#define DEATH_TIMEOUT 20
+#define RATE_UPDATE_INTERVAL (5*PA_USEC_PER_SEC)
+#define LATENCY_USEC (500*PA_USEC_PER_MSEC)
static const char* const valid_modargs[] = {
"sink",
@@ -74,102 +84,148 @@ static const char* const valid_modargs[] = {
struct session {
struct userdata *userdata;
+ PA_LLIST_FIELDS(struct session);
pa_sink_input *sink_input;
pa_memblockq *memblockq;
- pa_time_event *death_event;
-
- int first_packet;
+ pa_bool_t first_packet;
uint32_t ssrc;
uint32_t offset;
struct pa_sdp_info sdp_info;
pa_rtp_context rtp_context;
- pa_io_event* rtp_event;
+
+ pa_rtpoll_item *rtpoll_item;
+
+ pa_atomic_t timestamp;
+
+ pa_smoother *smoother;
+ pa_usec_t intended_latency;
+ pa_usec_t sink_latency;
+
+ pa_usec_t last_rate_update;
};
struct userdata {
pa_module *module;
- pa_core *core;
pa_sap_context sap_context;
pa_io_event* sap_event;
- pa_hashmap *by_origin;
+ pa_time_event *check_death_event;
char *sink_name;
+ PA_LLIST_HEAD(struct session, sessions);
+ pa_hashmap *by_origin;
int n_sessions;
};
-static void session_free(struct session *s, int from_hash);
+static void session_free(struct session *s);
+
+/* Called from I/O thread context */
+static int sink_input_process_msg(pa_msgobject *o, int code, void *data, int64_t offset, pa_memchunk *chunk) {
+ struct session *s = PA_SINK_INPUT(o)->userdata;
-static int sink_input_peek(pa_sink_input *i, pa_memchunk *chunk) {
+ switch (code) {
+ case PA_SINK_INPUT_MESSAGE_GET_LATENCY:
+ *((pa_usec_t*) data) = pa_bytes_to_usec(pa_memblockq_get_length(s->memblockq), &s->sink_input->sample_spec);
+
+ /* Fall through, the default handler will add in the extra
+ * latency added by the resampler */
+ break;
+ }
+
+ return pa_sink_input_process_msg(o, code, data, offset, chunk);
+}
+
+/* Called from I/O thread context */
+static int sink_input_pop_cb(pa_sink_input *i, size_t length, pa_memchunk *chunk) {
struct session *s;
- assert(i);
- s = i->userdata;
+ pa_sink_input_assert_ref(i);
+ pa_assert_se(s = i->userdata);
+
+ if (pa_memblockq_peek(s->memblockq, chunk) < 0)
+ return -1;
- return pa_memblockq_peek(s->memblockq, chunk);
+ pa_memblockq_drop(s->memblockq, chunk->length);
+
+ return 0;
}
-static void sink_input_drop(pa_sink_input *i, const pa_memchunk *chunk, size_t length) {
+/* Called from I/O thread context */
+static void sink_input_process_rewind_cb(pa_sink_input *i, size_t nbytes) {
struct session *s;
- assert(i);
- s = i->userdata;
- pa_memblockq_drop(s->memblockq, chunk, length);
+ pa_sink_input_assert_ref(i);
+ pa_assert_se(s = i->userdata);
+
+ pa_memblockq_rewind(s->memblockq, nbytes);
}
-static void sink_input_kill(pa_sink_input* i) {
+/* Called from thread context */
+static void sink_input_update_max_rewind_cb(pa_sink_input *i, size_t nbytes) {
struct session *s;
- assert(i);
- s = i->userdata;
- session_free(s, 1);
+ pa_sink_input_assert_ref(i);
+ pa_assert_se(s = i->userdata);
+
+ pa_memblockq_set_maxrewind(s->memblockq, nbytes);
}
-static pa_usec_t sink_input_get_latency(pa_sink_input *i) {
+/* Called from main context */
+static void sink_input_kill(pa_sink_input* i) {
struct session *s;
- assert(i);
- s = i->userdata;
+ pa_sink_input_assert_ref(i);
+ pa_assert_se(s = i->userdata);
- return pa_bytes_to_usec(pa_memblockq_get_length(s->memblockq), &i->sample_spec);
+ session_free(s);
}
-static void rtp_event_cb(pa_mainloop_api *m, pa_io_event *e, int fd, pa_io_event_flags_t flags, void *userdata) {
- struct session *s = userdata;
+/* Called from I/O thread context */
+static int rtpoll_work_cb(pa_rtpoll_item *i) {
pa_memchunk chunk;
int64_t k, j, delta;
- struct timeval tv;
-
- assert(m);
- assert(e);
- assert(s);
- assert(fd == s->rtp_context.fd);
- assert(flags == PA_IO_EVENT_INPUT);
-
- if (pa_rtp_recv(&s->rtp_context, &chunk, s->userdata->core->mempool) < 0)
- return;
+ struct timeval now;
+ struct session *s;
+ struct pollfd *p;
+
+ pa_assert_se(s = pa_rtpoll_item_get_userdata(i));
+
+ p = pa_rtpoll_item_get_pollfd(i, NULL);
+
+ if (p->revents & (POLLERR|POLLNVAL|POLLHUP|POLLOUT)) {
+ pa_log("poll() signalled bad revents.");
+ return -1;
+ }
+
+ if ((p->revents & POLLIN) == 0)
+ return 0;
+
+ p->revents = 0;
+
+ if (pa_rtp_recv(&s->rtp_context, &chunk, s->userdata->module->core->mempool) < 0)
+ return 0;
if (s->sdp_info.payload != s->rtp_context.payload) {
pa_memblock_unref(chunk.memblock);
- return;
+ return 0;
}
-
+
if (!s->first_packet) {
- s->first_packet = 1;
+ s->first_packet = TRUE;
s->ssrc = s->rtp_context.ssrc;
s->offset = s->rtp_context.timestamp;
- if (s->ssrc == s->userdata->core->cookie)
- pa_log_warn("WARNING! Detected RTP packet loop!");
+ if (s->ssrc == s->userdata->module->core->cookie)
+ pa_log_warn("Detected RTP packet loop!");
} else {
if (s->ssrc != s->rtp_context.ssrc) {
pa_memblock_unref(chunk.memblock);
- return;
+ return 0;
}
}
@@ -181,40 +237,125 @@ static void rtp_event_cb(pa_mainloop_api *m, pa_io_event *e, int fd, pa_io_event
delta = k;
else
delta = j;
-
+
pa_memblockq_seek(s->memblockq, delta * s->rtp_context.frame_size, PA_SEEK_RELATIVE);
+ pa_rtclock_get(&now);
+
+ pa_smoother_put(s->smoother, pa_timeval_load(&now), pa_bytes_to_usec(pa_memblockq_get_write_index(s->memblockq), &s->sink_input->sample_spec));
+
if (pa_memblockq_push(s->memblockq, &chunk) < 0) {
- /* queue overflow, let's flush it and try again */
- pa_memblockq_flush(s->memblockq);
- pa_memblockq_push(s->memblockq, &chunk);
+ pa_log_warn("Queue overrun");
+ pa_memblockq_seek(s->memblockq, chunk.length, PA_SEEK_RELATIVE);
}
-
+
+ pa_log("blocks in q: %u", pa_memblockq_get_nblocks(s->memblockq));
+
+ pa_memblock_unref(chunk.memblock);
+
/* The next timestamp we expect */
s->offset = s->rtp_context.timestamp + (chunk.length / s->rtp_context.frame_size);
-
- pa_memblock_unref(chunk.memblock);
- /* Reset death timer */
- pa_gettimeofday(&tv);
- pa_timeval_add(&tv, DEATH_TIMEOUT);
- m->time_restart(s->death_event, &tv);
+ pa_atomic_store(&s->timestamp, now.tv_sec);
+
+ if (s->last_rate_update + RATE_UPDATE_INTERVAL < pa_timeval_load(&now)) {
+ pa_usec_t wi, ri, render_delay, sink_delay = 0, latency, fix;
+ unsigned fix_samples;
+
+ pa_log("Updating sample rate");
+
+ wi = pa_smoother_get(s->smoother, pa_timeval_load(&now));
+ ri = pa_bytes_to_usec(pa_memblockq_get_read_index(s->memblockq), &s->sink_input->sample_spec);
+
+ if (PA_MSGOBJECT(s->sink_input->sink)->process_msg(PA_MSGOBJECT(s->sink_input->sink), PA_SINK_MESSAGE_GET_LATENCY, &sink_delay, 0, NULL) < 0)
+ sink_delay = 0;
+
+ render_delay = pa_bytes_to_usec(pa_memblockq_get_length(s->sink_input->thread_info.render_memblockq), &s->sink_input->sink->sample_spec);
+
+ if (ri > render_delay+sink_delay)
+ ri -= render_delay+sink_delay;
+ else
+ ri = 0;
+
+ if (wi < ri)
+ latency = 0;
+ else
+ latency = wi - ri;
+
+ pa_log_debug("Write index deviates by %0.2f ms, expected %0.2f ms", (double) latency/PA_USEC_PER_MSEC, (double) s->intended_latency/PA_USEC_PER_MSEC);
+
+ /* Calculate deviation */
+ if (latency < s->intended_latency)
+ fix = s->intended_latency - latency;
+ else
+ fix = latency - s->intended_latency;
+
+ /* How many samples is this per second? */
+ fix_samples = fix * s->sink_input->thread_info.sample_spec.rate / RATE_UPDATE_INTERVAL;
+
+ /* Check if deviation is in bounds */
+ if (fix_samples > s->sink_input->sample_spec.rate*.20)
+ pa_log_debug("Hmmm, rate fix is too large (%lu Hz), not applying.", (unsigned long) fix_samples);
+
+ /* Fix up rate */
+ if (latency < s->intended_latency)
+ s->sink_input->sample_spec.rate -= fix_samples;
+ else
+ s->sink_input->sample_spec.rate += fix_samples;
+
+ pa_resampler_set_input_rate(s->sink_input->thread_info.resampler, s->sink_input->sample_spec.rate);
+
+ pa_log_debug("Updated sampling rate to %lu Hz.", (unsigned long) s->sink_input->sample_spec.rate);
+
+ s->last_rate_update = pa_timeval_load(&now);
+ }
+
+ if (pa_memblockq_is_readable(s->memblockq) &&
+ s->sink_input->thread_info.underrun_for > 0) {
+ pa_log_debug("Requesting rewind due to end of underrun");
+ pa_sink_input_request_rewind(s->sink_input, 0, FALSE, TRUE);
+ }
+
+ return 1;
+}
+
+/* Called from I/O thread context */
+static void sink_input_attach(pa_sink_input *i) {
+ struct session *s;
+ struct pollfd *p;
+
+ pa_sink_input_assert_ref(i);
+ pa_assert_se(s = i->userdata);
+
+ pa_assert(!s->rtpoll_item);
+ s->rtpoll_item = pa_rtpoll_item_new(i->sink->rtpoll, PA_RTPOLL_LATE, 1);
+
+ p = pa_rtpoll_item_get_pollfd(s->rtpoll_item, NULL);
+ p->fd = s->rtp_context.fd;
+ p->events = POLLIN;
+ p->revents = 0;
+
+ pa_rtpoll_item_set_work_callback(s->rtpoll_item, rtpoll_work_cb);
+ pa_rtpoll_item_set_userdata(s->rtpoll_item, s);
}
-static void death_event_cb(pa_mainloop_api *m, pa_time_event *t, const struct timeval *tv, void *userdata) {
- struct session *s = userdata;
-
- assert(m);
- assert(t);
- assert(tv);
- assert(s);
+/* Called from I/O thread context */
+static void sink_input_detach(pa_sink_input *i) {
+ struct session *s;
+ pa_sink_input_assert_ref(i);
+ pa_assert_se(s = i->userdata);
- session_free(s, 1);
+ pa_assert(s->rtpoll_item);
+ pa_rtpoll_item_free(s->rtpoll_item);
+ s->rtpoll_item = NULL;
}
static int mcast_socket(const struct sockaddr* sa, socklen_t salen) {
int af, fd = -1, r, one;
-
+
+ pa_assert(sa);
+ pa_assert(salen > 0);
+
af = sa->sa_family;
if ((fd = socket(af, SOCK_DGRAM, 0)) < 0) {
pa_log("Failed to create socket: %s", pa_cstrerror(errno));
@@ -226,7 +367,7 @@ static int mcast_socket(const struct sockaddr* sa, socklen_t salen) {
pa_log("SO_REUSEADDR failed: %s", pa_cstrerror(errno));
goto fail;
}
-
+
if (af == AF_INET) {
struct ip_mreq mr4;
memset(&mr4, 0, sizeof(mr4));
@@ -243,14 +384,14 @@ static int mcast_socket(const struct sockaddr* sa, socklen_t salen) {
pa_log_info("Joining mcast group failed: %s", pa_cstrerror(errno));
goto fail;
}
-
+
if (bind(fd, sa, salen) < 0) {
pa_log("bind() failed: %s", pa_cstrerror(errno));
goto fail;
}
return fd;
-
+
fail:
if (fd >= 0)
close(fd);
@@ -260,136 +401,149 @@ fail:
static struct session *session_new(struct userdata *u, const pa_sdp_info *sdp_info) {
struct session *s = NULL;
- struct timeval tv;
- char *c;
pa_sink *sink;
int fd = -1;
- pa_memblock *silence;
+ pa_memchunk silence;
pa_sink_input_new_data data;
+ struct timeval now;
+
+ pa_assert(u);
+ pa_assert(sdp_info);
if (u->n_sessions >= MAX_SESSIONS) {
- pa_log("session limit reached.");
+ pa_log("Session limit reached.");
goto fail;
}
-
- if (!(sink = pa_namereg_get(u->core, u->sink_name, PA_NAMEREG_SINK, 1))) {
- pa_log("sink does not exist.");
+
+ if (!(sink = pa_namereg_get(u->module->core, u->sink_name, PA_NAMEREG_SINK, TRUE))) {
+ pa_log("Sink does not exist.");
goto fail;
}
+ pa_rtclock_get(&now);
+
s = pa_xnew0(struct session, 1);
s->userdata = u;
- s->first_packet = 0;
+ s->first_packet = FALSE;
s->sdp_info = *sdp_info;
+ s->rtpoll_item = NULL;
+ s->intended_latency = LATENCY_USEC;
+ s->smoother = pa_smoother_new(PA_USEC_PER_SEC*5, PA_USEC_PER_SEC*2, TRUE, 10);
+ pa_smoother_set_time_offset(s->smoother, pa_timeval_load(&now));
+ s->last_rate_update = pa_timeval_load(&now);
+ pa_atomic_store(&s->timestamp, now.tv_sec);
if ((fd = mcast_socket((const struct sockaddr*) &sdp_info->sa, sdp_info->salen)) < 0)
goto fail;
- c = pa_sprintf_malloc("RTP Stream%s%s%s",
- sdp_info->session_name ? " (" : "",
- sdp_info->session_name ? sdp_info->session_name : "",
- sdp_info->session_name ? ")" : "");
-
pa_sink_input_new_data_init(&data);
data.sink = sink;
data.driver = __FILE__;
- data.name = c;
+ pa_proplist_sets(data.proplist, PA_PROP_MEDIA_ROLE, "stream");
+ pa_proplist_setf(data.proplist, PA_PROP_MEDIA_NAME,
+ "RTP Stream%s%s%s",
+ sdp_info->session_name ? " (" : "",
+ sdp_info->session_name ? sdp_info->session_name : "",
+ sdp_info->session_name ? ")" : "");
+
+ if (sdp_info->session_name)
+ pa_proplist_sets(data.proplist, "rtp.session", sdp_info->session_name);
+ pa_proplist_sets(data.proplist, "rtp.origin", sdp_info->origin);
+ pa_proplist_setf(data.proplist, "rtp.payload", "%u", (unsigned) sdp_info->payload);
data.module = u->module;
pa_sink_input_new_data_set_sample_spec(&data, &sdp_info->sample_spec);
-
- s->sink_input = pa_sink_input_new(u->core, &data, 0);
- pa_xfree(c);
-
+
+ s->sink_input = pa_sink_input_new(u->module->core, &data, 0);
+ pa_sink_input_new_data_done(&data);
+
if (!s->sink_input) {
- pa_log("failed to create sink input.");
+ pa_log("Failed to create sink input.");
goto fail;
}
s->sink_input->userdata = s;
- s->sink_input->peek = sink_input_peek;
- s->sink_input->drop = sink_input_drop;
+ s->sink_input->parent.process_msg = sink_input_process_msg;
+ s->sink_input->pop = sink_input_pop_cb;
+ s->sink_input->process_rewind = sink_input_process_rewind_cb;
+ s->sink_input->update_max_rewind = sink_input_update_max_rewind_cb;
s->sink_input->kill = sink_input_kill;
- s->sink_input->get_latency = sink_input_get_latency;
+ s->sink_input->attach = sink_input_attach;
+ s->sink_input->detach = sink_input_detach;
+
+ pa_sink_input_get_silence(s->sink_input, &silence);
+
+ s->sink_latency = pa_sink_input_set_requested_latency(s->sink_input, s->intended_latency/2);
+
+ if (s->intended_latency < s->sink_latency*2)
+ s->intended_latency = s->sink_latency*2;
- silence = pa_silence_memblock_new(s->userdata->core->mempool,
- &s->sink_input->sample_spec,
- (pa_bytes_per_second(&s->sink_input->sample_spec)/128/pa_frame_size(&s->sink_input->sample_spec))*
- pa_frame_size(&s->sink_input->sample_spec));
-
s->memblockq = pa_memblockq_new(
0,
MEMBLOCKQ_MAXLENGTH,
MEMBLOCKQ_MAXLENGTH,
pa_frame_size(&s->sink_input->sample_spec),
- pa_bytes_per_second(&s->sink_input->sample_spec)/10+1,
+ pa_usec_to_bytes(s->intended_latency - s->sink_latency, &s->sink_input->sample_spec),
+ 0,
0,
- silence);
+ &silence);
- pa_memblock_unref(silence);
+ pa_memblock_unref(silence.memblock);
- s->rtp_event = u->core->mainloop->io_new(u->core->mainloop, fd, PA_IO_EVENT_INPUT, rtp_event_cb, s);
-
- pa_gettimeofday(&tv);
- pa_timeval_add(&tv, DEATH_TIMEOUT);
- s->death_event = u->core->mainloop->time_new(u->core->mainloop, &tv, death_event_cb, s);
+ pa_rtp_context_init_recv(&s->rtp_context, fd, pa_frame_size(&s->sdp_info.sample_spec));
pa_hashmap_put(s->userdata->by_origin, s->sdp_info.origin, s);
+ u->n_sessions++;
+ PA_LLIST_PREPEND(struct session, s->userdata->sessions, s);
- pa_rtp_context_init_recv(&s->rtp_context, fd, pa_frame_size(&s->sdp_info.sample_spec));
+ pa_sink_input_put(s->sink_input);
- pa_log_info("Found new session '%s'", s->sdp_info.session_name);
+ pa_log_info("New session '%s'", s->sdp_info.session_name);
- u->n_sessions++;
-
return s;
fail:
- if (s) {
- if (fd >= 0)
- close(fd);
-
- pa_xfree(s);
- }
+ pa_xfree(s);
+
+ if (fd >= 0)
+ pa_close(fd);
return NULL;
}
-static void session_free(struct session *s, int from_hash) {
- assert(s);
+static void session_free(struct session *s) {
+ pa_assert(s);
pa_log_info("Freeing session '%s'", s->sdp_info.session_name);
- s->userdata->core->mainloop->time_free(s->death_event);
- s->userdata->core->mainloop->io_free(s->rtp_event);
-
- if (from_hash)
- pa_hashmap_remove(s->userdata->by_origin, s->sdp_info.origin);
-
- pa_sink_input_disconnect(s->sink_input);
+ pa_sink_input_unlink(s->sink_input);
pa_sink_input_unref(s->sink_input);
+ PA_LLIST_REMOVE(struct session, s->userdata->sessions, s);
+ pa_assert(s->userdata->n_sessions >= 1);
+ s->userdata->n_sessions--;
+ pa_hashmap_remove(s->userdata->by_origin, s->sdp_info.origin);
+
pa_memblockq_free(s->memblockq);
pa_sdp_info_destroy(&s->sdp_info);
pa_rtp_context_destroy(&s->rtp_context);
- assert(s->userdata->n_sessions >= 1);
- s->userdata->n_sessions--;
-
+ pa_smoother_free(s->smoother);
+
pa_xfree(s);
}
static void sap_event_cb(pa_mainloop_api *m, pa_io_event *e, int fd, pa_io_event_flags_t flags, void *userdata) {
struct userdata *u = userdata;
- int goodbye;
+ pa_bool_t goodbye = FALSE;
pa_sdp_info info;
struct session *s;
-
- assert(m);
- assert(e);
- assert(u);
- assert(fd == u->sap_context.fd);
- assert(flags == PA_IO_EVENT_INPUT);
+
+ pa_assert(m);
+ pa_assert(e);
+ pa_assert(u);
+ pa_assert(fd == u->sap_context.fd);
+ pa_assert(flags == PA_IO_EVENT_INPUT);
if (pa_sap_recv(&u->sap_context, &goodbye) < 0)
return;
@@ -400,7 +554,7 @@ static void sap_event_cb(pa_mainloop_api *m, pa_io_event *e, int fd, pa_io_event
if (goodbye) {
if ((s = pa_hashmap_get(u->by_origin, info.origin)))
- session_free(s, 1);
+ session_free(s);
pa_sdp_info_destroy(&info);
} else {
@@ -408,20 +562,49 @@ static void sap_event_cb(pa_mainloop_api *m, pa_io_event *e, int fd, pa_io_event
if (!(s = pa_hashmap_get(u->by_origin, info.origin))) {
if (!(s = session_new(u, &info)))
pa_sdp_info_destroy(&info);
-
+
} else {
- struct timeval tv;
-
- pa_gettimeofday(&tv);
- pa_timeval_add(&tv, DEATH_TIMEOUT);
- m->time_restart(s->death_event, &tv);
-
+ struct timeval now;
+ pa_rtclock_get(&now);
+ pa_atomic_store(&s->timestamp, now.tv_sec);
+
pa_sdp_info_destroy(&info);
}
}
}
-int pa__init(pa_core *c, pa_module*m) {
+static void check_death_event_cb(pa_mainloop_api *m, pa_time_event *t, const struct timeval *ptv, void *userdata) {
+ struct session *s, *n;
+ struct userdata *u = userdata;
+ struct timeval now;
+ struct timeval tv;
+
+ pa_assert(m);
+ pa_assert(t);
+ pa_assert(ptv);
+ pa_assert(u);
+
+ pa_rtclock_get(&now);
+
+ pa_log_debug("Checking for dead streams ...");
+
+ for (s = u->sessions; s; s = n) {
+ int k;
+ n = s->next;
+
+ k = pa_atomic_load(&s->timestamp);
+
+ if (k + DEATH_TIMEOUT < now.tv_sec)
+ session_free(s);
+ }
+
+ /* Restart timer */
+ pa_gettimeofday(&tv);
+ pa_timeval_add(&tv, DEATH_TIMEOUT*PA_USEC_PER_SEC);
+ m->time_restart(t, &tv);
+}
+
+int pa__init(pa_module*m) {
struct userdata *u;
pa_modargs *ma = NULL;
struct sockaddr_in sa4;
@@ -430,9 +613,9 @@ int pa__init(pa_core *c, pa_module*m) {
socklen_t salen;
const char *sap_address;
int fd = -1;
-
- assert(c);
- assert(m);
+ struct timeval tv;
+
+ pa_assert(m);
if (!(ma = pa_modargs_new(m->argument, valid_modargs))) {
pa_log("failed to parse module arguments");
@@ -440,7 +623,7 @@ int pa__init(pa_core *c, pa_module*m) {
}
sap_address = pa_modargs_get_value(ma, "sap_address", DEFAULT_SAP_ADDRESS);
-
+
if (inet_pton(AF_INET6, sap_address, &sa6.sin6_addr) > 0) {
sa6.sin6_family = AF_INET6;
sa6.sin6_port = htons(SAP_PORT);
@@ -452,7 +635,7 @@ int pa__init(pa_core *c, pa_module*m) {
sa = (struct sockaddr*) &sa4;
salen = sizeof(sa4);
} else {
- pa_log("invalid SAP address '%s'", sap_address);
+ pa_log("Invalid SAP address '%s'", sap_address);
goto fail;
}
@@ -462,16 +645,19 @@ int pa__init(pa_core *c, pa_module*m) {
u = pa_xnew(struct userdata, 1);
m->userdata = u;
u->module = m;
- u->core = c;
u->sink_name = pa_xstrdup(pa_modargs_get_value(ma, "sink", NULL));
- u->n_sessions = 0;
- u->sap_event = c->mainloop->io_new(c->mainloop, fd, PA_IO_EVENT_INPUT, sap_event_cb, u);
+ u->sap_event = m->core->mainloop->io_new(m->core->mainloop, fd, PA_IO_EVENT_INPUT, sap_event_cb, u);
+ pa_sap_context_init_recv(&u->sap_context, fd);
+ PA_LLIST_HEAD_INIT(struct session, u->sessions);
+ u->n_sessions = 0;
u->by_origin = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
-
- pa_sap_context_init_recv(&u->sap_context, fd);
-
+
+ pa_gettimeofday(&tv);
+ pa_timeval_add(&tv, DEATH_TIMEOUT * PA_USEC_PER_SEC);
+ u->check_death_event = m->core->mainloop->time_new(m->core->mainloop, &tv, check_death_event_cb, u);
+
pa_modargs_free(ma);
return 0;
@@ -481,28 +667,35 @@ fail:
pa_modargs_free(ma);
if (fd >= 0)
- close(fd);
-
- return -1;
-}
+ pa_close(fd);
-static void free_func(void *p, PA_GCC_UNUSED void *userdata) {
- session_free(p, 0);
+ return -1;
}
-void pa__done(pa_core *c, pa_module*m) {
+void pa__done(pa_module*m) {
struct userdata *u;
- assert(c);
- assert(m);
+ struct session *s;
+
+ pa_assert(m);
if (!(u = m->userdata))
return;
- c->mainloop->io_free(u->sap_event);
+ if (u->sap_event)
+ m->core->mainloop->io_free(u->sap_event);
+
+ if (u->check_death_event)
+ m->core->mainloop->time_free(u->check_death_event);
+
pa_sap_context_destroy(&u->sap_context);
- pa_hashmap_free(u->by_origin, free_func, NULL);
-
+ if (u->by_origin) {
+ while ((s = pa_hashmap_get_first(u->by_origin)))
+ session_free(s);
+
+ pa_hashmap_free(u->by_origin, NULL, NULL);
+ }
+
pa_xfree(u->sink_name);
pa_xfree(u);
}
diff --git a/src/modules/rtp/module-rtp-send.c b/src/modules/rtp/module-rtp-send.c
index 7bbfabee..d0d06c4d 100644
--- a/src/modules/rtp/module-rtp-send.c
+++ b/src/modules/rtp/module-rtp-send.c
@@ -1,18 +1,18 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
-
+
+ Copyright 2006 Lennart Poettering
+
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
@@ -23,7 +23,6 @@
#include <config.h>
#endif
-#include <assert.h>
#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
@@ -46,6 +45,9 @@
#include <pulsecore/core-util.h>
#include <pulsecore/modargs.h>
#include <pulsecore/namereg.h>
+#include <pulsecore/sample-util.h>
+#include <pulsecore/macro.h>
+#include <pulsecore/socket-util.h>
#include "module-rtp-send-symdef.h"
@@ -53,9 +55,10 @@
#include "sdp.h"
#include "sap.h"
-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)
+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);
+PA_MODULE_LOAD_ONCE(FALSE);
PA_MODULE_USAGE(
"source=<name of the source> "
"format=<sample format> "
@@ -65,14 +68,14 @@ PA_MODULE_USAGE(
"port=<port number> "
"mtu=<maximum transfer unit> "
"loop=<loopback to local host?>"
-)
+);
#define DEFAULT_PORT 46000
#define SAP_PORT 9875
#define DEFAULT_DESTINATION "224.0.0.56"
#define MEMBLOCKQ_MAXLENGTH (1024*170)
#define DEFAULT_MTU 1280
-#define SAP_INTERVAL 5000000
+#define SAP_INTERVAL 5
static const char* const valid_modargs[] = {
"source",
@@ -88,7 +91,6 @@ static const char* const valid_modargs[] = {
struct userdata {
pa_module *module;
- pa_core *core;
pa_source_output *source_output;
pa_memblockq *memblockq;
@@ -100,56 +102,67 @@ struct userdata {
pa_time_event *sap_event;
};
+/* 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 */
static void source_output_push(pa_source_output *o, const pa_memchunk *chunk) {
struct userdata *u;
- assert(o);
- u = o->userdata;
+ pa_source_output_assert_ref(o);
+ pa_assert_se(u = o->userdata);
if (pa_memblockq_push(u->memblockq, chunk) < 0) {
- pa_log("Failed to push chunk into memblockq.");
+ pa_log_warn("Failed to push chunk into memblockq.");
return;
}
-
+
pa_rtp_send(&u->rtp_context, u->mtu, u->memblockq);
}
+/* Called from main context */
static void source_output_kill(pa_source_output* o) {
struct userdata *u;
- assert(o);
- u = o->userdata;
+ pa_source_output_assert_ref(o);
+ pa_assert_se(u = o->userdata);
pa_module_unload_request(u->module);
- pa_source_output_disconnect(u->source_output);
+ pa_source_output_unlink(u->source_output);
pa_source_output_unref(u->source_output);
u->source_output = NULL;
}
-static pa_usec_t source_output_get_latency (pa_source_output *o) {
- struct userdata *u;
- assert(o);
- u = o->userdata;
-
- return pa_bytes_to_usec(pa_memblockq_get_length(u->memblockq), &o->sample_spec);
-}
-
static void sap_event_cb(pa_mainloop_api *m, pa_time_event *t, const struct timeval *tv, void *userdata) {
struct userdata *u = userdata;
struct timeval next;
-
- assert(m);
- assert(t);
- assert(tv);
- assert(u);
+
+ pa_assert(m);
+ pa_assert(t);
+ pa_assert(tv);
+ pa_assert(u);
pa_sap_send(&u->sap_context, 0);
pa_gettimeofday(&next);
- pa_timeval_add(&next, SAP_INTERVAL);
+ pa_timeval_add(&next, SAP_INTERVAL * PA_USEC_PER_SEC);
m->time_restart(t, &next);
}
-int pa__init(pa_core *c, pa_module*m) {
+int pa__init(pa_module*m) {
struct userdata *u;
pa_modargs *ma = NULL;
const char *dest;
@@ -164,28 +177,27 @@ int pa__init(pa_core *c, pa_module*m) {
pa_source_output *o = NULL;
uint8_t payload;
char *p;
- int r;
+ int r, j;
socklen_t k;
struct timeval tv;
char hn[128], *n;
- int loop = 0;
+ pa_bool_t loop = FALSE;
pa_source_output_new_data data;
-
- assert(c);
- assert(m);
+
+ pa_assert(m);
if (!(ma = pa_modargs_new(m->argument, valid_modargs))) {
- pa_log("failed to parse module arguments");
+ 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, 1))) {
- pa_log("source does not exist.");
+ 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.");
+ pa_log("Failed to parse \"loop\" parameter.");
goto fail;
}
@@ -193,12 +205,12 @@ int pa__init(pa_core *c, pa_module*m) {
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");
+ 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");
+ pa_log("Specified sample type not compatible with RTP");
goto fail;
}
@@ -207,10 +219,10 @@ int pa__init(pa_core *c, pa_module*m) {
payload = pa_rtp_payload_from_sample_spec(&ss);
- mtu = (DEFAULT_MTU/pa_frame_size(&ss))*pa_frame_size(&ss);
-
+ mtu = 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.");
+ pa_log("Invalid MTU.");
goto fail;
}
@@ -221,7 +233,7 @@ int pa__init(pa_core *c, pa_module*m) {
}
if (port & 1)
- pa_log_warn("WARNING: port number not even as suggested in RFC3550!");
+ pa_log_warn("Port number not even as suggested in RFC3550!");
dest = pa_modargs_get_value(ma, "destination", DEFAULT_DESTINATION);
@@ -236,10 +248,10 @@ int pa__init(pa_core *c, pa_module*m) {
sap_sa4 = sa4;
sap_sa4.sin_port = htons(SAP_PORT);
} else {
- pa_log("invalid destination '%s'", dest);
+ pa_log("Invalid destination '%s'", dest);
goto fail;
}
-
+
if ((fd = socket(af, SOCK_DGRAM, 0)) < 0) {
pa_log("socket() failed: %s", pa_cstrerror(errno));
goto fail;
@@ -260,37 +272,49 @@ int pa__init(pa_core *c, pa_module*m) {
goto fail;
}
- if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP, &loop, sizeof(loop)) < 0 ||
- setsockopt(sap_fd, IPPROTO_IP, IP_MULTICAST_LOOP, &loop, sizeof(loop)) < 0) {
+ 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 the socket queue is full, let's drop packets */
+ pa_make_fd_nonblock(fd);
+ pa_make_udp_socket_low_delay(fd);
+ pa_make_fd_cloexec(fd);
+ pa_make_fd_cloexec(sap_fd);
+
pa_source_output_new_data_init(&data);
- data.name = "RTP Monitor Stream";
+ pa_proplist_sets(data.proplist, PA_PROP_MEDIA_NAME, "RTP Monitor Stream");
+ pa_proplist_sets(data.proplist, "rtp.destination", dest);
+ pa_proplist_setf(data.proplist, "rtp.mtu", "%lu", (unsigned long) mtu);
+ pa_proplist_setf(data.proplist, "rtp.port", "%lu", (unsigned long) port);
data.driver = __FILE__;
data.module = m;
data.source = s;
pa_source_output_new_data_set_sample_spec(&data, &ss);
pa_source_output_new_data_set_channel_map(&data, &cm);
-
- if (!(o = pa_source_output_new(c, &data, 0))) {
+
+ o = pa_source_output_new(m->core, &data, 0);
+ 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;
o->kill = source_output_kill;
- o->get_latency = source_output_get_latency;
-
+
u = pa_xnew(struct userdata, 1);
m->userdata = u;
o->userdata = u;
u->module = m;
- u->core = c;
u->source_output = o;
-
+
u->memblockq = pa_memblockq_new(
0,
MEMBLOCKQ_MAXLENGTH,
@@ -298,34 +322,36 @@ int pa__init(pa_core *c, pa_module*m) {
pa_frame_size(&ss),
1,
0,
+ 0,
NULL);
u->mtu = mtu;
-
+
k = sizeof(sa_dst);
- r = getsockname(fd, (struct sockaddr*) &sa_dst, &k);
- assert(r >= 0);
+ pa_assert_se((r = getsockname(fd, (struct sockaddr*) &sa_dst, &k)) >= 0);
n = pa_sprintf_malloc("PulseAudio RTP Stream on %s", pa_get_fqdn(hn, sizeof(hn)));
-
+
p = pa_sdp_build(af,
af == AF_INET ? (void*) &((struct sockaddr_in*) &sa_dst)->sin_addr : (void*) &((struct sockaddr_in6*) &sa_dst)->sin6_addr,
af == AF_INET ? (void*) &sa4.sin_addr : (void*) &sa6.sin6_addr,
n, port, payload, &ss);
pa_xfree(n);
-
- pa_rtp_context_init_send(&u->rtp_context, fd, c->cookie, payload, pa_frame_size(&ss));
+
+ 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, SSRC=0x%08x, payload=%u, initial sequence #%u", mtu, dest, port, u->rtp_context.ssrc, payload, u->rtp_context.sequence);
- pa_log_info("SDP-Data:\n%s\n"__FILE__": EOF", p);
+ pa_log_info("SDP-Data:\n%s\nEOF", p);
pa_sap_send(&u->sap_context, 0);
pa_gettimeofday(&tv);
- pa_timeval_add(&tv, SAP_INTERVAL);
- u->sap_event = c->mainloop->time_new(c->mainloop, &tv, sap_event_cb, u);
+ pa_timeval_add(&tv, SAP_INTERVAL * PA_USEC_PER_SEC);
+ u->sap_event = m->core->mainloop->time_new(m->core->mainloop, &tv, sap_event_cb, u);
+
+ pa_source_output_put(u->source_output);
pa_modargs_free(ma);
@@ -336,31 +362,31 @@ fail:
pa_modargs_free(ma);
if (fd >= 0)
- close(fd);
-
+ pa_close(fd);
+
if (sap_fd >= 0)
- close(sap_fd);
+ pa_close(sap_fd);
if (o) {
- pa_source_output_disconnect(o);
+ pa_source_output_unlink(o);
pa_source_output_unref(o);
}
-
+
return -1;
}
-void pa__done(pa_core *c, pa_module*m) {
+void pa__done(pa_module*m) {
struct userdata *u;
- assert(c);
- assert(m);
+ pa_assert(m);
if (!(u = m->userdata))
return;
- c->mainloop->time_free(u->sap_event);
-
+ if (u->sap_event)
+ m->core->mainloop->time_free(u->sap_event);
+
if (u->source_output) {
- pa_source_output_disconnect(u->source_output);
+ pa_source_output_unlink(u->source_output);
pa_source_output_unref(u->source_output);
}
@@ -369,7 +395,8 @@ void pa__done(pa_core *c, pa_module*m) {
pa_sap_send(&u->sap_context, 1);
pa_sap_context_destroy(&u->sap_context);
- pa_memblockq_free(u->memblockq);
-
+ if (u->memblockq)
+ pa_memblockq_free(u->memblockq);
+
pa_xfree(u);
}
diff --git a/src/modules/rtp/rtp.c b/src/modules/rtp/rtp.c
index a4362f84..5a33ebc2 100644
--- a/src/modules/rtp/rtp.c
+++ b/src/modules/rtp/rtp.c
@@ -1,18 +1,18 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
-
+
+ Copyright 2006 Lennart Poettering
+
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
@@ -23,7 +23,6 @@
#include <config.h>
#endif
-#include <assert.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
@@ -38,12 +37,14 @@
#include <pulsecore/core-error.h>
#include <pulsecore/log.h>
+#include <pulsecore/macro.h>
+#include <pulsecore/core-util.h>
#include "rtp.h"
pa_rtp_context* pa_rtp_context_init_send(pa_rtp_context *c, int fd, uint32_t ssrc, uint8_t payload, size_t frame_size) {
- assert(c);
- assert(fd >= 0);
+ pa_assert(c);
+ pa_assert(fd >= 0);
c->fd = fd;
c->sequence = (uint16_t) (rand()*rand());
@@ -51,7 +52,9 @@ pa_rtp_context* pa_rtp_context_init_send(pa_rtp_context *c, int fd, uint32_t ssr
c->ssrc = ssrc ? ssrc : (uint32_t) (rand()*rand());
c->payload = payload & 127;
c->frame_size = frame_size;
-
+
+ pa_memchunk_reset(&c->memchunk);
+
return c;
}
@@ -61,37 +64,39 @@ int pa_rtp_send(pa_rtp_context *c, size_t size, pa_memblockq *q) {
struct iovec iov[MAX_IOVECS];
pa_memblock* mb[MAX_IOVECS];
int iov_idx = 1;
- size_t n = 0, skip = 0;
-
- assert(c);
- assert(size > 0);
- assert(q);
+ size_t n = 0;
+
+ pa_assert(c);
+ pa_assert(size > 0);
+ pa_assert(q);
if (pa_memblockq_get_length(q) < size)
return 0;
-
+
for (;;) {
int r;
pa_memchunk chunk;
+ pa_memchunk_reset(&chunk);
+
if ((r = pa_memblockq_peek(q, &chunk)) >= 0) {
size_t k = n + chunk.length > size ? size - n : chunk.length;
- if (chunk.memblock) {
- iov[iov_idx].iov_base = (void*)((uint8_t*) pa_memblock_acquire(chunk.memblock) + chunk.index);
- iov[iov_idx].iov_len = k;
- mb[iov_idx] = chunk.memblock;
- iov_idx ++;
+ pa_assert(chunk.memblock);
- n += k;
- }
+ iov[iov_idx].iov_base = ((uint8_t*) pa_memblock_acquire(chunk.memblock) + chunk.index);
+ iov[iov_idx].iov_len = k;
+ mb[iov_idx] = chunk.memblock;
+ iov_idx ++;
- skip += k;
- pa_memblockq_drop(q, &chunk, k);
+ n += k;
+ pa_memblockq_drop(q, k);
}
- if (r < 0 || !chunk.memblock || n >= size || iov_idx >= MAX_IOVECS) {
+ pa_assert(n % c->frame_size == 0);
+
+ if (r < 0 || n >= size || iov_idx >= MAX_IOVECS) {
uint32_t header[3];
struct msghdr m;
int k, i;
@@ -103,7 +108,7 @@ int pa_rtp_send(pa_rtp_context *c, size_t size, pa_memblockq *q) {
iov[0].iov_base = (void*)header;
iov[0].iov_len = sizeof(header);
-
+
m.msg_name = NULL;
m.msg_namelen = 0;
m.msg_iov = iov;
@@ -111,7 +116,7 @@ int pa_rtp_send(pa_rtp_context *c, size_t size, pa_memblockq *q) {
m.msg_control = NULL;
m.msg_controllen = 0;
m.msg_flags = 0;
-
+
k = sendmsg(c->fd, &m, MSG_DONTWAIT);
for (i = 1; i < iov_idx; i++) {
@@ -123,19 +128,18 @@ int pa_rtp_send(pa_rtp_context *c, size_t size, pa_memblockq *q) {
} else
k = 0;
- c->timestamp += skip/c->frame_size;
-
+ c->timestamp += n/c->frame_size;
+
if (k < 0) {
- if (errno != EAGAIN) /* If the queue is full, just ignore it */
+ if (errno != EAGAIN && errno != EINTR) /* If the queue is full, just ignore it */
pa_log("sendmsg() failed: %s", pa_cstrerror(errno));
return -1;
}
-
+
if (r < 0 || pa_memblockq_get_length(q) < size)
break;
n = 0;
- skip = 0;
iov_idx = 1;
}
}
@@ -144,10 +148,12 @@ int pa_rtp_send(pa_rtp_context *c, size_t size, pa_memblockq *q) {
}
pa_rtp_context* pa_rtp_context_init_recv(pa_rtp_context *c, int fd, size_t frame_size) {
- assert(c);
+ pa_assert(c);
c->fd = fd;
c->frame_size = frame_size;
+
+ pa_memchunk_reset(&c->memchunk);
return c;
}
@@ -158,23 +164,39 @@ int pa_rtp_recv(pa_rtp_context *c, pa_memchunk *chunk, pa_mempool *pool) {
uint32_t header;
int cc;
ssize_t r;
-
- assert(c);
- assert(chunk);
- chunk->memblock = NULL;
+ pa_assert(c);
+ pa_assert(chunk);
+
+ pa_memchunk_reset(chunk);
if (ioctl(c->fd, FIONREAD, &size) < 0) {
- pa_log("FIONREAD failed: %s", pa_cstrerror(errno));
+ pa_log_warn("FIONREAD failed: %s", pa_cstrerror(errno));
goto fail;
}
- if (!size)
+ if (size <= 0)
return 0;
- chunk->memblock = pa_memblock_new(pool, size);
+ if (c->memchunk.length < (unsigned) size) {
+ size_t l;
+
+ if (c->memchunk.memblock)
+ pa_memblock_unref(c->memchunk.memblock);
- iov.iov_base = pa_memblock_acquire(chunk->memblock);
+ l = PA_MAX((size_t) size, pa_mempool_block_size_max(pool));
+
+ c->memchunk.memblock = pa_memblock_new(pool, l);
+ c->memchunk.index = 0;
+ c->memchunk.length = pa_memblock_get_length(c->memchunk.memblock);
+ }
+
+ pa_assert(c->memchunk.length >= (size_t) size);
+
+ chunk->memblock = pa_memblock_ref(c->memchunk.memblock);
+ chunk->index = c->memchunk.index;
+
+ iov.iov_base = (uint8_t*) pa_memblock_acquire(chunk->memblock) + chunk->index;
iov.iov_len = size;
m.msg_name = NULL;
@@ -184,37 +206,42 @@ int pa_rtp_recv(pa_rtp_context *c, pa_memchunk *chunk, pa_mempool *pool) {
m.msg_control = NULL;
m.msg_controllen = 0;
m.msg_flags = 0;
-
- if ((r = recvmsg(c->fd, &m, 0)) != size) {
- pa_log("recvmsg() failed: %s", r < 0 ? pa_cstrerror(errno) : "size mismatch");
+
+ r = recvmsg(c->fd, &m, 0);
+ pa_memblock_release(chunk->memblock);
+
+ if (r != size) {
+ if (r < 0 && errno != EAGAIN && errno != EINTR)
+ pa_log_warn("recvmsg() failed: %s", r < 0 ? pa_cstrerror(errno) : "size mismatch");
+
goto fail;
}
if (size < 12) {
- pa_log("RTP packet too short.");
+ pa_log_warn("RTP packet too short.");
goto fail;
}
memcpy(&header, iov.iov_base, sizeof(uint32_t));
memcpy(&c->timestamp, (uint8_t*) iov.iov_base + 4, sizeof(uint32_t));
memcpy(&c->ssrc, (uint8_t*) iov.iov_base + 8, sizeof(uint32_t));
-
+
header = ntohl(header);
c->timestamp = ntohl(c->timestamp);
c->ssrc = ntohl(c->ssrc);
if ((header >> 30) != 2) {
- pa_log("Unsupported RTP version.");
+ pa_log_warn("Unsupported RTP version.");
goto fail;
}
if ((header >> 29) & 1) {
- pa_log("RTP padding not supported.");
+ pa_log_warn("RTP padding not supported.");
goto fail;
}
if ((header >> 28) & 1) {
- pa_log("RTP header extensions not supported.");
+ pa_log_warn("RTP header extensions not supported.");
goto fail;
}
@@ -223,31 +250,37 @@ int pa_rtp_recv(pa_rtp_context *c, pa_memchunk *chunk, pa_mempool *pool) {
c->sequence = header & 0xFFFF;
if (12 + cc*4 > size) {
- pa_log("RTP packet too short. (CSRC)");
+ pa_log_warn("RTP packet too short. (CSRC)");
goto fail;
}
- chunk->index = 12 + cc*4;
- chunk->length = size - chunk->index;
+ chunk->index += 12 + cc*4;
+ chunk->length = size - 12 + cc*4;
if (chunk->length % c->frame_size != 0) {
- pa_log("Vad RTP packet size.");
+ pa_log_warn("Bad RTP packet size.");
goto fail;
}
-
+
+ c->memchunk.index = chunk->index + chunk->length;
+ c->memchunk.length = pa_memblock_get_length(c->memchunk.memblock) - c->memchunk.index;
+
+ if (c->memchunk.length <= 0) {
+ pa_memblock_unref(c->memchunk.memblock);
+ pa_memchunk_reset(&c->memchunk);
+ }
+
return 0;
fail:
- if (chunk->memblock) {
- pa_memblock_release(chunk->memblock);
+ if (chunk->memblock)
pa_memblock_unref(chunk->memblock);
- }
return -1;
}
uint8_t pa_rtp_payload_from_sample_spec(const pa_sample_spec *ss) {
- assert(ss);
+ pa_assert(ss);
if (ss->format == PA_SAMPLE_ULAW && ss->rate == 8000 && ss->channels == 1)
return 0;
@@ -257,12 +290,12 @@ uint8_t pa_rtp_payload_from_sample_spec(const pa_sample_spec *ss) {
return 10;
if (ss->format == PA_SAMPLE_S16BE && ss->rate == 44100 && ss->channels == 1)
return 11;
-
+
return 127;
}
pa_sample_spec *pa_rtp_sample_spec_from_payload(uint8_t payload, pa_sample_spec *ss) {
- assert(ss);
+ pa_assert(ss);
switch (payload) {
case 0:
@@ -282,7 +315,7 @@ pa_sample_spec *pa_rtp_sample_spec_from_payload(uint8_t payload, pa_sample_spec
ss->format = PA_SAMPLE_S16BE;
ss->rate = 44100;
break;
-
+
case 11:
ss->channels = 1;
ss->format = PA_SAMPLE_S16BE;
@@ -297,17 +330,17 @@ pa_sample_spec *pa_rtp_sample_spec_from_payload(uint8_t payload, pa_sample_spec
}
pa_sample_spec *pa_rtp_sample_spec_fixup(pa_sample_spec * ss) {
- assert(ss);
+ pa_assert(ss);
if (!pa_rtp_sample_spec_valid(ss))
ss->format = PA_SAMPLE_S16BE;
- assert(pa_rtp_sample_spec_valid(ss));
+ pa_assert(pa_rtp_sample_spec_valid(ss));
return ss;
}
int pa_rtp_sample_spec_valid(const pa_sample_spec *ss) {
- assert(ss);
+ pa_assert(ss);
if (!pa_sample_spec_valid(ss))
return 0;
@@ -320,9 +353,12 @@ int pa_rtp_sample_spec_valid(const pa_sample_spec *ss) {
}
void pa_rtp_context_destroy(pa_rtp_context *c) {
- assert(c);
+ pa_assert(c);
+
+ pa_assert_se(pa_close(c->fd) == 0);
- close(c->fd);
+ if (c->memchunk.memblock)
+ pa_memblock_unref(c->memchunk.memblock);
}
const char* pa_rtp_format_to_string(pa_sample_format_t f) {
@@ -341,8 +377,8 @@ const char* pa_rtp_format_to_string(pa_sample_format_t f) {
}
pa_sample_format_t pa_rtp_string_to_format(const char *s) {
- assert(s);
-
+ pa_assert(s);
+
if (!(strcmp(s, "L16")))
return PA_SAMPLE_S16BE;
else if (!strcmp(s, "L8"))
@@ -354,4 +390,3 @@ pa_sample_format_t pa_rtp_string_to_format(const char *s) {
else
return PA_SAMPLE_INVALID;
}
-
diff --git a/src/modules/rtp/rtp.h b/src/modules/rtp/rtp.h
index 123602b2..a2728f05 100644
--- a/src/modules/rtp/rtp.h
+++ b/src/modules/rtp/rtp.h
@@ -1,21 +1,21 @@
#ifndef foortphfoo
#define foortphfoo
-/* $Id$ */
-
/***
This file is part of PulseAudio.
-
+
+ Copyright 2006 Lennart Poettering
+
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
@@ -35,6 +35,8 @@ typedef struct pa_rtp_context {
uint32_t ssrc;
uint8_t payload;
size_t frame_size;
+
+ pa_memchunk memchunk;
} pa_rtp_context;
pa_rtp_context* pa_rtp_context_init_send(pa_rtp_context *c, int fd, uint32_t ssrc, uint8_t payload, size_t frame_size);
diff --git a/src/modules/rtp/sap.c b/src/modules/rtp/sap.c
index 022c7fa3..5d9b58fa 100644
--- a/src/modules/rtp/sap.c
+++ b/src/modules/rtp/sap.c
@@ -1,18 +1,18 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
-
+
+ Copyright 2006 Lennart Poettering
+
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
@@ -23,7 +23,6 @@
#include <config.h>
#endif
-#include <assert.h>
#include <time.h>
#include <stdlib.h>
#include <sys/types.h>
@@ -44,6 +43,7 @@
#include <pulsecore/core-error.h>
#include <pulsecore/core-util.h>
#include <pulsecore/log.h>
+#include <pulsecore/macro.h>
#include "sap.h"
#include "sdp.h"
@@ -51,25 +51,25 @@
#define MIME_TYPE "application/sdp"
pa_sap_context* pa_sap_context_init_send(pa_sap_context *c, int fd, char *sdp_data) {
- assert(c);
- assert(fd >= 0);
- assert(sdp_data);
+ pa_assert(c);
+ pa_assert(fd >= 0);
+ pa_assert(sdp_data);
c->fd = fd;
c->sdp_data = sdp_data;
c->msg_id_hash = (uint16_t) (rand()*rand());
-
- return c;
+
+ return c;
}
void pa_sap_context_destroy(pa_sap_context *c) {
- assert(c);
+ pa_assert(c);
- close(c->fd);
+ pa_close(c->fd);
pa_xfree(c->sdp_data);
}
-int pa_sap_send(pa_sap_context *c, int goodbye) {
+int pa_sap_send(pa_sap_context *c, pa_bool_t goodbye) {
uint32_t header;
struct sockaddr_storage sa_buf;
struct sockaddr *sa = (struct sockaddr*) &sa_buf;
@@ -83,8 +83,8 @@ int pa_sap_send(pa_sap_context *c, int goodbye) {
return -1;
}
- assert(sa->sa_family == AF_INET || sa->sa_family == AF_INET6);
-
+ pa_assert(sa->sa_family == AF_INET || sa->sa_family == AF_INET6);
+
header = htonl(((uint32_t) 1 << 29) |
(sa->sa_family == AF_INET6 ? (uint32_t) 1 << 28 : 0) |
(goodbye ? (uint32_t) 1 << 26 : 0) |
@@ -101,7 +101,7 @@ int pa_sap_send(pa_sap_context *c, int goodbye) {
iov[3].iov_base = c->sdp_data;
iov[3].iov_len = strlen(c->sdp_data);
-
+
m.msg_name = NULL;
m.msg_namelen = 0;
m.msg_iov = iov;
@@ -109,23 +109,23 @@ int pa_sap_send(pa_sap_context *c, int goodbye) {
m.msg_control = NULL;
m.msg_controllen = 0;
m.msg_flags = 0;
-
+
if ((k = sendmsg(c->fd, &m, MSG_DONTWAIT)) < 0)
- pa_log("sendmsg() failed: %s\n", pa_cstrerror(errno));
+ pa_log_warn("sendmsg() failed: %s\n", pa_cstrerror(errno));
return k;
}
pa_sap_context* pa_sap_context_init_recv(pa_sap_context *c, int fd) {
- assert(c);
- assert(fd >= 0);
+ pa_assert(c);
+ pa_assert(fd >= 0);
c->fd = fd;
c->sdp_data = NULL;
return c;
}
-int pa_sap_recv(pa_sap_context *c, int *goodbye) {
+int pa_sap_recv(pa_sap_context *c, pa_bool_t *goodbye) {
struct msghdr m;
struct iovec iov;
int size, k;
@@ -133,21 +133,18 @@ int pa_sap_recv(pa_sap_context *c, int *goodbye) {
uint32_t header;
int six, ac;
ssize_t r;
-
- assert(c);
- assert(goodbye);
+
+ pa_assert(c);
+ pa_assert(goodbye);
if (ioctl(c->fd, FIONREAD, &size) < 0) {
- pa_log("FIONREAD failed: %s", pa_cstrerror(errno));
+ pa_log_warn("FIONREAD failed: %s", pa_cstrerror(errno));
goto fail;
}
- if (!size)
- return 0;
-
buf = pa_xnew(char, size+1);
buf[size] = 0;
-
+
iov.iov_base = buf;
iov.iov_len = size;
@@ -158,14 +155,14 @@ int pa_sap_recv(pa_sap_context *c, int *goodbye) {
m.msg_control = NULL;
m.msg_controllen = 0;
m.msg_flags = 0;
-
+
if ((r = recvmsg(c->fd, &m, 0)) != size) {
- pa_log("recvmsg() failed: %s", r < 0 ? pa_cstrerror(errno) : "size mismatch");
+ pa_log_warn("recvmsg() failed: %s", r < 0 ? pa_cstrerror(errno) : "size mismatch");
goto fail;
}
if (size < 4) {
- pa_log("SAP packet too short.");
+ pa_log_warn("SAP packet too short.");
goto fail;
}
@@ -173,17 +170,17 @@ int pa_sap_recv(pa_sap_context *c, int *goodbye) {
header = ntohl(header);
if (header >> 29 != 1) {
- pa_log("Unsupported SAP version.");
+ pa_log_warn("Unsupported SAP version.");
goto fail;
}
if ((header >> 25) & 1) {
- pa_log("Encrypted SAP not supported.");
+ pa_log_warn("Encrypted SAP not supported.");
goto fail;
}
if ((header >> 24) & 1) {
- pa_log("Compressed SAP not supported.");
+ pa_log_warn("Compressed SAP not supported.");
goto fail;
}
@@ -192,7 +189,7 @@ int pa_sap_recv(pa_sap_context *c, int *goodbye) {
k = 4 + (six ? 16 : 4) + ac*4;
if (size < k) {
- pa_log("SAP packet too short (AD).");
+ pa_log_warn("SAP packet too short (AD).");
goto fail;
}
@@ -203,18 +200,18 @@ int pa_sap_recv(pa_sap_context *c, int *goodbye) {
e += sizeof(MIME_TYPE);
size -= sizeof(MIME_TYPE);
} else if ((unsigned) size < sizeof(PA_SDP_HEADER)-1 || strncmp(e, PA_SDP_HEADER, sizeof(PA_SDP_HEADER)-1)) {
- pa_log("Invalid SDP header.");
+ pa_log_warn("Invalid SDP header.");
goto fail;
}
if (c->sdp_data)
pa_xfree(c->sdp_data);
-
+
c->sdp_data = pa_xstrndup(e, size);
pa_xfree(buf);
-
+
*goodbye = !!((header >> 26) & 1);
-
+
return 0;
fail:
diff --git a/src/modules/rtp/sap.h b/src/modules/rtp/sap.h
index 987403e3..69c757cb 100644
--- a/src/modules/rtp/sap.h
+++ b/src/modules/rtp/sap.h
@@ -1,21 +1,21 @@
#ifndef foosaphfoo
#define foosaphfoo
-/* $Id$ */
-
/***
This file is part of PulseAudio.
-
+
+ Copyright 2006 Lennart Poettering
+
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
@@ -38,9 +38,9 @@ typedef struct pa_sap_context {
pa_sap_context* pa_sap_context_init_send(pa_sap_context *c, int fd, char *sdp_data);
void pa_sap_context_destroy(pa_sap_context *c);
-int pa_sap_send(pa_sap_context *c, int goodbye);
+int pa_sap_send(pa_sap_context *c, pa_bool_t goodbye);
pa_sap_context* pa_sap_context_init_recv(pa_sap_context *c, int fd);
-int pa_sap_recv(pa_sap_context *c, int *goodbye);
+int pa_sap_recv(pa_sap_context *c, pa_bool_t *goodbye);
#endif
diff --git a/src/modules/rtp/sdp.c b/src/modules/rtp/sdp.c
index 1b71a9a0..cef90433 100644
--- a/src/modules/rtp/sdp.c
+++ b/src/modules/rtp/sdp.c
@@ -1,18 +1,18 @@
-/* $Id$ */
-
/***
This file is part of PulseAudio.
-
+
+ Copyright 2006 Lennart Poettering
+
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
@@ -23,7 +23,6 @@
#include <config.h>
#endif
-#include <assert.h>
#include <time.h>
#include <stdlib.h>
#include <sys/types.h>
@@ -33,37 +32,34 @@
#include <string.h>
#include <pulse/xmalloc.h>
+#include <pulse/util.h>
#include <pulsecore/core-util.h>
#include <pulsecore/log.h>
+#include <pulsecore/macro.h>
#include "sdp.h"
#include "rtp.h"
-
char *pa_sdp_build(int af, const void *src, const void *dst, const char *name, uint16_t port, uint8_t payload, const pa_sample_spec *ss) {
uint32_t ntp;
- char buf_src[64], buf_dst[64];
+ char buf_src[64], buf_dst[64], un[64];
const char *u, *f, *a;
- assert(src);
- assert(dst);
- assert(af == AF_INET || af == AF_INET6);
-
- f = pa_rtp_format_to_string(ss->format);
- assert(f);
-
- if (!(u = getenv("USER")))
- if (!(u = getenv("USERNAME")))
- u = "-";
-
+ pa_assert(src);
+ pa_assert(dst);
+ pa_assert(af == AF_INET || af == AF_INET6);
+
+ pa_assert_se(f = pa_rtp_format_to_string(ss->format));
+
+ if (!(u = pa_get_user_name(un, sizeof(un))))
+ u = "-";
+
ntp = time(NULL) + 2208988800U;
- a = inet_ntop(af, src, buf_src, sizeof(buf_src));
- assert(a);
- a = inet_ntop(af, dst, buf_dst, sizeof(buf_dst));
- assert(a);
-
+ pa_assert_se(a = inet_ntop(af, src, buf_src, sizeof(buf_src)));
+ pa_assert_se(a = inet_ntop(af, dst, buf_dst, sizeof(buf_dst)));
+
return pa_sprintf_malloc(
PA_SDP_HEADER
"o=%s %lu 0 IN %s %s\n"
@@ -84,8 +80,8 @@ char *pa_sdp_build(int af, const void *src, const void *dst, const char *name, u
static pa_sample_spec *parse_sdp_sample_spec(pa_sample_spec *ss, char *c) {
unsigned rate, channels;
- assert(ss);
- assert(c);
+ pa_assert(ss);
+ pa_assert(c);
if (pa_startswith(c, "L16/")) {
ss->format = PA_SAMPLE_S16BE;
@@ -119,15 +115,15 @@ static pa_sample_spec *parse_sdp_sample_spec(pa_sample_spec *ss, char *c) {
pa_sdp_info *pa_sdp_parse(const char *t, pa_sdp_info *i, int is_goodbye) {
uint16_t port = 0;
- int ss_valid = 0;
+ pa_bool_t ss_valid = FALSE;
+
+ pa_assert(t);
+ pa_assert(i);
- assert(t);
- assert(i);
-
i->origin = i->session_name = NULL;
i->salen = 0;
i->payload = 255;
-
+
if (!pa_startswith(t, PA_SDP_HEADER)) {
pa_log("Failed to parse SDP data: invalid header.");
goto fail;
@@ -154,7 +150,7 @@ pa_sdp_info *pa_sdp_parse(const char *t, pa_sdp_info *i, int is_goodbye) {
size_t k;
k = l-8 > sizeof(a) ? sizeof(a) : l-8;
-
+
pa_strlcpy(a, t+9, k);
a[strcspn(a, "/")] = 0;
@@ -171,7 +167,7 @@ pa_sdp_info *pa_sdp_parse(const char *t, pa_sdp_info *i, int is_goodbye) {
size_t k;
k = l-8 > sizeof(a) ? sizeof(a) : l-8;
-
+
pa_strlcpy(a, t+9, k);
a[strcspn(a, "/")] = 0;
@@ -187,7 +183,7 @@ pa_sdp_info *pa_sdp_parse(const char *t, pa_sdp_info *i, int is_goodbye) {
if (i->payload > 127) {
int _port, _payload;
-
+
if (sscanf(t+8, "%i RTP/AVP %i", &_port, &_payload) == 2) {
if (_port <= 0 || _port > 0xFFFF) {
@@ -204,7 +200,7 @@ pa_sdp_info *pa_sdp_parse(const char *t, pa_sdp_info *i, int is_goodbye) {
i->payload = (uint8_t) _payload;
if (pa_rtp_sample_spec_from_payload(i->payload, &i->sample_spec))
- ss_valid = 1;
+ ss_valid = TRUE;
}
}
} else if (pa_startswith(t, "a=rtpmap:")) {
@@ -222,16 +218,16 @@ pa_sdp_info *pa_sdp_parse(const char *t, pa_sdp_info *i, int is_goodbye) {
if (_payload == i->payload) {
c[strcspn(c, "\n")] = 0;
-
+
if (parse_sdp_sample_spec(&i->sample_spec, c))
- ss_valid = 1;
+ ss_valid = TRUE;
}
}
}
}
-
+
t += l;
-
+
if (*t == '\n')
t++;
}
@@ -245,7 +241,7 @@ pa_sdp_info *pa_sdp_parse(const char *t, pa_sdp_info *i, int is_goodbye) {
((struct sockaddr_in*) &i->sa)->sin_port = htons(port);
else
((struct sockaddr_in6*) &i->sa)->sin6_port = htons(port);
-
+
return i;
fail:
@@ -256,7 +252,7 @@ fail:
}
void pa_sdp_info_destroy(pa_sdp_info *i) {
- assert(i);
+ pa_assert(i);
pa_xfree(i->origin);
pa_xfree(i->session_name);
diff --git a/src/modules/rtp/sdp.h b/src/modules/rtp/sdp.h
index b95ca633..933a602b 100644
--- a/src/modules/rtp/sdp.h
+++ b/src/modules/rtp/sdp.h
@@ -1,21 +1,21 @@
#ifndef foosdphfoo
#define foosdphfoo
-/* $Id$ */
-
/***
This file is part of PulseAudio.
-
+
+ Copyright 2006 Lennart Poettering
+
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