File Coverage

blib/lib/Net/SDP/Media.pm
Criterion Covered Total %
statement 91 146 62.3
branch 27 58 46.5
condition 5 15 33.3
subroutine 19 26 73.0
pod 18 19 94.7
total 160 264 60.6


line stmt bran cond sub pod time code
1             package Net::SDP::Media;
2              
3             ################
4             #
5             # Net::SDP - Session Description Protocol (rfc2327)
6             #
7             # Nicholas J Humfrey
8             # njh@cpan.org
9             #
10             # See the bottom of this file for the POD documentation.
11             #
12              
13 5     5   30 use strict;
  5         10  
  5         172  
14 5     5   24 use vars qw/$VERSION %avt_profile_map/;
  5         10  
  5         221  
15 5     5   22 use Carp;
  5         8  
  5         15589  
16             $VERSION="0.07";
17              
18              
19              
20             # Static Payload Type map built using data from:
21             #
22             # http://www.iana.org/assignments/rtp-parameters
23             # http://www.iana.org/assignments/media-types/
24              
25             %avt_profile_map = (
26             '0' => 'audio/PCMU/8000/1',
27             # '1' => reserved
28             # '2' => reserved
29             '3' => 'audio/GSM/8000/1',
30             '4' => 'audio/G723/8000/1',
31             '5' => 'audio/DVI4/8000/1',
32             '6' => 'audio/DVI4/16000/1',
33             '7' => 'audio/LPC/8000/1',
34             '8' => 'audio/PCMA/8000/1',
35             '9' => 'audio/G722/8000/1',
36             '10' => 'audio/L16/44100/2',
37             '11' => 'audio/L16/44100/1',
38             '12' => 'audio/QCELP/8000/1',
39             '13' => 'audio/CN/8000/1',
40             '14' => 'audio/MPA/90000',
41             '15' => 'audio/G728/8000/1',
42             '16' => 'audio/DVI4/11025/1',
43             '17' => 'audio/DVI4/22050/1',
44             '18' => 'audio/G729/8000/1',
45             # '19' => reserved,
46             # '20' => unassigned,
47             # '21' => unassigned,
48             # '22' => unassigned,
49             # '23' => unassigned,
50             # '24' => unassigned,
51             '25' => 'video/CelB/90000',
52             '26' => 'video/JPEG/90000',
53             # '27' => unassigned,
54             '28' => 'video/nv/90000',
55             # '29' => unassigned,
56             # '30' => unassigned,
57             '31' => 'video/H261/90000',
58             '32' => 'video/MPV/90000',
59             '33' => 'video/MP2T/90000',
60             '34' => 'video/H263/90000',
61             );
62              
63              
64              
65              
66              
67             sub new {
68 3     3 0 6 my $class = shift;
69 3         51 my $self = {
70             'm_media' => 'unknown',
71             'm_port' => 0,
72             'm_transport' => 'RTP/AVP',
73             'm_fmt_list' => [],
74             'i' => undef,
75             'c_net_type' => 'IN',
76             'c_addr_type' => 'IP4',
77             'c_address' => '0.0.0.0',
78             'c_ttl' => 5,
79             'a' => {}
80             };
81 3         8 bless $self, $class;
82              
83             # Initial value provided ?
84 3         7 my ($m) = @_;
85 3 100       18 $self->_parse_m($m) if (defined $m);
86            
87 3         9 return $self;
88             }
89              
90             #sub remove {
91             # my $self=shift;
92             #
93             # ### Delete ourselves from our parent's array
94             #
95             # undef $self;
96             #}
97              
98              
99              
100             sub _parse_m {
101 2     2   3 my $self = shift;
102 2         63 my ($m) = @_;
103            
104 2         23 ($self->{'m_media'},
105             my $port,
106             $self->{'m_transport'},
107             my @formats ) = split(/\s/, $m);
108              
109 2         6 $self->{'m_fmt_list'} = \@formats;
110            
111 2 100       15 if (defined $port) {
112 1         4 ($self->{'m_port'}, my $range) = split(/\//, $port);
113 1 0 33     5 if (defined $range and $range ne '' and $range ne '1') {
      33        
114 0         0 carp "Port ranges are not supported by Net::SDP.";
115             }
116             }
117            
118             # Success
119 2         4 return 1;
120             }
121              
122             sub _generate_m {
123 1     1   1 my $self = shift;
124              
125 1         6 return 'm='.$self->{'m_media'}.' '.
126             $self->{'m_port'}.' '.
127             $self->{'m_transport'}.' '.
128 1         6 join(' ', @{$self->{'m_fmt_list'}})."\n";
129             }
130              
131             sub _parse_c {
132 1     1   2 my $self = shift;
133 1         2 my ($c) = @_;
134            
135 1         7 ($self->{'c_net_type'}, $self->{'c_addr_type'}, my $address) = split(/\s/, $c);
136 1         5 ($self->{'c_address'}, $self->{'c_ttl'}, my $range) = split(/\//, $address);
137            
138 1 50       4 if ($self->{'c_net_type'} ne 'IN') {
139 0         0 carp "Network type is not Internet (IN): ".$self->{'c_net_type'};
140             }
141            
142 1 50 33     4 if ($self->{'c_addr_type'} ne 'IP4' and $self->{'c_addr_type'} ne 'IP6') {
143 0         0 carp "Address type is not IP4 or IP6: ".$self->{'c_addr_type'};
144             }
145            
146 1 50       5 if (!defined $self->{'c_ttl'}) {
147 0         0 $self->{'c_ttl'} = 0;
148             }
149            
150 1 0 33     4 if (defined $range and $range ne '' and $range ne '1') {
      33        
151 0         0 carp "Address ranges are not supported by Net::SDP.";
152             }
153            
154             # Success
155 1         5 return 1;
156             }
157              
158             sub _generate_c {
159 1     1   2 my $self = shift;
160 1         5 my $c = 'c='.$self->{'c_net_type'}.' '.
161             $self->{'c_addr_type'}.' '.
162             $self->{'c_address'};
163            
164 1 50       4 if ($self->{'c_ttl'}) {
165 1         3 $c .= '/'.$self->{'c_ttl'};
166             }
167              
168 1         4 return "$c\n";
169             }
170              
171              
172              
173              
174              
175             sub address {
176 2     2 1 12 my $self=shift;
177 2         3 my ($address) = @_;
178 2 100       7 $self->{'c_address'} = $address if defined $address;
179 2         8 return $self->{'c_address'};
180             }
181              
182             sub address_type {
183 2     2 1 6 my $self=shift;
184 2         5 my ($addr_type) = @_;
185 2 100       9 $self->{'c_addr_type'} = $addr_type if defined $addr_type;
186 2         8 return $self->{'c_addr_type'};
187             }
188              
189              
190             sub port {
191 2     2 1 6 my $self=shift;
192 2         4 my ($port) = @_;
193 2 100       6 $self->{'m_port'} = $port if defined $port;
194 2         8 return $self->{'m_port'};
195             }
196              
197             sub ttl {
198 2     2 1 7 my $self=shift;
199 2         4 my ($ttl) = @_;
200 2 100       9 $self->{'c_ttl'} = $ttl if defined $ttl;
201 2         13 return $self->{'c_ttl'};
202             }
203              
204             sub media_type {
205 3     3 1 7 my $self=shift;
206 3         4 my ($media) = @_;
207 3 100       22 $self->{'m_media'} = $media if defined $media;
208 3         15 return $self->{'m_media'};
209             }
210              
211             sub title {
212 3     3 1 411 my $self=shift;
213 3         10 my ($title) = @_;
214 3 100       20 $self->{'i'} = $title if defined $title;
215 3         12 return $self->{'i'};
216             }
217              
218             sub transport {
219 1     1 1 2 my $self=shift;
220 1         2 my ($transport) = @_;
221 1 50       3 $self->{'m_transport'} = $transport if defined $transport;
222 1         4 return $self->{'m_transport'};
223             }
224              
225             sub network_type {
226 1     1 1 2 my $self=shift;
227 1         3 my ($net_type) = @_;
228 1 50       4 $self->{'c_net_type'} = $net_type if defined $net_type;
229 1         4 return $self->{'c_net_type'};
230             }
231              
232              
233             sub attribute {
234 0     0 1 0 my $self=shift;
235              
236 0         0 return Net::SDP::_attribute( $self, @_);
237             }
238              
239             sub attributes {
240 0     0 1 0 my $self=shift;
241              
242 0         0 return $self->{'a'};
243             }
244              
245             sub add_attribute {
246 0     0 1 0 my $self = shift;
247 0         0 my ($name, $value) = @_;
248 0 0       0 carp "Missing attribute name" unless (defined $name);
249            
250 0         0 my $attrib = $name;
251 0 0       0 $attrib .= ":$value" if (defined $value);
252 0         0 Net::SDP::_add_attribute( $self, 'a', $attrib );
253             }
254              
255              
256              
257             sub remove_format_num {
258 0     0 1 0 my $self=shift;
259 0         0 my ($fmt_num) = @_;
260 0 0       0 carp "Missing format number to remove" unless (defined $fmt_num);
261            
262 0         0 foreach my $n ( 0 .. $#{$self->{'m_fmt_list'}}) {
  0         0  
263 0 0       0 if ($self->{'m_fmt_list'}->[$n] == $fmt_num) {
264 0         0 splice( @{$self->{'m_fmt_list'}}, $n, 1 );
  0         0  
265 0         0 return 1;
266             }
267             }
268              
269             # Failed to delete
270 0         0 return 0;
271             }
272              
273              
274             sub default_format_num {
275 1     1 1 3 my $self=shift;
276 1         1 my ($fmt_num) = @_;
277              
278 1 50       4 if (defined $fmt_num) {
279              
280             # Remove it from elsewhere in the list
281 0         0 $self->remove_format_num( $fmt_num );
282              
283             # Put it at the start of the format list
284 0         0 unshift( @{$self->{'m_fmt_list'}}, $fmt_num );
  0         0  
285             }
286              
287 1         5 return $self->{'m_fmt_list'}->[0];
288             }
289              
290             sub default_format {
291 0     0 1 0 my $self=shift;
292 0         0 my $fmt_list = $self->format_list();
293            
294 0         0 return $fmt_list->{ $self->default_format_num() };
295             }
296              
297              
298             sub format_num_list {
299 0     0 1 0 my $self=shift;
300 0         0 my ($fmt_list) = @_;
301              
302 0 0       0 if (defined $fmt_list) {
303 0 0       0 carp "Parameter should be an array ref" if (ref $fmt_list ne 'ARRAY');
304 0         0 $self->{'m_fmt_list'} = $fmt_list;
305             }
306            
307 0         0 return $self->{'m_fmt_list'};
308             }
309              
310             sub format_list {
311 0     0 1 0 my $self=shift;
312 0         0 my $fmt_list = {};
313              
314             # Build a list of formats from rtpmap attributes
315 0         0 my %rtpmap = ();
316 0         0 foreach( @{$self->{'a'}->{'rtpmap'}} ) {
  0         0  
317 0         0 /(\d+)\s(.*)$/;
318 0         0 $rtpmap{$1} = $self->{'m_media'}."/$2";
319             }
320              
321             # Build our payload type map
322 0         0 foreach (@{$self->{'m_fmt_list'}}) {
  0         0  
323 0 0       0 if (exists $rtpmap{$_}) {
    0          
324 0         0 $fmt_list->{$_} = $rtpmap{$_};
325             } elsif (exists $avt_profile_map{$_}) {
326 0         0 $fmt_list->{$_} = $avt_profile_map{$_};
327             } else {
328 0         0 $fmt_list->{$_} = '';
329             }
330             }
331              
332 0         0 return $fmt_list;
333             }
334              
335              
336             sub add_format {
337 1     1 1 6 my $self=shift;
338 1         31 my ($format_num, $mime) = @_;
339 1 50       4 carp "Missing format number to add" unless (defined $format_num);
340            
341            
342             # Appened the format number to the list
343             # (which means the first one you add is default)
344 1         2 push( @{$self->{'m_fmt_list'}}, $format_num );
  1         4  
345              
346              
347             # Mime type specified ?
348 1 50       4 if (!defined $mime) {
349 0         0 $mime = $avt_profile_map{$format_num};
350             }
351            
352 1 50       3 if (!defined $mime) {
353 0         0 warn "Payload format $format_num is unknown dynamic type.";
354 0         0 return;
355             }
356            
357             # Work out rtpmap entry
358 1         9 my ($mime_media, $mime_format) = ($mime =~ /^([^\/]+)\/(.+)$/);
359 1 50       16 if ($mime_media ne $self->{'m_media'}) {
360 0         0 warn "This Media Description is for ".$self->{'m_media'};
361             }
362            
363             # Appened the rtpmap entry for this format
364 1         2 push( @{$self->{'a'}->{'rtpmap'}}, "$format_num $mime_format" );
  1         7  
365             }
366              
367             sub as_string {
368 1     1 1 5 my $self=shift;
369 1         3 my $type = $self->{'m_media'};
370 1         9 $type =~ s/^(.+)/\u\L$1/;
371 1         6 return "$type Stream";
372             }
373              
374             1;
375              
376             __END__