]> git.sesse.net Git - vlc/blob - modules/access/rtp/input.c
stream_filter/httplive.c: Append new segment any (HLS Live playback) when gap in...
[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 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 <unistd.h>
34 #ifdef HAVE_POLL
35 # include <poll.h>
36 #endif
37
38 #include "rtp.h"
39 #ifdef HAVE_SRTP
40 # include <srtp.h>
41 #endif
42
43 /**
44  * Processes a packet received from the RTP socket.
45  */
46 static void rtp_process (demux_t *demux, block_t *block)
47 {
48     demux_sys_t *sys = demux->p_sys;
49
50     if (block->i_buffer < 2)
51         goto drop;
52     const uint8_t ptype = rtp_ptype (block);
53     if (ptype >= 72 && ptype <= 76)
54         goto drop; /* Muxed RTCP, ignore for now FIXME */
55
56 #ifdef HAVE_SRTP
57     if (sys->srtp != NULL)
58     {
59         size_t len = block->i_buffer;
60         if (srtp_recv (sys->srtp, block->p_buffer, &len))
61         {
62             msg_Dbg (demux, "SRTP authentication/decryption failed");
63             goto drop;
64         }
65         block->i_buffer = len;
66     }
67 #endif
68
69     /* TODO: use SDP and get rid of this hack */
70     if (unlikely(sys->autodetect))
71     {   /* Autodetect payload type, _before_ rtp_queue() */
72         if (rtp_autodetect (demux, sys->session, block))
73             goto drop;
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: %m");
141                 block_Release (block);
142             }
143         }
144
145     dequeue:
146         if (!rtp_dequeue (demux, sys->session, &deadline))
147             deadline = VLC_TS_INVALID;
148         vlc_restorecancel (canc);
149     }
150     return NULL;
151 }
152
153 /**
154  * RTP/RTCP session thread for stream sockets (framed RTP)
155  */
156 void *rtp_stream_thread (void *opaque)
157 {
158 #ifndef WIN32
159     demux_t *demux = opaque;
160     demux_sys_t *sys = demux->p_sys;
161     int fd = sys->fd;
162
163     for (;;)
164     {
165         /* There is no reordering on stream sockets, so no timeout. */
166         ssize_t val;
167
168         uint16_t frame_len;
169         if (recv (fd, &frame_len, 2, MSG_WAITALL) != 2)
170             break;
171
172         block_t *block = block_Alloc (ntohs (frame_len));
173         if (unlikely(block == NULL))
174             break;
175
176         block_cleanup_push (block);
177         val = recv (fd, block->p_buffer, block->i_buffer, MSG_WAITALL);
178         vlc_cleanup_pop ();
179
180         if (val != (ssize_t)block->i_buffer)
181         {
182             block_Release (block);
183             break;
184         }
185
186         int canc = vlc_savecancel ();
187         rtp_process (demux, block);
188         rtp_dequeue_force (demux, sys->session);
189         vlc_restorecancel (canc);
190     }
191 #else
192     (void) opaque;
193 #endif
194     return NULL;
195 }