⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 audio_buffer.cpp

📁 完整的RTP RTSP代码库
💻 CPP
📖 第 1 页 / 共 2 页
字号:
/**************************************************************************** *  APIs from sync task ****************************************************************************/int CBufferAudioSync::initialize_audio (int have_video){  if (m_hardware_initialized == false) {    if (m_audio_configured) {      if (InitializeHardware() < 0) {	return -1;      }      m_hardware_initialized = true;     } else {      return 0; // check again    }  }  return 1; // yes, we're initialized}      int CBufferAudioSync::is_audio_ready (uint64_t &disptime){  disptime = m_first_ts;#if 0  audio_message(LOG_DEBUG, "%d %u %u %u", 		m_dont_fill, m_filled_bytes, m_output_buffer_size_bytes,		m_sample_buffer_size);#endif  return m_dont_fill == false && m_filled_bytes >= 2 * m_output_buffer_size_bytes;}// This will need to be rewritten.bool CBufferAudioSync::check_audio_sync (uint64_t current_time, 					 uint64_t &resync_time,					 int64_t &wait_time,					 bool &have_eof,					 bool &restart_sync){  // if we have an eof indication, wait until we're paused by the callback  wait_time = 0;  if (get_eof() != 0) {    have_eof = m_audio_paused;    return false;  }  if (m_have_resync && m_audio_paused) {    // add latency to current_time    wait_time = m_resync_ts - current_time;    m_jitter_calc_ts =       m_first_ts = m_resync_ts;    m_jitter_calc_freq_ts =       m_first_freq_ts = m_resync_freq_ts;    if (wait_time > TO_D64(1000)) {      // the resync time is greater than a second off.  We want to      // change state.      resync_time = m_resync_ts;      return true;    }    if (wait_time > TO_D64(10)) {      // we're still waiting - under 1 sec until continue - means we had      // an outage of a number of frames.      return false;    }    if (wait_time >= TO_D64(-10)) {      // resync time is greater than 10 mseconds in the past.  We can      // go ahead and restart      audio_message(LOG_INFO, "restarting resync audio");      m_have_resync = false;      play_audio();      return false;    }    // resync time is further in the past than 10 msec.  We should    // just restart.    resync_time = m_resync_ts;    return true;  } else if (m_audio_paused) {    if (m_filled_bytes >= 2 * m_output_buffer_size_bytes) {      // we have them resync the time here after we've gotten bytes      resync_time = m_first_ts;      m_jitter_calc_ts = 	m_first_ts = resync_time;      m_jitter_calc_freq_ts = 	m_first_freq_ts = m_first_freq_ts;      wait_time = resync_time - current_time;      if (wait_time < 0) restart_sync = true;      audio_message(LOG_INFO, 		    "restart from stopped - resync time "U64" written "U64,		    resync_time, m_samples_written);      return true;    }   }  return false;}/* * play_audio - call from the sync task to start playing. */void CBufferAudioSync::play_audio (void) {  m_audio_paused = 0;  m_first_callback = true;  m_samples_written = 0;  m_have_resync = false;  m_have_jitter = false;  m_jitter_msec = 0;  m_jitter_msec_total = 0;  StartHardware();}/* * flush_sync_buffers - basically, a pause from the sync side -  * stop the hardware, indicate that the decoder shouldn't fill,  * and trigger the decoder task if it is waiting */void CBufferAudioSync::flush_sync_buffers (void){  clear_eof();  StopHardware();  m_dont_fill = true;  callback_done();}/*************************************************************************** * routines used for callback ***************************************************************************//* * callback_done - wake the decoder task, if it's waiting for us * to get done */void CBufferAudioSync::callback_done (void){  if (m_audio_waiting_buffer) {    m_audio_waiting_buffer = false;    SDL_SemPost(m_audio_waiting);  }}/* * audio_buffer_callback - callback that will put bytes in  * the output buffer.  * Inputs: *  outbuf - pointer to buffer *  len_bytes - length (in bytes, not sample) of output buffer *  latency_samples - latency in samples *  current_time - time latency measurement was taken */bool CBufferAudioSync::audio_buffer_callback (uint8_t *outbuf, 					      uint32_t len_bytes,					      uint32_t latency_samples,					      uint64_t current_time){  uint32_t outBufferSamples, outBufferBytes;  uint32_t decodedBufferBytes, decodedBufferSamples;  uint64_t hw_start_time = 0;  bool first_callback = m_first_callback;#ifdef DEBUG_AUDIO_CALLBACK  audio_message(LOG_DEBUG, "audio callback - filled %u bytes %u", 		m_filled_bytes, len_bytes);#endif  // If we don't have any bytes pending, stop the hardware.  Let the  // sync task resync us, if needed.  if (m_filled_bytes == 0) {    // this was commented out to let the sync task restart us... Let's    // see if it works.    //if (get_eof()) {    // note - there are 2 places that do this - see below      audio_message(LOG_DEBUG, "audio stopping");      StopHardware();      m_audio_paused = true;      m_first_filled = false;       m_restart_request = true;      m_have_jitter = false;      m_jitter_msec = 0;      m_jitter_msec_total = 0;      m_psptr->wake_sync_thread();      return false;      //}    // used to do a count of consecutive no buffers count here -     // I'm not sure that's a good idea.    //callback_done();    //return;  }    // Now, we're going to check the real timing vs. the theoretical#ifdef DEBUG_AUDIO_TIMING  audio_message(LOG_DEBUG, "samples "U64" latency %u", m_samples_written,		latency_samples);#endif  if (m_first_callback == false &&      m_samples_written > 5 * m_freq * m_bytes_per_sample_output) {    // we're going to check time vs samples written, perhaps remove    // or add samples.    uint64_t written_samples = m_samples_written;    uint64_t real_samples;    uint64_t diff;    bool add_samples;    written_samples -= latency_samples;    // this has something to do with when we have a latency reading    // at the beginning.  We could have a case where the current time    // is less than the start time.  I'm not sure why we flip the    // sign and it seems to work, but it does.    if (current_time >= m_hw_start_time) {      real_samples = current_time - m_hw_start_time;    } else {      real_samples = m_hw_start_time - current_time;    }    real_samples *= m_freq;    real_samples /= TO_U64(1000000);    if (real_samples >= written_samples) {      diff = real_samples - written_samples;      add_samples = false;    } else {      diff = written_samples - real_samples;      add_samples = true;    }#ifdef DEBUG_AUDIO_TIMING    audio_message(LOG_DEBUG, "current "U64" hwstart "U64,		  current_time, m_hw_start_time);    audio_message(LOG_DEBUG, "samples "U64" real "D64 " diff "U64 " %d",		  written_samples, real_samples, diff, add_samples);#endif    if (m_decode_format == AUDIO_FMT_HW_AC3) {      /*       * With AC3, we need to do whole frames worth - 256 * 6 samples       */      if (diff >= TO_U64(256 * 6)) {	if (add_samples) {	  m_total_samples_played += 256 * 6;	  uint16_t len = 0;	  CopyBytesToHardware((uint8_t *)&len,			      outbuf, 			      2);	  len_bytes -= 2;	  return true;	} else {	  uint16_t len = m_sample_buffer[m_play_offset] << 8;	  m_play_offset++;	  len |= m_sample_buffer[m_play_offset];	  m_play_offset++;	  m_play_offset += len;	  m_filled_bytes -= len + 2;	  m_samples_written += 256 * 6;	}      }    } else {      /*       * regular PCM buffers - remove or add samples       */      if (add_samples) {	if (diff >= TO_U64(3) &&	    m_last_add_samples && 	    m_last_diff >= TO_U64(3)) {	  // notice that we don't touch m_samples_written	  // also, we don't do this when play_offset is 0 - this means	  // we're at a wrapping point, and we don't want to be there...	  if (m_play_offset != 0) {	    void *interp = interpolate_3_samples(&m_sample_buffer[m_play_offset]);	    CopyBytesToHardware((uint8_t *)interp, 				outbuf, 				3 * m_bytes_per_sample_output);	    	    outbuf += 3 * m_bytes_per_sample_output;	    len_bytes -= 3 * m_bytes_per_sample_output;	    m_sync_samples_added += 3;#if defined(DEBUG_AUDIO_TIMING) || defined(DEBUG_AUDIO_TIMING_CHANGES)	    audio_message(LOG_INFO, "adding 3 samples of silence for clock sync "U64" %u",			  diff, m_filled_bytes);#endif	  }	}      } else {	if (diff >= TO_U64(10)) {	  uint64_t bytes;	  // need to remove samples	  diff /= 2;	  bytes = diff * m_bytes_per_sample_input;	  if (bytes > m_filled_bytes) {	    // restart here - this shouldn't happen...	    audio_message(LOG_ERR, "sync requires removing "U64" bytes - we only have %u in the buffer", 			  bytes, m_filled_bytes);	  } else {	    m_sync_samples_removed += diff;	    m_samples_written += diff;	    m_filled_bytes -= bytes;	    m_play_offset += bytes;	    if (m_play_offset > m_sample_buffer_size) {	      m_play_offset -= m_sample_buffer_size;	    }	  }#if defined(DEBUG_AUDIO_TIMING) || defined(DEBUG_AUDIO_TIMING_CHANGES)	  audio_message(LOG_INFO, "removing "U64" samples for sync", 			diff);#endif	}      }    }    // note - at some point, we'll need to compare the msec timestamp    // vs the frequency timestamp, to see if jitter has occurred there.    // this will be done in the load and fill routines, and then passed    // here or to the sync task - we'll want to adjust the start time.    m_last_add_samples = add_samples;    m_last_diff = diff;  }  if (m_decode_format == AUDIO_FMT_HW_AC3) {    // first 2 bytes are len.    uint16_t len = m_sample_buffer[m_play_offset] << 8;    m_play_offset++;    len |= m_sample_buffer[m_play_offset];    m_play_offset++;    if (m_play_offset >= m_sample_buffer_size) {      m_play_offset = 0;    }    while (len > 0) {      uint32_t to_copy;      if (m_play_offset + len > m_sample_buffer_size) {	to_copy = m_sample_buffer_size - m_play_offset;      } else {	to_copy = len;      }      CopyBytesToHardware(m_sample_buffer + m_play_offset, 			  outbuf,			  len);      len -= to_copy;      m_play_offset += len;      if (m_play_offset >= m_sample_buffer_size) {	m_play_offset = 0;      }    }    m_filled_bytes -= len + 2;    m_samples_written += 256 * 6; // always the same number of samples for AC3    m_total_samples_played += 256 * 6;  } else {    bool done = false;    if (m_filled_bytes / m_bytes_per_sample_input <	len_bytes / m_bytes_per_sample_output) {      audio_message(LOG_ERR, 		    "filled bytes less than requested: %u (%u) req %u (%u)",		    m_filled_bytes, m_bytes_per_sample_input,		    len_bytes, m_bytes_per_sample_output);    }    while (done == false) {      // We need to determine how many samples to write - the number      // of output bytes might not be the number of bytes in the buffer -       // due to channel/format conversion      if (m_have_resync) {	// if we have resync, write up to the resync value	if (m_resync_offset < m_play_offset) {	  decodedBufferBytes = m_sample_buffer_size - m_play_offset;	} else {	  decodedBufferBytes = m_resync_offset - m_play_offset;	}      } else {	// otherwise, make sure we're not going past the end of the	// buffer	if (m_play_offset + m_filled_bytes > m_sample_buffer_size) {	  decodedBufferBytes = m_sample_buffer_size - m_play_offset;	} else {	  decodedBufferBytes = m_filled_bytes;	}      }      // calculate the decoded samples from bytes      decodedBufferSamples = decodedBufferBytes / m_bytes_per_sample_input;      // calculate the number of samples we can write to the buffer      outBufferSamples = len_bytes / m_bytes_per_sample_output;      // take the min value      outBufferSamples = MIN(decodedBufferSamples, outBufferSamples);      m_samples_written += outBufferSamples;      m_total_samples_played += outBufferSamples;         // calculate the number of decoded and output buffer bytes      decodedBufferBytes = outBufferSamples * m_bytes_per_sample_input;      outBufferBytes = outBufferSamples * m_bytes_per_sample_output;      if (first_callback) {	hw_start_time = get_time_of_day_usec();	first_callback = false;      }      if (m_convert_buffer) {	// convert the data, and write it	audio_convert_data(m_sample_buffer + m_play_offset,			   outBufferSamples);	CopyBytesToHardware((uint8_t *)m_convert_buffer, outbuf, outBufferBytes);      } else {	// no conversion, just write	CopyBytesToHardware(m_sample_buffer + m_play_offset, 			    outbuf, 			    outBufferBytes);      }      // increment the output buffer      outbuf += outBufferBytes;      // increment the play offset      m_play_offset += decodedBufferBytes;      if (m_play_offset >= m_sample_buffer_size) {	m_play_offset = 0;      }      // increment the number of bytes left to copy      len_bytes -= outBufferBytes;      // increment the number of bytes left in the decode buffer      m_filled_bytes -= decodedBufferBytes;      // 3 ways we are done - if we have no bytes to copy,       // if we have no bytes left in the buffer,       // or if we have resync and are now at the resync offset      if (len_bytes == 0) {	done = true;      } else if (m_filled_bytes == 0) {	audio_message(LOG_DEBUG, "no filled bytes");	done = true;      } else if (m_have_resync && m_play_offset == m_resync_offset) {	done = true;      }    }  }  // TODO note - if m_filled_bytes is 0 here, we're going to have some  // problems - we might want to resync at the fill offset, because  // our # of samples written is not going to equal filled bytes -   // that is if len != 0  if (m_filled_bytes == 0 && len_bytes != 0 && get_eof() == false) {    // it's not really a resync - it's more like indicate that we    // need to restart the sync process    audio_message(LOG_DEBUG, "ran out of bytes");    StopHardware();    m_first_filled = false;     m_restart_request = true;    m_audio_paused = true;    m_have_jitter = false;    m_jitter_msec = 0;    m_jitter_msec_total = 0;    m_psptr->wake_sync_thread();   }#ifdef DEBUG_AUDIO_CALLBACK  audio_message(LOG_DEBUG, "callback fillbytes %u", m_filled_bytes);#endif  if (m_have_resync && m_play_offset == m_resync_offset) {    // need to do resync    audio_message(LOG_INFO, "stopping audio callback for resync");    StopHardware();    m_audio_paused = true;    m_psptr->wake_sync_thread();  }  if (m_first_callback) {    m_first_callback = false;    // need to adjust hw_start_time by latency, so we can determine    // when to start the video    uint64_t latency_usec = 0;    if (latency_samples > 0) {      latency_usec = latency_samples * TO_U64(1000000);      latency_usec /= m_freq;    }    m_hw_start_time = hw_start_time + latency_usec;    m_latency_value = latency_usec / TO_U64(1000);#ifdef DEBUG_AUDIO_TIMING    audio_message(LOG_DEBUG, "hw start "U64" latency "U64,		  m_hw_start_time, latency_usec);#endif    //     m_psptr->audio_is_ready(m_latency_value, m_first_ts);  } else {    if (m_have_jitter) {      audio_message(LOG_DEBUG, "adjusting start time "D64" due to jitter",		    m_jitter_msec);      m_psptr->adjust_start_time(m_jitter_msec);      m_have_jitter = false;      m_jitter_msec = 0;    }  }  callback_done();  return true;}void CBufferAudioSync::display_status (void){  audio_message(LOG_DEBUG, "audio buffer %d %u next %u "U64, 		m_audio_waiting_buffer, 		m_filled_bytes, m_buffer_next_freq_ts, m_buffer_next_ts);}/* end file audio_buffer.cpp */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -