📄 audio_macosx_old.cpp
字号:
need_convert = true; } PaError err; audio_message(LOG_DEBUG, "pa_open default %lx", format); err = Pa_OpenDefaultStream(&m_pa_stream, 0, m_channels, format, freq, m_sample_size, 0, c_audio_callback, this); m_got_channels = m_channels; if (err != paNoError) { if (err == paInvalidChannelCount) { format = paInt16; err = Pa_OpenDefaultStream(&m_pa_stream, 0, 2, format, freq, m_sample_size, 0, c_audio_callback, this); m_got_channels = 2; need_convert = true; } if (err != paNoError) { audio_message(LOG_CRIT, "Couldn't open audio, %s", Pa_GetErrorText(err)); return (-1); } } if (need_convert) { m_convert_buffer = malloc(m_sample_size); audio_message(LOG_DEBUG, "convert buffer size is %d", m_sample_size); m_fmt_buffer = (int16_t *)malloc(m_sample_size * 2 * m_channels); } m_audio_initialized = 1; //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);}// Used by the sync thread to see if resync is needed.// 0 - in sync. > 0 - sync time we need. -1 - need to do sync uint64_t CSDLAudioSync::check_audio_sync (uint64_t current_time, int &have_eof){ if (get_eof() != 0) { have_eof = m_audio_paused; return (0); } // audio is initialized. if (m_resync_required) { if (m_audio_paused && m_buffer_filled[m_resync_buffer]) { // Calculate the current time based on the latency SDL_LockMutex(m_pa_mutex); current_time += m_buffer_latency; uint64_t cmptime; int freed = 0; // Compare with times in buffer - we may need to skip if we fell // behind. do { cmptime = m_buffer_time[m_resync_buffer]; if (cmptime < current_time) {#ifdef DEBUG_SYNC audio_message(LOG_INFO, "Passed time " U64 " " U64 " %u", cmptime, current_time, m_resync_buffer);#endif m_buffer_filled[m_resync_buffer] = 0; m_resync_buffer++; m_resync_buffer %= DECODE_BUFFERS_MAX; freed = 1; } } while (m_buffer_filled[m_resync_buffer] == 1 && cmptime < current_time - 2); SDL_UnlockMutex(m_pa_mutex); if (m_buffer_filled[m_resync_buffer] == 0) { cmptime = 0; } else { if (cmptime >= current_time) { m_play_index = m_resync_buffer; m_resync_required = 0; play_audio();#ifdef DEBUG_SYNC audio_message(LOG_INFO, "Resynced audio at " U64 " %u %u", current_time, m_resync_buffer, m_play_index);#endif cmptime = 0; } } if (freed != 0 && m_audio_waiting_buffer) { m_audio_waiting_buffer = 0; SDL_SemPost(m_audio_waiting); // audio_message(LOG_DEBUG, "post free passed time"); } return cmptime; } else { return (0); } } return (0);}// Audio callback from SDL.int CSDLAudioSync::audio_callback (void *oStream, unsigned long bLen, PaTimestamp outtime){ uint8_t *outStream = (uint8_t *)oStream; int freed_buffer = 0; uint32_t outBufferTotalBytes = bLen * m_got_channels * m_bytes_per_sample_output; uint64_t this_time; uint64_t index_time; uint64_t delay; // audio_message(LOG_DEBUG,"bytes %u %lu outtime %g", // outBufferTotalBytes, bLen, outtime); if (m_resync_required) { // resync required from codec side. Shut down, and notify sync task if (m_resync_buffer == m_play_index) { //Pa_StopStream(m_pa_stream); m_audio_paused = 1; m_psptr->wake_sync_thread();#ifdef DEBUG_SYNC audio_message(LOG_DEBUG, "sempost");#endif return 1; } } m_play_time = m_psptr->get_current_time(); delay = 0; PaTimestamp realtime = Pa_StreamTime(m_pa_stream); delay = (uint64_t)(outtime - realtime); delay *= TO_U64(1000); delay /= m_freq;#ifdef DEBUG_DELAY audio_message(LOG_DEBUG, "cur time %llu delay %llu %12f %12f", m_play_time, delay, outtime, realtime);#endif uint64_t temp = 0; this_time = m_buffer_time[m_play_index]; if ((m_first_time == 0) && (m_play_sample_index != 0)) { temp = (uint64_t) m_play_sample_index * (uint64_t)m_msec_per_frame; temp /= (uint64_t) m_buffer_size; this_time += temp; }#if 0 audio_message(LOG_DEBUG, "time "U64" "U64, m_buffer_time[m_play_index], temp);#endif // Do we have a buffer ? If no, see if we need to stop. if (m_buffer_bytes_loaded == 0) { if (get_eof()) { //Pa_StopStream(m_pa_stream); m_audio_paused = 1; m_psptr->wake_sync_thread(); return 1; }#ifdef DEBUG_SYNC audio_message(LOG_DEBUG, "No buffer in audio callback %u %u", m_buffer_bytes_loaded, outBufferTotalBytes);#endif m_consec_no_buffers++; int ret = 0; if (m_consec_no_buffers > 10) { //Pa_StopStream(m_pa_stream); m_audio_paused = 1; m_resync_required = 1; m_resync_buffer = m_play_index; m_psptr->wake_sync_thread(); ret = 1; } if (m_audio_waiting_buffer) { m_audio_waiting_buffer = 0; SDL_SemPost(m_audio_waiting); //audio_message(LOG_DEBUG, "post no data"); } audio_message(LOG_DEBUG, "return - no samples"); return ret; } // We have a valid buffer. Push it to SDL. m_consec_no_buffers = 0; while (outBufferTotalBytes > 0) { uint32_t outBufferSamples, outBufferBytes; uint32_t decodedBufferBytes, decodedBufferSamples; // calculate number of bytes left in the decoded bytes ring decodedBufferBytes = m_buffer_size - m_play_sample_index; // samples from bytes decodedBufferSamples = decodedBufferBytes / (m_channels * m_bytes_per_sample_input); // See how many samples we can write into SDL buffers outBufferSamples = outBufferTotalBytes / (m_got_channels * m_bytes_per_sample_output); // Adjust bytes from decoded ring accordingly if (outBufferSamples < decodedBufferSamples) { decodedBufferBytes = outBufferSamples * m_channels * m_bytes_per_sample_input; decodedBufferSamples = outBufferSamples; } // Adjust bytes to copy outBufferBytes = decodedBufferSamples * m_got_channels * m_bytes_per_sample_output;#ifdef DEBUG_SYNC audio_message(LOG_DEBUG, "Playing "U64" offset %d", m_buffer_time[m_play_index], m_play_sample_index);#endif if (m_convert_buffer) { // Convert the buffer based on the number of samples audio_convert_data(&m_sample_buffer[m_play_index][m_play_sample_index], decodedBufferSamples); // Mix based on the number of bytes // need to adjust for volume memcpy(outStream, m_convert_buffer, outBufferBytes); } else { memcpy(outStream, &m_sample_buffer[m_play_index][m_play_sample_index], outBufferBytes); } outBufferTotalBytes -= outBufferBytes; outStream += outBufferBytes; if (decodedBufferBytes <= m_buffer_bytes_loaded) m_buffer_bytes_loaded -= decodedBufferBytes; else m_buffer_bytes_loaded = 0; m_play_sample_index += decodedBufferBytes; if (m_play_sample_index >= m_buffer_size) {#ifdef DEBUG_SYNC audio_message(LOG_DEBUG, "finished with buffer %d %d", m_play_index, m_buffer_bytes_loaded);#endif m_buffer_filled[m_play_index] = 0; m_play_index++; m_play_index %= DECODE_BUFFERS_MAX; m_play_sample_index = 0; freed_buffer = 1; if (m_resync_required) { // resync required from codec side. Shut down, and notify sync task if (m_resync_buffer == m_play_index) { Pa_StopStream(m_pa_stream); m_audio_paused = 1; m_psptr->wake_sync_thread();#ifdef DEBUG_SYNC audio_message(LOG_DEBUG, "sempost");#endif outBufferTotalBytes = 0; } } } } // Increment past this buffer. if (m_first_time != 0) { // First time through - tell the sync task we've started, so it can // keep sync time. m_first_time = 0; m_buffer_latency = delay; m_psptr->audio_is_ready(m_buffer_latency, this_time); m_consec_wrong_latency = 0; m_wrong_latency_total = 0; } else if (m_do_sync) {#define ALLOWED_LATENCY 2 // Here, we're using the delay value from the audio buffers, // rather than the calculated time... // Okay - now we check for latency changes. index_time = delay + m_play_time; if (this_time > index_time + ALLOWED_LATENCY || this_time < index_time - ALLOWED_LATENCY) {#ifdef DEBUG_SYNC_CHANGES audio_message(LOG_DEBUG, "potential change - index time "U64" time "U64" delay "U64, index_time, this_time, delay);#endif if (m_consec_wrong_latency == 0) { m_consec_wrong_latency = 1; } else { m_consec_wrong_latency++; int64_t test; test = this_time - index_time; m_wrong_latency_total += test; int64_t div; div = m_wrong_latency_total / (int64_t)(m_consec_wrong_latency - 1);#ifdef DEBUG_SYNC_CHANGES audio_message(LOG_DEBUG, "values are "D64" "D64" %d", test, div, m_consec_wrong_latency);#endif if (test > ALLOWED_LATENCY || test < -ALLOWED_LATENCY) { if (m_consec_wrong_latency > 5) { m_consec_wrong_latency = 0; m_wrong_latency_total = 0; if (test < -10000) { audio_message(LOG_ERR, "Latency error - test is "D64, test); } else { m_psptr->adjust_start_time(test); m_buffer_latency -= test; } } } else { // average wrong latency is not greater than allowed latency m_consec_wrong_latency = 0; m_wrong_latency_total = 0; } } } else { m_consec_wrong_latency = 0; m_wrong_latency_total = 0; } } else {#ifdef DEBUG_SYNC audio_message(LOG_DEBUG, "playing "U64" "U64" latency "U64, this_time, m_play_time, m_buffer_latency);#endif } // If we had the decoder task waiting, signal it. if (freed_buffer != 0 && m_audio_waiting_buffer) { m_audio_waiting_buffer = 0; SDL_SemPost(m_audio_waiting); //audio_message(LOG_DEBUG, "post freed"); } return 0;}void CSDLAudioSync::play_audio (void){ m_first_time = 1; //m_resync_required = 0; m_audio_paused = 0; m_play_sample_index = 0; audio_message(LOG_DEBUG, "Starting pa"); Pa_StartStream(m_pa_stream);}// Called from the sync thread when we want to stop. Pause the audio,// and indicate that we're not to fill any more buffers - this should let// the decode thread get back to receive the pause message. Only called// when pausing - could cause m_dont_fill race conditions if called on playvoid CSDLAudioSync::flush_sync_buffers (void){ // we don't need to signal the decode task right now - // Go ahead clear_eof(); Pa_StopStream(m_pa_stream); m_dont_fill = 1; if (m_audio_waiting_buffer) { m_audio_waiting_buffer = 0; SDL_SemPost(m_audio_waiting); //audio_message(LOG_DEBUG, "post flush sync"); } player_debug_message("Flushed sync");}// this is called from the decode thread. It gets called on entry into pause,// and entry into play. This way, m_dont_fill race conditions are resolved.void CSDLAudioSync::flush_decode_buffers (void){ int locked = 0; if (m_audio_initialized != 0) { locked = 1; SDL_LockMutex(m_pa_mutex); } m_dont_fill = 0; m_first_filled = 1; for (int ix = 0; ix < DECODE_BUFFERS_MAX; ix++) { m_buffer_filled[ix] = 0; } m_buffer_offset_on = 0; m_play_index = m_fill_index = 0; m_audio_paused = 1; m_resync_buffer = 0; m_buffer_bytes_loaded = 0; if (locked) SDL_UnlockMutex(m_pa_mutex); //player_debug_message("flushed decode");}void CSDLAudioSync::set_volume (int volume){ m_volume = (volume * SDL_MIX_MAXVOLUME)/100;}static void c_audio_config (void *ifptr, int freq, int chans, audio_format_t format, uint32_t max_buffer_size){ ((CSDLAudioSync *)ifptr)->set_config(freq, chans, format, max_buffer_size);}static uint8_t *c_get_audio_buffer (void *ifptr){ return ((CSDLAudioSync *)ifptr)->get_audio_buffer();}static void c_filled_audio_buffer (void *ifptr, uint32_t freq_ts, uint64_t ts, int resync_req){ ((CSDLAudioSync *)ifptr)->filled_audio_buffer(ts, resync_req);}static void c_load_audio_buffer (void *ifptr, uint8_t *from, uint32_t bytes, uint32_t freq_ts, uint64_t ts, int resync){ ((CSDLAudioSync *)ifptr)->load_audio_buffer(from, bytes, ts, resync);} static audio_vft_t audio_vft = { message, c_audio_config, c_get_audio_buffer, c_filled_audio_buffer, c_load_audio_buffer, NULL,};CAudioSync *create_audio_sync (CPlayerSession *psptr, int volume){ return new CSDLAudioSync(psptr, volume);}audio_vft_t *get_audio_vft (void){ audio_vft.pConfig = &config; return &audio_vft;}int do_we_have_audio (void) { PaError err; err = Pa_Initialize(); if (err != paNoError) { audio_message(LOG_ERR, "No audio - %d %s", err, Pa_GetErrorText(err)); return 0; } Pa_Terminate(); // Our_SDL_CloseAudio(); return (1);}/* end audio.cpp */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -