]> git.sesse.net Git - vlc/blob - modules/access/rtp/input.c
DCP: update authors
[vlc] / modules / access / rtp / input.c
1 /**
2  * @file input.c
3  * @brief RTP packet input
4  */
5 /*****************************************************************************
6  * Copyright © 2008 Rémi Denis-Courmont
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public License
10  * as published by the Free Software Foundation; either version 2.1
11  * of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
21  ****************************************************************************/
22
23 #ifdef HAVE_CONFIG_H
24 # include <config.h>
25 #endif
26
27 #include <vlc_common.h>
28 #include <vlc_demux.h>
29 #include <vlc_block.h>
30 #include <vlc_network.h>
31
32 #include <limits.h>
33 #include <errno.h>
34 #include <unistd.h>
35 #ifdef HAVE_POLL
36 # include <poll.h>
37 #endif
38
39 #include "rtp.h"
40 #ifdef HAVE_SRTP
41 # include <srtp.h>
42 #endif
43
44 /**
45  * Processes a packet received from the RTP socket.
46  */
47 static void rtp_process (demux_t *demux, block_t *block)
48 {
49     demux_sys_t *sys = demux->p_sys;
50
51     if (block->i_buffer < 2)
52         goto drop;
53     const uint8_t ptype = rtp_ptype (block);
54     if (ptype >= 72 && ptype <= 76)
55         goto drop; /* Muxed RTCP, ignore for now FIXME */
56
57 #ifdef HAVE_SRTP
58     if (sys->srtp != NULL)
59     {
60         size_t len = block->i_buffer;
61         if (srtp_recv (sys->srtp, block->p_buffer, &len))
62         {
63             msg_Dbg (demux, "SRTP authentication/decryption failed");
64             goto drop;
65         }
66         block->i_buffer = len;
67     }
68 #endif
69
70     /* TODO: use SDP and get rid of this hack */
71     if (unlikely(sys->autodetect))
72     {   /* Autodetect payload type, _before_ rtp_queue() */
73         rtp_autodetect (demux, sys->session, block);
74         sys->autodetect = false;
75     }
76
77     rtp_queue (demux, sys->session, block);
78     return;
79 drop:
80     block_Release (block);
81 }
82
83 static int rtp_timeout (mtime_t deadline)
84 {
85     if (deadline == VLC_TS_INVALID)
86         return -1; /* infinite */
87
88     mtime_t t = mdate ();
89     if (t >= deadline)
90         return 0;
91
92     t = (deadline - t) / (CLOCK_FREQ / INT64_C(1000));
93     if (unlikely(t > INT_MAX))
94         return INT_MAX;
95     return t;
96 }
97
98 /**
99  * RTP/RTCP session thread for datagram sockets
100  */
101 void *rtp_dgram_thread (void *opaque)
102 {
103     demux_t *demux = opaque;
104     demux_sys_t *sys = demux->p_sys;
105     mtime_t deadline = VLC_TS_INVALID;
106     int rtp_fd = sys->fd;
107
108     struct pollfd ufd[1];
109     ufd[0].fd = rtp_fd;
110     ufd[0].events = POLLIN;
111
112     for (;;)
113     {
114         int n = poll (ufd, 1, rtp_timeout (deadline));
115         if (n == -1)
116             continue;
117
118         int canc = vlc_savecancel ();
119         if (n == 0)
120             goto dequeue;
121
122         if (ufd[0].revents)
123         {
124             n--;
125             if (unlikely(ufd[0].revents & POLLHUP))
126                 break; /* RTP socket dead (DCCP only) */
127
128             block_t *block = block_Alloc (0xffff); /* TODO: p_sys->mru */
129             if (unlikely(block == NULL))
130                 break; /* we are totallly screwed */
131
132             ssize_t len = recv (rtp_fd, block->p_buffer, block->i_buffer, 0);
133             if (len != -1)
134             {
135                 block->i_buffer = len;
136                 rtp_process (demux, block);
137             }
138             else
139             {
140                 msg_Warn (demux, "RTP network error: %s",
141                           vlc_strerror_c(errno));
142                 block_Release (block);
143             }
144         }
145
146     dequeue:
147         if (!rtp_dequeue (demux, sys->session, &deadline))
148             deadline = VLC_TS_INVALID;
149         vlc_restorecancel (canc);
150     }
151     return NULL;
152 }
153
154 /**
155  * RTP/RTCP session thread for stream sockets (framed RTP)
156  */
157 void *rtp_stream_thread (void *opaque)
158 {
159 #ifndef _WIN32
160     demux_t *demux = opaque;
161     demux_sys_t *sys = demux->p_sys;
162     int fd = sys->fd;
163
164     for (;;)
165     {
166         /* There is no reordering on stream sockets, so no timeout. */
167         ssize_t val;
168
169         uint16_t frame_len;
170         if (recv (fd, &frame_len, 2, MSG_WAITALL) != 2)
171             break;
172
173         block_t *block = block_Alloc (ntohs (frame_len));
174         if (unlikely(block == NULL))
175             break;
176
177         block_cleanup_push (block);
178         val = recv (fd, block->p_buffer, block->i_buffer, MSG_WAITALL);
179         vlc_cleanup_pop ();
180
181         if (val != (ssize_t)block->i_buffer)
182         {
183             block_Release (block);
184             break;
185         }
186
187         int canc = vlc_savecancel ();
188         rtp_process (demux, block);
189         rtp_dequeue_force (demux, sys->session);
190         vlc_restorecancel (canc);
191     }
192 #else
193     (void) opaque;
194 #endif
195     return NULL;
196 }