static void aout_CheckRestart (audio_output_t *aout) { aout_owner_t *owner = aout_owner (aout); aout_assert_locked (aout); int restart = vlc_atomic_swap (&owner->restart, 0); if (likely(restart == 0)) return; assert (restart & AOUT_RESTART_INPUT); const aout_request_vout_t request_vout = owner->input->request_vout; if (likely(owner->input != NULL)) aout_InputDelete (aout, owner->input); owner->input = NULL; /* Reinitializes the output */ if (restart & AOUT_RESTART_OUTPUT) { aout_MixerDelete (owner->volume.mixer); owner->volume.mixer = NULL; aout_OutputDelete (aout); if (aout_OutputNew (aout, &owner->input_format)) return; /* we are officially screwed */ owner->volume.mixer = aout_MixerNew (aout, owner->mixer_format.i_format); } owner->input = aout_InputNew (aout, &owner->input_format, &owner->mixer_format, &request_vout); }
/** * Stops all plugins involved in the audio output. */ void aout_Shutdown (audio_output_t *p_aout) { aout_owner_t *owner = aout_owner (p_aout); aout_input_t *input; struct audio_mixer *mixer; aout_lock( p_aout ); /* Remove the input. */ input = owner->input; if (likely(input != NULL)) aout_InputDelete (p_aout, input); owner->input = NULL; mixer = owner->volume.mixer; owner->volume.mixer = NULL; var_DelCallback (p_aout, "audio-replay-gain-mode", ReplayGainCallback, owner); aout_OutputDelete( p_aout ); var_Destroy( p_aout, "audio-device" ); var_Destroy( p_aout, "audio-channels" ); aout_unlock( p_aout ); aout_MixerDelete (mixer); free (input); }
static int aout_CheckReady (audio_output_t *aout) { aout_owner_t *owner = aout_owner (aout); int status = AOUT_DEC_SUCCESS; int restart = atomic_exchange (&owner->restart, 0); if (unlikely(restart)) { if (owner->mixer_format.i_format) aout_FiltersDelete (aout, owner->filters); if (restart & AOUT_RESTART_OUTPUT) { /* Reinitializes the output */ msg_Dbg (aout, "restarting output..."); if (owner->mixer_format.i_format) aout_OutputDelete (aout); owner->mixer_format = owner->input_format; if (aout_OutputNew (aout, &owner->mixer_format)) owner->mixer_format.i_format = 0; aout_volume_SetFormat (owner->volume, owner->mixer_format.i_format); status = AOUT_DEC_CHANGED; } msg_Dbg (aout, "restarting filters..."); owner->sync.end = VLC_TS_INVALID; owner->sync.resamp_type = AOUT_RESAMPLING_NONE; if (owner->mixer_format.i_format) { owner->filters = aout_FiltersNew (aout, &owner->input_format, &owner->mixer_format, &owner->request_vout); if (owner->filters == NULL) { aout_OutputDelete (aout); owner->mixer_format.i_format = 0; } } /* TODO: This would be a good time to call clean up any video output * left over by an audio visualization: input_resource_TerminatVout(MAGIC HERE); */ } return (owner->mixer_format.i_format) ? status : AOUT_DEC_FAILED; }
static int aout_CheckReady (audio_output_t *aout) { aout_owner_t *owner = aout_owner (aout); aout_assert_locked (aout); int restart = atomic_exchange (&owner->restart, 0); if (unlikely(restart)) { const aout_request_vout_t request_vout = owner->request_vout; if (owner->mixer_format.i_format) aout_FiltersDelete (aout); if (restart & AOUT_RESTART_OUTPUT) { /* Reinitializes the output */ msg_Dbg (aout, "restarting output..."); if (owner->mixer_format.i_format) aout_OutputDelete (aout); owner->mixer_format = owner->input_format; if (aout_OutputNew (aout, &owner->mixer_format)) owner->mixer_format.i_format = 0; aout_volume_SetFormat (owner->volume, owner->mixer_format.i_format); } msg_Dbg (aout, "restarting filters..."); owner->sync.end = VLC_TS_INVALID; owner->sync.resamp_type = AOUT_RESAMPLING_NONE; if (owner->mixer_format.i_format && aout_FiltersNew (aout, &owner->input_format, &owner->mixer_format, &request_vout)) { aout_OutputDelete (aout); owner->mixer_format.i_format = 0; } } return (owner->mixer_format.i_format) ? 0 : -1; }
/** * Stops all plugins involved in the audio output. */ void aout_DecDelete (audio_output_t *aout) { aout_owner_t *owner = aout_owner (aout); aout_OutputLock (aout); if (owner->mixer_format.i_format) { aout_FiltersDelete (aout, owner->filters); aout_OutputDelete (aout); } aout_volume_Delete (owner->volume); aout_OutputUnlock (aout); var_Destroy (aout, "stereo-mode"); }
/***************************************************************************** * aout_DecDelete : delete a decoder *****************************************************************************/ int aout_DecDelete( aout_instance_t * p_aout, aout_input_t * p_input ) { int i_input; /* This function can only be called by the decoder itself, so no need * to lock p_input->lock. */ vlc_mutex_lock( &p_aout->mixer_lock ); for ( i_input = 0; i_input < p_aout->i_nb_inputs; i_input++ ) { if ( p_aout->pp_inputs[i_input] == p_input ) { break; } } if ( i_input == p_aout->i_nb_inputs ) { msg_Err( p_aout, "cannot find an input to delete" ); return -1; } /* Remove the input from the list. */ memmove( &p_aout->pp_inputs[i_input], &p_aout->pp_inputs[i_input + 1], (AOUT_MAX_INPUTS - i_input - 1) * sizeof(aout_input_t *) ); p_aout->i_nb_inputs--; aout_InputDelete( p_aout, p_input ); vlc_mutex_destroy( &p_input->lock ); free( p_input ); if ( !p_aout->i_nb_inputs ) { aout_OutputDelete( p_aout ); aout_MixerDelete( p_aout ); if ( var_Type( p_aout, "audio-device" ) != 0 ) { var_Destroy( p_aout, "audio-device" ); } if ( var_Type( p_aout, "audio-channels" ) != 0 ) { var_Destroy( p_aout, "audio-channels" ); } } vlc_mutex_unlock( &p_aout->mixer_lock ); return 0; }
/** * Creates an audio output */ int aout_DecNew( audio_output_t *p_aout, const audio_sample_format_t *p_format, const audio_replay_gain_t *p_replay_gain, const aout_request_vout_t *p_request_vout ) { /* Sanitize audio format */ unsigned i_channels = aout_FormatNbChannels( p_format ); if( i_channels != p_format->i_channels && AOUT_FMT_LINEAR( p_format ) ) { msg_Err( p_aout, "incompatible audio channels count with layout mask" ); return -1; } if( p_format->i_rate > 352800 ) { msg_Err( p_aout, "excessive audio sample frequency (%u)", p_format->i_rate ); return -1; } if( p_format->i_rate < 4000 ) { msg_Err( p_aout, "too low audio sample frequency (%u)", p_format->i_rate ); return -1; } var_Create (p_aout, "stereo-mode", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT); vlc_value_t txt; txt.psz_string = _("Stereo audio mode"); var_Change (p_aout, "stereo-mode", VLC_VAR_SETTEXT, &txt, NULL); aout_owner_t *owner = aout_owner(p_aout); /* TODO: reduce lock scope depending on decoder's real need */ aout_OutputLock (p_aout); /* Create the audio output stream */ owner->volume = aout_volume_New (p_aout, p_replay_gain); atomic_store (&owner->restart, 0); owner->input_format = *p_format; owner->mixer_format = owner->input_format; owner->request_vout = *p_request_vout; if (aout_OutputNew (p_aout, &owner->mixer_format)) goto error; aout_volume_SetFormat (owner->volume, owner->mixer_format.i_format); /* Create the audio filtering "input" pipeline */ owner->filters = aout_FiltersNew (p_aout, p_format, &owner->mixer_format, &owner->request_vout); if (owner->filters == NULL) { aout_OutputDelete (p_aout); error: aout_volume_Delete (owner->volume); owner->volume = NULL; aout_OutputUnlock (p_aout); var_Destroy (p_aout, "stereo-mode"); return -1; } owner->sync.end = VLC_TS_INVALID; owner->sync.resamp_type = AOUT_RESAMPLING_NONE; owner->sync.discontinuity = true; aout_OutputUnlock (p_aout); atomic_init (&owner->buffers_lost, 0); atomic_init (&owner->buffers_played, 0); return 0; }
/** * Creates an audio output */ int aout_DecNew( audio_output_t *p_aout, const audio_sample_format_t *p_format, const audio_replay_gain_t *p_replay_gain, const aout_request_vout_t *p_request_vout ) { /* Sanitize audio format */ if( p_format->i_channels != aout_FormatNbChannels( p_format ) ) { msg_Err( p_aout, "incompatible audio channels count with layout mask" ); return -1; } if( p_format->i_rate > 352800 ) { msg_Err( p_aout, "excessive audio sample frequency (%u)", p_format->i_rate ); return -1; } if( p_format->i_rate < 4000 ) { msg_Err( p_aout, "too low audio sample frequency (%u)", p_format->i_rate ); return -1; } aout_owner_t *owner = aout_owner(p_aout); /* TODO: reduce lock scope depending on decoder's real need */ aout_OutputLock (p_aout); var_Destroy( p_aout, "stereo-mode" ); /* Create the audio output stream */ owner->volume = aout_volume_New (p_aout, p_replay_gain); atomic_store (&owner->restart, (atomic_uchar)0); // sunqueen modify owner->input_format = *p_format; owner->mixer_format = owner->input_format; owner->request_vout = *p_request_vout; if (aout_OutputNew (p_aout, &owner->mixer_format)) goto error; aout_volume_SetFormat (owner->volume, owner->mixer_format.i_format); /* Create the audio filtering "input" pipeline */ owner->filters = aout_FiltersNew (p_aout, p_format, &owner->mixer_format, &owner->request_vout); if (owner->filters == NULL) { aout_OutputDelete (p_aout); error: aout_volume_Delete (owner->volume); aout_OutputUnlock (p_aout); return -1; } owner->sync.end = VLC_TS_INVALID; owner->sync.resamp_type = AOUT_RESAMPLING_NONE; owner->sync.discontinuity = true; aout_OutputUnlock (p_aout); atomic_init (&owner->buffers_lost, 0); return 0; }
/***************************************************************************** * aout_DecNew : create a decoder *****************************************************************************/ static aout_input_t * DecNew( vlc_object_t * p_this, aout_instance_t * p_aout, audio_sample_format_t * p_format ) { aout_input_t * p_input; input_thread_t * p_input_thread; vlc_value_t val; /* We can only be called by the decoder, so no need to lock * p_input->lock. */ vlc_mutex_lock( &p_aout->mixer_lock ); if ( p_aout->i_nb_inputs >= AOUT_MAX_INPUTS ) { msg_Err( p_aout, "too many inputs already (%d)", p_aout->i_nb_inputs ); return NULL; } p_input = malloc(sizeof(aout_input_t)); if ( p_input == NULL ) { msg_Err( p_aout, "out of memory" ); return NULL; } vlc_mutex_init( p_aout, &p_input->lock ); p_input->b_changed = 0; p_input->b_error = 1; aout_FormatPrepare( p_format ); memcpy( &p_input->input, p_format, sizeof(audio_sample_format_t) ); p_aout->pp_inputs[p_aout->i_nb_inputs] = p_input; p_aout->i_nb_inputs++; if ( p_aout->mixer.b_error ) { int i; var_Destroy( p_aout, "audio-device" ); var_Destroy( p_aout, "audio-channels" ); /* Recreate the output using the new format. */ if ( aout_OutputNew( p_aout, p_format ) < 0 ) { for ( i = 0; i < p_aout->i_nb_inputs - 1; i++ ) { vlc_mutex_lock( &p_aout->pp_inputs[i]->lock ); aout_InputDelete( p_aout, p_aout->pp_inputs[i] ); vlc_mutex_unlock( &p_aout->pp_inputs[i]->lock ); } vlc_mutex_unlock( &p_aout->mixer_lock ); return p_input; } /* Create other input streams. */ for ( i = 0; i < p_aout->i_nb_inputs - 1; i++ ) { vlc_mutex_lock( &p_aout->pp_inputs[i]->lock ); aout_InputDelete( p_aout, p_aout->pp_inputs[i] ); aout_InputNew( p_aout, p_aout->pp_inputs[i] ); vlc_mutex_unlock( &p_aout->pp_inputs[i]->lock ); } } else { aout_MixerDelete( p_aout ); } if ( aout_MixerNew( p_aout ) == -1 ) { aout_OutputDelete( p_aout ); vlc_mutex_unlock( &p_aout->mixer_lock ); return NULL; } aout_InputNew( p_aout, p_input ); vlc_mutex_unlock( &p_aout->mixer_lock ); var_Create( p_this, "audio-desync", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT ); var_Get( p_this, "audio-desync", &val ); p_input->i_desync = val.i_int * 1000; p_input_thread = (input_thread_t *)vlc_object_find( p_this, VLC_OBJECT_INPUT, FIND_PARENT ); if( p_input_thread ) { p_input->i_pts_delay = p_input_thread->i_pts_delay; p_input->i_pts_delay += p_input->i_desync; vlc_object_release( p_input_thread ); } else { p_input->i_pts_delay = DEFAULT_PTS_DELAY; p_input->i_pts_delay += p_input->i_desync; } return p_input; }
/***************************************************************************** * aout_Restart : re-open the output device and rebuild the input and output * pipelines ***************************************************************************** * This function is used whenever the parameters of the output plug-in are * changed (eg. selecting S/PDIF or PCM). *****************************************************************************/ static int aout_Restart( aout_instance_t * p_aout ) { int i; bool b_error = 0; aout_lock_mixer( p_aout ); if ( p_aout->i_nb_inputs == 0 ) { aout_unlock_mixer( p_aout ); msg_Err( p_aout, "no decoder thread" ); return -1; } /* Lock all inputs. */ aout_lock_input_fifos( p_aout ); for ( i = 0; i < p_aout->i_nb_inputs; i++ ) { aout_lock_input( p_aout, p_aout->pp_inputs[i] ); aout_InputDelete( p_aout, p_aout->pp_inputs[i] ); } aout_MixerDelete( p_aout ); /* Re-open the output plug-in. */ aout_OutputDelete( p_aout ); if ( aout_OutputNew( p_aout, &p_aout->pp_inputs[0]->input ) == -1 ) { /* Release all locks and report the error. */ for ( i = 0; i < p_aout->i_nb_inputs; i++ ) { vlc_mutex_unlock( &p_aout->pp_inputs[i]->lock ); } aout_unlock_input_fifos( p_aout ); aout_unlock_mixer( p_aout ); return -1; } if ( aout_MixerNew( p_aout ) == -1 ) { aout_OutputDelete( p_aout ); for ( i = 0; i < p_aout->i_nb_inputs; i++ ) { vlc_mutex_unlock( &p_aout->pp_inputs[i]->lock ); } aout_unlock_input_fifos( p_aout ); aout_unlock_mixer( p_aout ); return -1; } /* Re-open all inputs. */ for ( i = 0; i < p_aout->i_nb_inputs; i++ ) { aout_input_t * p_input = p_aout->pp_inputs[i]; b_error |= aout_InputNew( p_aout, p_input ); p_input->b_changed = 1; aout_unlock_input( p_aout, p_input ); } aout_unlock_input_fifos( p_aout ); aout_unlock_mixer( p_aout ); return b_error; }
/** * Creates an audio output */ int aout_DecNew( audio_output_t *p_aout, const audio_sample_format_t *p_format, const audio_replay_gain_t *p_replay_gain, const aout_request_vout_t *p_request_vout ) { /* Sanitize audio format */ if( p_format->i_channels > 32 ) { msg_Err( p_aout, "too many audio channels (%u)", p_format->i_channels ); return -1; } if( p_format->i_channels <= 0 ) { msg_Err( p_aout, "no audio channels" ); return -1; } if( p_format->i_channels != aout_FormatNbChannels( p_format ) ) { msg_Err( p_aout, "incompatible audio channels count with layout mask" ); return -1; } if( p_format->i_rate > 192000 ) { msg_Err( p_aout, "excessive audio sample frequency (%u)", p_format->i_rate ); return -1; } if( p_format->i_rate < 4000 ) { msg_Err( p_aout, "too low audio sample frequency (%u)", p_format->i_rate ); return -1; } aout_owner_t *owner = aout_owner(p_aout); #ifdef RECYCLE /* Calling decoder is responsible for serializing aout_DecNew() and * aout_DecDelete(). So no need to lock to _read_ those properties. */ if (owner->module != NULL) /* <- output exists */ { /* Check if we can recycle the existing output and pipelines */ if (AOUT_FMTS_IDENTICAL(&owner->input_format, p_format)) return 0; /* TODO? If the new input format is closer to the output format than * the old input format was, then the output could be recycled. The * input pipeline however would need to be restarted. */ /* No recycling: delete everything and restart from scratch */ aout_Shutdown (p_aout); } #endif int ret = 0; /* TODO: reduce lock scope depending on decoder's real need */ aout_lock( p_aout ); assert (owner->module == NULL); /* Create the audio output stream */ var_Destroy( p_aout, "audio-device" ); var_Destroy( p_aout, "audio-channels" ); owner->input_format = *p_format; vlc_atomic_set (&owner->restart, 0); if( aout_OutputNew( p_aout, p_format ) < 0 ) { ret = -1; goto error; } /* Allocate a software mixer */ assert (owner->volume.mixer == NULL); owner->volume.mixer = aout_MixerNew (p_aout, owner->mixer_format.i_format); aout_ReplayGainInit (&owner->gain.data, p_replay_gain); var_AddCallback (p_aout, "audio-replay-gain-mode", ReplayGainCallback, owner); var_TriggerCallback (p_aout, "audio-replay-gain-mode"); /* Create the audio filtering "input" pipeline */ date_Init (&owner->sync.date, owner->mixer_format.i_rate, 1); date_Set (&owner->sync.date, VLC_TS_INVALID); assert (owner->input == NULL); owner->input = aout_InputNew (p_aout, p_format, &owner->mixer_format, p_request_vout); if (owner->input == NULL) { struct audio_mixer *mixer = owner->volume.mixer; owner->volume.mixer = NULL; aout_OutputDelete (p_aout); aout_unlock (p_aout); aout_MixerDelete (mixer); return -1; } error: aout_unlock( p_aout ); return ret; }