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

📄 audio_buffer.cpp

📁 完整的RTP RTSP代码库
💻 CPP
📖 第 1 页 / 共 2 页
字号:
/* * The contents of this file are subject to the Mozilla Public * License Version 1.1 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.mozilla.org/MPL/ *  * Software distributed under the License is distributed on an "AS * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or * implied. See the License for the specific language governing * rights and limitations under the License. *  * The Original Code is MPEG4IP. *  * The Initial Developer of the Original Code is Cisco Systems Inc. * Portions created by Cisco Systems Inc. are * Copyright (C) Cisco Systems Inc. 2004.  All Rights Reserved. *  * Contributor(s):  *              Bill May        wmay@cisco.com *//* * audio_buffer.cpp contains code to handle an audio ring buffer with a * generic set of rendering code. */#include "audio_buffer.h"#include "player_session.h"#include "player_util.h"#include "our_config_file.h"//#define DEBUG_AUDIO_FILL 1//#define DEBUG_AUDIO_CALLBACK 1//#define DEBUG_AUDIO_TIMING 1//#define DEBUG_AUDIO_TIMING_CHANGES 1#ifdef _WIN32DEFINE_MESSAGE_MACRO(audio_message, "audiobuf")#else#define audio_message(loglevel, fmt...) message(loglevel, "audiobuf", fmt)#endifCBufferAudioSync::CBufferAudioSync (CPlayerSession *psptr, int volume) :  CAudioSync(psptr){  m_sample_buffer = NULL;  m_local_buffer = NULL;  m_fill_offset = 0;  m_play_offset = 0;  m_first_filled = false;  m_dont_fill = false;  m_audio_waiting_buffer = false;  m_audio_waiting = SDL_CreateSemaphore(0);  m_have_resync = false;  m_waiting_on_resync = false;  m_resync_offset = 0;  m_resync_ts = 0;  m_resync_freq_ts = 0;  m_audio_configured = false;  m_mutex = SDL_CreateMutex();   m_hardware_initialized = false;  m_audio_paused = true;  m_first_callback = true;  m_restart_request = true;  m_sync_samples_added = 0;  m_sync_samples_removed = 0;  m_total_samples_played = 0;  m_have_jitter = false;  m_jitter_msec = 0;  m_jitter_msec_total = 0;  m_last_add_samples = false;}CBufferAudioSync::~CBufferAudioSync (void){  CHECK_AND_FREE(m_sample_buffer);  CHECK_AND_FREE(m_local_buffer);  SDL_DestroySemaphore(m_audio_waiting);  SDL_DestroyMutex(m_mutex);  // display stats  audio_message(LOG_INFO, "total samples played: "U64, m_total_samples_played);  audio_message(LOG_INFO, "sync samples added  : "U64, m_sync_samples_added);  audio_message(LOG_INFO, "sync samples removed: "U64, m_sync_samples_removed);  if (m_total_samples_played > 0) {    uint64_t calc = m_total_samples_played +       m_sync_samples_added - m_sync_samples_removed;    calc *= m_freq;    calc /= m_total_samples_played;    audio_message(LOG_INFO, "calculated output frequency : "U64, calc);  }}/**************************************************************************** * routines used when filling buffers ****************************************************************************//* * do_we_need_resync - look at the freq_ts given, and see if it matches * what we are expecting. * returns true if we need a resync, false if we're on or about the time  *  - silence_samples will contain the number of samples that freq_ts is *    past the expected time */  bool CBufferAudioSync::do_we_need_resync (uint32_t freq_ts,					  uint32_t &silence_samples){  if (m_first_filled == false) return false;  if (m_buffer_next_freq_ts == freq_ts)    return false;  int32_t sample_diff = freq_ts - m_buffer_next_freq_ts;  int32_t compare_val = 4 * m_samples_per_frame;  // note - the 2 is so that we handle rounding errors that occur when  // converting timescales to frequency scales (ie: 90000 to 44100).  if (sample_diff > 2 && sample_diff <= compare_val) {    audio_message(LOG_DEBUG, "sample diff is %d %d", sample_diff, compare_val);    audio_message(LOG_DEBUG, "freq_ts %u next %u", 		  freq_ts, m_buffer_next_freq_ts);    silence_samples = sample_diff;    return false;  } else if (sample_diff >= -1) {    m_buffer_next_freq_ts = freq_ts; // rounding error, probably    return false;  }  return true;}/* * wait_for_callback - will perform a wait until the callback routine * signals us */void CBufferAudioSync::wait_for_callback (void){  m_audio_waiting_buffer = true;  SDL_SemWait(m_audio_waiting);  m_audio_waiting_buffer = false;}/* * fill_silence will copy the correct number of silence bytes into * the output buffer */void CBufferAudioSync::fill_silence (uint32_t silence_bytes){  audio_message(LOG_INFO, "Inserting %u silence bytes at "U64" (%u)",		silence_bytes, m_buffer_next_ts, m_buffer_next_freq_ts);  bool lock = Lock();  while (silence_bytes > 0) {    uint32_t diff = m_sample_buffer_size - m_fill_offset;    uint32_t copied = MIN(diff, silence_bytes);    memset(m_sample_buffer + m_fill_offset, 	   m_silence, 	   copied);    m_fill_offset += copied;    m_filled_bytes += copied;    if (m_fill_offset >= m_sample_buffer_size) {      m_fill_offset = 0;    }    silence_bytes -= copied;  }  if (lock) Unlock();}/* * check_for_bytes makes sure that there is the correct number of * bytes in the buffer for us to insert */bool CBufferAudioSync::check_for_bytes (uint32_t bytes,					uint32_t silence_bytes){  bool locked;  uint32_t diff;  uint32_t to_insert;  uint32_t count;  to_insert = bytes + silence_bytes;  count = 0;  // this has changed a bit - we're going to wait a couple of  // callbacks, in case the output sample size rate is < the number  // of bytes to fill.  do {    if (m_dont_fill) return false;    locked = Lock();    diff = m_sample_buffer_size - m_filled_bytes;    if (locked) Unlock();        if (diff >= to_insert) return true;    count++;    wait_for_callback();  } while (count < 5);  return false;}/************************************************************************** * APIs from plugins **************************************************************************//* * set_config - set up the audio stream configuration */void CBufferAudioSync::set_config (uint32_t freq, 				   uint32_t chans,				   audio_format_t format, 				   uint32_t samples_per_frame){  if (m_audio_configured == false) {    audio_message(LOG_DEBUG, "audio configure");    m_freq = freq;    m_decode_format = format;    m_channels = chans;    m_samples_per_frame = samples_per_frame;    m_silence = 0;    switch (format) {    case AUDIO_FMT_U8:      m_silence = 0x80;      // fall through    case AUDIO_FMT_S8:    case AUDIO_FMT_HW_AC3:      m_bytes_per_sample_input = sizeof(uint8_t);      break;    case AUDIO_FMT_U16LSB:    case AUDIO_FMT_S16LSB:    case AUDIO_FMT_U16MSB:    case AUDIO_FMT_S16MSB:    case AUDIO_FMT_U16:    case AUDIO_FMT_S16:      m_bytes_per_sample_input = sizeof(int16_t);      break;    case AUDIO_FMT_FLOAT:      m_bytes_per_sample_input = sizeof(float);      break;    }       // this can be used for converting directly from bytes to samples    m_bytes_per_sample_input *= m_channels;    if (samples_per_frame == 0) {      if (config.get_config_value(CONFIG_LIMIT_AUDIO_SDL_BUFFER) > 1) {	m_samples_per_frame = config.get_config_value(CONFIG_LIMIT_AUDIO_SDL_BUFFER);      } else 	m_samples_per_frame = m_freq / 20; // estimate for inserting silence      m_sample_buffer_size = m_freq;    } else {      m_sample_buffer_size = 32 * m_samples_per_frame;    }    // allocate so if plugin gives the number of samples, that we    // never have wrap...    m_sample_buffer_size *= m_bytes_per_sample_input;    m_sample_buffer = (uint8_t *)malloc(m_sample_buffer_size);    audio_message(LOG_DEBUG, "ring buffer size is %u", m_sample_buffer_size);    m_bytes_per_frame = m_samples_per_frame * m_bytes_per_sample_input;    m_msec_per_frame = (m_samples_per_frame * 1000);    m_msec_per_frame /= m_freq;    m_audio_configured = true;    m_psptr->send_sync_thread_a_message(MSG_AUDIO_CONFIGURED);  }}/* * get_audio_buffer - get a fixed size buffer - # of samples passed in when * config'ed.  Paired with filled_audio_buffer to complete transaction. * because the get_audio_buffer and filled_audio_buffer do similiar things,  * and we might want to inject a couple of bytes of silence, we're just * using a temp buffer to fill. */uint8_t *CBufferAudioSync::get_audio_buffer (uint32_t freq_ts,					     uint64_t ts){  if (m_dont_fill) {    return NULL;  }  if (m_local_buffer == NULL) {    m_local_buffer = (uint8_t *)malloc(m_bytes_per_frame);  }  m_got_buffer_ts = ts;  m_got_buffer_freq_ts = freq_ts;  return m_local_buffer;}  /* * filled_audio_buffer - plugin is done writing frame into buffer */void CBufferAudioSync::filled_audio_buffer (void){  load_audio_buffer(m_local_buffer, 		    m_bytes_per_frame, 		    m_got_buffer_freq_ts,		    m_got_buffer_ts);}/* * load_audio_buffer - used by routines that don't know how many * samples/bytes they need to write at 1 time */void CBufferAudioSync::load_audio_buffer (const uint8_t *from,					  uint32_t bytes,					  uint32_t freq_ts,					  uint64_t ts){  uint32_t silence_bytes = 0;  bool locked;  bool need_resync;  uint32_t samples;  uint32_t write_bytes;  if (m_dont_fill) return;   if (m_decode_format == AUDIO_FMT_HW_AC3) {    samples = 256 * 6;    write_bytes = bytes + 2;  } else {    samples = bytes / m_bytes_per_sample_input;    write_bytes = bytes;  }#ifdef DEBUG_AUDIO_FILL  audio_message(LOG_DEBUG, "load samples %u ts "U64"(%u) - expect %u", 		bytes, ts, freq_ts, m_buffer_next_freq_ts);#endif  need_resync = do_we_need_resync(freq_ts, silence_bytes);  if (need_resync) {    // we need to resync    locked = Lock();    if (m_have_resync) {      // we have another resync pending asdf      if (locked) Unlock();      wait_for_callback();    } else {      if (locked) Unlock();    }  }      // we may have a situation where we don't have enough for the  // silence byte, but enough for the frame - this means resync -   // for now, we're not going to allow  silence_bytes *= m_bytes_per_sample_input;  if (check_for_bytes(write_bytes, silence_bytes) == false) {    // can't insert.  If no silence bytes, return NULL    if (silence_bytes == 0) {      audio_message(LOG_ERR, "Couldn't insert encoded %u bytes at %u", 		    write_bytes, freq_ts);      return;    }    // See if we can insert this frame without the silence bytes -     // this will require a resync, but at least we don't lose anything    silence_bytes = 0;    need_resync = true;    if (check_for_bytes(write_bytes, 0) == false) {      audio_message(LOG_ERR, "Couldn't put %u resync bytes at %u", 		    write_bytes, freq_ts);      return;    }  }  if (silence_bytes > 0) {    fill_silence(silence_bytes);  }    locked = Lock();  if (need_resync) {    m_resync_offset = m_fill_offset;    m_resync_ts = ts;    m_resync_freq_ts = freq_ts;    m_have_resync = need_resync;    m_first_filled = false;    // reset jitter calcs    m_have_jitter = false;    m_jitter_msec = 0;    m_jitter_msec_total = 0;  } else {    if (m_first_filled) {      int32_t diff = freq_ts - m_jitter_calc_freq_ts;      int64_t calc_diff = (int64_t)diff;      calc_diff *= TO_D64(1000);      calc_diff /= (int64_t)m_freq;      int64_t msec_diff = ts - m_jitter_calc_ts;      int64_t add_diff;      msec_diff -= m_jitter_msec_total;      add_diff = msec_diff - calc_diff;      if (add_diff != 0) {#if 0	static int64_t last_diff = 0;	if (last_diff != msec_diff) {	  audio_message(LOG_DEBUG, "first diff "D64 " %u", msec_diff,			m_filled_bytes);	  last_diff = msec_diff;	}#endif	if (add_diff > TO_D64(10) || add_diff < TO_D64(-10)) {	  audio_message(LOG_DEBUG, "jitter calc start %u now %u diff %d",			m_jitter_calc_freq_ts, freq_ts, diff);	  audio_message(LOG_DEBUG, "ts start "U64" now "U64" diff "D64,			ts, m_jitter_calc_ts, msec_diff);	  audio_message(LOG_DEBUG, "calc diff "D64" add "D64,			calc_diff, add_diff);	  m_jitter_msec_total += add_diff;	  m_have_jitter = true;	  m_jitter_msec += add_diff;	}      }       if (diff > (int32_t) m_freq || add_diff == 0) {	m_jitter_calc_freq_ts = freq_ts;	m_jitter_calc_ts = ts;      }    }  }  if (m_decode_format == AUDIO_FMT_HW_AC3) {    // write header here    m_sample_buffer[m_fill_offset] = bytes >> 8;    m_fill_offset++;    if (m_fill_offset >= m_sample_buffer_size) m_fill_offset = 0;    m_sample_buffer[m_fill_offset] = bytes & 0xff;    m_fill_offset++;    if (m_fill_offset >= m_sample_buffer_size) m_fill_offset = 0;  }  // copy the bytes to the buffer - be aware of wrap at the end of  // the buffer.  while (bytes > 0) {    uint32_t to_copy = MIN(bytes, m_sample_buffer_size - m_fill_offset);    memcpy(m_sample_buffer + m_fill_offset, 	   from,	   to_copy);    from += to_copy;    m_fill_offset += to_copy;    if (m_fill_offset >= m_sample_buffer_size) {      m_fill_offset = 0;    }    bytes -= to_copy;    m_filled_bytes += to_copy;  }  if (need_resync) {    audio_message(LOG_DEBUG, "resync - freq ts %u should be %u",		  freq_ts, m_buffer_next_freq_ts);  }  // record timestamp information for next frame.  // note - if first_ts is used, we may need to move this inside the  // mutex routines.  if (m_first_filled == false) {    m_first_ts = ts;    m_first_freq_ts = freq_ts;    m_first_filled = true;    m_jitter_calc_freq_ts = freq_ts;    m_jitter_calc_ts = ts;  }  /*   * TODO note: we're going to need to calculate to see if there is   * any jitter between the freq_ts and the ts   */  m_buffer_next_freq_ts = freq_ts + samples;  m_buffer_next_ts = ts + (samples * 1000) / m_freq;  m_have_resync |= need_resync;  if (locked) Unlock();#ifdef DEBUG_AUDIO_FILL  audio_message(LOG_DEBUG, "filled %u bytes at %u - total %u %u", 		write_bytes, freq_ts, m_filled_bytes, 		m_sample_buffer_size);#endif}/* * flush_decode_buffers - clear out the information so we can start * from scratch. */void CBufferAudioSync::flush_decode_buffers (void){  bool locked = Lock();  m_dont_fill = false;  m_first_filled = false;  m_fill_offset = 0;  m_play_offset = 0;  m_filled_bytes = 0;  // m_have_resync = true;  why ?  m_audio_paused = true;  m_have_jitter = false;  m_jitter_msec = 0;  m_jitter_msec_total = 0;  if (locked) Unlock();}

⌨️ 快捷键说明

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