]>
code.delx.au - pulseaudio/blob - src/modules/rtp/rtp.c
2 This file is part of PulseAudio.
4 Copyright 2006 Lennart Poettering
6 PulseAudio is free software; you can redistribute it and/or modify
7 it under the terms of the GNU Lesser General Public License as published
8 by the Free Software Foundation; either version 2.1 of the License,
9 or (at your option) any later version.
11 PulseAudio is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public License
17 along with PulseAudio; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
31 #include <sys/ioctl.h>
33 #ifdef HAVE_SYS_FILIO_H
34 #include <sys/filio.h>
41 #include <pulsecore/core-error.h>
42 #include <pulsecore/log.h>
43 #include <pulsecore/macro.h>
44 #include <pulsecore/core-util.h>
45 #include <pulsecore/arpa-inet.h>
49 pa_rtp_context
* pa_rtp_context_init_send(pa_rtp_context
*c
, int fd
, uint32_t ssrc
, uint8_t payload
, size_t frame_size
) {
54 c
->sequence
= (uint16_t) (rand()*rand());
56 c
->ssrc
= ssrc
? ssrc
: (uint32_t) (rand()*rand());
57 c
->payload
= (uint8_t) (payload
& 127U);
58 c
->frame_size
= frame_size
;
60 pa_memchunk_reset(&c
->memchunk
);
67 int pa_rtp_send(pa_rtp_context
*c
, size_t size
, pa_memblockq
*q
) {
68 struct iovec iov
[MAX_IOVECS
];
69 pa_memblock
* mb
[MAX_IOVECS
];
77 if (pa_memblockq_get_length(q
) < size
)
84 pa_memchunk_reset(&chunk
);
86 if ((r
= pa_memblockq_peek(q
, &chunk
)) >= 0) {
88 size_t k
= n
+ chunk
.length
> size
? size
- n
: chunk
.length
;
90 pa_assert(chunk
.memblock
);
92 iov
[iov_idx
].iov_base
= ((uint8_t*) pa_memblock_acquire(chunk
.memblock
) + chunk
.index
);
93 iov
[iov_idx
].iov_len
= k
;
94 mb
[iov_idx
] = chunk
.memblock
;
98 pa_memblockq_drop(q
, k
);
101 pa_assert(n
% c
->frame_size
== 0);
103 if (r
< 0 || n
>= size
|| iov_idx
>= MAX_IOVECS
) {
110 header
[0] = htonl(((uint32_t) 2 << 30) | ((uint32_t) c
->payload
<< 16) | ((uint32_t) c
->sequence
));
111 header
[1] = htonl(c
->timestamp
);
112 header
[2] = htonl(c
->ssrc
);
114 iov
[0].iov_base
= (void*)header
;
115 iov
[0].iov_len
= sizeof(header
);
120 m
.msg_iovlen
= (size_t) iov_idx
;
121 m
.msg_control
= NULL
;
122 m
.msg_controllen
= 0;
125 k
= sendmsg(c
->fd
, &m
, MSG_DONTWAIT
);
127 for (i
= 1; i
< iov_idx
; i
++) {
128 pa_memblock_release(mb
[i
]);
129 pa_memblock_unref(mb
[i
]);
136 c
->timestamp
+= (unsigned) (n
/c
->frame_size
);
139 if (errno
!= EAGAIN
&& errno
!= EINTR
) /* If the queue is full, just ignore it */
140 pa_log("sendmsg() failed: %s", pa_cstrerror(errno
));
144 if (r
< 0 || pa_memblockq_get_length(q
) < size
)
155 pa_rtp_context
* pa_rtp_context_init_recv(pa_rtp_context
*c
, int fd
, size_t frame_size
) {
159 c
->frame_size
= frame_size
;
161 pa_memchunk_reset(&c
->memchunk
);
165 int pa_rtp_recv(pa_rtp_context
*c
, pa_memchunk
*chunk
, pa_mempool
*pool
, struct timeval
*tstamp
) {
174 pa_bool_t found_tstamp
= FALSE
;
179 pa_memchunk_reset(chunk
);
181 if (ioctl(c
->fd
, FIONREAD
, &size
) < 0) {
182 pa_log_warn("FIONREAD failed: %s", pa_cstrerror(errno
));
189 if (c
->memchunk
.length
< (unsigned) size
) {
192 if (c
->memchunk
.memblock
)
193 pa_memblock_unref(c
->memchunk
.memblock
);
195 l
= PA_MAX((size_t) size
, pa_mempool_block_size_max(pool
));
197 c
->memchunk
.memblock
= pa_memblock_new(pool
, l
);
198 c
->memchunk
.index
= 0;
199 c
->memchunk
.length
= pa_memblock_get_length(c
->memchunk
.memblock
);
202 pa_assert(c
->memchunk
.length
>= (size_t) size
);
204 chunk
->memblock
= pa_memblock_ref(c
->memchunk
.memblock
);
205 chunk
->index
= c
->memchunk
.index
;
207 iov
.iov_base
= (uint8_t*) pa_memblock_acquire(chunk
->memblock
) + chunk
->index
;
208 iov
.iov_len
= (size_t) size
;
215 m
.msg_controllen
= sizeof(aux
);
218 r
= recvmsg(c
->fd
, &m
, 0);
219 pa_memblock_release(chunk
->memblock
);
222 if (r
< 0 && errno
!= EAGAIN
&& errno
!= EINTR
)
223 pa_log_warn("recvmsg() failed: %s", r
< 0 ? pa_cstrerror(errno
) : "size mismatch");
229 pa_log_warn("RTP packet too short.");
233 memcpy(&header
, iov
.iov_base
, sizeof(uint32_t));
234 memcpy(&c
->timestamp
, (uint8_t*) iov
.iov_base
+ 4, sizeof(uint32_t));
235 memcpy(&c
->ssrc
, (uint8_t*) iov
.iov_base
+ 8, sizeof(uint32_t));
237 header
= ntohl(header
);
238 c
->timestamp
= ntohl(c
->timestamp
);
239 c
->ssrc
= ntohl(c
->ssrc
);
241 if ((header
>> 30) != 2) {
242 pa_log_warn("Unsupported RTP version.");
246 if ((header
>> 29) & 1) {
247 pa_log_warn("RTP padding not supported.");
251 if ((header
>> 28) & 1) {
252 pa_log_warn("RTP header extensions not supported.");
256 cc
= (header
>> 24) & 0xF;
257 c
->payload
= (uint8_t) ((header
>> 16) & 127U);
258 c
->sequence
= (uint16_t) (header
& 0xFFFFU
);
260 if (12 + cc
*4 > (unsigned) size
) {
261 pa_log_warn("RTP packet too short. (CSRC)");
265 chunk
->index
+= 12 + cc
*4;
266 chunk
->length
= (size_t) size
- 12 + cc
*4;
268 if (chunk
->length
% c
->frame_size
!= 0) {
269 pa_log_warn("Bad RTP packet size.");
273 c
->memchunk
.index
= chunk
->index
+ chunk
->length
;
274 c
->memchunk
.length
= pa_memblock_get_length(c
->memchunk
.memblock
) - c
->memchunk
.index
;
276 if (c
->memchunk
.length
<= 0) {
277 pa_memblock_unref(c
->memchunk
.memblock
);
278 pa_memchunk_reset(&c
->memchunk
);
281 for (cm
= CMSG_FIRSTHDR(&m
); cm
; cm
= CMSG_NXTHDR(&m
, cm
))
282 if (cm
->cmsg_level
== SOL_SOCKET
&& cm
->cmsg_type
== SO_TIMESTAMP
) {
283 memcpy(tstamp
, CMSG_DATA(cm
), sizeof(struct timeval
));
289 pa_log_warn("Couldn't find SO_TIMESTAMP data in auxiliary recvmsg() data!");
290 memset(tstamp
, 0, sizeof(tstamp
));
297 pa_memblock_unref(chunk
->memblock
);
302 uint8_t pa_rtp_payload_from_sample_spec(const pa_sample_spec
*ss
) {
305 if (ss
->format
== PA_SAMPLE_ULAW
&& ss
->rate
== 8000 && ss
->channels
== 1)
307 if (ss
->format
== PA_SAMPLE_ALAW
&& ss
->rate
== 8000 && ss
->channels
== 1)
309 if (ss
->format
== PA_SAMPLE_S16BE
&& ss
->rate
== 44100 && ss
->channels
== 2)
311 if (ss
->format
== PA_SAMPLE_S16BE
&& ss
->rate
== 44100 && ss
->channels
== 1)
317 pa_sample_spec
*pa_rtp_sample_spec_from_payload(uint8_t payload
, pa_sample_spec
*ss
) {
323 ss
->format
= PA_SAMPLE_ULAW
;
329 ss
->format
= PA_SAMPLE_ALAW
;
335 ss
->format
= PA_SAMPLE_S16BE
;
341 ss
->format
= PA_SAMPLE_S16BE
;
352 pa_sample_spec
*pa_rtp_sample_spec_fixup(pa_sample_spec
* ss
) {
355 if (!pa_rtp_sample_spec_valid(ss
))
356 ss
->format
= PA_SAMPLE_S16BE
;
358 pa_assert(pa_rtp_sample_spec_valid(ss
));
362 int pa_rtp_sample_spec_valid(const pa_sample_spec
*ss
) {
365 if (!pa_sample_spec_valid(ss
))
369 ss
->format
== PA_SAMPLE_U8
||
370 ss
->format
== PA_SAMPLE_ALAW
||
371 ss
->format
== PA_SAMPLE_ULAW
||
372 ss
->format
== PA_SAMPLE_S16BE
;
375 void pa_rtp_context_destroy(pa_rtp_context
*c
) {
378 pa_assert_se(pa_close(c
->fd
) == 0);
380 if (c
->memchunk
.memblock
)
381 pa_memblock_unref(c
->memchunk
.memblock
);
384 const char* pa_rtp_format_to_string(pa_sample_format_t f
) {
386 case PA_SAMPLE_S16BE
:
399 pa_sample_format_t
pa_rtp_string_to_format(const char *s
) {
402 if (!(strcmp(s
, "L16")))
403 return PA_SAMPLE_S16BE
;
404 else if (!strcmp(s
, "L8"))
406 else if (!strcmp(s
, "PCMA"))
407 return PA_SAMPLE_ALAW
;
408 else if (!strcmp(s
, "PCMU"))
409 return PA_SAMPLE_ULAW
;
411 return PA_SAMPLE_INVALID
;