1 /*
2 * rtp-play.cc --
3 *
4 * RTP Play for archive streams
5 *
6 * Copyright (c) 1997-2002 The Regents of the University of California.
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions are met:
11 *
12 * A. Redistributions of source code must retain the above copyright notice,
13 * this list of conditions and the following disclaimer.
14 * B. Redistributions in binary form must reproduce the above copyright notice,
15 * this list of conditions and the following disclaimer in the documentation
16 * and/or other materials provided with the distribution.
17 * C. Neither the names of the copyright holders nor the names of its
18 * contributors may be used to endorse or promote products derived from this
19 * software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS
22 * IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
23 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
25 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 * POSSIBILITY OF SUCH DAMAGE.
32 */
33
34 #include <tclcl.h>
35 #include "net/net.h"
36 #include "rtp/rtp.h"
37 #include "misc/mtrace.h"
38 #include "archive/archive-stream.h"
39 #include "archive/rtp-play.h"
40 #include "misc/nethost.h"
41 #include "tclcl-mappings.h"
42
43
44
45
46 DEFINE_OTCL_CLASS(RTPPlaybackStream, "ArchiveStream/Play/RTP") {
47 INSTPROC(buffer_pool);
48 INSTPROC(attach_agent);
49 INSTPROC(header_info);
50 }
51
52 DEFINE_OTCL_CLASS(RTPPlayRcvr, "Module/RTPPlay") {
53 }
54
55
56 RTPPlaybackStream::RTPPlaybackStream()
57 : PlaybackStream(), startTS_(0), endTS_(0), dnet_(NULL), cnet_(NULL),
58 free_(NULL), eof_(0), skipctrl_(1), converter_(0.0),
59 firstTime_(TRUE), bufferPool_(NULL), cs_(0), firstseq_(0),
60 p_(0), lastp_(0), agent_(NULL), lastNotify_(0.0)
61 {
62 }
63
64 RTPPlaybackStream::~RTPPlaybackStream() {
65 printf("In rtp-play.cc destroy\n");
66 agent_->send_bye();
67 }
68
69
70 int
71 RTPPlaybackStream::header_info(int argc, const char * const *argv)
72 {
73 Tcl &tcl = Tcl::instance();
74 int returnValue;
75 FileHeader hdrNet;
76 RTPprivatehdr phdrNet;
77 const char *hdrArray;
78
79 double last_recv;
80 u_int32_t last_rtp;
81 double first_recv, new_scale;
82
83 int modend, endpos;
84
85 DataFile* file = DataFile_();
86 IndexFile* ifile = IndexFile_();
87
88 BEGIN_PARSE_ARGS(argc, argv);
89 ARG(hdrArray);
90 END_PARSE_ARGS;
91
92 if (file->IsOpen()==FALSE) {
93 tcl.resultf("file not open");
94 goto error;
95 }
96
97 returnValue = file->Read(&hdrNet, (u_char *)&phdrNet, sizeof(RTPprivatehdr));
98
99 net2host(hdrNet, hdr_);
100 net2host(phdrNet, phdr_);
101 MTrace(trcArchive|trcVerbose, ("%s Default Scale = %lu\n",hdr_.name, phdr_.scale));
102
103 // Calculate scale, using recv timestamps
104 IndexRecord iNet, iHost;
105
106 if (ifile->Seek(0, SEEK_END)==TCL_ERROR)
107 return TCL_ERROR;
108 endpos = ifile->Tell();
109 // This is only necessary in pathological cases, where the disk filled up, etc
110 modend = ((endpos - sizeof(FileHeader)) % sizeof(IndexRecord));
111 if (modend != 0) {
112 MTrace(trcArchive, ("Wrong Size, truncing"));
113 endpos = endpos - modend;
114 }
115
116 if (ifile->Seek(endpos - sizeof(IndexRecord), SEEK_SET)==TCL_ERROR)
117 return TCL_ERROR;
118
119
120 //if (ifile->Seek(-1*((int)sizeof(IndexRecord)), SEEK_END)==TCL_ERROR) {
121 //return TCL_ERROR;
122 //}
123
124 if (ifile->Read(&iNet)==TCL_ERROR) {
125 return TCL_ERROR;
126 }
127 net2host(iNet, iHost);
128
129 last_rtp = logical2rtp(iHost.sentTS_sec, iHost.sentTS_usec, phdr_.scale, phdr_.ref_rtp, phdr_.ref_tv_sec, phdr_.ref_tv_usec);
130 last_recv = iHost.recvTS_sec + iHost.recvTS_usec/1000000.0;
131 first_recv = phdr_.ref_tv_sec + phdr_.ref_tv_usec/1000000.0;
132 new_scale = (last_rtp - phdr_.ref_rtp) / (last_recv - first_recv);
133 /*FIXME*/
134 if (new_scale > 7800 && new_scale < 8200) {
135 //printf("warning mccanne hack\n");
136 new_scale = 8000;
137 }
138 MTrace(trcArchive|trcVerbose, ("New Scale = %g\n", new_scale));
139 phdr_.scale = (int) new_scale;
140 //printf("first_recv=%g last_recv=%g last_rtp=%u first_rtp=%g\n", first_recv, last_recv, last_rtp, phdr_.ref_rtp);
141 //
142
143 char c_ssrc[16];
144 sprintf(c_ssrc, "%u", host2net(phdr_.ssrc));
145
146 if (Tcl_SetVar2(tcl.interp(), (char*)hdrArray, "cname",
147 hdr_.cname, TCL_LEAVE_ERR_MSG)==NULL) {
148 tcl.resultf("\nwhile writing to array '%s'", hdrArray);
149 goto error;
150 }
151 if (Tcl_SetVar2(tcl.interp(), (char*)hdrArray, "name",
152 hdr_.name, TCL_LEAVE_ERR_MSG)==NULL) {
153 tcl.resultf("\nwhile writing to array '%s'", hdrArray);
154 goto error;
155 }
156 if (Tcl_SetVar2(tcl.interp(), (char*)hdrArray, "email",
157 phdr_.email, TCL_LEAVE_ERR_MSG)==NULL) {
158 tcl.resultf("\nwhile writing to array '%s'", hdrArray);
159 goto error;
160 }
161 if (Tcl_SetVar2(tcl.interp(), (char*)hdrArray, "ssrc",
162 c_ssrc, TCL_LEAVE_ERR_MSG)==NULL) {
163 tcl.resultf("\nwhile writing to array '%s'", hdrArray);
164 goto error;
165 }
166 if (Tcl_SetVar2(tcl.interp(), (char*)hdrArray, "phone",
167 phdr_.phone, TCL_LEAVE_ERR_MSG)==NULL) {
168 tcl.resultf("\nwhile writing to array '%s'", hdrArray);
169 goto error;
170 }
171 if (Tcl_SetVar2(tcl.interp(), (char*)hdrArray, "loc",
172 phdr_.loc, TCL_LEAVE_ERR_MSG)==NULL) {
173 tcl.resultf("\nwhile writing to array '%s'", hdrArray);
174 goto error;
175 }
176 if (Tcl_SetVar2(tcl.interp(), (char*)hdrArray, "tool",
177 phdr_.tool, TCL_LEAVE_ERR_MSG)==NULL) {
178 tcl.resultf("\nwhile writing to array '%s'", hdrArray);
179 goto error;
180 }
181 tcl.resultf("");
182 return TCL_OK;
183
184 error:
185 tcl.add_errorf("\ninvoked from within RTPPlaybackStream::Header_Info()");
186 return TCL_ERROR;
187 }
188
189
190
191
192 int
193 RTPPlaybackStream::attach_agent(int argc, const char * const *argv)
194 {
195 TclObject* agent;
196
197 BEGIN_PARSE_ARGS(argc, argv);
198 ARG(agent);
199 END_PARSE_ARGS;
200
201 agent_=(RTPPlaySession *)agent;
202 return TCL_OK;
203 }
204
205 int
206 RTPPlaybackStream::buffer_pool(int argc, const char * const *argv)
207 {
208 TclObject* bufferPool;
209
210 BEGIN_PARSE_ARGS(argc, argv);
211 ARG(bufferPool);
212 END_PARSE_ARGS;
213
214 bufferPool_=(BufferPool *)bufferPool;
215
216 /*FIXME*/
217 int npack = 64;/*FIXME*/
218 for (int i = 0; i < npack; ++i) {
219 RTPPacket* p = new RTPPacket;
220 p->buf=bufferPool_->alloc();
221 free(p);
222 }
223 return TCL_OK;
224 }
225
226
227 #if OLD
228 int
229 RTPPlaybackStream::Datanet(int argc, const char * const *argv)
230 {
231 TclObject* datanet;
232
233 BEGIN_PARSE_ARGS(argc, argv);
234 ARG(datanet);
235 END_PARSE_ARGS;
236
237 dnet_=(Network *)datanet;
238 return TCL_OK;
239 }
240
241 int
242 RTPPlaybackStream::Ctrlnet(int argc, const char * const *argv)
243 {
244 TclObject* ctrlnet;
245
246 BEGIN_PARSE_ARGS(argc, argv);
247 ARG(ctrlnet);
248 END_PARSE_ARGS;
249
250 cnet_=(Network *)ctrlnet;
251 return TCL_OK;
252 }
253 #endif
254
255
256 void
257 RTPPlaybackStream::Clip(timeval start, timeval end)
258 {
259 startTS_= logical2rtp(start, phdr_.scale, phdr_.ref_rtp,
260 phdr_.ref_tv_sec, phdr_.ref_tv_usec);
261 endTS_ = logical2rtp(end, phdr_.scale, phdr_.ref_rtp,
262 phdr_.ref_tv_sec, phdr_.ref_tv_usec);
263 //startTS_ = logical2rtp(start.tv_sec, start.tv_usec, converter_);
264 //endTS_ = logical2rtp(end.tv_sec, end.tv_usec, converter_);
265 }
266
267
268
269 /*
270 * add packet p to the queue of waiting packets for this
271 * source. The queue is ordered by seqno.
272 */
273 void
274 RTPPlaybackStream::addpacket(RTPPacket* p, u_int ts, u_int seqno)
275 {
276 //MTrace(trcArchive, ("addpacket %u %u",ts, seqno));
277
278 /* convert the seqno to 32 bits */
279 if (p->type) { // if it's a control packet
280 MTrace(trcArchive|trcVerbose, ("addpacket control pkt"));
281 seqno = firstseq_;
282 if (lastp_) {
283 seqno += lastp_->seq;
284 ts = lastp_->its;
285 }
286 } else { // Data packet
287 register int c = cs_;
288 register int d = seqno - c;
289 if (d < -1024 || d > 1024) {
290 cs_ = seqno;
291 if (seqno < 512 && c > 0x10000-512) {
292 /*
293 * seq no. wrapped - subtract 64k from firstseq to
294 * account for it.
295 */
296 firstseq_ -= 0x10000;
297 } else {
298 /*
299 * the seq. no made a very large
300 * jump. assume that the other
301 * side restarted without telling
302 * us about it so just re-sync
303 * (i.e., pretend this was the
304 * first packet).
305 */
306 firstseq_ = seqno - 1;
307 }
308 } else if (d > 0) {
309 /*
310 * d <= 0 means duplicate or reordered packet so
311 * don't move cs_
312 */
313 cs_ = seqno;
314 }
315 }
316 seqno -= firstseq_;
317 p->seq = seqno;
318 MTrace(trcArchive, ("addpacket %u", seqno));
319
320 p->its=ts;
321 //MTrace(trcArchive, ("addpacket %u",ts));
322 /*
323 * find where in the queue to insert this packet.
324 * the usual case of inserting at the tail is special cased
325 * for performance reasons.
326 */
327 if (lastp_ == 0) {
328 lastp_ = p;
329 p_ = p;
330 p->next = 0;
331 } else if (lastp_->its < p->its ||
332 (p->its == lastp_->its && int(seqno - lastp_->seq) > 0)) {
333 lastp_->next = p;
334 lastp_ = p;
335 p->next = 0;
336 } else if (p->its < p_->its ||
337 (p->its == p_->its && int(seqno - p_->seq) <= 0)) {
338 p->next = p_;
339 p_ = p;
340 } else {
341 RTPPacket* np;
342 for (RTPPacket* lp = p_; (np = lp->next) != 0; lp = np) {
343 if (p->its < np->its ||
344 (p->its == np->its && int(seqno - np->seq) <= 0)) {
345 lp->next = p;
346 p->next = np;
347 break;
348 }
349 }
350 }
351 }
352
353
354
355 u_int
356 RTPPlaybackStream::ts() const
357 {
358 if (p_ == 0)
359 /*FIXME*/
360 return (0);
361
362 return (p_->its);
363 }
364
365 RTPPacket*
366 RTPPlaybackStream::getpkt(u_int now)
367 {
368 RTPPacket* p = p_;
369 //MTrace(trcArchive, ("getpkt %f %f %d", p->ts, ts));
370 if (p && ((int)(p->its - now) <= 0 || now == 0)) {
371 RTPPacket* np = p->next;
372 p_ = np;
373 if (np == 0)
374 lastp_ = 0;
375 return (p);
376 }
377 return (0);
378 }
379
380 RTPPacket*
381 RTPPlaybackStream::allocate()
382 {
383
384 RTPPacket* temp = free_;
385 free_ = temp->next;
386 temp->buf = bufferPool_->alloc();
387 return temp;
388
389 }
390
391 void
392 RTPPlaybackStream::EmptyBuffs()
393 {
394
395 RTPPacket *p; RTPPacket *np;
396
397 p = p_;
398 while (p) {
399 np=p->next;
400 free (p);
401 p=np;
402 }
403 p_=0;
404 lastp_=0;
405
406 }
407
408 void
409 RTPPlaybackStream::IterateIndex(int real_endpos) {
410
411 IndexFile* ifile;
412 DataFile* dfile;
413 IndexRecord iNet, iHost;
414
415 ifile = IndexFile_();
416 dfile = DataFile_();
417
418
419 int curpos = ifile->Tell();
420 while (curpos < real_endpos) {
421 if (ifile->Read(&iNet)==TCL_ERROR)
422 return;
423 net2host(iNet, iHost);
424 printf("recv-sent = %d \n", iHost.recvTS_sec - iHost.sentTS_sec);
425 curpos = ifile->Tell();
426 }
427
428
429 }
430
431
432 Bool
433 RTPPlaybackStream::SeekTime(timeval goal) {
434
435 IndexFile* ifile;
436 DataFile* dfile;
437 IndexRecord iNet, iHost;
438 int actual_end, endpos;
439
440
441 eof_=0;
442
443 u_int32_t goalsec= (u_int32_t) goal.tv_sec;
444 u_int32_t goalusec= (u_int32_t)goal.tv_usec;
445
446 ifile = IndexFile_();
447 dfile = DataFile_();
448
449 if (ifile->Seek(sizeof(FileHeader), SEEK_SET)==TCL_ERROR)
450 return TCL_ERROR;
451 if (ifile->Read(&iNet)==TCL_ERROR)
452 return TCL_ERROR;
453 net2host(iNet, iHost);
454 if ((goalsec < iHost.sentTS_sec) || ((goalsec == iHost.sentTS_sec) && (goalusec <= iHost.sentTS_usec))) {
455 dfile->Seek(sizeof(FileHeader) + sizeof(RTPprivatehdr), SEEK_SET);
456 return TCL_OK;
457 }
458
459 int startpos = sizeof(FileHeader);
460
461 if (ifile->Seek(0, SEEK_END)==TCL_ERROR)
462 return TCL_ERROR;
463 actual_end = ifile->Tell();
464 endpos = actual_end;
465 // This is only necessary in pathological cases, where the disk filled up, etc
466 int modend = ((endpos - sizeof(FileHeader)) % sizeof(IndexRecord));
467 if (modend != 0) {
468 MTrace(trcArchive, ("Wrong Size, truncing"));
469 endpos = endpos - modend;
470 }
471
472 if (ifile->Seek(endpos - sizeof(IndexRecord), SEEK_SET)==TCL_ERROR)
473 return TCL_ERROR;
474 //int real_endpos = endpos;
475 if (ifile->Read(&iNet)==TCL_ERROR)
476 return TCL_ERROR;
477 net2host(iNet, iHost);
478
479 //ref_end_rec_ = iHost.recvTS_sec + iHost.recvTS_usec/1000000.0;
480
481 if (goalsec > iHost.sentTS_sec) {
482 if (dfile->Seek(0,SEEK_END)==TCL_ERROR)
483 return TCL_ERROR;
484 MTrace(trcArchive, ("Sought too end"));
485 return TCL_OK;
486 }
487 if ((goalsec == iHost.sentTS_sec) &&
488 (goalusec >= iHost.sentTS_usec))
489 {
490 if (dfile->Seek(iHost.filePointer, SEEK_SET)==TCL_ERROR)
491 return TCL_ERROR;
492 MTrace(trcArchive, ("Sought too %u",iHost.seqno));
493 return TCL_OK;
494 }
495 int newpos=((((endpos-startpos)/sizeof(IndexRecord))/2) * sizeof(IndexRecord)) + startpos;
496
497
498 int curpos;
499
500
501 for (;;) {
502 if (ifile->Seek(newpos, SEEK_SET)==TCL_ERROR)
503 return TCL_ERROR;
504 if (ifile->Read(&iNet)==TCL_ERROR)
505 return TCL_ERROR;
506 net2host(iNet, iHost);
507
508 if ((goalsec == iHost.sentTS_sec)
509 && (goalusec == iHost.sentTS_usec)) {
510 if (dfile->Seek(iHost.filePointer, SEEK_SET)==TCL_ERROR)
511 return TCL_ERROR;
512 MTrace(trcArchive, ("Sought too %u",iHost.seqno));
513
514
515 return TCL_OK;
516 }
517 if ((goalsec > iHost.sentTS_sec) || ((goalsec == iHost.sentTS_sec) && (goalusec >= iHost.sentTS_usec))) {
518 startpos = newpos + sizeof(IndexRecord);
519 newpos=((((endpos-startpos)/sizeof(IndexRecord))/2) * sizeof(IndexRecord)) + startpos;
520 }
521 if ((goalsec < iHost.sentTS_sec) || ((goalsec == iHost.sentTS_sec) && (goalusec <= iHost.sentTS_usec))) {
522 endpos = newpos;
523 newpos=((((endpos-startpos)/sizeof(IndexRecord))/2) * sizeof(IndexRecord)) + startpos;
524 if (newpos == endpos) {
525 if (dfile->Seek(iHost.filePointer, SEEK_SET)==TCL_ERROR)
526 return TCL_ERROR;
527 MTrace(trcArchive, ("Sought too %u",iHost.seqno));
528 curpos = ifile->Tell();
529
530
531
532 return TCL_OK;
533 }
534 }
535 }
536
537
538
539 }
540
541
542 void
543 RTPPlaybackStream::LTS_Speed()
544 {
545 PlaybackStream::LTS_Speed();
546 }
547
548
549 void
550 RTPPlaybackStream::LTS_Reference()
551 {
552 EmptyBuffs();
553 timeval now = LTS_()->NowLogical();
554 MTrace (trcArchive, ("LTS_Reference %u %u", now.tv_sec, now.tv_usec));
555 if (SeekTime(now)==TCL_ERROR) {
556 // FIXME: LTS_Reference should have an error-returning mechanism
557 return;
558 }
559
560 PlaybackStream::LTS_Reference();
561 }
562
563 void
564 RTPPlaybackStream::free(RTPPacket* p)
565 {
566 p->next = free_;
567 free_ = p;
568 p->buf->release();
569 }
570
571
572
573 int
574 RTPPlaybackStream::nextpkt(RTPPacket* p)
575 {
576
577 DataFile *file;
578 struct recordhdr *rh = (recordhdr *) p->buf->data;
579
580 file = DataFile_();
581 if (firstTime_==TRUE) {
582
583 if (file->Seek(file->getHeaderSize(), SEEK_SET)==TCL_ERROR)
584 return (-1);
585
586 }
587
588
589 // read header (gives us len and type)
590
591 if (file->Read((unsigned char*)rh, sizeof(recordhdr))==0) {
592 eof_ = 1;
593 return (-1);
594 }
595
596 int len = net2host(rh->len);
597 int type = rh->type;
598
599 //MTrace(trcArchive, ("nextpkt type %d", type));
600
601 int amt = len;
602 if (len > MTU - 4) {
603 /* FIXME packet too big */
604 for (len -= amt; len > 0; len -= amt) {
605 amt = len;
606 if (amt > MTU)
607 amt = MTU;
608 if (file->Read((u_char*) p->buf->data, amt) == 0) {
609 eof_ = 1;
610 return (-1);
611 }
612 }
613 return (1);
614 }
615
616 // now read the rtp packet itself; overwrites recordhdr
617 if (file->Read((u_char*) p->buf->data, amt) == 0) {
618 eof_ = 1;
619 return (-1);
620 }
621
622 // assign relevant fields
623 // others in the RTPPacket struct are assigned in
624 // addpacket
625
626 p->type = type;
627 p->len = amt;
628
629
630
631
632 return (len);
633 }
634
635
636
637 int
638 RTPPlaybackStream::fillone()
639 {
640
641 int rval;
642 u_int id, ts, seq;
643
644
645 RTPPacket *p = allocate();
646 rval = nextpkt(p); /* Actually read from disk */
647
648 if (rval < 0) {
649 eof_ = 1;
650 p->next = free_;
651 free_ = p;
652 return (rval);
653 }
654
655 if (rval < 2) {
656 return (rval);
657 }
658
659 struct rtphdr *rh = (struct rtphdr *)p->buf->data;
660
661 // p.type and p.len will have been filled in by nextpkt above
662
663 switch (p->type) {
664 default:
665 return (1);
666 case 0:
667 // DATA packet (RTP)
668
669 skipctrl_ = 0;
670 id = net2host(rh->rh_ssrc);
671 ts = net2host(rh->rh_ts);
672 seq = net2host(rh->rh_seqno);
673 MTrace (trcArchive|trcVerbose,
674 ("fillone seqno=%u ts=%u", seq, ts));
675
676 break;
677
678 case 0x80:
679 // CONTROL packet (RTCP)
680 // Currently, shouldn't get here
681 // FIX THIS
682 struct rtcp_compound {
683 rtcphdr rt;
684 rtcp_sr sr;
685 } *th = (rtcp_compound *) p->buf->data;
686 if (skipctrl_ || (ntohs(th->rt.rh_flags) & 0xff) \
687 != RTCP_PT_SR) {
688 /* not a sender report */
689 return (1);
690 }
691 id = net2host(th->rt.rh_ssrc);
692 ts = net2host(th->sr.sr_ts);
693 seq = ~0;
694 break;
695 }
696
697 if (firstTime_ == TRUE) {
698 // Move this to nextpkt after we fix ctrl pkts
699 cs_=seq;
700 firstseq_=seq;
701 firstTime_=FALSE;
702 }
703
704 addpacket(p, ts, seq); /* Put the packet in the queue */
705 return (0);
706 }
707
708
709 int
710 RTPPlaybackStream::IsDone()
711 {
712 if ((p_==0) && (eof_==1)) {
713 return 1;
714 }
715 return 0;
716
717
718 /*if ((eof_ == 0) && (p_ != 0))
719 return (0);
720
721 if (p_!=0)
722 return (0);
723 return (1); */
724 }
725
726 int
727 RTPPlaybackStream::NextEvent(timeval &logical)
728 {
729
730 /* fill all free packet buffers with disk data */
731 while (free_ && (fillone() >= 0)) {
732 }
733
734
735 if (IsDone()) {
736 MTrace(trcArchive, ("RTP playback source is done"));
737 logical.tv_sec = logical.tv_usec = 0;
738 EmptyBuffs();
739 return TCL_OK;
740
741 }
742
743 u_int dt=ts();
744 if (endTS_ > 0 && dt > endTS_) {
745 //we are done
746 MTrace(trcArchive, ("Exceeded ending ts (%lu): %lu",
747 (unsigned long) endTS_,
748 (unsigned long) dt));
749 logical.tv_sec = logical.tv_usec = 0;
750 return TCL_OK;
751 }
752
753
754 //set logical to be time when next pkt should play
755 timeval ref;
756 ref.tv_sec = phdr_.ref_tv_sec;
757 ref.tv_usec = phdr_.ref_tv_usec;
758 //FIXME logical time starts at 0!
759 //ref.tv_sec = ref.tv_usec = 0;
760 //ref.tv_usec = 1;//except 0 has special meaning... FIXME
761
762 logical = rtp2logical(dt, phdr_.scale, phdr_.ref_rtp,
763 ref);
764 MTrace(trcArchive|trcVerbose,
765 ("RTP playback source returned logical timeof %u %u.%u %u",
766 dt, logical.tv_sec, logical.tv_usec, p_->seq));
767 return TCL_OK;
768
769 }
770
771 void
772 RTPPlaybackStream::DoEvent()
773 {
774 double now;
775 timeval ts = LTS_()->NowLogical();
776 u_int dts = logical2rtp(ts, phdr_.scale, phdr_.ref_rtp,
777 phdr_.ref_tv_sec, phdr_.ref_tv_usec);
778 for (;;) {
779 RTPPacket *p = getpkt(dts);
780 if (p == 0)
781 return;
782
783 MTrace(trcArchive, ("Send seq=%d ",p->seq));
784
785 p->buf->len = p->len;
786 p->buf->next = 0; //??
787
788 //p->buf->layer = 1; //Change this when we support layered video
789 agent_->send(p->buf);
790
791 now = tvtof(LTS_()->NowSystem());
792 if (now - lastNotify_ > 0.25) {
793 Invokef("notify_observers bytes_sent 0");
794 lastNotify_ = now;
795 }
796
797 p->next = free_;
798 free_ = p;
799
800 // p->buf is released in transmitter-rtp
801 }
802 }
803
This page was automatically generated by the
LXR engine.
Visit the LXR main site for more
information.