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

📄 audio_sdl.cpp

📁 网络MPEG4IP流媒体开发源代码
💻 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. 2000, 2001.  All Rights Reserved. *  * Contributor(s):  *              Bill May        wmay@cisco.com *//* * audio.cpp provides an interface (CAudioSync) between the codec and * the SDL audio APIs. */#include <stdlib.h>#include <string.h>#include "player_session.h"#include "audio_sdl.h"#include "player_util.h"#include <SDL_thread.h>#include "our_config_file.h"//#define DEBUG_SYNC 1//#define DEBUG_SYNC_CHANGES 1//#define DEBUG_AUDIO_FILL 1//#define DEBUG_DELAY 1#ifdef _WIN32DEFINE_MESSAGE_MACRO(audio_message, "audiosync")#else#define audio_message(loglevel, fmt...) message(loglevel, "audiosync", fmt)#endif/* * c routine to call into the AudioSync class callback */static void c_audio_callback (void *userdata, Uint8 *stream, int len){  CSDLAudioSync *a = (CSDLAudioSync *)userdata;  a->audio_callback(stream, len);}/* * Create an CSDLAudioSync for a session.  Don't alloc any buffers until * config is called by codec */CSDLAudioSync::CSDLAudioSync (CPlayerSession *psptr, int volume) :  CAudioSync(psptr){  SDL_Init(SDL_INIT_AUDIO | SDL_INIT_NOPARACHUTE);  m_fill_index = m_play_index = 0;  for (int ix = 0; ix < DECODE_BUFFERS_MAX; ix++) {    m_buffer_filled[ix] = 0;    m_sample_buffer[ix] = NULL;  }  m_buffer_size = 0;  m_config_set = 0;  m_audio_initialized = 0;  m_audio_paused = 1;  m_resync_required = 0;  m_dont_fill = 0;  m_consec_no_buffers = 0;  //SDL_Init(SDL_INIT_AUDIO);  m_audio_waiting_buffer = 0;  m_audio_waiting = SDL_CreateSemaphore(0); //NULL; // will be set by decode thread  m_skipped_buffers = 0;  m_didnt_fill_buffers = 0;  m_play_time = 0         ;  m_buffer_latency = 0;  m_volume = (volume * SDL_MIX_MAXVOLUME)/100;  m_first_time = 1;  m_first_filled = 1;  m_buffer_offset_on = 0;  m_buffer_ts = 0;  m_load_audio_do_next_resync = 0;}/* * Close out audio sync - stop and disconnect from SDL */CSDLAudioSync::~CSDLAudioSync (void){  SDL_PauseAudio(1);  SDL_CloseAudio();  for (int ix = 0; ix < DECODE_BUFFERS_MAX; ix++) {    if (m_sample_buffer[ix] != NULL)      free(m_sample_buffer[ix]);    m_sample_buffer[ix] = NULL;  }  audio_message(LOG_NOTICE, 		"Audio sync skipped %u buffers", 		m_skipped_buffers);  audio_message(LOG_NOTICE, "didn't fill %u buffers", m_didnt_fill_buffers);  SDL_DestroySemaphore(m_audio_waiting);}/* * codec api - set up information about the stream */void CSDLAudioSync::set_config (int freq, 			     int channels, 			     int format, 			     uint32_t sample_size) {  if (m_config_set != 0)     return;    if (format == AUDIO_U8 || format == AUDIO_S8)    m_bytes_per_sample = 1;  else    m_bytes_per_sample = 2;  if (sample_size == 0) {    int temp;    temp = freq;    while ((temp & 0x1) == 0) temp >>= 1;    sample_size = temp;    while (sample_size < 1024) sample_size *= 2;    while (((sample_size * 1000) % freq) != 0) sample_size *= 2;  }     m_buffer_size = channels * sample_size * m_bytes_per_sample;  for (int ix = 0; ix < DECODE_BUFFERS_MAX; ix++) {    m_buffer_filled[ix] = 0;    // I'm not sure where the 2 * comes in... Check this out    m_sample_buffer[ix] =       (uint8_t *)malloc(2 * m_buffer_size);  }  m_freq = freq;  m_channels = channels;  m_format = format;  m_config_set = 1;  m_msec_per_frame = (sample_size * 1000) / m_freq;  audio_message(LOG_DEBUG, "buffer size %d msec per frame %d", 		m_buffer_size, m_msec_per_frame);};/* * Codec api - get_audio_buffer - will wait if there are no available * buffers */uint8_t *CSDLAudioSync::get_audio_buffer (void){  int ret;  int locked = 0;  if (m_dont_fill == 1) {#ifdef DEBUG_AUDIO_FILL    audio_message(LOG_DEBUG, "first dont fill");#endif    return (NULL);  }  if (m_audio_initialized != 0) {    locked = 1;    SDL_LockAudio();  }  ret = m_buffer_filled[m_fill_index];  if (locked)    SDL_UnlockAudio();  if (ret == 1) {    m_audio_waiting_buffer = 1;    SDL_SemWait(m_audio_waiting);    m_audio_waiting_buffer = 0;    if (m_dont_fill != 0) {#ifdef DEBUG_AUDIO_FILL      audio_message(LOG_DEBUG, "2nd don't fill");#endif      return (NULL);    }    locked = 0;    if (m_audio_initialized != 0) {      SDL_LockAudio();      locked = 1;    }    ret = m_buffer_filled[m_fill_index];    if (locked)      SDL_UnlockAudio();    if (ret == 1) {#ifdef DEBUG_AUDIO_FILL      audio_message(LOG_DEBUG, "no buff");#endif      return (NULL);    }  }  return (m_sample_buffer[m_fill_index]);}void CSDLAudioSync::load_audio_buffer (uint8_t *from, 				       uint32_t bytes, 				       uint64_t ts, 				       int resync){  uint8_t *to;  uint32_t copied;#ifdef DEBUG_AUDIO_FILL  audio_message(LOG_DEBUG, "fill %d bytes at "LLU", offset %d resync %d", 		bytes, ts, m_buffer_offset_on, resync);#endif  copied = 0;  if (m_buffer_offset_on == 0) {    if (m_buffer_ts != 0 && m_buffer_ts != ts) {      m_load_audio_do_next_resync = 1;      audio_message(LOG_DEBUG, "timeslot doesn't match - %llu %llu",		    ts, m_buffer_ts);    }    m_buffer_ts = ts;  } else {    int64_t check;    check = ts - m_loaded_next_ts;    if (check > m_msec_per_frame) {      audio_message(LOG_DEBUG, "potential resync at ts "LLU" should be ts "LLU,		    ts, m_loaded_next_ts);      uint32_t left;      left = m_buffer_size - m_buffer_offset_on;      to = get_audio_buffer();      memset(to + m_buffer_offset_on, 0, left);      filled_audio_buffer(m_buffer_ts, 0);      m_buffer_offset_on = 0;      m_load_audio_do_next_resync = 1;      m_buffer_ts = ts;    }  }  m_loaded_next_ts = bytes * M_LLU;  m_loaded_next_ts /= m_bytes_per_sample;  m_loaded_next_ts /= m_freq;  m_loaded_next_ts += ts;  while ( bytes > 0) {    to = get_audio_buffer();    if (to == NULL) {      return;    }    int copy;    uint32_t left;    left = m_buffer_size - m_buffer_offset_on;    copy = MIN(left, bytes);    memcpy(to + m_buffer_offset_on, 	   from,	   copy);    bytes -= copy;    copied += copy;    from += copy;    m_buffer_offset_on += copy;    if (m_buffer_offset_on >= m_buffer_size) {      m_buffer_offset_on = 0;      filled_audio_buffer(m_buffer_ts, resync | m_load_audio_do_next_resync);      m_buffer_ts += m_msec_per_frame;      resync = 0;      m_load_audio_do_next_resync = 0;    }  }  return;}      /* * filled_audio_buffer - codec API - after codec fills the buffer from * get_audio_buffer, it will call here. */void CSDLAudioSync::filled_audio_buffer (uint64_t ts, int resync){  uint32_t fill_index;  int locked;  // m_dont_fill will be set when we have a pause  if (m_dont_fill == 1) {    return;  }  //  resync = 0;  fill_index = m_fill_index;  m_fill_index++;  m_fill_index %= DECODE_BUFFERS_MAX;  locked = 0;  if (m_audio_initialized != 0) {    SDL_LockAudio();    locked = 1;  }  if (m_first_filled != 0) {    m_first_filled = 0;    resync = 0;    m_resync_required = 0;  } else {    int64_t diff;    diff = ts - m_last_fill_timestamp;    if (diff - m_msec_per_frame > m_msec_per_frame) {      // have a hole here - don't want to resync#ifdef DEBUG_AUDIO_FILL      audio_message(LOG_DEBUG, 		    "Filling - last %llu new %llu", m_last_fill_timestamp, ts);#endif      if (diff > ((m_msec_per_frame + 1) * 4)) {#ifdef DEBUG_AUDIO_FILL      audio_message(LOG_DEBUG, 		    "resync required %lld", diff);#endif	resync = 1;      } else {	// try to fill the holes	m_last_fill_timestamp += m_msec_per_frame + 1; // fill plus extra	if (locked)	  SDL_UnlockAudio();	int64_t ts_diff;	do {	  uint8_t *retbuffer;	  // Get and swap buffers.	  retbuffer = get_audio_buffer();	  if (retbuffer == NULL) {	    return;	  }	  if (retbuffer != m_sample_buffer[m_fill_index]) {	    audio_message(LOG_ERR, "retbuffer not fill index in audio sync");	    return;	  }	  locked = 0;	  if (m_audio_initialized != 0) {	    SDL_LockAudio();	    locked = 1;	  }	  m_sample_buffer[m_fill_index] = m_sample_buffer[fill_index];	  m_sample_buffer[fill_index] = retbuffer;	  memset(retbuffer, m_obtained.silence, m_buffer_size);	  m_buffer_time[fill_index] = m_last_fill_timestamp;	  m_buffer_filled[fill_index] = 1;	  m_samples_loaded += m_buffer_size;	  fill_index++;	  fill_index %= DECODE_BUFFERS_MAX;	  m_fill_index++;	  m_fill_index %= DECODE_BUFFERS_MAX;	  if (locked)	    SDL_UnlockAudio();	  audio_message(LOG_NOTICE, "Filling timestamp %llu with silence",			m_last_fill_timestamp);	  m_last_fill_timestamp += m_msec_per_frame + 1; // fill plus extra	  ts_diff = ts - m_last_fill_timestamp;	  audio_message(LOG_DEBUG, "diff is %lld", ts_diff);	} while (ts_diff > 0);	locked = 0;	if (m_audio_initialized != 0) {	  SDL_LockAudio();	  locked = 1;	}      }    } else {      if (m_last_fill_timestamp == ts) {	audio_message(LOG_NOTICE, "Repeat timestamp with audio %llu", ts);	if (locked)	  SDL_UnlockAudio();	return;      }    }  }  m_last_fill_timestamp = ts;  m_buffer_filled[fill_index] = 1;  m_samples_loaded += m_buffer_size;  m_buffer_time[fill_index] = ts;  if (resync) {    m_resync_required = 1;    m_resync_buffer = fill_index;#ifdef DEBUG_AUDIO_FILL    audio_message(LOG_DEBUG, "Resync from filled_audio_buffer");#endif  }  if (locked)    SDL_UnlockAudio();  // Check this - we might not want to do this unless we're resyncing  if (resync)    m_psptr->wake_sync_thread();#ifdef DEBUG_AUDIO_FILL  audio_message(LOG_DEBUG, "Filling " LLU " %u %u", 		ts, fill_index, m_samples_loaded);#endif}void CSDLAudioSync::set_eof(void) {   uint8_t *to;  if (m_buffer_offset_on != 0) {    to = get_audio_buffer();    if (to != NULL) {      uint32_t left;      left = m_buffer_size - m_buffer_offset_on;      memset(to + m_buffer_offset_on, 0, left);      m_buffer_offset_on = 0;      filled_audio_buffer(m_buffer_ts, 0);      m_buffer_ts += m_msec_per_frame;    }  }  CAudioSync::set_eof();}// Sync task api - initialize the sucker.// May need to check out non-standard frequencies, see about conversion.// returns 0 for not yet, 1 for initialized, -1 for errorint CSDLAudioSync::initialize_audio (int have_video) {  if (m_audio_initialized == 0) {    if (m_config_set) {      SDL_AudioSpec wanted;      m_do_sync = have_video;      memset(&wanted, 0, sizeof(wanted));      wanted.freq = m_freq;      wanted.channels = m_channels;      wanted.format = m_format;      int sample_size;      sample_size = m_buffer_size / (m_channels * m_bytes_per_sample);#ifndef _WIN32      uint32_t ix;      for (ix = 2; ix <= 0x8000; ix <<= 1) {	if ((sample_size & ~(ix - 1)) == 0) {	  break;	}      }      ix >>= 1;      audio_message(LOG_DEBUG, "Sample size is %d", ix);      m_sample_size = ix;#else      m_sample_size = 4096;#endif      if ((m_do_sync == 0) && m_sample_size < 4096)	m_sample_size = 4096;      if (config.get_config_value(CONFIG_LIMIT_AUDIO_SDL_BUFFER) > 0 &&	  m_sample_size > 4096) 	m_sample_size = 4096;      wanted.samples = m_sample_size;      wanted.callback = c_audio_callback;      wanted.userdata = this;#if 1       audio_message(LOG_INFO, 		     "requested f %d chan %d format %x samples %d",		     wanted.freq,		     wanted.channels,		     wanted.format,		     wanted.samples);#endif      int ret = SDL_OpenAudio(&wanted, &m_obtained);      if (ret < 0) {	audio_message(LOG_CRIT, "Couldn't open audio, %s", SDL_GetError());	return (-1);      }#if 1       audio_message(LOG_INFO, "got f %d chan %d format %x samples %d size %u",		     m_obtained.freq,		     m_obtained.channels,		     m_obtained.format,		     m_obtained.samples,		     m_obtained.size);#endif      m_audio_initialized = 1;      m_use_SDL_delay = SDL_HasAudioDelayMsec();      if (m_use_SDL_delay)	audio_message(LOG_NOTICE, "Using delay measurement from SDL");    } else {      return 0; // check again pretty soon...    }  }  return (1);}// This is used by the sync thread to determine if a valid amount of// buffers are ready, and what time they start.  It is used to determine// when we should start.int CSDLAudioSync::is_audio_ready (uint64_t &disptime){  disptime = m_buffer_time[m_play_index];  return (m_dont_fill == 0 && m_buffer_filled[m_play_index] == 1);

⌨️ 快捷键说明

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