- Timestamp:
- 02/10/07 04:06:26 (17 years ago)
- Files:
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
branches/streaming-rework/src/libutil/TimestampedBuffer.cpp
r391 r392 41 41 m_event_size(0), m_events_per_frame(0), m_buffer_size(0), 42 42 m_bytes_per_frame(0), m_bytes_per_buffer(0), 43 m_wrap_at(0xFFFFFFFFFFFFFFFFLLU), 43 44 m_Client(c), m_framecounter(0), m_buffer_tail_timestamp(0), 45 m_buffer_next_tail_timestamp(0), 44 46 m_dll_e2(0.0), m_dll_b(0.877), m_dll_c(0.384), 45 47 m_nominal_rate(0.0), m_update_period(0) 46 48 { 49 pthread_mutex_init(&m_framecounter_lock, NULL); 47 50 48 51 } … … 53 56 } 54 57 58 /** 59 * \brief Set the nominal rate in frames/timeunit 60 * 61 * Sets the nominal rate in frames per time unit. This rate is used 62 * to initialize the DLL that will extract the effective rate based 63 * upon the timestamps it gets fed. 64 * 65 * @param r rate 66 * @return true if successful 67 */ 68 bool TimestampedBuffer::setNominalRate(float r) { 69 m_nominal_rate=r; 70 debugOutput(DEBUG_LEVEL_VERBOSE," nominal rate=%e set to %e\n", 71 m_nominal_rate, r); 72 return true; 73 } 74 75 /** 76 * \brief Set the nominal update period (in frames) 77 * 78 * Sets the nominal update period. This period is the number of frames 79 * between two timestamp updates (hence buffer writes) 80 * 81 * @param n period in frames 82 * @return true if successful 83 */ 84 bool TimestampedBuffer::setUpdatePeriod(unsigned int n) { 85 m_update_period=n; 86 return true; 87 } 88 89 /** 90 * \brief set the value at which timestamps should wrap around 91 * @param w value to wrap at 92 * @return true if successful 93 */ 94 bool TimestampedBuffer::setWrapValue(uint64_t w) { 95 m_wrap_at=w; 96 return true; 97 } 98 99 /** 100 * \brief return the effective rate 101 * 102 * Returns the effective rate calculated by the DLL. 103 * 104 * @return rate (in frames/timeunit) 105 */ 106 float TimestampedBuffer::getRate() { 107 return ((float) m_update_period)/m_dll_e2; 108 } 109 110 /** 111 * \brief Sets the size of the events 112 * @param s event size in bytes 113 * @return true if successful 114 */ 55 115 bool TimestampedBuffer::setEventSize(unsigned int s) { 56 116 m_event_size=s; … … 62 122 } 63 123 64 bool TimestampedBuffer::setEventsPerFrame(unsigned int s) { 65 m_events_per_frame=s; 124 /** 125 * \brief Sets the number of events per frame 126 * @param n number of events per frame 127 * @return true if successful 128 */ 129 bool TimestampedBuffer::setEventsPerFrame(unsigned int n) { 130 m_events_per_frame=n; 66 131 67 132 m_bytes_per_frame=m_event_size*m_events_per_frame; … … 70 135 return true; 71 136 } 72 73 bool TimestampedBuffer::setBufferSize(unsigned int s) { 74 m_buffer_size=s; 75 137 /** 138 * \brief Sets the buffer size in frames 139 * @param n number frames 140 * @return true if successful 141 */ 142 bool TimestampedBuffer::setBufferSize(unsigned int n) { 143 m_buffer_size=n; 144 76 145 m_bytes_per_frame=m_event_size*m_events_per_frame; 77 146 m_bytes_per_buffer=m_bytes_per_frame*m_buffer_size; 78 79 return true; 80 } 81 147 148 return true; 149 } 150 151 /** 152 * \brief Returns the current fill of the buffer 153 * 154 * This returns the buffer fill of the internal ringbuffer. This 155 * can only be used as an indication because it's state is not 156 * guaranteed to be consistent at all times due to threading issues. 157 * 158 * In order to get the number of frames in the buffer, use the 159 * getFrameCounter, getBufferHeadTimestamp, getBufferTailTimestamp 160 * functions 161 * 162 * @return the internal buffer fill in frames 163 */ 82 164 unsigned int TimestampedBuffer::getBufferFill() { 83 165 return freebob_ringbuffer_read_space(m_event_buffer)/(m_bytes_per_frame); 84 166 } 85 167 168 /** 169 * \brief Initializes the TimestampedBuffer 170 * 171 * Initializes the TimestampedBuffer, should be called before anything else 172 * is done. 173 * 174 * @return true if successful 175 */ 86 176 bool TimestampedBuffer::init() { 87 88 pthread_mutex_init(&m_framecounter_lock, NULL); 89 90 return true; 91 } 92 177 return true; 178 } 179 180 /** 181 * \brief Resets the TimestampedBuffer 182 * 183 * Resets the TimestampedBuffer, clearing the buffers and counters. 184 * (not true yet: Also resets the DLL to the nominal values.) 185 * 186 * \note when this is called, you should make sure that the buffer 187 * tail timestamp gets set before continuing 188 * 189 * @return true if successful 190 */ 93 191 bool TimestampedBuffer::reset() { 94 192 freebob_ringbuffer_reset(m_event_buffer); … … 99 197 } 100 198 101 void TimestampedBuffer::dumpInfo() { 102 103 uint64_t ts_head, fc; 104 getBufferHeadTimestamp(&ts_head,&fc); 105 106 int64_t diff=(int64_t)ts_head - (int64_t)m_buffer_tail_timestamp; 107 108 debugOutputShort( DEBUG_LEVEL_NORMAL, " TimestampedBuffer (%p) info:\n",this); 109 debugOutputShort( DEBUG_LEVEL_NORMAL, " Frame counter : %d\n", m_framecounter); 110 debugOutputShort( DEBUG_LEVEL_NORMAL, " Buffer head timestamp : %011llu\n",ts_head); 111 debugOutputShort( DEBUG_LEVEL_NORMAL, " Buffer tail timestamp : %011llu\n",m_buffer_tail_timestamp); 112 debugOutputShort( DEBUG_LEVEL_NORMAL, " Head - Tail : %011lld\n",diff); 113 debugOutputShort( DEBUG_LEVEL_NORMAL, " rate : %lf (%f)\n",m_dll_e2,m_dll_e2/m_update_period); 114 } 115 199 /** 200 * \brief Perpares the TimestampedBuffer 201 * 202 * Prepare the TimestampedBuffer. This allocates all internal buffers and 203 * initializes all data structures. 204 * 205 * This should be called after parameters such as buffer size, event size etc.. are set, 206 * and before any read/write operations are performed. 207 * 208 * @return true if successful 209 */ 116 210 bool TimestampedBuffer::prepare() { 117 211 debugOutput(DEBUG_LEVEL_VERBOSE,"Preparing buffer (%p)\n",this); 118 212 debugOutput(DEBUG_LEVEL_VERBOSE," Size=%u events, events/frame=%u, event size=%ubytes\n", 119 213 m_buffer_size,m_events_per_frame,m_event_size); 214 215 debugOutput(DEBUG_LEVEL_VERBOSE," update period %u\n", 216 m_update_period); 217 debugOutput(DEBUG_LEVEL_VERBOSE," nominal rate=%f\n", 218 m_nominal_rate); 219 220 debugOutput(DEBUG_LEVEL_VERBOSE," wrapping at %llu\n",m_wrap_at); 120 221 121 222 assert(m_buffer_size); … … 123 224 assert(m_event_size); 124 225 226 assert(m_nominal_rate != 0.0L); 227 assert(m_update_period != 0); 228 125 229 if( !(m_event_buffer=freebob_ringbuffer_create( 126 230 (m_events_per_frame * m_buffer_size) * m_event_size))) { 127 128 231 debugFatal("Could not allocate memory event ringbuffer\n"); 129 232 return false; … … 136 239 return false; 137 240 } 138 139 assert(m_nominal_rate != 0.0);140 assert(m_update_period != 0);141 241 142 242 // init the DLL … … 149 249 } 150 250 151 bool TimestampedBuffer::writeFrames(unsigned int nevents, char *data) { 152 153 unsigned int write_size=nevents*m_event_size*m_events_per_frame; 251 /** 252 * @brief Write frames to the buffer 253 * 254 * Copies \ref nframes of frames from the buffer pointed to by \ref data to the 255 * internal ringbuffer. The time of the last frame in the buffer is set to \ref ts. 256 * 257 * @param nframes number of frames to copy 258 * @param data pointer to the frame buffer 259 * @param ts timestamp of the last frame copied 260 * @return true if successful 261 */ 262 bool TimestampedBuffer::writeFrames(unsigned int nframes, char *data, uint64_t ts) { 263 264 unsigned int write_size=nframes*m_event_size*m_events_per_frame; 154 265 155 266 // add the data payload to the ringbuffer … … 159 270 return false; 160 271 } 161 return true; 162 163 } 164 165 bool TimestampedBuffer::readFrames(unsigned int nevents, char *data) { 166 167 unsigned int read_size=nevents*m_event_size*m_events_per_frame; 272 273 incrementFrameCounter(nframes,ts); 274 275 return true; 276 277 } 278 /** 279 * @brief Read frames from the buffer 280 * 281 * Copies \ref nframes of frames from the internal buffer to the data buffer pointed 282 * to by \ref data. 283 * 284 * @param nframes number of frames to copy 285 * @param data pointer to the frame buffer 286 * @return true if successful 287 */ 288 bool TimestampedBuffer::readFrames(unsigned int nframes, char *data) { 289 290 unsigned int read_size=nframes*m_event_size*m_events_per_frame; 168 291 169 292 // get the data payload to the ringbuffer … … 173 296 return false; 174 297 } 175 return true; 176 177 } 178 298 299 decrementFrameCounter(nframes); 300 301 return true; 302 303 } 304 305 /** 306 * @brief Performs block processing write of frames 307 * 308 * This function allows for zero-copy writing into the ringbuffer. 309 * It calls the client's processWriteBlock function to write frames 310 * into the internal buffer's data area, in a thread safe fashion. 311 * 312 * It also updates the timestamp. 313 * 314 * @param nbframes number of frames to process 315 * @param ts timestamp of the last frame written to the buffer 316 * @return true if successful 317 */ 179 318 bool TimestampedBuffer::blockProcessWriteFrames(unsigned int nbframes, int64_t ts) { 180 319 … … 266 405 } 267 406 268 return true; 269 270 } 271 407 incrementFrameCounter(nbframes,ts); 408 409 return true; 410 411 } 412 413 /** 414 * @brief Performs block processing read of frames 415 * 416 * This function allows for zero-copy reading from the ringbuffer. 417 * It calls the client's processReadBlock function to read frames 418 * directly from the internal buffer's data area, in a thread safe 419 * fashion. 420 * 421 * @param nbframes number of frames to process 422 * @return true if successful 423 */ 272 424 bool TimestampedBuffer::blockProcessReadFrames(unsigned int nbframes) { 273 425 … … 302 454 303 455 if(vec[0].len==0) { // this indicates an empty event buffer 304 debugError(" RCV: Event buffer underrun in processor %p\n",this);456 debugError("Event buffer underrun in buffer %p\n",this); 305 457 return false; 306 458 } … … 321 473 if(xrun<0) { 322 474 // xrun detected 323 debugError(" RCV: Frame buffer overrun in processor %p\n",this);475 debugError("Frame buffer overrun in buffer %p\n",this); 324 476 return false; 325 477 } … … 342 494 if(xrun<0) { 343 495 // xrun detected 344 debugError(" RCV: Frame buffer overrun in processor %p\n",this);496 debugError("Frame buffer overrun in buffer %p\n",this); 345 497 return false; 346 498 } … … 354 506 } 355 507 356 return true; 357 } 358 359 /** 360 * Decrements the frame counter, in a atomic way. 508 decrementFrameCounter(nbframes); 509 510 return true; 511 } 512 513 /** 514 * @brief Sets the buffer tail timestamp. 515 * 516 * Set the buffer tail timestamp to \ref new_timestamp. This will recalculate 517 * the internal state such that the buffer's timeframe starts at 518 * \ref new_timestamp. 519 * 520 * This is thread safe. 521 * 522 * @param new_timestamp 523 */ 524 void TimestampedBuffer::setBufferTailTimestamp(uint64_t new_timestamp) { 525 526 pthread_mutex_lock(&m_framecounter_lock); 527 528 m_buffer_tail_timestamp = new_timestamp; 529 530 m_dll_e2=m_update_period * m_nominal_rate; 531 m_buffer_next_tail_timestamp = (uint64_t)((double)m_buffer_tail_timestamp + m_dll_e2); 532 533 pthread_mutex_unlock(&m_framecounter_lock); 534 535 debugOutput(DEBUG_LEVEL_VERBOSE, "Set buffer tail timestamp for (%p) to %11llu, NTS=%llu, DLL2=%f\n", 536 this, new_timestamp, m_buffer_next_tail_timestamp, m_dll_e2); 537 538 } 539 540 /** 541 * \brief return the timestamp of the first frame in the buffer 542 * 543 * This function returns the timestamp of the very first sample in 544 * the StreamProcessor's buffer. It also returns the framecounter value 545 * for which this timestamp is valid. 546 * 547 * @param ts address to store the timestamp in 548 * @param fc address to store the associated framecounter in 549 */ 550 void TimestampedBuffer::getBufferHeadTimestamp(uint64_t *ts, uint64_t *fc) { 551 double rate=(double)m_buffer_next_tail_timestamp - (double)m_buffer_tail_timestamp; 552 rate /= (double)m_update_period; 553 554 int64_t timestamp; 555 556 pthread_mutex_lock(&m_framecounter_lock); 557 *fc = m_framecounter; 558 559 // ts(x) = m_buffer_tail_timestamp - 560 // (m_buffer_next_tail_timestamp - m_buffer_tail_timestamp)/(samples_between_updates)*(x) 561 562 // buffer head is the frame that is framecounter-1 away from the tail 563 timestamp=(int64_t)m_buffer_tail_timestamp - (int64_t)((m_framecounter) * rate); 564 565 pthread_mutex_unlock(&m_framecounter_lock); 566 567 debugOutput(DEBUG_LEVEL_VERBOSE, "(%p): HTS = %011lld, TTS=%011llu, FC=%05u, RATE=%f\n", 568 this, timestamp, m_buffer_tail_timestamp, *fc, rate); 569 570 if(timestamp >= (int64_t)m_wrap_at) { 571 timestamp -= m_wrap_at; 572 } else if(timestamp < 0) { 573 timestamp += m_wrap_at; 574 } 575 576 *ts=timestamp; 577 578 debugOutput(DEBUG_LEVEL_VERBOSE, " HTS = %011lld, FC=%05u\n", 579 *ts, *fc); 580 581 } 582 583 /** 584 * \brief return the timestamp of the last frame in the buffer 585 * 586 * This function returns the timestamp of the last frame in 587 * the StreamProcessor's buffer. It also returns the framecounter 588 * value for which this timestamp is valid. 589 * 590 * @param ts address to store the timestamp in 591 * @param fc address to store the associated framecounter in 592 */ 593 void TimestampedBuffer::getBufferTailTimestamp(uint64_t *ts, uint64_t *fc) { 594 pthread_mutex_lock(&m_framecounter_lock); 595 *fc = m_framecounter; 596 *ts = m_buffer_tail_timestamp; 597 pthread_mutex_unlock(&m_framecounter_lock); 598 } 599 600 /** 601 * Resets the frame counter, in a atomic way. This 361 602 * is thread safe. 603 */ 604 void TimestampedBuffer::resetFrameCounter() { 605 pthread_mutex_lock(&m_framecounter_lock); 606 m_framecounter = 0; 607 pthread_mutex_unlock(&m_framecounter_lock); 608 } 609 610 /** 611 * Decrements the frame counter in a thread safe way. 612 * 613 * @param nbframes number of frames to decrement 362 614 */ 363 615 void TimestampedBuffer::decrementFrameCounter(int nbframes) { … … 368 620 369 621 /** 370 * Increments the frame counter, in a atomic way. 371 * also sets the buffer tail timestamp 372 * This is thread safe. 622 * Increments the frame counter in a thread safe way. 623 * Also updates the timestamp. 624 * 625 * @param nbframes the number of frames to add 626 * @param new_timestamp the new timestamp 373 627 */ 374 628 void TimestampedBuffer::incrementFrameCounter(int nbframes, uint64_t new_timestamp) { 375 debugOutput(DEBUG_LEVEL_VER Y_VERBOSE, "Setting buffer tail timestamp for (%p) to %11llu\n",629 debugOutput(DEBUG_LEVEL_VERBOSE, "Setting buffer tail timestamp for (%p) to %11llu\n", 376 630 this, new_timestamp); 377 631 … … 390 644 391 645 // the maximal difference we can allow (64secs) 392 const int64_t max= TICKS_PER_SECOND*64L;646 const int64_t max=m_wrap_at/2; 393 647 394 648 if(diff > max) { 395 diff -= TICKS_PER_SECOND*128L;649 diff -= m_wrap_at; 396 650 } else if (diff < -max) { 397 diff += TICKS_PER_SECOND*128L;651 diff += m_wrap_at; 398 652 } 399 653 … … 401 655 402 656 debugOutputShort(DEBUG_LEVEL_VERY_VERBOSE, "diff2=%lld err=%f\n", 403 diff, err); 404 debugOutput(DEBUG_LEVEL_VERY_VERBOSE, "FC=%10u, TS=%011llu\n",m_framecounter, m_buffer_tail_timestamp); 657 diff, err); 658 debugOutput(DEBUG_LEVEL_VERY_VERBOSE, "B: FC=%10u, TS=%011llu, NTS=%011llu\n", 659 m_framecounter, m_buffer_tail_timestamp, m_buffer_next_tail_timestamp); 405 660 406 661 m_buffer_tail_timestamp=m_buffer_next_tail_timestamp; 407 662 m_buffer_next_tail_timestamp += (uint64_t)(m_dll_b * err + m_dll_e2); 408 663 409 if (m_buffer_next_tail_timestamp > TICKS_PER_SECOND*128L) { 410 m_buffer_next_tail_timestamp -= TICKS_PER_SECOND*128L; 664 if (m_buffer_next_tail_timestamp >= m_wrap_at) { 665 m_buffer_next_tail_timestamp -= m_wrap_at; 666 667 debugOutput(DEBUG_LEVEL_VERY_VERBOSE, "Unwrapping next tail timestamp: %11llu\n", 668 m_buffer_next_tail_timestamp); 411 669 } 412 670 413 671 m_dll_e2 += m_dll_c*err; 414 672 415 debugOutput(DEBUG_LEVEL_VER Y_VERBOSE, "TS=%011llu, NTS=%011llu, DLLe2=%f\n",673 debugOutput(DEBUG_LEVEL_VERBOSE, "A: TS=%011llu, NTS=%011llu, DLLe2=%f\n", 416 674 m_buffer_tail_timestamp, m_buffer_next_tail_timestamp, m_dll_e2); 417 675 418 676 pthread_mutex_unlock(&m_framecounter_lock); 677 678 if(m_buffer_tail_timestamp>=m_wrap_at) { 679 debugError("Wrapping failed for m_buffer_tail_timestamp!\n"); 680 } 681 if(m_buffer_next_tail_timestamp>=m_wrap_at) { 682 debugError("Wrapping failed for m_buffer_next_tail_timestamp!\n"); 683 } 419 684 420 685 // this DLL allows the calculation of any sample timestamp relative to the buffer tail, … … 427 692 428 693 /** 429 * Sets the buffer tail timestamp (in usecs) 430 * This is thread safe. 431 */ 432 void TimestampedBuffer::setBufferTailTimestamp(uint64_t new_timestamp) { 433 434 pthread_mutex_lock(&m_framecounter_lock); 435 436 m_buffer_tail_timestamp = new_timestamp; 437 438 m_dll_e2=m_update_period * m_nominal_rate; 439 m_buffer_next_tail_timestamp = (uint64_t)((double)m_buffer_tail_timestamp + m_dll_e2); 440 441 pthread_mutex_unlock(&m_framecounter_lock); 442 443 debugOutput(DEBUG_LEVEL_VERY_VERBOSE, "Set buffer tail timestamp for (%p) to %11llu, NTS=%llu, DLL2=%f\n", 444 this, new_timestamp, m_buffer_next_tail_timestamp, m_dll_e2); 445 446 } 447 448 /** 449 * \brief return the timestamp of the first frame in the buffer 450 * 451 * This function returns the timestamp of the very first sample in 452 * the StreamProcessor's buffer. This is useful for slave StreamProcessors 453 * to find out what the base for their timestamp generation should 454 * be. It also returns the framecounter value for which this timestamp 455 * is valid. 456 * 457 * The system is built in such a way that we assume that the processing 458 * of the buffers doesn't take any time. Assume we have a buffer transfer at 459 * time T1, meaning that the last sample of this buffer occurs at T1. As 460 * processing does not take time, we don't have to add anything to T1. When 461 * transferring the processed buffer to the xmit processor, the timestamp 462 * of the last sample is still T1. 463 * 464 * When starting the streams, we don't have any information on this last 465 * timestamp. We prefill the buffer at the xmit side, and we should find 466 * out what the timestamp for the last sample in the buffer is. If we sync 467 * on a receive SP, we know that the last prefilled sample corresponds with 468 * the first sample received - 1 sample duration. This is the same as if the last 469 * transfer from iso to client would have emptied the receive buffer. 470 * 471 * 472 * @param ts address to store the timestamp in 473 * @param fc address to store the associated framecounter in 474 */ 475 void TimestampedBuffer::getBufferHeadTimestamp(uint64_t *ts, uint64_t *fc) { 476 double rate=(double)m_buffer_next_tail_timestamp - (double)m_buffer_tail_timestamp; 477 rate /= (double)m_update_period; 478 479 pthread_mutex_lock(&m_framecounter_lock); 480 *fc = m_framecounter; 481 482 // ts(x) = m_buffer_tail_timestamp + 483 // (m_buffer_next_tail_timestamp - m_buffer_tail_timestamp)/(samples_between_updates)*x 484 485 *ts=m_buffer_tail_timestamp + (uint64_t)(m_framecounter * rate); 486 487 pthread_mutex_unlock(&m_framecounter_lock); 488 if(*ts > TICKS_PER_SECOND*128L) { 489 *ts -= TICKS_PER_SECOND*128L; 490 } 491 } 492 493 /** 494 * \brief return the timestamp of the last frame in the buffer 495 * 496 * This function returns the timestamp of the last frame in 497 * the StreamProcessor's buffer. It also returns the framecounter 498 * value for which this timestamp is valid. 499 * 500 * @param ts address to store the timestamp in 501 * @param fc address to store the associated framecounter in 502 */ 503 void TimestampedBuffer::getBufferTailTimestamp(uint64_t *ts, uint64_t *fc) { 504 pthread_mutex_lock(&m_framecounter_lock); 505 *fc = m_framecounter; 506 *ts = m_buffer_tail_timestamp; 507 pthread_mutex_unlock(&m_framecounter_lock); 508 } 509 510 /** 511 * Resets the frame counter, in a atomic way. This 512 * is thread safe. 513 */ 514 void TimestampedBuffer::resetFrameCounter() { 515 pthread_mutex_lock(&m_framecounter_lock); 516 m_framecounter = 0; 517 pthread_mutex_unlock(&m_framecounter_lock); 518 } 519 694 * @brief Print status info. 695 */ 696 void TimestampedBuffer::dumpInfo() { 697 698 uint64_t ts_head, fc; 699 getBufferHeadTimestamp(&ts_head,&fc); 700 701 int64_t diff=(int64_t)ts_head - (int64_t)m_buffer_tail_timestamp; 702 703 debugOutputShort( DEBUG_LEVEL_NORMAL, " TimestampedBuffer (%p) info:\n",this); 704 debugOutputShort( DEBUG_LEVEL_NORMAL, " Frame counter : %d\n", m_framecounter); 705 debugOutputShort( DEBUG_LEVEL_NORMAL, " Buffer head timestamp : %011llu\n",ts_head); 706 debugOutputShort( DEBUG_LEVEL_NORMAL, " Buffer tail timestamp : %011llu\n",m_buffer_tail_timestamp); 707 debugOutputShort( DEBUG_LEVEL_NORMAL, " Head - Tail : %011lld\n",diff); 708 debugOutputShort( DEBUG_LEVEL_NORMAL, " rate : %lf (%f)\n",m_dll_e2,m_dll_e2/m_update_period); 709 } 520 710 521 711 } // end of namespace FreebobUtil