?? pulse.c
字號:
/***************************************************************************** * pulse.c : Pulseaudio output plugin for vlc ***************************************************************************** * Copyright (C) 2008 the VideoLAN team * * Authors: Martin Hamrle <hamrle @ post . cz> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. *****************************************************************************//***************************************************************************** * Preamble *****************************************************************************/#ifdef HAVE_CONFIG_H# include "config.h"#endif#include <vlc_common.h>#include <vlc_plugin.h>#include <vlc_aout.h>#include <pulse/pulseaudio.h>#include <assert.h>/***************************************************************************** * aout_sys_t: Pulseaudio output method descriptor ***************************************************************************** * This structure is part of the audio output thread descriptor. * It describes the specific properties of an audio device. *****************************************************************************/struct aout_sys_t{ /** PulseAudio playback stream object */ struct pa_stream *stream; /** PulseAudio connection context */ struct pa_context *context; /** Main event loop object */ struct pa_threaded_mainloop *mainloop; int started; size_t buffer_size; mtime_t start_date;};#define PULSE_CLIENT_NAME N_("VLC media player")#if 0#define PULSE_DEBUG( ...) \ msg_Dbg( p_aout, __VA_ARGS__ )#else#define PULSE_DEBUG( ...) \ (void) 0#endif#define CHECK_DEAD_GOTO(label) do { \if (!p_sys->context || pa_context_get_state(p_sys->context) != PA_CONTEXT_READY || \ !p_sys->stream || pa_stream_get_state(p_sys->stream) != PA_STREAM_READY) { \ msg_Err(p_aout, "Connection died: %s", p_sys->context ? pa_strerror(pa_context_errno(p_sys->context)) : "NULL"); \ goto label; \ } \} while(0);/***************************************************************************** * Local prototypes *****************************************************************************/static int Open ( vlc_object_t * );static void Close ( vlc_object_t * );static void Play ( aout_instance_t * );static void context_state_cb(pa_context *c, void *userdata);static void stream_state_cb(pa_stream *s, void * userdata);static void stream_request_cb(pa_stream *s, size_t length, void *userdata);static void stream_latency_update_cb(pa_stream *s, void *userdata);static void success_cb(pa_stream *s, int sucess, void *userdata);static void uninit(aout_instance_t *p_aout);/***************************************************************************** * Module descriptor *****************************************************************************/vlc_module_begin(); set_shortname( "Pulse Audio" ); set_description( N_("Pulseaudio audio output") ); set_capability( "audio output", 40 ); set_category( CAT_AUDIO ); set_subcategory( SUBCAT_AUDIO_AOUT ); add_shortcut( "pulseaudio" ); add_shortcut( "pa" ); set_callbacks( Open, Close );vlc_module_end();/***************************************************************************** * Open: open the audio device *****************************************************************************/static int Open ( vlc_object_t *p_this ){ aout_instance_t *p_aout = (aout_instance_t *)p_this; struct aout_sys_t * p_sys; struct pa_sample_spec ss; const struct pa_buffer_attr *buffer_attr; struct pa_buffer_attr a; struct pa_channel_map map; /* Allocate structures */ p_aout->output.p_sys = p_sys = malloc( sizeof( aout_sys_t ) ); if( p_sys == NULL ) return VLC_ENOMEM; memset( p_sys, 0, sizeof( aout_sys_t ) ); PULSE_DEBUG( "Pulse start initialization"); ss.rate = p_aout->output.output.i_rate; ss.channels = 2; ss.format = PA_SAMPLE_S16LE; p_aout->output.output.i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT; p_aout->output.output.i_format = AOUT_FMT_S16_NE; if (!pa_sample_spec_valid(&ss)) { msg_Err(p_aout,"Invalid sample spec"); goto fail; } a.maxlength = pa_bytes_per_second(&ss)/4/pa_frame_size(&ss); a.tlength = a.maxlength*9/10; a.prebuf = a.tlength/2; a.minreq = a.tlength/10; a.maxlength *= pa_frame_size(&ss); a.tlength *= pa_frame_size(&ss); a.prebuf *= pa_frame_size(&ss); a.minreq *= pa_frame_size(&ss); p_sys->buffer_size = a.minreq; pa_channel_map_init_stereo(&map); if (!(p_sys->mainloop = pa_threaded_mainloop_new())) { msg_Err(p_aout, "Failed to allocate main loop"); goto fail; } if (!(p_sys->context = pa_context_new(pa_threaded_mainloop_get_api(p_sys->mainloop), _( PULSE_CLIENT_NAME )))) { msg_Err(p_aout, "Failed to allocate context"); goto fail; } pa_context_set_state_callback(p_sys->context, context_state_cb, p_aout); PULSE_DEBUG( "Pulse before context connect"); if (pa_context_connect(p_sys->context, NULL, 0, NULL) < 0) { msg_Err(p_aout, "Failed to connect to server: %s", pa_strerror(pa_context_errno(p_sys->context))); goto fail; } PULSE_DEBUG( "Pulse after context connect"); pa_threaded_mainloop_lock(p_sys->mainloop); if (pa_threaded_mainloop_start(p_sys->mainloop) < 0) { msg_Err(p_aout, "Failed to start main loop"); goto unlock_and_fail; } msg_Dbg(p_aout, "Pulse mainloop started"); /* Wait until the context is ready */ pa_threaded_mainloop_wait(p_sys->mainloop); if (pa_context_get_state(p_sys->context) != PA_CONTEXT_READY) { msg_Err(p_aout, "Failed to connect to server: %s", pa_strerror(pa_context_errno(p_sys->context))); goto unlock_and_fail; } if (!(p_sys->stream = pa_stream_new(p_sys->context, "audio stream", &ss, &map))) { msg_Err(p_aout, "Failed to create stream: %s", pa_strerror(pa_context_errno(p_sys->context))); goto unlock_and_fail; } PULSE_DEBUG( "Pulse after new stream"); pa_stream_set_state_callback(p_sys->stream, stream_state_cb, p_aout); pa_stream_set_write_callback(p_sys->stream, stream_request_cb, p_aout); pa_stream_set_latency_update_callback(p_sys->stream, stream_latency_update_cb, p_aout); if (pa_stream_connect_playback(p_sys->stream, NULL, &a, PA_STREAM_INTERPOLATE_TIMING|PA_STREAM_AUTO_TIMING_UPDATE, NULL, NULL) < 0) { msg_Err(p_aout, "Failed to connect stream: %s", pa_strerror(pa_context_errno(p_sys->context))); goto unlock_and_fail; } PULSE_DEBUG("Pulse stream connect"); /* Wait until the stream is ready */ pa_threaded_mainloop_wait(p_sys->mainloop); msg_Dbg(p_aout,"Pulse stream connected"); if (pa_stream_get_state(p_sys->stream) != PA_STREAM_READY) { msg_Err(p_aout, "Failed to connect to server: %s", pa_strerror(pa_context_errno(p_sys->context))); goto unlock_and_fail; } PULSE_DEBUG("Pulse after stream get status"); pa_threaded_mainloop_unlock(p_sys->mainloop); buffer_attr = pa_stream_get_buffer_attr(p_sys->stream); p_aout->output.i_nb_samples = buffer_attr->minreq / pa_frame_size(&ss); p_aout->output.pf_play = Play; aout_VolumeSoftInit(p_aout); msg_Dbg(p_aout, "Pulse initialized successfully"); { char cmt[PA_CHANNEL_MAP_SNPRINT_MAX], sst[PA_SAMPLE_SPEC_SNPRINT_MAX]; msg_Dbg(p_aout, "Buffer metrics: maxlength=%u, tlength=%u, prebuf=%u, minreq=%u", buffer_attr->maxlength, buffer_attr->tlength, buffer_attr->prebuf, buffer_attr->minreq); msg_Dbg(p_aout, "Using sample spec '%s', channel map '%s'.", pa_sample_spec_snprint(sst, sizeof(sst), pa_stream_get_sample_spec(p_sys->stream)),
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -