add an RTP sender module
[profile/ivi/pulseaudio-panda.git] / src / modules / rtp / rtp.c
1 /* $Id$ */
2
3 /***
4   This file is part of polypaudio.
5  
6   polypaudio 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 of the License,
9   or (at your option) any later version.
10  
11   polypaudio 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.
15  
16   You should have received a copy of the GNU Lesser General Public License
17   along with polypaudio; if not, write to the Free Software
18   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
19   USA.
20 ***/
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <assert.h>
27 #include <fcntl.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <errno.h>
31 #include <arpa/inet.h>
32 #include <unistd.h>
33
34 #include <polypcore/log.h>
35
36 #include "rtp.h"
37
38 pa_rtp_context* pa_rtp_context_init_send(pa_rtp_context *c, int fd, uint32_t ssrc, uint8_t payload) {
39     assert(c);
40     assert(fd >= 0);
41
42     c->fd = fd;
43     c->sequence = (uint16_t) (rand()*rand());
44     c->timestamp = 0;
45     c->ssrc = ssrc ? ssrc : (uint32_t) (rand()*rand());
46     c->payload = payload & 127;
47
48     return c;
49 }
50
51 #define MAX_IOVECS 16
52
53 int pa_rtp_send(pa_rtp_context *c, size_t size, pa_memblockq *q) {
54     struct iovec iov[MAX_IOVECS];
55     pa_memblock* mb[MAX_IOVECS];
56     int iov_idx = 1;
57     size_t n = 0, skip = 0;
58     
59     assert(c);
60     assert(size > 0);
61     assert(q);
62
63     if (pa_memblockq_get_length(q) < size)
64         return 0;
65     
66     for (;;) {
67         int r;
68         pa_memchunk chunk;
69
70         if ((r = pa_memblockq_peek(q, &chunk)) >= 0) {
71
72             size_t k = n + chunk.length > size ? size - n : chunk.length;
73
74             if (chunk.memblock) {
75                 iov[iov_idx].iov_base = (uint8_t*) chunk.memblock->data + chunk.index;
76                 iov[iov_idx].iov_len = k;
77                 mb[iov_idx] = chunk.memblock;
78                 iov_idx ++;
79
80                 n += k;
81             }
82
83             skip += k;
84             pa_memblockq_drop(q, &chunk, k);
85         }
86
87         if (r < 0 || !chunk.memblock || n >= size || iov_idx >= MAX_IOVECS) {
88             uint32_t header[3];
89             struct msghdr m;
90             int k, i;
91
92             if (n > 0) {
93                 header[0] = htonl(((uint32_t) 2 << 30) | ((uint32_t) c->payload << 16) | ((uint32_t) c->sequence));
94                 header[1] = htonl(c->timestamp);
95                 header[2] = htonl(c->ssrc);
96
97                 iov[0].iov_base = header;
98                 iov[0].iov_len = sizeof(header);
99                 
100                 m.msg_name = NULL;
101                 m.msg_namelen = 0;
102                 m.msg_iov = iov;
103                 m.msg_iovlen = iov_idx;
104                 m.msg_control = NULL;
105                 m.msg_controllen = 0;
106                 m.msg_flags = 0;
107                 
108                 k = sendmsg(c->fd, &m, MSG_DONTWAIT);
109
110                 for (i = 1; i < iov_idx; i++)
111                     pa_memblock_unref(mb[i]);
112
113                 c->sequence++;
114             } else
115                 k = 0;
116
117             c->timestamp += skip;
118             
119             if (k < 0) {
120                 if (errno != EAGAIN) /* If the queue is full, just ignore it */
121                     pa_log(__FILE__": sendmsg() failed: %s", strerror(errno));
122                 return -1;
123             }
124             
125             if (r < 0 || pa_memblockq_get_length(q) < size)
126                 break;
127
128             n = 0;
129             skip = 0;
130             iov_idx = 1;
131         }
132     }
133
134     return 0;
135 }
136
137 pa_rtp_context* pa_rtp_context_init_recv(pa_rtp_context *c, int fd) {
138     assert(c);
139
140     c->fd = fd;
141     return c;
142 }
143
144 int pa_rtp_recv(pa_rtp_context *c, pa_memchunk *chunk) {
145     assert(c);
146     assert(chunk);
147
148     return 0;
149 }
150
151 uint8_t pa_rtp_payload_type(const pa_sample_spec *ss) {
152     assert(ss);
153
154     if (ss->format == PA_SAMPLE_ULAW && ss->rate == 8000 && ss->channels == 1)
155         return 0;
156     if (ss->format == PA_SAMPLE_ALAW && ss->rate == 8000 && ss->channels == 1)
157         return 0;
158     if (ss->format == PA_SAMPLE_S16BE && ss->rate == 44100 && ss->channels == 2)
159         return 10;
160     if (ss->format == PA_SAMPLE_S16BE && ss->rate == 44100 && ss->channels == 1)
161         return 11;
162     
163     return 127;
164 }
165
166 pa_sample_spec *pa_rtp_sample_spec_fixup(pa_sample_spec * ss) {
167     assert(ss);
168
169     if (!pa_rtp_sample_spec_valid(ss))
170         ss->format = PA_SAMPLE_S16BE;
171
172     assert(pa_rtp_sample_spec_valid(ss));
173     return ss;
174 }
175
176 int pa_rtp_sample_spec_valid(const pa_sample_spec *ss) {
177     assert(ss);
178
179     if (!pa_sample_spec_valid(ss))
180         return 0;
181
182     return
183         ss->format == PA_SAMPLE_U8 ||
184         ss->format == PA_SAMPLE_ALAW ||
185         ss->format == PA_SAMPLE_ULAW ||
186         ss->format == PA_SAMPLE_S16BE;
187 }
188
189 void pa_rtp_context_destroy(pa_rtp_context *c) {
190     assert(c);
191
192     close(c->fd);
193 }