/***************************************************************************** * Close: close the audio device *****************************************************************************/ static void Stop ( audio_output_t *p_aout ) { aout_sys_t *p_sys = p_aout->sys; kaiClose( p_sys->hkai ); kaiDone(); aout_PacketDestroy( p_aout ); }
/***************************************************************************** * Close: close the audio device *****************************************************************************/ static void Close ( vlc_object_t *p_this ) { audio_output_t *p_aout = (audio_output_t *)p_this; struct aout_sys_t * p_sys = p_aout->sys; msg_Dbg(p_aout, "Stopping AudioQueue"); AudioQueueStop(p_sys->audioQueue, false); msg_Dbg(p_aout, "Disposing of AudioQueue"); AudioQueueDispose(p_sys->audioQueue, false); aout_PacketDestroy(p_aout); free (p_sys); }
/***************************************************************************** * Close: close the audio device *****************************************************************************/ static void Close ( vlc_object_t *p_this ) { audio_output_t *p_aout = (audio_output_t *)p_this; aout_sys_t *p_sys = p_aout->sys; msg_Dbg( p_aout, "closing portaudio"); #ifdef PORTAUDIO_IS_SERIOUSLY_BROKEN /* Signal end of stream */ vlc_mutex_lock( &pa_thread->lock_signal ); pa_thread->b_signal = true; vlc_cond_signal( &pa_thread->signal ); vlc_mutex_unlock( &pa_thread->lock_signal ); /* Wait until thread is ready */ vlc_mutex_lock( &pa_thread->lock_wait ); while( !pa_thread->b_wait ) vlc_cond_wait( &pa_thread->wait, &pa_thread->lock_wait ); vlc_mutex_unlock( &pa_thread->lock_wait ); pa_thread->b_wait = false; #else int i_err = Pa_StopStream( p_sys->p_stream ); if( i_err != paNoError ) { msg_Err( p_aout, "Pa_StopStream: %d (%s)", i_err, Pa_GetErrorText( i_err ) ); } i_err = Pa_CloseStream( p_sys->p_stream ); if( i_err != paNoError ) { msg_Err( p_aout, "Pa_CloseStream: %d (%s)", i_err, Pa_GetErrorText( i_err ) ); } i_err = Pa_Terminate(); if( i_err != paNoError ) { msg_Err( p_aout, "Pa_Terminate: %d (%s)", i_err, Pa_GetErrorText( i_err ) ); } #endif msg_Dbg( p_aout, "portaudio closed"); aout_PacketDestroy( p_aout ); free( p_sys ); }
/***************************************************************************** * Close: close the DSP audio device *****************************************************************************/ static void Close( vlc_object_t * p_this ) { audio_output_t *p_aout = (audio_output_t *)p_this; struct aout_sys_t * p_sys = p_aout->sys; vlc_cancel( p_sys->thread ); vlc_join( p_sys->thread, NULL ); p_aout->b_die = false; var_DelCallback( p_aout, "audio-device", aout_ChannelsRestart, NULL ); ioctl( p_sys->i_fd, SNDCTL_DSP_RESET, NULL ); close( p_sys->i_fd ); aout_PacketDestroy( p_aout ); free( p_sys ); }
/***************************************************************************** * Close: close the JACK client *****************************************************************************/ static void Close( vlc_object_t *p_this ) { int i_error; audio_output_t *p_aout = (audio_output_t *)p_this; struct aout_sys_t *p_sys = p_aout->sys; i_error = jack_deactivate( p_sys->p_jack_client ); if( i_error ) { msg_Err( p_aout, "jack_deactivate failed (error %d)", i_error ); } i_error = jack_client_close( p_sys->p_jack_client ); if( i_error ) { msg_Err( p_aout, "jack_client_close failed (error %d)", i_error ); } free( p_sys->p_jack_ports ); free( p_sys->p_jack_buffers ); aout_PacketDestroy( p_aout ); free( p_sys ); }
/***************************************************************************** * Open: create a JACK client *****************************************************************************/ static int Open( vlc_object_t *p_this ) { char psz_name[32]; audio_output_t *p_aout = (audio_output_t *)p_this; struct aout_sys_t *p_sys = NULL; int status = VLC_SUCCESS; unsigned int i; int i_error; /* Allocate structure */ p_sys = calloc( 1, sizeof( aout_sys_t ) ); if( p_sys == NULL ) { status = VLC_ENOMEM; goto error_out; } p_aout->sys = p_sys; p_sys->latency = 0; /* Connect to the JACK server */ snprintf( psz_name, sizeof(psz_name), "vlc_%d", getpid()); psz_name[sizeof(psz_name) - 1] = '\0'; p_sys->p_jack_client = jack_client_open( psz_name, JackNullOption | JackNoStartServer, NULL ); if( p_sys->p_jack_client == NULL ) { msg_Err( p_aout, "failed to connect to JACK server" ); status = VLC_EGENERIC; goto error_out; } /* Set the process callback */ jack_set_process_callback( p_sys->p_jack_client, Process, p_aout ); jack_set_graph_order_callback ( p_sys->p_jack_client, GraphChange, p_aout ); p_aout->pf_play = aout_PacketPlay; p_aout->pf_pause = aout_PacketPause; p_aout->pf_flush = aout_PacketFlush; aout_PacketInit( p_aout, &p_sys->packet, jack_get_buffer_size( p_sys->p_jack_client ) ); aout_VolumeSoftInit( p_aout ); /* JACK only supports fl32 format */ p_aout->format.i_format = VLC_CODEC_FL32; // TODO add buffer size callback p_aout->format.i_rate = jack_get_sample_rate( p_sys->p_jack_client ); p_sys->i_channels = aout_FormatNbChannels( &p_aout->format ); p_sys->p_jack_ports = malloc( p_sys->i_channels * sizeof(jack_port_t *) ); if( p_sys->p_jack_ports == NULL ) { status = VLC_ENOMEM; goto error_out; } p_sys->p_jack_buffers = malloc( p_sys->i_channels * sizeof(jack_sample_t *) ); if( p_sys->p_jack_buffers == NULL ) { status = VLC_ENOMEM; goto error_out; } /* Create the output ports */ for( i = 0; i < p_sys->i_channels; i++ ) { snprintf( psz_name, sizeof(psz_name), "out_%d", i + 1); psz_name[sizeof(psz_name) - 1] = '\0'; p_sys->p_jack_ports[i] = jack_port_register( p_sys->p_jack_client, psz_name, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0 ); if( p_sys->p_jack_ports[i] == NULL ) { msg_Err( p_aout, "failed to register a JACK port" ); status = VLC_EGENERIC; goto error_out; } } /* Tell the JACK server we are ready */ i_error = jack_activate( p_sys->p_jack_client ); if( i_error ) { msg_Err( p_aout, "failed to activate JACK client (error %d)", i_error ); status = VLC_EGENERIC; goto error_out; } /* Auto connect ports if we were asked to */ if( var_InheritBool( p_aout, AUTO_CONNECT_OPTION ) ) { unsigned int i_in_ports; char *psz_regex = var_InheritString( p_aout, CONNECT_REGEX_OPTION ); const char **pp_in_ports = jack_get_ports( p_sys->p_jack_client, psz_regex, NULL, JackPortIsInput ); free( psz_regex ); /* Count the number of returned ports */ i_in_ports = 0; while( pp_in_ports && pp_in_ports[i_in_ports] ) { i_in_ports++; } /* Tie the output ports to JACK input ports */ for( i = 0; i_in_ports > 0 && i < p_sys->i_channels; i++ ) { const char* psz_in = pp_in_ports[i % i_in_ports]; const char* psz_out = jack_port_name( p_sys->p_jack_ports[i] ); i_error = jack_connect( p_sys->p_jack_client, psz_out, psz_in ); if( i_error ) { msg_Err( p_aout, "failed to connect port %s to port %s (error %d)", psz_out, psz_in, i_error ); } else { msg_Dbg( p_aout, "connecting port %s to port %s", psz_out, psz_in ); } } free( pp_in_ports ); } msg_Dbg( p_aout, "JACK audio output initialized (%d channels, rate=%d)", p_sys->i_channels, p_aout->format.i_rate ); error_out: /* Clean up, if an error occurred */ if( status != VLC_SUCCESS && p_sys != NULL) { if( p_sys->p_jack_client ) { jack_deactivate( p_sys->p_jack_client ); jack_client_close( p_sys->p_jack_client ); aout_PacketDestroy( p_aout ); } free( p_sys->p_jack_ports ); free( p_sys->p_jack_buffers ); free( p_sys ); } return status; }
/***************************************************************************** * Open: open the audio device (the digital sound processor) ***************************************************************************** * This function opens the DSP as a usual non-blocking write-only file, and * modifies the p_aout->p_sys->i_fd with the file's descriptor. *****************************************************************************/ static int Open( vlc_object_t *p_this ) { audio_output_t * p_aout = (audio_output_t *)p_this; struct aout_sys_t * p_sys; char * psz_device; vlc_value_t val; /* Allocate structure */ p_aout->sys = p_sys = malloc( sizeof( aout_sys_t ) ); if( p_sys == NULL ) return VLC_ENOMEM; /* Get device name */ if( (psz_device = var_InheritString( p_aout, "oss-audio-device" )) == NULL ) { msg_Err( p_aout, "no audio device specified (maybe /dev/dsp?)" ); free( p_sys ); return VLC_EGENERIC; } /* Open the sound device in non-blocking mode, because ALSA's OSS * emulation and some broken OSS drivers would make a blocking call * wait forever until the device is available. Since this breaks the * OSS spec, we immediately put it back to blocking mode if the * operation was successful. */ p_sys->i_fd = vlc_open( psz_device, O_WRONLY | O_NDELAY ); if( p_sys->i_fd < 0 ) { msg_Err( p_aout, "cannot open audio device (%s)", psz_device ); free( psz_device ); free( p_sys ); return VLC_EGENERIC; } /* if the opening was ok, put the device back in blocking mode */ fcntl( p_sys->i_fd, F_SETFL, fcntl( p_sys->i_fd, F_GETFL ) &~ FNDELAY ); free( psz_device ); p_aout->pf_play = aout_PacketPlay; p_aout->pf_pause = aout_PacketPause; p_aout->pf_flush = aout_PacketFlush; if ( var_Type( p_aout, "audio-device" ) == 0 ) Probe( p_aout ); var_AddCallback( p_aout, "audio-device", aout_ChannelsRestart, NULL ); if ( var_Get( p_aout, "audio-device", &val ) < 0 ) /* Probe() has failed. */ goto error; if ( val.i_int == AOUT_VAR_SPDIF ) { p_aout->format.i_format = VLC_CODEC_SPDIFL; } else if ( val.i_int == AOUT_VAR_5_1 ) { p_aout->format.i_format = VLC_CODEC_S16N; p_aout->format.i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT | AOUT_CHAN_LFE; } else if ( val.i_int == AOUT_VAR_2F2R ) { p_aout->format.i_format = VLC_CODEC_S16N; p_aout->format.i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT; } else if ( val.i_int == AOUT_VAR_STEREO ) { p_aout->format.i_format = VLC_CODEC_S16N; p_aout->format.i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT; } else if ( val.i_int == AOUT_VAR_MONO ) { p_aout->format.i_format = VLC_CODEC_S16N; p_aout->format.i_physical_channels = AOUT_CHAN_CENTER; } else { /* This should not happen ! */ msg_Err( p_aout, "internal: can't find audio-device (%"PRId64")", val.i_int ); goto error; } var_TriggerCallback( p_aout, "intf-change" ); /* Reset the DSP device */ if( ioctl( p_sys->i_fd, SNDCTL_DSP_RESET, NULL ) < 0 ) { msg_Err( p_aout, "cannot reset OSS audio device" ); goto error; } /* Set the output format */ if ( AOUT_FMT_SPDIF( &p_aout->format ) ) { int i_format = AFMT_AC3; if( ioctl( p_sys->i_fd, SNDCTL_DSP_SETFMT, &i_format ) < 0 || i_format != AFMT_AC3 ) { msg_Err( p_aout, "cannot reset OSS audio device" ); goto error; } p_aout->format.i_format = VLC_CODEC_SPDIFL; p_aout->format.i_bytes_per_frame = AOUT_SPDIF_SIZE; p_aout->format.i_frame_length = A52_FRAME_NB; aout_PacketInit( p_aout, &p_sys->packet, A52_FRAME_NB ); aout_VolumeNoneInit( p_aout ); } else { unsigned int i_format = AFMT_S16_NE; unsigned int i_frame_size, i_fragments; unsigned int i_rate; unsigned int i_nb_channels; audio_buf_info audio_buf; if( ioctl( p_sys->i_fd, SNDCTL_DSP_SETFMT, &i_format ) < 0 ) { msg_Err( p_aout, "cannot set audio output format" ); goto error; } switch ( i_format ) { case AFMT_U8: p_aout->format.i_format = VLC_CODEC_U8; break; case AFMT_S8: p_aout->format.i_format = VLC_CODEC_S8; break; case AFMT_U16_LE: p_aout->format.i_format = VLC_CODEC_U16L; break; case AFMT_S16_LE: p_aout->format.i_format = VLC_CODEC_S16L; break; case AFMT_U16_BE: p_aout->format.i_format = VLC_CODEC_U16B; break; case AFMT_S16_BE: p_aout->format.i_format = VLC_CODEC_S16B; break; default: msg_Err( p_aout, "OSS fell back to an unknown format (%d)", i_format ); goto error; } i_nb_channels = aout_FormatNbChannels( &p_aout->format ); /* Set the number of channels */ if( ioctl( p_sys->i_fd, SNDCTL_DSP_CHANNELS, &i_nb_channels ) < 0 || i_nb_channels != aout_FormatNbChannels( &p_aout->format ) ) { msg_Err( p_aout, "cannot set number of audio channels (%s)", aout_FormatPrintChannels( &p_aout->format) ); goto error; } /* Set the output rate */ i_rate = p_aout->format.i_rate; if( ioctl( p_sys->i_fd, SNDCTL_DSP_SPEED, &i_rate ) < 0 ) { msg_Err( p_aout, "cannot set audio output rate (%i)", p_aout->format.i_rate ); goto error; } if( i_rate != p_aout->format.i_rate ) { p_aout->format.i_rate = i_rate; } /* Set the fragment size */ aout_FormatPrepare( &p_aout->format ); /* i_fragment = xxxxyyyy where: xxxx is fragtotal * 1 << yyyy is fragsize */ i_frame_size = ((uint64_t)p_aout->format.i_bytes_per_frame * p_aout->format.i_rate * 65536) / (48000 * 2 * 2) / FRAME_COUNT; i_fragments = 4; while( i_fragments < 12 && (1U << i_fragments) < i_frame_size ) { ++i_fragments; } i_fragments |= FRAME_COUNT << 16; if( ioctl( p_sys->i_fd, SNDCTL_DSP_SETFRAGMENT, &i_fragments ) < 0 ) { msg_Warn( p_aout, "cannot set fragment size (%.8x)", i_fragments ); } if( ioctl( p_sys->i_fd, SNDCTL_DSP_GETOSPACE, &audio_buf ) < 0 ) { msg_Err( p_aout, "cannot get fragment size" ); goto error; } /* Number of fragments actually allocated */ p_aout->sys->i_fragstotal = audio_buf.fragstotal; /* Maximum duration the soundcard's buffer can hold */ p_aout->sys->max_buffer_duration = (mtime_t)audio_buf.fragstotal * audio_buf.fragsize * 1000000 / p_aout->format.i_bytes_per_frame / p_aout->format.i_rate * p_aout->format.i_frame_length; aout_PacketInit( p_aout, &p_sys->packet, audio_buf.fragsize/p_aout->format.i_bytes_per_frame ); aout_VolumeSoftInit( p_aout ); } /* Create OSS thread and wait for its readiness. */ if( vlc_clone( &p_sys->thread, OSSThread, p_aout, VLC_THREAD_PRIORITY_OUTPUT ) ) { msg_Err( p_aout, "cannot create OSS thread (%m)" ); aout_PacketDestroy( p_aout ); goto error; } return VLC_SUCCESS; error: var_DelCallback( p_aout, "audio-device", aout_ChannelsRestart, NULL ); close( p_sys->i_fd ); free( p_sys ); return VLC_EGENERIC; }
static int PAOpenStream( audio_output_t *p_aout ) { aout_sys_t *p_sys = p_aout->sys; const PaHostErrorInfo* paLastHostErrorInfo = Pa_GetLastHostErrorInfo(); PaStreamParameters paStreamParameters; vlc_value_t val; int i_channels, i_err; uint32_t i_channel_mask; if( var_Get( p_aout, "audio-device", &val ) < 0 ) { return VLC_EGENERIC; } if( val.i_int == AOUT_VAR_5_1 ) { p_aout->format.i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT | AOUT_CHAN_LFE; } else if( val.i_int == AOUT_VAR_3F2R ) { p_aout->format.i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT; } else if( val.i_int == AOUT_VAR_2F2R ) { p_aout->format.i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT; } else if( val.i_int == AOUT_VAR_MONO ) { p_aout->format.i_physical_channels = AOUT_CHAN_CENTER; } else { p_aout->format.i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT; } i_channels = aout_FormatNbChannels( &p_aout->format ); msg_Dbg( p_aout, "nb_channels requested = %d", i_channels ); i_channel_mask = p_aout->format.i_physical_channels; /* Calculate the frame size in bytes */ p_sys->i_sample_size = 4 * i_channels; aout_FormatPrepare( &p_aout->format ); aout_PacketInit( p_aout, &p_sys->packet, FRAME_SIZE ); aout_VolumeSoftInit( p_aout ); /* Check for channel reordering */ p_aout->sys->i_channel_mask = i_channel_mask; p_aout->sys->i_bits_per_sample = 32; /* forced to paFloat32 */ p_aout->sys->i_channels = i_channels; p_aout->sys->b_chan_reorder = aout_CheckChannelReorder( NULL, pi_channels_out, i_channel_mask, i_channels, p_aout->sys->pi_chan_table ); if( p_aout->sys->b_chan_reorder ) { msg_Dbg( p_aout, "channel reordering needed" ); } paStreamParameters.device = p_sys->i_device_id; paStreamParameters.channelCount = i_channels; paStreamParameters.sampleFormat = paFloat32; paStreamParameters.suggestedLatency = p_sys->deviceInfo->defaultLowOutputLatency; paStreamParameters.hostApiSpecificStreamInfo = NULL; i_err = Pa_OpenStream( &p_sys->p_stream, NULL /* no input */, &paStreamParameters, (double)p_aout->format.i_rate, FRAME_SIZE, paClipOff, paCallback, p_sys ); if( i_err != paNoError ) { msg_Err( p_aout, "Pa_OpenStream returns %d : %s", i_err, Pa_GetErrorText( i_err ) ); if( i_err == paUnanticipatedHostError ) { msg_Err( p_aout, "type %d code %ld : %s", paLastHostErrorInfo->hostApiType, paLastHostErrorInfo->errorCode, paLastHostErrorInfo->errorText ); } p_sys->p_stream = 0; aout_PacketDestroy( p_aout ); return VLC_EGENERIC; } i_err = Pa_StartStream( p_sys->p_stream ); if( i_err != paNoError ) { msg_Err( p_aout, "Pa_StartStream() failed" ); Pa_CloseStream( p_sys->p_stream ); aout_PacketDestroy( p_aout ); return VLC_EGENERIC; } return VLC_SUCCESS; }