/** * 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; }
/***************************************************************************** * 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; } for ( i = 0; i < p_aout->i_nb_inputs; i++ ) { aout_lock_input( p_aout, p_aout->pp_inputs[i] ); aout_lock_input_fifos( p_aout ); aout_InputDelete( p_aout, p_aout->pp_inputs[i] ); aout_unlock_input_fifos( p_aout ); } /* Lock all inputs. */ aout_lock_input_fifos( p_aout ); 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->request_vout ); 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; }