2004-07-16 19:56:36 +00:00
/***
2006-06-19 21:53:48 +00:00
This file is part of PulseAudio .
2007-01-04 13:43:45 +00:00
2007-02-13 15:35:19 +00:00
Copyright 2004 - 2006 Lennart Poettering
Copyright 2006 Pierre Ossman < ossman @ cendio . se > for Cendio AB
2006-06-19 21:53:48 +00:00
PulseAudio is free software ; you can redistribute it and / or modify
2004-11-14 14:58:54 +00:00
it under the terms of the GNU Lesser General Public License as published
2009-03-03 20:23:02 +00:00
by the Free Software Foundation ; either version 2.1 of the License ,
2004-07-16 19:56:36 +00:00
or ( at your option ) any later version .
2007-01-04 13:43:45 +00:00
2006-06-19 21:53:48 +00:00
PulseAudio is distributed in the hope that it will be useful , but
2004-07-16 19:56:36 +00:00
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 .
2007-01-04 13:43:45 +00:00
2004-11-14 14:58:54 +00:00
You should have received a copy of the GNU Lesser General Public License
2006-06-19 21:53:48 +00:00
along with PulseAudio ; if not , write to the Free Software
2004-07-16 19:56:36 +00:00
Foundation , Inc . , 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307
USA .
* * */
2004-07-16 19:16:42 +00:00
# ifdef HAVE_CONFIG_H
# include <config.h>
# endif
2004-07-06 00:08:44 +00:00
# include <string.h>
2004-06-20 01:12:13 +00:00
# include <stdio.h>
# include <stdlib.h>
2006-02-24 15:12:42 +00:00
# include <unistd.h>
2004-06-20 01:12:13 +00:00
2009-04-05 02:13:43 +03:00
# include <pulse/rtclock.h>
2006-06-19 21:53:48 +00:00
# include <pulse/timeval.h>
# include <pulse/version.h>
# include <pulse/utf8.h>
# include <pulse/util.h>
# include <pulse/xmalloc.h>
2006-03-02 21:56:15 +00:00
2006-06-19 21:53:48 +00:00
# include <pulsecore/native-common.h>
# include <pulsecore/packet.h>
# include <pulsecore/client.h>
# include <pulsecore/source-output.h>
# include <pulsecore/sink-input.h>
# include <pulsecore/pstream.h>
# include <pulsecore/tagstruct.h>
# include <pulsecore/pdispatch.h>
# include <pulsecore/pstream-util.h>
# include <pulsecore/authkey.h>
# include <pulsecore/namereg.h>
# include <pulsecore/core-scache.h>
# include <pulsecore/core-subscribe.h>
# include <pulsecore/log.h>
# include <pulsecore/strlist.h>
2008-08-01 02:10:54 +03:00
# include <pulsecore/shared.h>
2006-06-19 21:53:48 +00:00
# include <pulsecore/sample-util.h>
# include <pulsecore/llist.h>
2006-07-19 21:48:35 +00:00
# include <pulsecore/creds.h>
# include <pulsecore/core-util.h>
2006-07-20 18:43:20 +00:00
# include <pulsecore/ipacl.h>
2007-10-28 19:13:50 +00:00
# include <pulsecore/thread-mq.h>
2006-02-17 12:10:58 +00:00
2004-06-08 23:54:24 +00:00
# include "protocol-native.h"
2004-11-18 00:28:26 +00:00
/* Kick a client if it doesn't authenticate within this time */
2009-04-05 02:13:43 +03:00
# define AUTH_TIMEOUT (60 * PA_USEC_PER_SEC)
2004-11-18 00:28:26 +00:00
/* Don't accept more connection than this */
2006-06-21 16:36:58 +00:00
# define MAX_CONNECTIONS 64
2004-11-18 00:28:26 +00:00
2006-02-22 21:02:27 +00:00
# define MAX_MEMBLOCKQ_LENGTH (4*1024*1024) /* 4MB */
2008-05-15 23:34:41 +00:00
# define DEFAULT_TLENGTH_MSEC 2000 /* 2s */
# define DEFAULT_PROCESS_MSEC 20 /* 20ms */
# define DEFAULT_FRAGSIZE_MSEC DEFAULT_TLENGTH_MSEC
2006-02-22 21:02:27 +00:00
2008-08-03 16:44:38 +02:00
struct pa_native_protocol ;
2004-06-20 01:12:13 +00:00
2007-10-28 19:13:50 +00:00
typedef struct record_stream {
pa_msgobject parent ;
2008-08-04 18:58:29 +02:00
pa_native_connection * connection ;
2004-06-20 01:12:13 +00:00
uint32_t index ;
2007-10-28 19:13:50 +00:00
2006-01-11 01:17:39 +00:00
pa_source_output * source_output ;
pa_memblockq * memblockq ;
2009-03-30 18:46:12 +02:00
pa_bool_t adjust_latency : 1 ;
pa_bool_t early_requests : 1 ;
pa_buffer_attr buffer_attr ;
2009-04-05 02:59:02 +02:00
pa_atomic_t on_the_fly ;
pa_usec_t configured_source_latency ;
size_t drop_initial ;
/* Only updated after SOURCE_OUTPUT_MESSAGE_UPDATE_LATENCY */
size_t on_the_fly_snapshot ;
pa_usec_t current_monitor_latency ;
pa_usec_t current_source_latency ;
2007-10-28 19:13:50 +00:00
} record_stream ;
2008-08-03 16:44:38 +02:00
PA_DECLARE_CLASS ( record_stream ) ;
# define RECORD_STREAM(o) (record_stream_cast(o))
static PA_DEFINE_CHECK_TYPE ( record_stream , pa_msgobject ) ;
2007-10-28 19:13:50 +00:00
typedef struct output_stream {
pa_msgobject parent ;
} output_stream ;
2004-06-20 01:12:13 +00:00
2008-08-03 16:44:38 +02:00
PA_DECLARE_CLASS ( output_stream ) ;
# define OUTPUT_STREAM(o) (output_stream_cast(o))
static PA_DEFINE_CHECK_TYPE ( output_stream , pa_msgobject ) ;
2007-10-28 19:13:50 +00:00
typedef struct playback_stream {
output_stream parent ;
2008-08-04 18:58:29 +02:00
pa_native_connection * connection ;
2004-06-20 01:12:13 +00:00
uint32_t index ;
2007-10-28 19:13:50 +00:00
2006-01-11 01:17:39 +00:00
pa_sink_input * sink_input ;
pa_memblockq * memblockq ;
2009-03-30 18:46:12 +02:00
pa_bool_t adjust_latency : 1 ;
pa_bool_t early_requests : 1 ;
2008-06-27 00:35:40 +02:00
pa_bool_t is_underrun : 1 ;
pa_bool_t drain_request : 1 ;
2004-07-07 22:02:15 +00:00
uint32_t drain_tag ;
2006-02-20 04:05:16 +00:00
uint32_t syncid ;
2007-10-28 19:13:50 +00:00
pa_atomic_t missing ;
2009-04-05 02:59:02 +02:00
pa_usec_t configured_sink_latency ;
2009-03-30 18:46:12 +02:00
pa_buffer_attr buffer_attr ;
2007-10-28 19:13:50 +00:00
/* Only updated after SINK_INPUT_MESSAGE_UPDATE_LATENCY */
int64_t read_index , write_index ;
2008-05-15 23:34:41 +00:00
size_t render_memblockq_length ;
2009-04-05 02:59:02 +02:00
pa_usec_t current_sink_latency ;
uint64_t playing_for , underrun_for ;
2007-10-28 19:13:50 +00:00
} playback_stream ;
2004-06-08 23:54:24 +00:00
2008-08-03 16:44:38 +02:00
PA_DECLARE_CLASS ( playback_stream ) ;
# define PLAYBACK_STREAM(o) (playback_stream_cast(o))
static PA_DEFINE_CHECK_TYPE ( playback_stream , output_stream ) ;
2007-10-28 19:13:50 +00:00
typedef struct upload_stream {
output_stream parent ;
2008-08-04 18:58:29 +02:00
pa_native_connection * connection ;
2004-08-03 19:26:56 +00:00
uint32_t index ;
2007-10-28 19:13:50 +00:00
2006-01-11 01:17:39 +00:00
pa_memchunk memchunk ;
2004-08-03 19:26:56 +00:00
size_t length ;
char * name ;
2006-01-11 01:17:39 +00:00
pa_sample_spec sample_spec ;
2006-01-27 16:25:31 +00:00
pa_channel_map channel_map ;
2008-05-15 23:34:41 +00:00
pa_proplist * proplist ;
2007-10-28 19:13:50 +00:00
} upload_stream ;
2004-08-03 19:26:56 +00:00
2008-08-03 16:44:38 +02:00
PA_DECLARE_CLASS ( upload_stream ) ;
# define UPLOAD_STREAM(o) (upload_stream_cast(o))
static PA_DEFINE_CHECK_TYPE ( upload_stream , output_stream ) ;
2008-08-04 18:58:29 +02:00
struct pa_native_connection {
2007-10-28 19:13:50 +00:00
pa_msgobject parent ;
2008-08-03 16:44:38 +02:00
pa_native_protocol * protocol ;
pa_native_options * options ;
2008-06-17 18:29:00 +00:00
pa_bool_t authorized : 1 ;
pa_bool_t is_local : 1 ;
2006-03-02 21:56:15 +00:00
uint32_t version ;
2006-01-11 01:17:39 +00:00
pa_client * client ;
pa_pstream * pstream ;
pa_pdispatch * pdispatch ;
pa_idxset * record_streams , * output_streams ;
2004-07-10 16:50:22 +00:00
uint32_t rrobin_index ;
2006-01-11 01:17:39 +00:00
pa_subscription * subscription ;
pa_time_event * auth_timeout_event ;
2004-06-20 01:12:13 +00:00
} ;
2004-06-08 23:54:24 +00:00
2008-08-04 18:58:29 +02:00
PA_DECLARE_CLASS ( pa_native_connection ) ;
# define PA_NATIVE_CONNECTION(o) (pa_native_connection_cast(o))
static PA_DEFINE_CHECK_TYPE ( pa_native_connection , pa_msgobject ) ;
2007-10-28 19:13:50 +00:00
2008-08-03 16:44:38 +02:00
struct pa_native_protocol {
PA_REFCNT_DECLARE ;
2006-01-11 01:17:39 +00:00
pa_core * core ;
pa_idxset * connections ;
2008-08-03 16:44:38 +02:00
pa_strlist * servers ;
2008-08-04 18:58:29 +02:00
pa_hook hooks [ PA_NATIVE_HOOK_MAX ] ;
2008-08-03 16:44:38 +02:00
2008-08-03 18:56:10 +02:00
pa_hashmap * extensions ;
2004-06-20 01:12:13 +00:00
} ;
2009-04-05 02:59:02 +02:00
enum {
SOURCE_OUTPUT_MESSAGE_UPDATE_LATENCY = PA_SOURCE_OUTPUT_MESSAGE_MAX
} ;
2007-10-28 19:13:50 +00:00
enum {
SINK_INPUT_MESSAGE_POST_DATA = PA_SINK_INPUT_MESSAGE_MAX , /* data from main loop to sink input */
SINK_INPUT_MESSAGE_DRAIN , /* disabled prebuf, get playback started. */
SINK_INPUT_MESSAGE_FLUSH ,
SINK_INPUT_MESSAGE_TRIGGER ,
SINK_INPUT_MESSAGE_SEEK ,
SINK_INPUT_MESSAGE_PREBUF_FORCE ,
2009-03-30 18:46:12 +02:00
SINK_INPUT_MESSAGE_UPDATE_LATENCY ,
SINK_INPUT_MESSAGE_UPDATE_BUFFER_ATTR
2007-10-28 19:13:50 +00:00
} ;
enum {
PLAYBACK_STREAM_MESSAGE_REQUEST_DATA , /* data requested from sink input from the main loop */
PLAYBACK_STREAM_MESSAGE_UNDERFLOW ,
PLAYBACK_STREAM_MESSAGE_OVERFLOW ,
2008-05-15 23:34:41 +00:00
PLAYBACK_STREAM_MESSAGE_DRAIN_ACK ,
2009-03-30 18:46:12 +02:00
PLAYBACK_STREAM_MESSAGE_STARTED ,
PLAYBACK_STREAM_MESSAGE_UPDATE_TLENGTH
2007-10-28 19:13:50 +00:00
} ;
enum {
RECORD_STREAM_MESSAGE_POST_DATA /* data from source output to main loop */
} ;
enum {
CONNECTION_MESSAGE_RELEASE ,
CONNECTION_MESSAGE_REVOKE
} ;
2008-05-15 23:34:41 +00:00
static int sink_input_pop_cb ( pa_sink_input * i , size_t length , pa_memchunk * chunk ) ;
2006-01-11 01:17:39 +00:00
static void sink_input_kill_cb ( pa_sink_input * i ) ;
2007-11-21 01:30:40 +00:00
static void sink_input_suspend_cb ( pa_sink_input * i , pa_bool_t suspend ) ;
2009-04-01 03:04:39 +02:00
static void sink_input_moving_cb ( pa_sink_input * i , pa_sink * dest ) ;
2008-05-15 23:34:41 +00:00
static void sink_input_process_rewind_cb ( pa_sink_input * i , size_t nbytes ) ;
static void sink_input_update_max_rewind_cb ( pa_sink_input * i , size_t nbytes ) ;
2008-06-28 01:09:07 +02:00
static void sink_input_update_max_request_cb ( pa_sink_input * i , size_t nbytes ) ;
2009-02-12 03:18:05 +01:00
static void sink_input_send_event_cb ( pa_sink_input * i , const char * event , pa_proplist * pl ) ;
2004-06-23 23:17:30 +00:00
2008-08-04 18:58:29 +02:00
static void native_connection_send_memblock ( pa_native_connection * c ) ;
static void playback_stream_request_bytes ( struct playback_stream * s ) ;
2004-06-23 23:17:30 +00:00
2006-01-11 01:17:39 +00:00
static void source_output_kill_cb ( pa_source_output * o ) ;
static void source_output_push_cb ( pa_source_output * o , const pa_memchunk * chunk ) ;
2007-11-21 01:30:40 +00:00
static void source_output_suspend_cb ( pa_source_output * o , pa_bool_t suspend ) ;
2009-04-01 03:04:39 +02:00
static void source_output_moving_cb ( pa_source_output * o , pa_source * dest ) ;
2006-01-11 01:17:39 +00:00
static pa_usec_t source_output_get_latency_cb ( pa_source_output * o ) ;
2009-02-12 03:18:05 +01:00
static void source_output_send_event_cb ( pa_source_output * o , const char * event , pa_proplist * pl ) ;
2006-01-11 01:17:39 +00:00
2007-10-28 19:13:50 +00:00
static int sink_input_process_msg ( pa_msgobject * o , int code , void * userdata , int64_t offset , pa_memchunk * chunk ) ;
2009-04-05 02:59:02 +02:00
static int source_output_process_msg ( pa_msgobject * o , int code , void * userdata , int64_t offset , pa_memchunk * chunk ) ;
2007-10-28 19:13:50 +00:00
2006-01-11 01:17:39 +00:00
static void command_exit ( pa_pdispatch * pd , uint32_t command , uint32_t tag , pa_tagstruct * t , void * userdata ) ;
static void command_create_playback_stream ( pa_pdispatch * pd , uint32_t command , uint32_t tag , pa_tagstruct * t , void * userdata ) ;
static void command_drain_playback_stream ( pa_pdispatch * pd , uint32_t command , uint32_t tag , pa_tagstruct * t , void * userdata ) ;
static void command_create_record_stream ( pa_pdispatch * pd , uint32_t command , uint32_t tag , pa_tagstruct * t , void * userdata ) ;
static void command_delete_stream ( pa_pdispatch * pd , uint32_t command , uint32_t tag , pa_tagstruct * t , void * userdata ) ;
static void command_auth ( pa_pdispatch * pd , uint32_t command , uint32_t tag , pa_tagstruct * t , void * userdata ) ;
static void command_set_client_name ( pa_pdispatch * pd , uint32_t command , uint32_t tag , pa_tagstruct * t , void * userdata ) ;
static void command_lookup ( pa_pdispatch * pd , uint32_t command , uint32_t tag , pa_tagstruct * t , void * userdata ) ;
static void command_stat ( pa_pdispatch * pd , uint32_t command , uint32_t tag , pa_tagstruct * t , void * userdata ) ;
static void command_get_playback_latency ( pa_pdispatch * pd , uint32_t command , uint32_t tag , pa_tagstruct * t , void * userdata ) ;
static void command_get_record_latency ( pa_pdispatch * pd , uint32_t command , uint32_t tag , pa_tagstruct * t , void * userdata ) ;
static void command_create_upload_stream ( pa_pdispatch * pd , uint32_t command , uint32_t tag , pa_tagstruct * t , void * userdata ) ;
static void command_finish_upload_stream ( pa_pdispatch * pd , uint32_t command , uint32_t tag , pa_tagstruct * t , void * userdata ) ;
static void command_play_sample ( pa_pdispatch * pd , uint32_t command , uint32_t tag , pa_tagstruct * t , void * userdata ) ;
static void command_remove_sample ( pa_pdispatch * pd , uint32_t command , uint32_t tag , pa_tagstruct * t , void * userdata ) ;
static void command_get_info ( pa_pdispatch * pd , uint32_t command , uint32_t tag , pa_tagstruct * t , void * userdata ) ;
static void command_get_info_list ( pa_pdispatch * pd , uint32_t command , uint32_t tag , pa_tagstruct * t , void * userdata ) ;
static void command_get_server_info ( pa_pdispatch * pd , uint32_t command , uint32_t tag , pa_tagstruct * t , void * userdata ) ;
static void command_subscribe ( pa_pdispatch * pd , uint32_t command , uint32_t tag , pa_tagstruct * t , void * userdata ) ;
static void command_set_volume ( pa_pdispatch * pd , uint32_t command , uint32_t tag , pa_tagstruct * t , void * userdata ) ;
2006-02-23 12:04:31 +00:00
static void command_set_mute ( pa_pdispatch * pd , uint32_t command , uint32_t tag , pa_tagstruct * t , void * userdata ) ;
2006-01-11 01:17:39 +00:00
static void command_cork_playback_stream ( pa_pdispatch * pd , uint32_t command , uint32_t tag , pa_tagstruct * t , void * userdata ) ;
2007-10-28 19:13:50 +00:00
static void command_trigger_or_flush_or_prebuf_playback_stream ( pa_pdispatch * pd , uint32_t command , uint32_t tag , pa_tagstruct * t , void * userdata ) ;
2006-01-11 01:17:39 +00:00
static void command_set_default_sink_or_source ( pa_pdispatch * pd , uint32_t command , uint32_t tag , pa_tagstruct * t , void * userdata ) ;
static void command_set_stream_name ( pa_pdispatch * pd , uint32_t command , uint32_t tag , pa_tagstruct * t , void * userdata ) ;
static void command_kill ( pa_pdispatch * pd , uint32_t command , uint32_t tag , pa_tagstruct * t , void * userdata ) ;
static void command_load_module ( pa_pdispatch * pd , uint32_t command , uint32_t tag , pa_tagstruct * t , void * userdata ) ;
static void command_unload_module ( pa_pdispatch * pd , uint32_t command , uint32_t tag , pa_tagstruct * t , void * userdata ) ;
static void command_cork_record_stream ( pa_pdispatch * pd , uint32_t command , uint32_t tag , pa_tagstruct * t , void * userdata ) ;
static void command_flush_record_stream ( pa_pdispatch * pd , uint32_t command , uint32_t tag , pa_tagstruct * t , void * userdata ) ;
2006-07-31 21:54:46 +00:00
static void command_move_stream ( pa_pdispatch * pd , uint32_t command , uint32_t tag , pa_tagstruct * t , void * userdata ) ;
2007-10-28 19:13:50 +00:00
static void command_suspend ( pa_pdispatch * pd , uint32_t command , uint32_t tag , pa_tagstruct * t , void * userdata ) ;
2007-11-21 01:30:40 +00:00
static void command_set_stream_buffer_attr ( pa_pdispatch * pd , uint32_t command , uint32_t tag , pa_tagstruct * t , void * userdata ) ;
static void command_update_stream_sample_rate ( pa_pdispatch * pd , uint32_t command , uint32_t tag , pa_tagstruct * t , void * userdata ) ;
2008-05-15 23:34:41 +00:00
static void command_update_proplist ( pa_pdispatch * pd , uint32_t command , uint32_t tag , pa_tagstruct * t , void * userdata ) ;
static void command_remove_proplist ( pa_pdispatch * pd , uint32_t command , uint32_t tag , pa_tagstruct * t , void * userdata ) ;
2008-08-03 18:56:10 +02:00
static void command_extension ( pa_pdispatch * pd , uint32_t command , uint32_t tag , pa_tagstruct * t , void * userdata ) ;
2009-01-21 03:04:04 +01:00
static void command_set_card_profile ( pa_pdispatch * pd , uint32_t command , uint32_t tag , pa_tagstruct * t , void * userdata ) ;
2009-06-17 04:52:41 +02:00
static void command_set_sink_or_source_port ( pa_pdispatch * pd , uint32_t command , uint32_t tag , pa_tagstruct * t , void * userdata ) ;
2006-01-11 01:17:39 +00:00
2006-02-20 22:41:02 +00:00
static const pa_pdispatch_cb_t command_table [ PA_COMMAND_MAX ] = {
2006-01-11 01:17:39 +00:00
[ PA_COMMAND_ERROR ] = NULL ,
[ PA_COMMAND_TIMEOUT ] = NULL ,
[ PA_COMMAND_REPLY ] = NULL ,
[ PA_COMMAND_CREATE_PLAYBACK_STREAM ] = command_create_playback_stream ,
[ PA_COMMAND_DELETE_PLAYBACK_STREAM ] = command_delete_stream ,
[ PA_COMMAND_DRAIN_PLAYBACK_STREAM ] = command_drain_playback_stream ,
[ PA_COMMAND_CREATE_RECORD_STREAM ] = command_create_record_stream ,
[ PA_COMMAND_DELETE_RECORD_STREAM ] = command_delete_stream ,
[ PA_COMMAND_AUTH ] = command_auth ,
[ PA_COMMAND_REQUEST ] = NULL ,
[ PA_COMMAND_EXIT ] = command_exit ,
[ PA_COMMAND_SET_CLIENT_NAME ] = command_set_client_name ,
[ PA_COMMAND_LOOKUP_SINK ] = command_lookup ,
[ PA_COMMAND_LOOKUP_SOURCE ] = command_lookup ,
[ PA_COMMAND_STAT ] = command_stat ,
[ PA_COMMAND_GET_PLAYBACK_LATENCY ] = command_get_playback_latency ,
[ PA_COMMAND_GET_RECORD_LATENCY ] = command_get_record_latency ,
[ PA_COMMAND_CREATE_UPLOAD_STREAM ] = command_create_upload_stream ,
[ PA_COMMAND_DELETE_UPLOAD_STREAM ] = command_delete_stream ,
[ PA_COMMAND_FINISH_UPLOAD_STREAM ] = command_finish_upload_stream ,
[ PA_COMMAND_PLAY_SAMPLE ] = command_play_sample ,
[ PA_COMMAND_REMOVE_SAMPLE ] = command_remove_sample ,
[ PA_COMMAND_GET_SINK_INFO ] = command_get_info ,
[ PA_COMMAND_GET_SOURCE_INFO ] = command_get_info ,
[ PA_COMMAND_GET_CLIENT_INFO ] = command_get_info ,
2009-01-20 03:25:29 +01:00
[ PA_COMMAND_GET_CARD_INFO ] = command_get_info ,
2006-01-11 01:17:39 +00:00
[ PA_COMMAND_GET_MODULE_INFO ] = command_get_info ,
[ PA_COMMAND_GET_SINK_INPUT_INFO ] = command_get_info ,
[ PA_COMMAND_GET_SOURCE_OUTPUT_INFO ] = command_get_info ,
[ PA_COMMAND_GET_SAMPLE_INFO ] = command_get_info ,
[ PA_COMMAND_GET_SINK_INFO_LIST ] = command_get_info_list ,
[ PA_COMMAND_GET_SOURCE_INFO_LIST ] = command_get_info_list ,
[ PA_COMMAND_GET_MODULE_INFO_LIST ] = command_get_info_list ,
[ PA_COMMAND_GET_CLIENT_INFO_LIST ] = command_get_info_list ,
2009-01-20 03:25:29 +01:00
[ PA_COMMAND_GET_CARD_INFO_LIST ] = command_get_info_list ,
2006-01-11 01:17:39 +00:00
[ PA_COMMAND_GET_SINK_INPUT_INFO_LIST ] = command_get_info_list ,
[ PA_COMMAND_GET_SOURCE_OUTPUT_INFO_LIST ] = command_get_info_list ,
[ PA_COMMAND_GET_SAMPLE_INFO_LIST ] = command_get_info_list ,
[ PA_COMMAND_GET_SERVER_INFO ] = command_get_server_info ,
[ PA_COMMAND_SUBSCRIBE ] = command_subscribe ,
[ PA_COMMAND_SET_SINK_VOLUME ] = command_set_volume ,
[ PA_COMMAND_SET_SINK_INPUT_VOLUME ] = command_set_volume ,
2006-02-22 14:11:23 +00:00
[ PA_COMMAND_SET_SOURCE_VOLUME ] = command_set_volume ,
2007-01-04 13:43:45 +00:00
2006-02-23 12:04:31 +00:00
[ PA_COMMAND_SET_SINK_MUTE ] = command_set_mute ,
2007-10-28 19:13:50 +00:00
[ PA_COMMAND_SET_SINK_INPUT_MUTE ] = command_set_mute ,
2006-02-23 12:04:31 +00:00
[ PA_COMMAND_SET_SOURCE_MUTE ] = command_set_mute ,
2007-10-28 19:13:50 +00:00
[ PA_COMMAND_SUSPEND_SINK ] = command_suspend ,
[ PA_COMMAND_SUSPEND_SOURCE ] = command_suspend ,
2006-01-11 01:17:39 +00:00
[ PA_COMMAND_CORK_PLAYBACK_STREAM ] = command_cork_playback_stream ,
2007-10-28 19:13:50 +00:00
[ PA_COMMAND_FLUSH_PLAYBACK_STREAM ] = command_trigger_or_flush_or_prebuf_playback_stream ,
[ PA_COMMAND_TRIGGER_PLAYBACK_STREAM ] = command_trigger_or_flush_or_prebuf_playback_stream ,
[ PA_COMMAND_PREBUF_PLAYBACK_STREAM ] = command_trigger_or_flush_or_prebuf_playback_stream ,
2007-01-04 13:43:45 +00:00
2006-01-11 01:17:39 +00:00
[ PA_COMMAND_CORK_RECORD_STREAM ] = command_cork_record_stream ,
[ PA_COMMAND_FLUSH_RECORD_STREAM ] = command_flush_record_stream ,
2007-01-04 13:43:45 +00:00
2006-01-11 01:17:39 +00:00
[ PA_COMMAND_SET_DEFAULT_SINK ] = command_set_default_sink_or_source ,
[ PA_COMMAND_SET_DEFAULT_SOURCE ] = command_set_default_sink_or_source ,
2007-01-04 13:43:45 +00:00
[ PA_COMMAND_SET_PLAYBACK_STREAM_NAME ] = command_set_stream_name ,
2006-01-11 01:17:39 +00:00
[ PA_COMMAND_SET_RECORD_STREAM_NAME ] = command_set_stream_name ,
[ PA_COMMAND_KILL_CLIENT ] = command_kill ,
[ PA_COMMAND_KILL_SINK_INPUT ] = command_kill ,
[ PA_COMMAND_KILL_SOURCE_OUTPUT ] = command_kill ,
[ PA_COMMAND_LOAD_MODULE ] = command_load_module ,
[ PA_COMMAND_UNLOAD_MODULE ] = command_unload_module ,
2009-01-15 20:07:13 +01:00
[ PA_COMMAND_GET_AUTOLOAD_INFO___OBSOLETE ] = NULL ,
[ PA_COMMAND_GET_AUTOLOAD_INFO_LIST___OBSOLETE ] = NULL ,
[ PA_COMMAND_ADD_AUTOLOAD___OBSOLETE ] = NULL ,
[ PA_COMMAND_REMOVE_AUTOLOAD___OBSOLETE ] = NULL ,
2006-07-31 21:54:46 +00:00
[ PA_COMMAND_MOVE_SINK_INPUT ] = command_move_stream ,
2007-11-21 01:30:40 +00:00
[ PA_COMMAND_MOVE_SOURCE_OUTPUT ] = command_move_stream ,
[ PA_COMMAND_SET_PLAYBACK_STREAM_BUFFER_ATTR ] = command_set_stream_buffer_attr ,
[ PA_COMMAND_SET_RECORD_STREAM_BUFFER_ATTR ] = command_set_stream_buffer_attr ,
[ PA_COMMAND_UPDATE_PLAYBACK_STREAM_SAMPLE_RATE ] = command_update_stream_sample_rate ,
2008-05-15 23:34:41 +00:00
[ PA_COMMAND_UPDATE_RECORD_STREAM_SAMPLE_RATE ] = command_update_stream_sample_rate ,
[ PA_COMMAND_UPDATE_RECORD_STREAM_PROPLIST ] = command_update_proplist ,
[ PA_COMMAND_UPDATE_PLAYBACK_STREAM_PROPLIST ] = command_update_proplist ,
[ PA_COMMAND_UPDATE_CLIENT_PROPLIST ] = command_update_proplist ,
[ PA_COMMAND_REMOVE_RECORD_STREAM_PROPLIST ] = command_remove_proplist ,
[ PA_COMMAND_REMOVE_PLAYBACK_STREAM_PROPLIST ] = command_remove_proplist ,
[ PA_COMMAND_REMOVE_CLIENT_PROPLIST ] = command_remove_proplist ,
2008-08-03 18:56:10 +02:00
2009-01-21 03:04:04 +01:00
[ PA_COMMAND_SET_CARD_PROFILE ] = command_set_card_profile ,
2009-06-17 04:52:41 +02:00
[ PA_COMMAND_SET_SINK_PORT ] = command_set_sink_or_source_port ,
[ PA_COMMAND_SET_SOURCE_PORT ] = command_set_sink_or_source_port ,
2008-08-03 18:56:10 +02:00
[ PA_COMMAND_EXTENSION ] = command_extension
2004-06-23 23:17:30 +00:00
} ;
/* structure management */
2009-03-30 18:26:23 +02:00
/* Called from main context */
2007-10-28 19:13:50 +00:00
static void upload_stream_unlink ( upload_stream * s ) {
pa_assert ( s ) ;
if ( ! s - > connection )
return ;
pa_assert_se ( pa_idxset_remove_by_data ( s - > connection - > output_streams , s , NULL ) = = s ) ;
s - > connection = NULL ;
upload_stream_unref ( s ) ;
}
2009-03-30 18:26:23 +02:00
/* Called from main context */
2007-10-28 19:13:50 +00:00
static void upload_stream_free ( pa_object * o ) {
upload_stream * s = UPLOAD_STREAM ( o ) ;
pa_assert ( s ) ;
upload_stream_unlink ( s ) ;
pa_xfree ( s - > name ) ;
2007-01-04 13:43:45 +00:00
2008-05-15 23:34:41 +00:00
if ( s - > proplist )
pa_proplist_free ( s - > proplist ) ;
2007-10-28 19:13:50 +00:00
if ( s - > memchunk . memblock )
pa_memblock_unref ( s - > memchunk . memblock ) ;
2007-01-04 13:43:45 +00:00
2007-10-28 19:13:50 +00:00
pa_xfree ( s ) ;
}
2009-03-30 18:26:23 +02:00
/* Called from main context */
2007-10-28 19:13:50 +00:00
static upload_stream * upload_stream_new (
2008-08-04 18:58:29 +02:00
pa_native_connection * c ,
2007-10-28 19:13:50 +00:00
const pa_sample_spec * ss ,
const pa_channel_map * map ,
2008-05-15 23:34:41 +00:00
const char * name ,
size_t length ,
pa_proplist * p ) {
2007-10-28 19:13:50 +00:00
upload_stream * s ;
pa_assert ( c ) ;
pa_assert ( ss ) ;
pa_assert ( name ) ;
pa_assert ( length > 0 ) ;
2008-05-15 23:34:41 +00:00
pa_assert ( p ) ;
2007-10-28 19:13:50 +00:00
s = pa_msgobject_new ( upload_stream ) ;
s - > parent . parent . parent . free = upload_stream_free ;
2004-08-03 19:26:56 +00:00
s - > connection = c ;
s - > sample_spec = * ss ;
2006-01-27 16:25:31 +00:00
s - > channel_map = * map ;
2004-08-04 16:39:30 +00:00
s - > name = pa_xstrdup ( name ) ;
2007-10-28 19:13:50 +00:00
pa_memchunk_reset ( & s - > memchunk ) ;
2004-08-03 19:26:56 +00:00
s - > length = length ;
2008-05-15 23:34:41 +00:00
s - > proplist = pa_proplist_copy ( p ) ;
pa_proplist_update ( s - > proplist , PA_UPDATE_MERGE , c - > client - > proplist ) ;
2007-01-04 13:43:45 +00:00
2004-08-03 19:26:56 +00:00
pa_idxset_put ( c - > output_streams , s , & s - > index ) ;
2007-10-28 19:13:50 +00:00
2004-08-03 19:26:56 +00:00
return s ;
}
2009-03-30 18:26:23 +02:00
/* Called from main context */
2007-10-28 19:13:50 +00:00
static void record_stream_unlink ( record_stream * s ) {
pa_assert ( s ) ;
if ( ! s - > connection )
return ;
if ( s - > source_output ) {
pa_source_output_unlink ( s - > source_output ) ;
pa_source_output_unref ( s - > source_output ) ;
s - > source_output = NULL ;
}
pa_assert_se ( pa_idxset_remove_by_data ( s - > connection - > record_streams , s , NULL ) = = s ) ;
s - > connection = NULL ;
record_stream_unref ( s ) ;
}
2009-03-30 18:26:23 +02:00
/* Called from main context */
2007-10-28 19:13:50 +00:00
static void record_stream_free ( pa_object * o ) {
record_stream * s = RECORD_STREAM ( o ) ;
pa_assert ( s ) ;
record_stream_unlink ( s ) ;
pa_memblockq_free ( s - > memblockq ) ;
pa_xfree ( s ) ;
}
2009-03-30 18:26:23 +02:00
/* Called from main context */
2007-10-28 19:13:50 +00:00
static int record_stream_process_msg ( pa_msgobject * o , int code , void * userdata , int64_t offset , pa_memchunk * chunk ) {
record_stream * s = RECORD_STREAM ( o ) ;
record_stream_assert_ref ( s ) ;
2004-08-03 19:26:56 +00:00
2007-10-28 19:13:50 +00:00
if ( ! s - > connection )
return - 1 ;
2004-08-03 19:26:56 +00:00
2007-10-28 19:13:50 +00:00
switch ( code ) {
2007-01-04 13:43:45 +00:00
2007-10-28 19:13:50 +00:00
case RECORD_STREAM_MESSAGE_POST_DATA :
2007-01-04 13:43:45 +00:00
2009-04-05 02:59:02 +02:00
/* We try to keep up to date with how many bytes are
* currently on the fly */
pa_atomic_sub ( & s - > on_the_fly , chunk - > length ) ;
2007-10-28 19:13:50 +00:00
if ( pa_memblockq_push_align ( s - > memblockq , chunk ) < 0 ) {
/* pa_log_warn("Failed to push data into output queue."); */
return - 1 ;
}
if ( ! pa_pstream_is_pending ( s - > connection - > pstream ) )
2008-08-04 18:58:29 +02:00
native_connection_send_memblock ( s - > connection ) ;
2007-10-28 19:13:50 +00:00
break ;
}
return 0 ;
2004-08-03 19:26:56 +00:00
}
2009-03-30 18:46:12 +02:00
/* Called from main context */
static void fix_record_buffer_attr_pre ( record_stream * s ) {
2008-09-03 18:31:46 +02:00
size_t frame_size ;
pa_usec_t orig_fragsize_usec , fragsize_usec , source_usec ;
2008-05-15 23:34:41 +00:00
pa_assert ( s ) ;
2009-03-30 18:46:12 +02:00
/* This function will be called from the main thread, before as
* well as after the source output has been activated using
* pa_source_output_put ( ) ! That means it may not touch any
* - > thread_info data ! */
2008-05-15 23:34:41 +00:00
2008-09-03 18:31:46 +02:00
frame_size = pa_frame_size ( & s - > source_output - > sample_spec ) ;
2009-03-30 18:46:12 +02:00
if ( s - > buffer_attr . maxlength = = ( uint32_t ) - 1 | | s - > buffer_attr . maxlength > MAX_MEMBLOCKQ_LENGTH )
s - > buffer_attr . maxlength = MAX_MEMBLOCKQ_LENGTH ;
if ( s - > buffer_attr . maxlength < = 0 )
s - > buffer_attr . maxlength = ( uint32_t ) frame_size ;
2008-05-15 23:34:41 +00:00
2009-03-30 18:46:12 +02:00
if ( s - > buffer_attr . fragsize = = ( uint32_t ) - 1 )
s - > buffer_attr . fragsize = ( uint32_t ) pa_usec_to_bytes ( DEFAULT_FRAGSIZE_MSEC * PA_USEC_PER_MSEC , & s - > source_output - > sample_spec ) ;
if ( s - > buffer_attr . fragsize < = 0 )
s - > buffer_attr . fragsize = ( uint32_t ) frame_size ;
2008-09-03 18:31:46 +02:00
2009-03-30 18:46:12 +02:00
orig_fragsize_usec = fragsize_usec = pa_bytes_to_usec ( s - > buffer_attr . fragsize , & s - > source_output - > sample_spec ) ;
2008-05-15 23:34:41 +00:00
2009-03-30 18:46:12 +02:00
if ( s - > early_requests ) {
2008-09-03 18:31:46 +02:00
/* In early request mode we need to emulate the classic
* fragment - based playback model . We do this setting the source
* latency to the fragment size . */
source_usec = fragsize_usec ;
2009-03-30 18:46:12 +02:00
} else if ( s - > adjust_latency ) {
2008-05-15 23:34:41 +00:00
/* So, the user asked us to adjust the latency according to
2008-05-17 09:11:21 +00:00
* what the source can provide . Half the latency will be
2008-05-15 23:34:41 +00:00
* spent on the hw buffer , half of it in the async buffer
* queue we maintain for each client . */
2008-09-03 18:31:46 +02:00
source_usec = fragsize_usec / 2 ;
} else {
/* Ok, the user didn't ask us to adjust the latency, hence we
* don ' t */
2008-05-15 23:34:41 +00:00
2009-04-05 02:59:02 +02:00
source_usec = ( pa_usec_t ) - 1 ;
2008-09-03 18:31:46 +02:00
}
2009-04-05 02:59:02 +02:00
if ( source_usec ! = ( pa_usec_t ) - 1 )
s - > configured_source_latency = pa_source_output_set_requested_latency ( s - > source_output , source_usec ) ;
2008-09-03 18:31:46 +02:00
else
2009-04-05 02:59:02 +02:00
s - > configured_source_latency = 0 ;
2008-09-03 18:31:46 +02:00
2009-03-30 18:46:12 +02:00
if ( s - > early_requests ) {
2008-09-03 18:31:46 +02:00
/* Ok, we didn't necessarily get what we were asking for, so
* let ' s tell the user */
2009-04-05 02:59:02 +02:00
fragsize_usec = s - > configured_source_latency ;
2008-09-03 18:31:46 +02:00
2009-03-30 18:46:12 +02:00
} else if ( s - > adjust_latency ) {
2008-09-03 18:31:46 +02:00
/* Now subtract what we actually got */
2008-05-15 23:34:41 +00:00
2009-04-05 02:59:02 +02:00
if ( fragsize_usec > = s - > configured_source_latency * 2 )
fragsize_usec - = s - > configured_source_latency ;
2008-05-15 23:34:41 +00:00
else
2009-04-05 02:59:02 +02:00
fragsize_usec = s - > configured_source_latency ;
2008-09-03 18:31:46 +02:00
}
2008-05-15 23:34:41 +00:00
2008-09-03 18:31:46 +02:00
if ( pa_usec_to_bytes ( orig_fragsize_usec , & s - > source_output - > sample_spec ) ! =
pa_usec_to_bytes ( fragsize_usec , & s - > source_output - > sample_spec ) )
2008-09-01 02:41:03 +02:00
2009-03-30 18:46:12 +02:00
s - > buffer_attr . fragsize = ( uint32_t ) pa_usec_to_bytes ( fragsize_usec , & s - > source_output - > sample_spec ) ;
2008-09-03 18:31:46 +02:00
2009-03-30 18:46:12 +02:00
if ( s - > buffer_attr . fragsize < = 0 )
s - > buffer_attr . fragsize = ( uint32_t ) frame_size ;
2008-05-15 23:34:41 +00:00
}
2009-03-30 18:46:12 +02:00
/* Called from main context */
static void fix_record_buffer_attr_post ( record_stream * s ) {
2008-05-15 23:34:41 +00:00
size_t base ;
pa_assert ( s ) ;
2009-03-30 18:46:12 +02:00
/* This function will be called from the main thread, before as
* well as after the source output has been activated using
* pa_source_output_put ( ) ! That means it may not touch and
* - > thread_info data ! */
2008-05-15 23:34:41 +00:00
base = pa_frame_size ( & s - > source_output - > sample_spec ) ;
2009-03-30 18:46:12 +02:00
s - > buffer_attr . fragsize = ( s - > buffer_attr . fragsize / base ) * base ;
if ( s - > buffer_attr . fragsize < = 0 )
s - > buffer_attr . fragsize = base ;
2008-05-15 23:34:41 +00:00
2009-03-30 18:46:12 +02:00
if ( s - > buffer_attr . fragsize > s - > buffer_attr . maxlength )
s - > buffer_attr . fragsize = s - > buffer_attr . maxlength ;
2008-05-15 23:34:41 +00:00
}
2009-03-30 18:26:23 +02:00
/* Called from main context */
2007-10-28 19:13:50 +00:00
static record_stream * record_stream_new (
2008-08-04 18:58:29 +02:00
pa_native_connection * c ,
2007-10-28 19:13:50 +00:00
pa_source * source ,
2007-11-21 01:30:40 +00:00
pa_sample_spec * ss ,
pa_channel_map * map ,
2008-05-15 23:34:41 +00:00
pa_bool_t peak_detect ,
2009-03-30 18:46:12 +02:00
pa_buffer_attr * attr ,
2008-05-15 23:34:41 +00:00
pa_source_output_flags_t flags ,
pa_proplist * p ,
2008-06-13 21:56:19 +00:00
pa_bool_t adjust_latency ,
2008-09-03 18:31:46 +02:00
pa_sink_input * direct_on_input ,
2009-02-03 03:14:20 +01:00
pa_bool_t early_requests ,
int * ret ) {
2007-01-04 13:43:45 +00:00
2007-10-28 19:13:50 +00:00
record_stream * s ;
2009-02-04 18:33:01 +01:00
pa_source_output * source_output = NULL ;
2004-07-10 16:50:22 +00:00
size_t base ;
2006-08-13 19:55:17 +00:00
pa_source_output_new_data data ;
2007-01-04 13:43:45 +00:00
2007-10-28 19:13:50 +00:00
pa_assert ( c ) ;
pa_assert ( ss ) ;
2008-05-15 23:34:41 +00:00
pa_assert ( p ) ;
2009-02-03 03:14:20 +01:00
pa_assert ( ret ) ;
2004-07-10 16:50:22 +00:00
2006-08-13 19:55:17 +00:00
pa_source_output_new_data_init ( & data ) ;
2008-05-15 23:34:41 +00:00
pa_proplist_update ( data . proplist , PA_UPDATE_REPLACE , p ) ;
data . driver = __FILE__ ;
2008-08-03 16:44:38 +02:00
data . module = c - > options - > module ;
2007-10-28 19:13:50 +00:00
data . client = c - > client ;
2006-08-13 19:55:17 +00:00
data . source = source ;
2008-06-13 21:56:19 +00:00
data . direct_on_input = direct_on_input ;
2006-08-13 19:55:17 +00:00
pa_source_output_new_data_set_sample_spec ( & data , ss ) ;
pa_source_output_new_data_set_channel_map ( & data , map ) ;
2008-05-15 23:34:41 +00:00
if ( peak_detect )
data . resample_method = PA_RESAMPLER_PEAKS ;
2007-01-04 13:43:45 +00:00
2009-02-04 18:33:01 +01:00
* ret = - pa_source_output_new ( & source_output , c - > protocol - > core , & data , flags ) ;
2008-05-15 23:34:41 +00:00
pa_source_output_new_data_done ( & data ) ;
if ( ! source_output )
2004-07-10 16:50:22 +00:00
return NULL ;
2007-10-28 19:13:50 +00:00
s = pa_msgobject_new ( record_stream ) ;
s - > parent . parent . free = record_stream_free ;
s - > parent . process_msg = record_stream_process_msg ;
2004-07-10 16:50:22 +00:00
s - > connection = c ;
s - > source_output = source_output ;
2009-03-30 18:46:12 +02:00
s - > buffer_attr = * attr ;
s - > adjust_latency = adjust_latency ;
s - > early_requests = early_requests ;
2009-04-05 02:59:02 +02:00
pa_atomic_store ( & s - > on_the_fly , 0 ) ;
2008-05-15 23:34:41 +00:00
2009-04-05 02:59:02 +02:00
s - > source_output - > parent . process_msg = source_output_process_msg ;
2004-07-10 16:50:22 +00:00
s - > source_output - > push = source_output_push_cb ;
s - > source_output - > kill = source_output_kill_cb ;
2004-09-16 00:05:56 +00:00
s - > source_output - > get_latency = source_output_get_latency_cb ;
2009-03-30 18:21:34 +02:00
s - > source_output - > moving = source_output_moving_cb ;
2007-11-21 01:30:40 +00:00
s - > source_output - > suspend = source_output_suspend_cb ;
2009-02-12 03:18:05 +01:00
s - > source_output - > send_event = source_output_send_event_cb ;
2004-07-10 16:50:22 +00:00
s - > source_output - > userdata = s ;
2009-03-30 18:46:12 +02:00
fix_record_buffer_attr_pre ( s ) ;
2008-05-15 23:34:41 +00:00
2006-02-20 04:05:16 +00:00
s - > memblockq = pa_memblockq_new (
0 ,
2009-03-30 18:46:12 +02:00
s - > buffer_attr . maxlength ,
2006-02-20 04:05:16 +00:00
0 ,
2008-05-15 23:34:41 +00:00
base = pa_frame_size ( & source_output - > sample_spec ) ,
2006-02-20 04:05:16 +00:00
1 ,
0 ,
2008-05-15 23:34:41 +00:00
0 ,
2006-08-18 19:55:18 +00:00
NULL ) ;
2004-07-10 16:50:22 +00:00
2009-03-30 18:46:12 +02:00
pa_memblockq_get_attr ( s - > memblockq , & s - > buffer_attr ) ;
fix_record_buffer_attr_post ( s ) ;
2007-11-21 01:30:40 +00:00
* ss = s - > source_output - > sample_spec ;
* map = s - > source_output - > channel_map ;
2004-07-10 16:50:22 +00:00
pa_idxset_put ( c - > record_streams , s , & s - > index ) ;
2007-10-28 19:13:50 +00:00
2008-05-17 09:11:21 +00:00
pa_log_info ( " Final latency %0.2f ms = %0.2f ms + %0.2f ms " ,
2009-04-05 02:59:02 +02:00
( ( double ) pa_bytes_to_usec ( s - > buffer_attr . fragsize , & source_output - > sample_spec ) + ( double ) s - > configured_source_latency ) / PA_USEC_PER_MSEC ,
2009-03-30 18:46:12 +02:00
( double ) pa_bytes_to_usec ( s - > buffer_attr . fragsize , & source_output - > sample_spec ) / PA_USEC_PER_MSEC ,
2009-04-05 02:59:02 +02:00
( double ) s - > configured_source_latency / PA_USEC_PER_MSEC ) ;
2008-05-17 09:11:21 +00:00
2007-10-28 19:13:50 +00:00
pa_source_output_put ( s - > source_output ) ;
2004-07-10 16:50:22 +00:00
return s ;
}
2009-03-30 18:26:23 +02:00
/* Called from main context */
2008-08-04 18:58:29 +02:00
static void record_stream_send_killed ( record_stream * r ) {
pa_tagstruct * t ;
record_stream_assert_ref ( r ) ;
t = pa_tagstruct_new ( NULL , 0 ) ;
pa_tagstruct_putu32 ( t , PA_COMMAND_RECORD_STREAM_KILLED ) ;
pa_tagstruct_putu32 ( t , ( uint32_t ) - 1 ) ; /* tag */
pa_tagstruct_putu32 ( t , r - > index ) ;
pa_pstream_send_tagstruct ( r - > connection - > pstream , t ) ;
}
2009-03-30 18:26:23 +02:00
/* Called from main context */
2007-10-28 19:13:50 +00:00
static void playback_stream_unlink ( playback_stream * s ) {
pa_assert ( s ) ;
if ( ! s - > connection )
return ;
if ( s - > sink_input ) {
pa_sink_input_unlink ( s - > sink_input ) ;
pa_sink_input_unref ( s - > sink_input ) ;
s - > sink_input = NULL ;
}
if ( s - > drain_request )
pa_pstream_send_error ( s - > connection - > pstream , s - > drain_tag , PA_ERR_NOENTITY ) ;
pa_assert_se ( pa_idxset_remove_by_data ( s - > connection - > output_streams , s , NULL ) = = s ) ;
s - > connection = NULL ;
playback_stream_unref ( s ) ;
}
2009-03-30 18:26:23 +02:00
/* Called from main context */
2007-10-28 19:13:50 +00:00
static void playback_stream_free ( pa_object * o ) {
playback_stream * s = PLAYBACK_STREAM ( o ) ;
pa_assert ( s ) ;
playback_stream_unlink ( s ) ;
pa_memblockq_free ( s - > memblockq ) ;
pa_xfree ( s ) ;
}
2009-03-30 18:26:23 +02:00
/* Called from main context */
2007-10-28 19:13:50 +00:00
static int playback_stream_process_msg ( pa_msgobject * o , int code , void * userdata , int64_t offset , pa_memchunk * chunk ) {
playback_stream * s = PLAYBACK_STREAM ( o ) ;
playback_stream_assert_ref ( s ) ;
if ( ! s - > connection )
return - 1 ;
switch ( code ) {
2009-08-15 00:05:17 +02:00
2007-10-28 19:13:50 +00:00
case PLAYBACK_STREAM_MESSAGE_REQUEST_DATA : {
pa_tagstruct * t ;
2009-04-01 23:05:09 +02:00
int l = 0 ;
2007-10-28 19:13:50 +00:00
for ( ; ; ) {
2009-04-01 23:05:09 +02:00
if ( ( l = pa_atomic_load ( & s - > missing ) ) < = 0 )
return 0 ;
2007-10-28 19:13:50 +00:00
2009-04-01 23:05:09 +02:00
if ( pa_atomic_cmpxchg ( & s - > missing , l , 0 ) )
2007-10-28 19:13:50 +00:00
break ;
}
t = pa_tagstruct_new ( NULL , 0 ) ;
pa_tagstruct_putu32 ( t , PA_COMMAND_REQUEST ) ;
pa_tagstruct_putu32 ( t , ( uint32_t ) - 1 ) ; /* tag */
pa_tagstruct_putu32 ( t , s - > index ) ;
2009-04-01 23:05:09 +02:00
pa_tagstruct_putu32 ( t , ( uint32_t ) l ) ;
2007-10-28 19:13:50 +00:00
pa_pstream_send_tagstruct ( s - > connection - > pstream , t ) ;
2008-05-15 23:34:41 +00:00
/* pa_log("Requesting %lu bytes", (unsigned long) l); */
2007-10-28 19:13:50 +00:00
break ;
}
case PLAYBACK_STREAM_MESSAGE_UNDERFLOW : {
pa_tagstruct * t ;
2008-09-03 18:31:46 +02:00
/* pa_log("signalling underflow"); */
2007-10-28 19:13:50 +00:00
/* Report that we're empty */
t = pa_tagstruct_new ( NULL , 0 ) ;
pa_tagstruct_putu32 ( t , PA_COMMAND_UNDERFLOW ) ;
pa_tagstruct_putu32 ( t , ( uint32_t ) - 1 ) ; /* tag */
pa_tagstruct_putu32 ( t , s - > index ) ;
pa_pstream_send_tagstruct ( s - > connection - > pstream , t ) ;
break ;
}
case PLAYBACK_STREAM_MESSAGE_OVERFLOW : {
pa_tagstruct * t ;
/* Notify the user we're overflowed*/
t = pa_tagstruct_new ( NULL , 0 ) ;
pa_tagstruct_putu32 ( t , PA_COMMAND_OVERFLOW ) ;
pa_tagstruct_putu32 ( t , ( uint32_t ) - 1 ) ; /* tag */
pa_tagstruct_putu32 ( t , s - > index ) ;
pa_pstream_send_tagstruct ( s - > connection - > pstream , t ) ;
break ;
}
2004-06-20 01:12:13 +00:00
2008-05-15 23:34:41 +00:00
case PLAYBACK_STREAM_MESSAGE_STARTED :
if ( s - > connection - > version > = 13 ) {
pa_tagstruct * t ;
2009-03-19 19:38:30 +01:00
/* Notify the user we started playback */
2008-05-15 23:34:41 +00:00
t = pa_tagstruct_new ( NULL , 0 ) ;
pa_tagstruct_putu32 ( t , PA_COMMAND_STARTED ) ;
pa_tagstruct_putu32 ( t , ( uint32_t ) - 1 ) ; /* tag */
pa_tagstruct_putu32 ( t , s - > index ) ;
pa_pstream_send_tagstruct ( s - > connection - > pstream , t ) ;
}
break ;
2007-10-28 19:13:50 +00:00
case PLAYBACK_STREAM_MESSAGE_DRAIN_ACK :
pa_pstream_send_simple_ack ( s - > connection - > pstream , PA_PTR_TO_UINT ( userdata ) ) ;
break ;
2009-03-30 18:46:12 +02:00
case PLAYBACK_STREAM_MESSAGE_UPDATE_TLENGTH : {
pa_tagstruct * t ;
s - > buffer_attr . tlength = ( uint32_t ) offset ;
t = pa_tagstruct_new ( NULL , 0 ) ;
pa_tagstruct_putu32 ( t , PA_COMMAND_PLAYBACK_BUFFER_ATTR_CHANGED ) ;
pa_tagstruct_putu32 ( t , ( uint32_t ) - 1 ) ; /* tag */
pa_tagstruct_putu32 ( t , s - > index ) ;
pa_tagstruct_putu32 ( t , s - > buffer_attr . maxlength ) ;
pa_tagstruct_putu32 ( t , s - > buffer_attr . tlength ) ;
pa_tagstruct_putu32 ( t , s - > buffer_attr . prebuf ) ;
pa_tagstruct_putu32 ( t , s - > buffer_attr . minreq ) ;
2009-04-05 02:59:02 +02:00
pa_tagstruct_put_usec ( t , s - > configured_sink_latency ) ;
2009-03-30 18:46:12 +02:00
pa_pstream_send_tagstruct ( s - > connection - > pstream , t ) ;
break ;
}
2007-10-28 19:13:50 +00:00
}
return 0 ;
2004-06-20 01:12:13 +00:00
}
2009-03-30 18:46:12 +02:00
/* Called from main context */
static void fix_playback_buffer_attr ( playback_stream * s ) {
2009-04-06 22:09:38 +02:00
size_t frame_size , max_prebuf ;
2008-09-01 02:41:03 +02:00
pa_usec_t orig_tlength_usec , tlength_usec , orig_minreq_usec , minreq_usec , sink_usec ;
2008-05-15 23:34:41 +00:00
pa_assert ( s ) ;
2009-03-30 18:46:12 +02:00
/* This function will be called from the main thread, before as
* well as after the sink input has been activated using
* pa_sink_input_put ( ) ! That means it may not touch any
* - > thread_info data , such as the memblockq ! */
2008-05-15 23:34:41 +00:00
2008-06-27 00:34:17 +02:00
frame_size = pa_frame_size ( & s - > sink_input - > sample_spec ) ;
2009-03-30 18:46:12 +02:00
if ( s - > buffer_attr . maxlength = = ( uint32_t ) - 1 | | s - > buffer_attr . maxlength > MAX_MEMBLOCKQ_LENGTH )
s - > buffer_attr . maxlength = MAX_MEMBLOCKQ_LENGTH ;
if ( s - > buffer_attr . maxlength < = 0 )
s - > buffer_attr . maxlength = ( uint32_t ) frame_size ;
2008-06-27 00:34:17 +02:00
2009-03-30 18:46:12 +02:00
if ( s - > buffer_attr . tlength = = ( uint32_t ) - 1 )
s - > buffer_attr . tlength = ( uint32_t ) pa_usec_to_bytes_round_up ( DEFAULT_TLENGTH_MSEC * PA_USEC_PER_MSEC , & s - > sink_input - > sample_spec ) ;
if ( s - > buffer_attr . tlength < = 0 )
s - > buffer_attr . tlength = ( uint32_t ) frame_size ;
2008-05-15 23:34:41 +00:00
2009-03-30 18:46:12 +02:00
if ( s - > buffer_attr . minreq = = ( uint32_t ) - 1 )
s - > buffer_attr . minreq = ( uint32_t ) pa_usec_to_bytes_round_up ( DEFAULT_PROCESS_MSEC * PA_USEC_PER_MSEC , & s - > sink_input - > sample_spec ) ;
if ( s - > buffer_attr . minreq < = 0 )
s - > buffer_attr . minreq = ( uint32_t ) frame_size ;
2008-06-27 00:34:17 +02:00
2009-03-30 18:46:12 +02:00
if ( s - > buffer_attr . tlength < s - > buffer_attr . minreq + frame_size )
s - > buffer_attr . tlength = s - > buffer_attr . minreq + ( uint32_t ) frame_size ;
2008-05-15 23:34:41 +00:00
2009-03-30 18:46:12 +02:00
orig_tlength_usec = tlength_usec = pa_bytes_to_usec ( s - > buffer_attr . tlength , & s - > sink_input - > sample_spec ) ;
orig_minreq_usec = minreq_usec = pa_bytes_to_usec ( s - > buffer_attr . minreq , & s - > sink_input - > sample_spec ) ;
2008-05-15 23:34:41 +00:00
pa_log_info ( " Requested tlength=%0.2f ms, minreq=%0.2f ms " ,
( double ) tlength_usec / PA_USEC_PER_MSEC ,
( double ) minreq_usec / PA_USEC_PER_MSEC ) ;
2009-03-30 18:46:12 +02:00
if ( s - > early_requests ) {
2008-09-03 18:31:46 +02:00
/* In early request mode we need to emulate the classic
* fragment - based playback model . We do this setting the sink
* latency to the fragment size . */
sink_usec = minreq_usec ;
pa_log_debug ( " Early requests mode enabled, configuring sink latency to minreq. " ) ;
2009-03-30 18:46:12 +02:00
} else if ( s - > adjust_latency ) {
2008-05-15 23:34:41 +00:00
/* So, the user asked us to adjust the latency of the stream
* buffer according to the what the sink can provide . The
* tlength passed in shall be the overall latency . Roughly
* half the latency will be spent on the hw buffer , the other
* half of it in the async buffer queue we maintain for each
* client . In between we ' ll have a safety space of size
* 2 * minreq . Why the 2 * minreq ? When the hw buffer is completey
* empty and needs to be filled , then our buffer must have
* enough data to fulfill this request immediatly and thus
* have at least the same tlength as the size of the hw
* buffer . It additionally needs space for 2 times minreq
* because if the buffer ran empty and a partial fillup
* happens immediately on the next iteration we need to be
* able to fulfill it and give the application also minreq
* time to fill it up again for the next request Makes 2 times
* minreq in plus . . */
if ( tlength_usec > minreq_usec * 2 )
sink_usec = ( tlength_usec - minreq_usec * 2 ) / 2 ;
else
sink_usec = 0 ;
2008-09-03 18:31:46 +02:00
pa_log_debug ( " Adjust latency mode enabled, configuring sink latency to half of overall latency. " ) ;
2008-05-15 23:34:41 +00:00
} else {
/* Ok, the user didn't ask us to adjust the latency, but we
* still need to make sure that the parameters from the user
* do make sense . */
if ( tlength_usec > minreq_usec * 2 )
sink_usec = ( tlength_usec - minreq_usec * 2 ) ;
else
sink_usec = 0 ;
2008-09-03 18:31:46 +02:00
pa_log_debug ( " Traditional mode enabled, modifying sink usec only for compat with minreq. " ) ;
2008-05-15 23:34:41 +00:00
}
2009-04-05 02:59:02 +02:00
s - > configured_sink_latency = pa_sink_input_set_requested_latency ( s - > sink_input , sink_usec ) ;
2008-05-15 23:34:41 +00:00
2009-03-30 18:46:12 +02:00
if ( s - > early_requests ) {
2008-09-03 18:31:46 +02:00
/* Ok, we didn't necessarily get what we were asking for, so
* let ' s tell the user */
2009-04-05 02:59:02 +02:00
minreq_usec = s - > configured_sink_latency ;
2008-09-03 18:31:46 +02:00
2009-03-30 18:46:12 +02:00
} else if ( s - > adjust_latency ) {
2008-09-03 18:31:46 +02:00
2008-05-15 23:34:41 +00:00
/* Ok, we didn't necessarily get what we were asking for, so
* let ' s subtract from what we asked for for the remaining
* buffer space */
2009-04-05 02:59:02 +02:00
if ( tlength_usec > = s - > configured_sink_latency )
tlength_usec - = s - > configured_sink_latency ;
2008-05-15 23:34:41 +00:00
}
2008-06-28 01:09:07 +02:00
/* FIXME: This is actually larger than necessary, since not all of
* the sink latency is actually rewritable . */
2009-04-05 02:59:02 +02:00
if ( tlength_usec < s - > configured_sink_latency + 2 * minreq_usec )
tlength_usec = s - > configured_sink_latency + 2 * minreq_usec ;
2008-05-15 23:34:41 +00:00
2008-09-01 02:41:03 +02:00
if ( pa_usec_to_bytes_round_up ( orig_tlength_usec , & s - > sink_input - > sample_spec ) ! =
pa_usec_to_bytes_round_up ( tlength_usec , & s - > sink_input - > sample_spec ) )
2009-03-30 18:46:12 +02:00
s - > buffer_attr . tlength = ( uint32_t ) pa_usec_to_bytes_round_up ( tlength_usec , & s - > sink_input - > sample_spec ) ;
2008-09-01 02:41:03 +02:00
if ( pa_usec_to_bytes ( orig_minreq_usec , & s - > sink_input - > sample_spec ) ! =
pa_usec_to_bytes ( minreq_usec , & s - > sink_input - > sample_spec ) )
2009-03-30 18:46:12 +02:00
s - > buffer_attr . minreq = ( uint32_t ) pa_usec_to_bytes ( minreq_usec , & s - > sink_input - > sample_spec ) ;
2008-05-15 23:34:41 +00:00
2009-03-30 18:46:12 +02:00
if ( s - > buffer_attr . minreq < = 0 ) {
s - > buffer_attr . minreq = ( uint32_t ) frame_size ;
s - > buffer_attr . tlength + = ( uint32_t ) frame_size * 2 ;
2008-05-15 23:34:41 +00:00
}
2009-03-30 18:46:12 +02:00
if ( s - > buffer_attr . tlength < = s - > buffer_attr . minreq )
s - > buffer_attr . tlength = s - > buffer_attr . minreq * 2 + ( uint32_t ) frame_size ;
2008-09-03 18:31:46 +02:00
2009-04-06 22:09:38 +02:00
max_prebuf = s - > buffer_attr . tlength + ( uint32_t ) frame_size - s - > buffer_attr . minreq ;
if ( s - > buffer_attr . prebuf = = ( uint32_t ) - 1 | |
s - > buffer_attr . prebuf > max_prebuf )
s - > buffer_attr . prebuf = max_prebuf ;
2008-05-15 23:34:41 +00:00
}
2009-03-30 18:26:23 +02:00
/* Called from main context */
2007-10-28 19:13:50 +00:00
static playback_stream * playback_stream_new (
2008-08-04 18:58:29 +02:00
pa_native_connection * c ,
2006-08-13 16:19:56 +00:00
pa_sink * sink ,
2007-11-21 01:30:40 +00:00
pa_sample_spec * ss ,
pa_channel_map * map ,
2009-03-30 18:46:12 +02:00
pa_buffer_attr * a ,
2006-08-13 16:19:56 +00:00
pa_cvolume * volume ,
2008-05-15 23:34:41 +00:00
pa_bool_t muted ,
2008-10-26 19:32:04 +01:00
pa_bool_t muted_set ,
2007-10-28 19:13:50 +00:00
uint32_t syncid ,
2007-11-21 01:30:40 +00:00
uint32_t * missing ,
2008-05-15 23:34:41 +00:00
pa_sink_input_flags_t flags ,
pa_proplist * p ,
2008-09-03 18:31:46 +02:00
pa_bool_t adjust_latency ,
2009-02-03 03:14:20 +01:00
pa_bool_t early_requests ,
int * ret ) {
2007-01-04 13:43:45 +00:00
2007-10-28 19:13:50 +00:00
playback_stream * s , * ssync ;
2009-02-04 18:33:01 +01:00
pa_sink_input * sink_input = NULL ;
2008-05-15 23:34:41 +00:00
pa_memchunk silence ;
2006-02-20 04:05:16 +00:00
uint32_t idx ;
int64_t start_index ;
2006-08-13 16:19:56 +00:00
pa_sink_input_new_data data ;
2007-01-04 13:43:45 +00:00
2007-10-28 19:13:50 +00:00
pa_assert ( c ) ;
pa_assert ( ss ) ;
2008-05-15 23:34:41 +00:00
pa_assert ( missing ) ;
pa_assert ( p ) ;
2009-02-03 03:14:20 +01:00
pa_assert ( ret ) ;
2004-06-20 01:12:13 +00:00
2006-02-20 04:05:16 +00:00
/* Find syncid group */
2006-02-24 15:12:42 +00:00
for ( ssync = pa_idxset_first ( c - > output_streams , & idx ) ; ssync ; ssync = pa_idxset_next ( c - > output_streams , & idx ) ) {
2007-01-04 13:43:45 +00:00
2007-10-28 19:13:50 +00:00
if ( ! playback_stream_isinstance ( ssync ) )
2006-02-20 04:05:16 +00:00
continue ;
2006-02-24 15:12:42 +00:00
if ( ssync - > syncid = = syncid )
2006-02-20 04:05:16 +00:00
break ;
}
/* Synced streams must connect to the same sink */
2007-10-28 19:13:50 +00:00
if ( ssync ) {
if ( ! sink )
sink = ssync - > sink_input - > sink ;
2009-02-03 03:14:20 +01:00
else if ( sink ! = ssync - > sink_input - > sink ) {
* ret = PA_ERR_INVALID ;
2007-10-28 19:13:50 +00:00
return NULL ;
2009-02-03 03:14:20 +01:00
}
2007-10-28 19:13:50 +00:00
}
2006-08-13 16:19:56 +00:00
pa_sink_input_new_data_init ( & data ) ;
2008-05-15 23:34:41 +00:00
pa_proplist_update ( data . proplist , PA_UPDATE_REPLACE , p ) ;
2006-08-13 16:19:56 +00:00
data . driver = __FILE__ ;
2008-08-03 16:44:38 +02:00
data . module = c - > options - > module ;
2008-05-15 23:34:41 +00:00
data . client = c - > client ;
data . sink = sink ;
2006-08-13 16:19:56 +00:00
pa_sink_input_new_data_set_sample_spec ( & data , ss ) ;
pa_sink_input_new_data_set_channel_map ( & data , map ) ;
2008-08-18 17:49:18 +02:00
if ( volume )
2009-02-04 18:34:08 +01:00
pa_sink_input_new_data_set_volume ( & data , volume ) ;
2008-10-26 19:32:04 +01:00
if ( muted_set )
pa_sink_input_new_data_set_muted ( & data , muted ) ;
2007-10-28 19:13:50 +00:00
data . sync_base = ssync ? ssync - > sink_input : NULL ;
2006-08-13 16:19:56 +00:00
2009-02-04 18:33:01 +01:00
* ret = - pa_sink_input_new ( & sink_input , c - > protocol - > core , & data , flags ) ;
2008-05-15 23:34:41 +00:00
pa_sink_input_new_data_done ( & data ) ;
if ( ! sink_input )
2004-07-10 16:50:22 +00:00
return NULL ;
2007-01-04 13:43:45 +00:00
2007-10-28 19:13:50 +00:00
s = pa_msgobject_new ( playback_stream ) ;
s - > parent . parent . parent . free = playback_stream_free ;
s - > parent . parent . process_msg = playback_stream_process_msg ;
2004-06-20 01:12:13 +00:00
s - > connection = c ;
2006-02-20 04:05:16 +00:00
s - > syncid = syncid ;
2004-07-10 16:50:22 +00:00
s - > sink_input = sink_input ;
2008-06-27 00:35:40 +02:00
s - > is_underrun = TRUE ;
s - > drain_request = FALSE ;
pa_atomic_store ( & s - > missing , 0 ) ;
2009-03-30 18:46:12 +02:00
s - > buffer_attr = * a ;
s - > adjust_latency = adjust_latency ;
s - > early_requests = early_requests ;
2007-01-04 13:43:45 +00:00
2007-10-28 19:13:50 +00:00
s - > sink_input - > parent . process_msg = sink_input_process_msg ;
2008-05-15 23:34:41 +00:00
s - > sink_input - > pop = sink_input_pop_cb ;
s - > sink_input - > process_rewind = sink_input_process_rewind_cb ;
s - > sink_input - > update_max_rewind = sink_input_update_max_rewind_cb ;
2008-06-28 01:09:07 +02:00
s - > sink_input - > update_max_request = sink_input_update_max_request_cb ;
2004-06-23 23:17:30 +00:00
s - > sink_input - > kill = sink_input_kill_cb ;
2009-03-30 18:21:34 +02:00
s - > sink_input - > moving = sink_input_moving_cb ;
2007-11-21 01:30:40 +00:00
s - > sink_input - > suspend = sink_input_suspend_cb ;
2009-02-12 03:18:05 +01:00
s - > sink_input - > send_event = sink_input_send_event_cb ;
2004-06-23 23:17:30 +00:00
s - > sink_input - > userdata = s ;
2004-06-20 01:12:13 +00:00
2007-10-28 19:13:50 +00:00
start_index = ssync ? pa_memblockq_get_read_index ( ssync - > memblockq ) : 0 ;
2007-01-04 13:43:45 +00:00
2009-03-30 18:46:12 +02:00
fix_playback_buffer_attr ( s ) ;
2007-01-04 13:43:45 +00:00
2009-03-30 18:46:12 +02:00
pa_sink_input_get_silence ( sink_input , & silence ) ;
2006-02-20 04:05:16 +00:00
s - > memblockq = pa_memblockq_new (
start_index ,
2009-03-30 18:46:12 +02:00
s - > buffer_attr . maxlength ,
s - > buffer_attr . tlength ,
2008-05-15 23:34:41 +00:00
pa_frame_size ( & sink_input - > sample_spec ) ,
2009-03-30 18:46:12 +02:00
s - > buffer_attr . prebuf ,
s - > buffer_attr . minreq ,
2008-05-15 23:34:41 +00:00
0 ,
& silence ) ;
pa_memblock_unref ( silence . memblock ) ;
2009-03-30 18:46:12 +02:00
pa_memblockq_get_attr ( s - > memblockq , & s - > buffer_attr ) ;
2007-01-04 13:43:45 +00:00
2007-10-28 19:13:50 +00:00
* missing = ( uint32_t ) pa_memblockq_pop_missing ( s - > memblockq ) ;
2007-11-21 01:30:40 +00:00
* ss = s - > sink_input - > sample_spec ;
* map = s - > sink_input - > channel_map ;
2004-08-03 19:26:56 +00:00
pa_idxset_put ( c - > output_streams , s , & s - > index ) ;
2006-02-20 04:05:16 +00:00
2008-05-15 23:34:41 +00:00
pa_log_info ( " Final latency %0.2f ms = %0.2f ms + 2*%0.2f ms + %0.2f ms " ,
2009-04-05 02:59:02 +02:00
( ( double ) pa_bytes_to_usec ( s - > buffer_attr . tlength , & sink_input - > sample_spec ) + ( double ) s - > configured_sink_latency ) / PA_USEC_PER_MSEC ,
2009-03-30 18:46:12 +02:00
( double ) pa_bytes_to_usec ( s - > buffer_attr . tlength - s - > buffer_attr . minreq * 2 , & sink_input - > sample_spec ) / PA_USEC_PER_MSEC ,
( double ) pa_bytes_to_usec ( s - > buffer_attr . minreq , & sink_input - > sample_spec ) / PA_USEC_PER_MSEC ,
2009-04-05 02:59:02 +02:00
( double ) s - > configured_sink_latency / PA_USEC_PER_MSEC ) ;
2007-10-28 19:13:50 +00:00
2008-05-15 23:34:41 +00:00
pa_sink_input_put ( s - > sink_input ) ;
2004-06-20 01:12:13 +00:00
return s ;
}
2009-03-30 18:26:23 +02:00
/* Called from IO context */
2008-08-04 18:58:29 +02:00
static void playback_stream_request_bytes ( playback_stream * s ) {
2009-04-01 23:05:09 +02:00
size_t m , minreq ;
int previous_missing ;
2008-08-04 18:58:29 +02:00
playback_stream_assert_ref ( s ) ;
m = pa_memblockq_pop_missing ( s - > memblockq ) ;
if ( m < = 0 )
return ;
/* pa_log("request_bytes(%lu)", (unsigned long) m); */
2009-04-01 23:05:09 +02:00
previous_missing = pa_atomic_add ( & s - > missing , ( int ) m ) ;
2009-03-30 18:46:12 +02:00
minreq = pa_memblockq_get_minreq ( s - > memblockq ) ;
2008-08-04 18:58:29 +02:00
if ( pa_memblockq_prebuf_active ( s - > memblockq ) | |
2009-04-01 23:05:09 +02:00
( previous_missing < ( int ) minreq & & previous_missing + ( int ) m > = ( int ) minreq ) )
2008-08-04 18:58:29 +02:00
pa_asyncmsgq_post ( pa_thread_mq_get ( ) - > outq , PA_MSGOBJECT ( s ) , PLAYBACK_STREAM_MESSAGE_REQUEST_DATA , NULL , 0 , NULL , NULL ) ;
}
2009-03-30 18:26:23 +02:00
/* Called from main context */
2008-08-04 18:58:29 +02:00
static void playback_stream_send_killed ( playback_stream * p ) {
pa_tagstruct * t ;
playback_stream_assert_ref ( p ) ;
t = pa_tagstruct_new ( NULL , 0 ) ;
pa_tagstruct_putu32 ( t , PA_COMMAND_PLAYBACK_STREAM_KILLED ) ;
pa_tagstruct_putu32 ( t , ( uint32_t ) - 1 ) ; /* tag */
pa_tagstruct_putu32 ( t , p - > index ) ;
pa_pstream_send_tagstruct ( p - > connection - > pstream , t ) ;
}
2009-03-30 18:26:23 +02:00
/* Called from main context */
2008-08-04 18:58:29 +02:00
static int native_connection_process_msg ( pa_msgobject * o , int code , void * userdata , int64_t offset , pa_memchunk * chunk ) {
pa_native_connection * c = PA_NATIVE_CONNECTION ( o ) ;
pa_native_connection_assert_ref ( c ) ;
2004-06-20 01:12:13 +00:00
2007-10-28 19:13:50 +00:00
if ( ! c - > protocol )
return - 1 ;
2006-02-20 04:05:16 +00:00
2007-10-28 19:13:50 +00:00
switch ( code ) {
2004-07-07 22:02:15 +00:00
2007-10-28 19:13:50 +00:00
case CONNECTION_MESSAGE_REVOKE :
pa_pstream_send_revoke ( c - > pstream , PA_PTR_TO_UINT ( userdata ) ) ;
break ;
case CONNECTION_MESSAGE_RELEASE :
pa_pstream_send_release ( c - > pstream , PA_PTR_TO_UINT ( userdata ) ) ;
break ;
}
return 0 ;
2004-06-20 01:12:13 +00:00
}
2009-03-30 18:26:23 +02:00
/* Called from main context */
2008-08-04 18:58:29 +02:00
static void native_connection_unlink ( pa_native_connection * c ) {
2007-10-28 19:13:50 +00:00
record_stream * r ;
output_stream * o ;
pa_assert ( c ) ;
if ( ! c - > protocol )
return ;
2004-06-20 01:12:13 +00:00
2008-08-04 18:58:29 +02:00
pa_hook_fire ( & c - > protocol - > hooks [ PA_NATIVE_HOOK_CONNECTION_UNLINK ] , c ) ;
2008-08-03 16:44:38 +02:00
if ( c - > options )
pa_native_options_unref ( c - > options ) ;
2004-07-03 23:35:12 +00:00
while ( ( r = pa_idxset_first ( c - > record_streams , NULL ) ) )
2007-10-28 19:13:50 +00:00
record_stream_unlink ( r ) ;
2004-06-20 01:12:13 +00:00
2004-08-03 19:26:56 +00:00
while ( ( o = pa_idxset_first ( c - > output_streams , NULL ) ) )
2007-10-28 19:13:50 +00:00
if ( playback_stream_isinstance ( o ) )
playback_stream_unlink ( PLAYBACK_STREAM ( o ) ) ;
2004-08-03 19:26:56 +00:00
else
2007-10-28 19:13:50 +00:00
upload_stream_unlink ( UPLOAD_STREAM ( o ) ) ;
2004-08-11 15:11:26 +00:00
if ( c - > subscription )
pa_subscription_free ( c - > subscription ) ;
2004-11-18 00:28:26 +00:00
2007-10-28 19:13:50 +00:00
if ( c - > pstream )
pa_pstream_unlink ( c - > pstream ) ;
if ( c - > auth_timeout_event ) {
2004-11-18 00:28:26 +00:00
c - > protocol - > core - > mainloop - > time_free ( c - > auth_timeout_event ) ;
2007-10-28 19:13:50 +00:00
c - > auth_timeout_event = NULL ;
}
2007-01-04 13:43:45 +00:00
2007-10-28 19:13:50 +00:00
pa_assert_se ( pa_idxset_remove_by_data ( c - > protocol - > connections , c , NULL ) = = c ) ;
c - > protocol = NULL ;
2008-08-04 18:58:29 +02:00
pa_native_connection_unref ( c ) ;
2004-06-20 01:12:13 +00:00
}
2009-03-30 18:26:23 +02:00
/* Called from main context */
2008-08-04 18:58:29 +02:00
static void native_connection_free ( pa_object * o ) {
pa_native_connection * c = PA_NATIVE_CONNECTION ( o ) ;
2004-06-20 01:12:13 +00:00
2007-10-28 19:13:50 +00:00
pa_assert ( c ) ;
2007-01-04 13:43:45 +00:00
2008-08-04 18:58:29 +02:00
native_connection_unlink ( c ) ;
2004-06-27 17:50:02 +00:00
2007-10-28 19:13:50 +00:00
pa_idxset_free ( c - > record_streams , NULL , NULL ) ;
pa_idxset_free ( c - > output_streams , NULL , NULL ) ;
2004-07-07 00:22:46 +00:00
2007-10-28 19:13:50 +00:00
pa_pdispatch_unref ( c - > pdispatch ) ;
pa_pstream_unref ( c - > pstream ) ;
pa_client_free ( c - > client ) ;
2007-01-04 13:43:45 +00:00
2007-10-28 19:13:50 +00:00
pa_xfree ( c ) ;
}
2004-06-27 17:50:02 +00:00
2009-03-30 18:26:23 +02:00
/* Called from main context */
2008-08-04 18:58:29 +02:00
static void native_connection_send_memblock ( pa_native_connection * c ) {
2004-07-10 16:50:22 +00:00
uint32_t start ;
2007-10-28 19:13:50 +00:00
record_stream * r ;
2004-07-10 16:50:22 +00:00
start = PA_IDXSET_INVALID ;
for ( ; ; ) {
2006-01-11 01:17:39 +00:00
pa_memchunk chunk ;
2007-01-04 13:43:45 +00:00
2007-10-28 19:13:50 +00:00
if ( ! ( r = RECORD_STREAM ( pa_idxset_rrobin ( c - > record_streams , & c - > rrobin_index ) ) ) )
2004-07-10 16:50:22 +00:00
return ;
if ( start = = PA_IDXSET_INVALID )
start = c - > rrobin_index ;
else if ( start = = c - > rrobin_index )
return ;
if ( pa_memblockq_peek ( r - > memblockq , & chunk ) > = 0 ) {
2006-01-11 01:17:39 +00:00
pa_memchunk schunk = chunk ;
2007-01-04 13:43:45 +00:00
2009-03-30 18:46:12 +02:00
if ( schunk . length > r - > buffer_attr . fragsize )
schunk . length = r - > buffer_attr . fragsize ;
2004-07-10 16:50:22 +00:00
2006-02-20 04:05:16 +00:00
pa_pstream_send_memblock ( c - > pstream , r - > index , 0 , PA_SEEK_RELATIVE , & schunk ) ;
2007-10-28 19:13:50 +00:00
pa_memblockq_drop ( r - > memblockq , schunk . length ) ;
2004-09-06 18:55:47 +00:00
pa_memblock_unref ( schunk . memblock ) ;
2007-01-04 13:43:45 +00:00
2004-07-10 16:50:22 +00:00
return ;
}
}
}
2007-10-28 19:13:50 +00:00
/*** sink input callbacks ***/
2004-06-23 23:17:30 +00:00
2009-03-30 18:26:23 +02:00
/* Called from thread context */
2008-05-15 23:34:41 +00:00
static void handle_seek ( playback_stream * s , int64_t indexw ) {
playback_stream_assert_ref ( s ) ;
/* pa_log("handle_seek: %llu -- %i", (unsigned long long) s->sink_input->thread_info.underrun_for, pa_memblockq_is_readable(s->memblockq)); */
if ( s - > sink_input - > thread_info . underrun_for > 0 ) {
/* pa_log("%lu vs. %lu", (unsigned long) pa_memblockq_get_length(s->memblockq), (unsigned long) pa_memblockq_get_prebuf(s->memblockq)); */
if ( pa_memblockq_is_readable ( s - > memblockq ) ) {
/* We just ended an underrun, let's ask the sink
* for a complete rewind rewrite */
pa_log_debug ( " Requesting rewind due to end of underrun. " ) ;
pa_sink_input_request_rewind ( s - > sink_input ,
2008-08-20 03:33:06 +03:00
( size_t ) ( s - > sink_input - > thread_info . underrun_for = = ( size_t ) - 1 ? 0 : s - > sink_input - > thread_info . underrun_for ) ,
2009-01-15 00:40:06 +01:00
FALSE , TRUE , FALSE ) ;
2008-05-15 23:34:41 +00:00
}
} else {
int64_t indexr ;
indexr = pa_memblockq_get_read_index ( s - > memblockq ) ;
if ( indexw < indexr ) {
/* OK, the sink already asked for this data, so
* let ' s have it usk us again */
pa_log_debug ( " Requesting rewind due to rewrite. " ) ;
2009-01-15 00:40:06 +01:00
pa_sink_input_request_rewind ( s - > sink_input , ( size_t ) ( indexr - indexw ) , TRUE , FALSE , FALSE ) ;
2008-05-15 23:34:41 +00:00
}
}
2008-08-04 18:58:29 +02:00
playback_stream_request_bytes ( s ) ;
2008-05-15 23:34:41 +00:00
}
2007-10-28 19:13:50 +00:00
/* Called from thread context */
static int sink_input_process_msg ( pa_msgobject * o , int code , void * userdata , int64_t offset , pa_memchunk * chunk ) {
pa_sink_input * i = PA_SINK_INPUT ( o ) ;
playback_stream * s ;
2004-06-23 23:17:30 +00:00
2007-10-28 19:13:50 +00:00
pa_sink_input_assert_ref ( i ) ;
s = PLAYBACK_STREAM ( i - > userdata ) ;
playback_stream_assert_ref ( s ) ;
switch ( code ) {
2008-05-15 23:34:41 +00:00
case SINK_INPUT_MESSAGE_SEEK : {
int64_t windex ;
windex = pa_memblockq_get_write_index ( s - > memblockq ) ;
2009-04-01 23:05:09 +02:00
/* The client side is incapable of accounting correctly
* for seeks of a type ! = PA_SEEK_RELATIVE . We need to be
* able to deal with that . */
pa_memblockq_seek ( s - > memblockq , offset , PA_PTR_TO_UINT ( userdata ) , PA_PTR_TO_UINT ( userdata ) = = PA_SEEK_RELATIVE ) ;
2008-05-15 23:34:41 +00:00
handle_seek ( s , windex ) ;
2007-10-28 19:13:50 +00:00
return 0 ;
2008-05-15 23:34:41 +00:00
}
2007-10-28 19:13:50 +00:00
case SINK_INPUT_MESSAGE_POST_DATA : {
2008-05-15 23:34:41 +00:00
int64_t windex ;
2007-10-28 19:13:50 +00:00
pa_assert ( chunk ) ;
2008-05-15 23:34:41 +00:00
windex = pa_memblockq_get_write_index ( s - > memblockq ) ;
2007-10-28 19:13:50 +00:00
2008-05-15 23:34:41 +00:00
/* pa_log("sink input post: %lu %lli", (unsigned long) chunk->length, (long long) windex); */
2007-10-28 19:13:50 +00:00
2008-05-15 23:34:41 +00:00
if ( pa_memblockq_push_align ( s - > memblockq , chunk ) < 0 ) {
2007-10-28 19:13:50 +00:00
pa_log_warn ( " Failed to push data into queue " ) ;
pa_asyncmsgq_post ( pa_thread_mq_get ( ) - > outq , PA_MSGOBJECT ( s ) , PLAYBACK_STREAM_MESSAGE_OVERFLOW , NULL , 0 , NULL , NULL ) ;
2009-04-01 23:05:09 +02:00
pa_memblockq_seek ( s - > memblockq , ( int64_t ) chunk - > length , PA_SEEK_RELATIVE , TRUE ) ;
2007-10-28 19:13:50 +00:00
}
2006-02-20 04:05:16 +00:00
2008-05-15 23:34:41 +00:00
handle_seek ( s , windex ) ;
2006-02-20 04:05:16 +00:00
2008-05-15 23:34:41 +00:00
/* pa_log("sink input post2: %lu", (unsigned long) pa_memblockq_get_length(s->memblockq)); */
2007-10-28 19:13:50 +00:00
return 0 ;
}
2008-05-15 23:34:41 +00:00
case SINK_INPUT_MESSAGE_DRAIN :
2007-10-28 19:13:50 +00:00
case SINK_INPUT_MESSAGE_FLUSH :
case SINK_INPUT_MESSAGE_PREBUF_FORCE :
case SINK_INPUT_MESSAGE_TRIGGER : {
2008-05-15 23:34:41 +00:00
int64_t windex ;
2007-10-28 19:13:50 +00:00
pa_sink_input * isync ;
void ( * func ) ( pa_memblockq * bq ) ;
switch ( code ) {
case SINK_INPUT_MESSAGE_FLUSH :
2008-06-26 00:39:31 +02:00
func = pa_memblockq_flush_write ;
2007-10-28 19:13:50 +00:00
break ;
case SINK_INPUT_MESSAGE_PREBUF_FORCE :
func = pa_memblockq_prebuf_force ;
break ;
2008-05-15 23:34:41 +00:00
case SINK_INPUT_MESSAGE_DRAIN :
2007-10-28 19:13:50 +00:00
case SINK_INPUT_MESSAGE_TRIGGER :
func = pa_memblockq_prebuf_disable ;
break ;
default :
pa_assert_not_reached ( ) ;
}
2008-05-15 23:34:41 +00:00
windex = pa_memblockq_get_write_index ( s - > memblockq ) ;
2007-10-28 19:13:50 +00:00
func ( s - > memblockq ) ;
2008-05-15 23:34:41 +00:00
handle_seek ( s , windex ) ;
2007-10-28 19:13:50 +00:00
/* Do the same for all other members in the sync group */
for ( isync = i - > sync_prev ; isync ; isync = isync - > sync_prev ) {
playback_stream * ssync = PLAYBACK_STREAM ( isync - > userdata ) ;
2008-05-15 23:34:41 +00:00
windex = pa_memblockq_get_write_index ( ssync - > memblockq ) ;
2007-10-28 19:13:50 +00:00
func ( ssync - > memblockq ) ;
2008-05-15 23:34:41 +00:00
handle_seek ( ssync , windex ) ;
2007-10-28 19:13:50 +00:00
}
for ( isync = i - > sync_next ; isync ; isync = isync - > sync_next ) {
playback_stream * ssync = PLAYBACK_STREAM ( isync - > userdata ) ;
2008-05-15 23:34:41 +00:00
windex = pa_memblockq_get_write_index ( ssync - > memblockq ) ;
2007-10-28 19:13:50 +00:00
func ( ssync - > memblockq ) ;
2008-05-15 23:34:41 +00:00
handle_seek ( ssync , windex ) ;
}
if ( code = = SINK_INPUT_MESSAGE_DRAIN ) {
if ( ! pa_memblockq_is_readable ( s - > memblockq ) )
pa_asyncmsgq_post ( pa_thread_mq_get ( ) - > outq , PA_MSGOBJECT ( s ) , PLAYBACK_STREAM_MESSAGE_DRAIN_ACK , userdata , 0 , NULL , NULL ) ;
else {
s - > drain_tag = PA_PTR_TO_UINT ( userdata ) ;
s - > drain_request = TRUE ;
}
2007-10-28 19:13:50 +00:00
}
return 0 ;
}
case SINK_INPUT_MESSAGE_UPDATE_LATENCY :
2009-04-05 02:59:02 +02:00
/* Atomically get a snapshot of all timing parameters... */
2007-10-28 19:13:50 +00:00
s - > read_index = pa_memblockq_get_read_index ( s - > memblockq ) ;
s - > write_index = pa_memblockq_get_write_index ( s - > memblockq ) ;
2008-05-15 23:34:41 +00:00
s - > render_memblockq_length = pa_memblockq_get_length ( s - > sink_input - > thread_info . render_memblockq ) ;
2009-04-05 02:59:02 +02:00
s - > current_sink_latency = pa_sink_get_latency_within_thread ( s - > sink_input - > sink ) ;
s - > underrun_for = s - > sink_input - > thread_info . underrun_for ;
s - > playing_for = s - > sink_input - > thread_info . playing_for ;
2007-10-28 19:13:50 +00:00
return 0 ;
2008-05-15 23:34:41 +00:00
case PA_SINK_INPUT_MESSAGE_SET_STATE : {
int64_t windex ;
windex = pa_memblockq_get_write_index ( s - > memblockq ) ;
2007-10-28 19:13:50 +00:00
pa_memblockq_prebuf_force ( s - > memblockq ) ;
2008-05-15 23:34:41 +00:00
handle_seek ( s , windex ) ;
/* Fall through to the default handler */
2007-10-28 19:13:50 +00:00
break ;
2008-05-15 23:34:41 +00:00
}
2007-10-28 19:13:50 +00:00
case PA_SINK_INPUT_MESSAGE_GET_LATENCY : {
pa_usec_t * r = userdata ;
* r = pa_bytes_to_usec ( pa_memblockq_get_length ( s - > memblockq ) , & i - > sample_spec ) ;
/* Fall through, the default handler will add in the extra
* latency added by the resampler */
break ;
}
2009-03-30 18:46:12 +02:00
case SINK_INPUT_MESSAGE_UPDATE_BUFFER_ATTR : {
pa_memblockq_apply_attr ( s - > memblockq , & s - > buffer_attr ) ;
pa_memblockq_get_attr ( s - > memblockq , & s - > buffer_attr ) ;
return 0 ;
}
2007-10-28 19:13:50 +00:00
}
return pa_sink_input_process_msg ( o , code , userdata , offset , chunk ) ;
}
/* Called from thread context */
2008-05-15 23:34:41 +00:00
static int sink_input_pop_cb ( pa_sink_input * i , size_t nbytes , pa_memchunk * chunk ) {
2007-10-28 19:13:50 +00:00
playback_stream * s ;
pa_sink_input_assert_ref ( i ) ;
s = PLAYBACK_STREAM ( i - > userdata ) ;
playback_stream_assert_ref ( s ) ;
pa_assert ( chunk ) ;
2008-06-27 00:35:40 +02:00
/* pa_log("%s, pop(): %lu", pa_proplist_gets(i->proplist, PA_PROP_MEDIA_NAME), (unsigned long) pa_memblockq_get_length(s->memblockq)); */
2008-05-15 23:34:41 +00:00
2008-06-27 00:35:40 +02:00
if ( pa_memblockq_is_readable ( s - > memblockq ) )
s - > is_underrun = FALSE ;
else {
2009-04-10 01:16:24 +02:00
if ( ! s - > is_underrun )
pa_log_debug ( " Underrun on '%s', %lu bytes in queue. " , pa_strnull ( pa_proplist_gets ( i - > proplist , PA_PROP_MEDIA_NAME ) ) , ( unsigned long ) pa_memblockq_get_length ( s - > memblockq ) ) ;
2008-05-15 23:34:41 +00:00
if ( s - > drain_request & & pa_sink_input_safe_to_remove ( i ) ) {
s - > drain_request = FALSE ;
pa_asyncmsgq_post ( pa_thread_mq_get ( ) - > outq , PA_MSGOBJECT ( s ) , PLAYBACK_STREAM_MESSAGE_DRAIN_ACK , PA_UINT_TO_PTR ( s - > drain_tag ) , 0 , NULL , NULL ) ;
2008-06-27 00:35:40 +02:00
} else if ( ! s - > is_underrun )
2008-05-15 23:34:41 +00:00
pa_asyncmsgq_post ( pa_thread_mq_get ( ) - > outq , PA_MSGOBJECT ( s ) , PLAYBACK_STREAM_MESSAGE_UNDERFLOW , NULL , 0 , NULL , NULL ) ;
2008-06-27 00:35:40 +02:00
s - > is_underrun = TRUE ;
2008-05-15 23:34:41 +00:00
2008-08-04 18:58:29 +02:00
playback_stream_request_bytes ( s ) ;
2006-02-20 04:05:16 +00:00
}
2004-06-23 23:17:30 +00:00
2008-06-27 00:35:40 +02:00
/* This call will not fail with prebuf=0, hence we check for
underrun explicitly above */
if ( pa_memblockq_peek ( s - > memblockq , chunk ) < 0 )
return - 1 ;
2008-05-15 23:34:41 +00:00
2008-05-27 22:07:27 +00:00
chunk - > length = PA_MIN ( nbytes , chunk - > length ) ;
2008-05-15 23:34:41 +00:00
if ( i - > thread_info . underrun_for > 0 )
pa_asyncmsgq_post ( pa_thread_mq_get ( ) - > outq , PA_MSGOBJECT ( s ) , PLAYBACK_STREAM_MESSAGE_STARTED , NULL , 0 , NULL , NULL ) ;
2007-10-28 19:13:50 +00:00
2008-05-15 23:34:41 +00:00
pa_memblockq_drop ( s - > memblockq , chunk - > length ) ;
2008-08-04 18:58:29 +02:00
playback_stream_request_bytes ( s ) ;
2007-01-04 13:43:45 +00:00
2004-06-23 23:17:30 +00:00
return 0 ;
2004-06-20 01:12:13 +00:00
}
2009-03-30 18:26:23 +02:00
/* Called from thread context */
2008-05-15 23:34:41 +00:00
static void sink_input_process_rewind_cb ( pa_sink_input * i , size_t nbytes ) {
2007-10-28 19:13:50 +00:00
playback_stream * s ;
2004-06-20 01:12:13 +00:00
2007-10-28 19:13:50 +00:00
pa_sink_input_assert_ref ( i ) ;
s = PLAYBACK_STREAM ( i - > userdata ) ;
playback_stream_assert_ref ( s ) ;
2006-02-20 04:05:16 +00:00
2008-05-15 23:34:41 +00:00
/* If we are in an underrun, then we don't rewind */
if ( i - > thread_info . underrun_for > 0 )
return ;
2004-07-07 22:02:15 +00:00
2008-05-15 23:34:41 +00:00
pa_memblockq_rewind ( s - > memblockq , nbytes ) ;
}
2004-08-27 01:29:49 +00:00
2009-03-30 18:26:23 +02:00
/* Called from thread context */
2008-05-15 23:34:41 +00:00
static void sink_input_update_max_rewind_cb ( pa_sink_input * i , size_t nbytes ) {
playback_stream * s ;
pa_sink_input_assert_ref ( i ) ;
s = PLAYBACK_STREAM ( i - > userdata ) ;
playback_stream_assert_ref ( s ) ;
2004-06-23 23:17:30 +00:00
2008-05-15 23:34:41 +00:00
pa_memblockq_set_maxrewind ( s - > memblockq , nbytes ) ;
2004-06-23 23:17:30 +00:00
}
2009-03-30 18:26:23 +02:00
/* Called from thread context */
2008-06-28 01:09:07 +02:00
static void sink_input_update_max_request_cb ( pa_sink_input * i , size_t nbytes ) {
playback_stream * s ;
2009-03-31 21:36:45 +02:00
size_t new_tlength , old_tlength ;
2008-06-28 01:09:07 +02:00
pa_sink_input_assert_ref ( i ) ;
s = PLAYBACK_STREAM ( i - > userdata ) ;
playback_stream_assert_ref ( s ) ;
2009-03-31 21:36:45 +02:00
old_tlength = pa_memblockq_get_tlength ( s - > memblockq ) ;
new_tlength = nbytes + 2 * pa_memblockq_get_minreq ( s - > memblockq ) ;
2008-06-28 01:09:07 +02:00
2009-03-31 21:36:45 +02:00
if ( old_tlength < new_tlength ) {
pa_log_debug ( " max_request changed, trying to update from %zu to %zu. " , old_tlength , new_tlength ) ;
pa_memblockq_set_tlength ( s - > memblockq , new_tlength ) ;
new_tlength = pa_memblockq_get_tlength ( s - > memblockq ) ;
if ( new_tlength = = old_tlength )
pa_log_debug ( " Failed to increase tlength " ) ;
else {
pa_log_debug ( " Notifying client about increased tlength " ) ;
pa_asyncmsgq_post ( pa_thread_mq_get ( ) - > outq , PA_MSGOBJECT ( s ) , PLAYBACK_STREAM_MESSAGE_UPDATE_TLENGTH , NULL , pa_memblockq_get_tlength ( s - > memblockq ) , NULL , NULL ) ;
}
2009-03-30 18:46:12 +02:00
}
2008-06-28 01:09:07 +02:00
}
2007-11-21 01:30:40 +00:00
/* Called from main context */
2007-10-28 19:13:50 +00:00
static void sink_input_kill_cb ( pa_sink_input * i ) {
playback_stream * s ;
2004-06-23 23:17:30 +00:00
2007-10-28 19:13:50 +00:00
pa_sink_input_assert_ref ( i ) ;
s = PLAYBACK_STREAM ( i - > userdata ) ;
playback_stream_assert_ref ( s ) ;
2007-01-04 13:43:45 +00:00
2008-08-04 18:58:29 +02:00
playback_stream_send_killed ( s ) ;
2007-10-28 19:13:50 +00:00
playback_stream_unlink ( s ) ;
2004-06-23 23:17:30 +00:00
}
2009-02-12 03:18:05 +01:00
/* Called from main context */
static void sink_input_send_event_cb ( pa_sink_input * i , const char * event , pa_proplist * pl ) {
playback_stream * s ;
pa_tagstruct * t ;
pa_sink_input_assert_ref ( i ) ;
s = PLAYBACK_STREAM ( i - > userdata ) ;
playback_stream_assert_ref ( s ) ;
if ( s - > connection - > version < 15 )
return ;
t = pa_tagstruct_new ( NULL , 0 ) ;
pa_tagstruct_putu32 ( t , PA_COMMAND_PLAYBACK_STREAM_EVENT ) ;
pa_tagstruct_putu32 ( t , ( uint32_t ) - 1 ) ; /* tag */
pa_tagstruct_putu32 ( t , s - > index ) ;
pa_tagstruct_puts ( t , event ) ;
pa_tagstruct_put_proplist ( t , pl ) ;
pa_pstream_send_tagstruct ( s - > connection - > pstream , t ) ;
}
2007-11-21 01:30:40 +00:00
/* Called from main context */
static void sink_input_suspend_cb ( pa_sink_input * i , pa_bool_t suspend ) {
playback_stream * s ;
pa_tagstruct * t ;
pa_sink_input_assert_ref ( i ) ;
s = PLAYBACK_STREAM ( i - > userdata ) ;
playback_stream_assert_ref ( s ) ;
2008-01-04 14:59:09 +00:00
if ( s - > connection - > version < 12 )
return ;
2007-11-21 01:30:40 +00:00
t = pa_tagstruct_new ( NULL , 0 ) ;
pa_tagstruct_putu32 ( t , PA_COMMAND_PLAYBACK_STREAM_SUSPENDED ) ;
pa_tagstruct_putu32 ( t , ( uint32_t ) - 1 ) ; /* tag */
pa_tagstruct_putu32 ( t , s - > index ) ;
pa_tagstruct_put_boolean ( t , suspend ) ;
pa_pstream_send_tagstruct ( s - > connection - > pstream , t ) ;
}
/* Called from main context */
2009-04-01 03:04:39 +02:00
static void sink_input_moving_cb ( pa_sink_input * i , pa_sink * dest ) {
2007-11-21 01:30:40 +00:00
playback_stream * s ;
pa_tagstruct * t ;
pa_sink_input_assert_ref ( i ) ;
s = PLAYBACK_STREAM ( i - > userdata ) ;
playback_stream_assert_ref ( s ) ;
2009-08-15 00:05:17 +02:00
if ( ! dest )
return ;
2009-03-30 18:46:12 +02:00
fix_playback_buffer_attr ( s ) ;
pa_memblockq_apply_attr ( s - > memblockq , & s - > buffer_attr ) ;
pa_memblockq_get_attr ( s - > memblockq , & s - > buffer_attr ) ;
2008-05-15 23:34:41 +00:00
2008-01-04 14:59:09 +00:00
if ( s - > connection - > version < 12 )
return ;
2007-11-21 01:30:40 +00:00
t = pa_tagstruct_new ( NULL , 0 ) ;
pa_tagstruct_putu32 ( t , PA_COMMAND_PLAYBACK_STREAM_MOVED ) ;
pa_tagstruct_putu32 ( t , ( uint32_t ) - 1 ) ; /* tag */
pa_tagstruct_putu32 ( t , s - > index ) ;
2009-04-01 03:04:39 +02:00
pa_tagstruct_putu32 ( t , dest - > index ) ;
pa_tagstruct_puts ( t , dest - > name ) ;
pa_tagstruct_put_boolean ( t , pa_sink_get_state ( dest ) = = PA_SINK_SUSPENDED ) ;
2008-05-15 23:34:41 +00:00
if ( s - > connection - > version > = 13 ) {
2009-03-30 18:46:12 +02:00
pa_tagstruct_putu32 ( t , s - > buffer_attr . maxlength ) ;
pa_tagstruct_putu32 ( t , s - > buffer_attr . tlength ) ;
pa_tagstruct_putu32 ( t , s - > buffer_attr . prebuf ) ;
pa_tagstruct_putu32 ( t , s - > buffer_attr . minreq ) ;
2009-04-05 02:59:02 +02:00
pa_tagstruct_put_usec ( t , s - > configured_sink_latency ) ;
2008-05-15 23:34:41 +00:00
}
2007-11-21 01:30:40 +00:00
pa_pstream_send_tagstruct ( s - > connection - > pstream , t ) ;
}
2004-07-10 16:50:22 +00:00
/*** source_output callbacks ***/
2009-04-05 02:59:02 +02:00
/* Called from thread context */
static int source_output_process_msg ( pa_msgobject * _o , int code , void * userdata , int64_t offset , pa_memchunk * chunk ) {
pa_source_output * o = PA_SOURCE_OUTPUT ( _o ) ;
record_stream * s ;
pa_source_output_assert_ref ( o ) ;
s = RECORD_STREAM ( o - > userdata ) ;
record_stream_assert_ref ( s ) ;
switch ( code ) {
case SOURCE_OUTPUT_MESSAGE_UPDATE_LATENCY :
/* Atomically get a snapshot of all timing parameters... */
s - > current_monitor_latency = o - > source - > monitor_of ? pa_sink_get_latency_within_thread ( o - > source - > monitor_of ) : 0 ;
s - > current_source_latency = pa_source_get_latency_within_thread ( o - > source ) ;
s - > on_the_fly_snapshot = pa_atomic_load ( & s - > on_the_fly ) ;
return 0 ;
}
return pa_source_output_process_msg ( _o , code , userdata , offset , chunk ) ;
}
2007-10-28 19:13:50 +00:00
/* Called from thread context */
2006-01-11 01:17:39 +00:00
static void source_output_push_cb ( pa_source_output * o , const pa_memchunk * chunk ) {
2007-10-28 19:13:50 +00:00
record_stream * s ;
2007-01-04 13:43:45 +00:00
2007-10-28 19:13:50 +00:00
pa_source_output_assert_ref ( o ) ;
s = RECORD_STREAM ( o - > userdata ) ;
record_stream_assert_ref ( s ) ;
pa_assert ( chunk ) ;
2007-01-04 13:43:45 +00:00
2009-04-05 02:59:02 +02:00
pa_atomic_add ( & s - > on_the_fly , chunk - > length ) ;
2007-10-28 19:13:50 +00:00
pa_asyncmsgq_post ( pa_thread_mq_get ( ) - > outq , PA_MSGOBJECT ( s ) , RECORD_STREAM_MESSAGE_POST_DATA , NULL , 0 , chunk , NULL ) ;
2004-07-10 16:50:22 +00:00
}
2006-01-11 01:17:39 +00:00
static void source_output_kill_cb ( pa_source_output * o ) {
2007-10-28 19:13:50 +00:00
record_stream * s ;
pa_source_output_assert_ref ( o ) ;
s = RECORD_STREAM ( o - > userdata ) ;
record_stream_assert_ref ( s ) ;
2008-08-04 18:58:29 +02:00
record_stream_send_killed ( s ) ;
2007-10-28 19:13:50 +00:00
record_stream_unlink ( s ) ;
2004-07-10 16:50:22 +00:00
}
2006-01-11 01:17:39 +00:00
static pa_usec_t source_output_get_latency_cb ( pa_source_output * o ) {
2007-10-28 19:13:50 +00:00
record_stream * s ;
pa_source_output_assert_ref ( o ) ;
s = RECORD_STREAM ( o - > userdata ) ;
record_stream_assert_ref ( s ) ;
2004-09-16 00:05:56 +00:00
2006-08-18 21:38:40 +00:00
/*pa_log("get_latency: %u", pa_memblockq_get_length(s->memblockq));*/
2007-01-04 13:43:45 +00:00
2004-09-16 00:05:56 +00:00
return pa_bytes_to_usec ( pa_memblockq_get_length ( s - > memblockq ) , & o - > sample_spec ) ;
}
2009-02-12 03:18:05 +01:00
/* Called from main context */
static void source_output_send_event_cb ( pa_source_output * o , const char * event , pa_proplist * pl ) {
record_stream * s ;
pa_tagstruct * t ;
pa_source_output_assert_ref ( o ) ;
s = RECORD_STREAM ( o - > userdata ) ;
record_stream_assert_ref ( s ) ;
if ( s - > connection - > version < 15 )
return ;
t = pa_tagstruct_new ( NULL , 0 ) ;
pa_tagstruct_putu32 ( t , PA_COMMAND_RECORD_STREAM_EVENT ) ;
pa_tagstruct_putu32 ( t , ( uint32_t ) - 1 ) ; /* tag */
pa_tagstruct_putu32 ( t , s - > index ) ;
pa_tagstruct_puts ( t , event ) ;
pa_tagstruct_put_proplist ( t , pl ) ;
pa_pstream_send_tagstruct ( s - > connection - > pstream , t ) ;
}
2007-11-21 01:30:40 +00:00
/* Called from main context */
static void source_output_suspend_cb ( pa_source_output * o , pa_bool_t suspend ) {
record_stream * s ;
pa_tagstruct * t ;
pa_source_output_assert_ref ( o ) ;
s = RECORD_STREAM ( o - > userdata ) ;
record_stream_assert_ref ( s ) ;
2008-01-04 14:59:09 +00:00
if ( s - > connection - > version < 12 )
return ;
2007-11-21 01:30:40 +00:00
t = pa_tagstruct_new ( NULL , 0 ) ;
pa_tagstruct_putu32 ( t , PA_COMMAND_RECORD_STREAM_SUSPENDED ) ;
pa_tagstruct_putu32 ( t , ( uint32_t ) - 1 ) ; /* tag */
pa_tagstruct_putu32 ( t , s - > index ) ;
pa_tagstruct_put_boolean ( t , suspend ) ;
pa_pstream_send_tagstruct ( s - > connection - > pstream , t ) ;
}
/* Called from main context */
2009-04-01 03:04:39 +02:00
static void source_output_moving_cb ( pa_source_output * o , pa_source * dest ) {
2007-11-21 01:30:40 +00:00
record_stream * s ;
pa_tagstruct * t ;
pa_source_output_assert_ref ( o ) ;
s = RECORD_STREAM ( o - > userdata ) ;
record_stream_assert_ref ( s ) ;
2009-08-15 00:05:17 +02:00
if ( ! dest )
return ;
2009-03-30 18:46:12 +02:00
fix_record_buffer_attr_pre ( s ) ;
pa_memblockq_set_maxlength ( s - > memblockq , s - > buffer_attr . maxlength ) ;
pa_memblockq_get_attr ( s - > memblockq , & s - > buffer_attr ) ;
fix_record_buffer_attr_post ( s ) ;
2008-05-15 23:34:41 +00:00
2008-01-04 14:59:09 +00:00
if ( s - > connection - > version < 12 )
return ;
2007-11-21 01:30:40 +00:00
t = pa_tagstruct_new ( NULL , 0 ) ;
pa_tagstruct_putu32 ( t , PA_COMMAND_RECORD_STREAM_MOVED ) ;
pa_tagstruct_putu32 ( t , ( uint32_t ) - 1 ) ; /* tag */
pa_tagstruct_putu32 ( t , s - > index ) ;
2009-04-01 03:04:39 +02:00
pa_tagstruct_putu32 ( t , dest - > index ) ;
pa_tagstruct_puts ( t , dest - > name ) ;
pa_tagstruct_put_boolean ( t , pa_source_get_state ( dest ) = = PA_SOURCE_SUSPENDED ) ;
2008-05-15 23:34:41 +00:00
if ( s - > connection - > version > = 13 ) {
2009-03-30 18:46:12 +02:00
pa_tagstruct_putu32 ( t , s - > buffer_attr . maxlength ) ;
pa_tagstruct_putu32 ( t , s - > buffer_attr . fragsize ) ;
2009-04-05 02:59:02 +02:00
pa_tagstruct_put_usec ( t , s - > configured_source_latency ) ;
2008-05-15 23:34:41 +00:00
}
2007-11-21 01:30:40 +00:00
pa_pstream_send_tagstruct ( s - > connection - > pstream , t ) ;
}
2004-06-23 23:17:30 +00:00
/*** pdispatch callbacks ***/
2008-08-04 18:58:29 +02:00
static void protocol_error ( pa_native_connection * c ) {
2006-08-18 21:38:40 +00:00
pa_log ( " protocol error, kicking client " ) ;
2008-08-04 18:58:29 +02:00
native_connection_unlink ( c ) ;
2004-07-07 00:22:46 +00:00
}
2006-02-22 18:54:21 +00:00
# define CHECK_VALIDITY(pstream, expression, tag, error) do { \
if ( ! ( expression ) ) { \
pa_pstream_send_error ( ( pstream ) , ( tag ) , ( error ) ) ; \
return ; \
} \
} while ( 0 ) ;
static pa_tagstruct * reply_new ( uint32_t tag ) {
pa_tagstruct * reply ;
2007-01-04 13:43:45 +00:00
2006-02-22 18:54:21 +00:00
reply = pa_tagstruct_new ( NULL , 0 ) ;
pa_tagstruct_putu32 ( reply , PA_COMMAND_REPLY ) ;
pa_tagstruct_putu32 ( reply , tag ) ;
return reply ;
}
2008-08-09 16:20:29 +02:00
static void command_create_playback_stream ( pa_pdispatch * pd , uint32_t command , uint32_t tag , pa_tagstruct * t , void * userdata ) {
2008-08-04 18:58:29 +02:00
pa_native_connection * c = PA_NATIVE_CONNECTION ( userdata ) ;
2007-10-28 19:13:50 +00:00
playback_stream * s ;
2009-03-30 18:46:12 +02:00
uint32_t sink_index , syncid , missing ;
pa_buffer_attr attr ;
2008-05-15 23:34:41 +00:00
const char * name = NULL , * sink_name ;
2006-01-11 01:17:39 +00:00
pa_sample_spec ss ;
2006-01-27 16:25:31 +00:00
pa_channel_map map ;
2006-01-11 01:17:39 +00:00
pa_tagstruct * reply ;
2006-08-19 23:06:45 +00:00
pa_sink * sink = NULL ;
2006-01-27 16:25:31 +00:00
pa_cvolume volume ;
2008-05-15 23:34:41 +00:00
pa_bool_t
corked = FALSE ,
no_remap = FALSE ,
no_remix = FALSE ,
fix_format = FALSE ,
fix_rate = FALSE ,
fix_channels = FALSE ,
no_move = FALSE ,
variable_rate = FALSE ,
muted = FALSE ,
2008-09-03 18:31:46 +02:00
adjust_latency = FALSE ,
2008-10-26 19:32:04 +01:00
early_requests = FALSE ,
dont_inhibit_auto_suspend = FALSE ,
2009-02-03 02:23:46 +01:00
muted_set = FALSE ,
fail_on_suspend = FALSE ;
2007-11-21 01:30:40 +00:00
pa_sink_input_flags_t flags = 0 ;
2008-05-15 23:34:41 +00:00
pa_proplist * p ;
2008-08-18 17:49:18 +02:00
pa_bool_t volume_set = TRUE ;
2009-02-03 03:14:20 +01:00
int ret = PA_ERR_INVALID ;
2007-01-04 13:43:45 +00:00
2008-08-04 18:58:29 +02:00
pa_native_connection_assert_ref ( c ) ;
2007-10-28 19:13:50 +00:00
pa_assert ( t ) ;
2009-03-30 18:46:12 +02:00
memset ( & attr , 0 , sizeof ( attr ) ) ;
2007-01-04 13:43:45 +00:00
2008-05-15 23:34:41 +00:00
if ( ( c - > version < 13 & & ( pa_tagstruct_gets ( t , & name ) < 0 | | ! name ) ) | |
pa_tagstruct_get (
t ,
PA_TAG_SAMPLE_SPEC , & ss ,
PA_TAG_CHANNEL_MAP , & map ,
PA_TAG_U32 , & sink_index ,
PA_TAG_STRING , & sink_name ,
2009-03-30 18:46:12 +02:00
PA_TAG_U32 , & attr . maxlength ,
2008-05-15 23:34:41 +00:00
PA_TAG_BOOLEAN , & corked ,
2009-03-30 18:46:12 +02:00
PA_TAG_U32 , & attr . tlength ,
PA_TAG_U32 , & attr . prebuf ,
PA_TAG_U32 , & attr . minreq ,
2008-05-15 23:34:41 +00:00
PA_TAG_U32 , & syncid ,
PA_TAG_CVOLUME , & volume ,
PA_TAG_INVALID ) < 0 ) {
2007-11-21 01:30:40 +00:00
protocol_error ( c ) ;
return ;
}
2008-05-15 23:34:41 +00:00
CHECK_VALIDITY ( c - > pstream , c - > authorized , tag , PA_ERR_ACCESS ) ;
2008-08-18 17:48:04 +02:00
CHECK_VALIDITY ( c - > pstream , ! sink_name | | pa_namereg_is_valid_name ( sink_name ) , tag , PA_ERR_INVALID ) ;
CHECK_VALIDITY ( c - > pstream , sink_index = = PA_INVALID_INDEX | | ! sink_name , tag , PA_ERR_INVALID ) ;
CHECK_VALIDITY ( c - > pstream , ! sink_name | | sink_index = = PA_INVALID_INDEX , tag , PA_ERR_INVALID ) ;
2008-05-15 23:34:41 +00:00
CHECK_VALIDITY ( c - > pstream , pa_channel_map_valid ( & map ) , tag , PA_ERR_INVALID ) ;
CHECK_VALIDITY ( c - > pstream , pa_sample_spec_valid ( & ss ) , tag , PA_ERR_INVALID ) ;
CHECK_VALIDITY ( c - > pstream , pa_cvolume_valid ( & volume ) , tag , PA_ERR_INVALID ) ;
CHECK_VALIDITY ( c - > pstream , map . channels = = ss . channels & & volume . channels = = ss . channels , tag , PA_ERR_INVALID ) ;
p = pa_proplist_new ( ) ;
if ( name )
pa_proplist_sets ( p , PA_PROP_MEDIA_NAME , name ) ;
2007-11-21 01:30:40 +00:00
if ( c - > version > = 12 ) {
/* Since 0.9.8 the user can ask for a couple of additional flags */
if ( pa_tagstruct_get_boolean ( t , & no_remap ) < 0 | |
pa_tagstruct_get_boolean ( t , & no_remix ) < 0 | |
pa_tagstruct_get_boolean ( t , & fix_format ) < 0 | |
pa_tagstruct_get_boolean ( t , & fix_rate ) < 0 | |
pa_tagstruct_get_boolean ( t , & fix_channels ) < 0 | |
pa_tagstruct_get_boolean ( t , & no_move ) < 0 | |
pa_tagstruct_get_boolean ( t , & variable_rate ) < 0 ) {
2008-05-15 23:34:41 +00:00
protocol_error ( c ) ;
pa_proplist_free ( p ) ;
return ;
}
}
if ( c - > version > = 13 ) {
if ( pa_tagstruct_get_boolean ( t , & muted ) < 0 | |
pa_tagstruct_get_boolean ( t , & adjust_latency ) < 0 | |
pa_tagstruct_get_proplist ( t , p ) < 0 ) {
2007-11-21 01:30:40 +00:00
protocol_error ( c ) ;
2008-05-15 23:34:41 +00:00
pa_proplist_free ( p ) ;
2007-11-21 01:30:40 +00:00
return ;
}
}
2008-08-18 17:49:18 +02:00
if ( c - > version > = 14 ) {
2008-09-03 18:31:46 +02:00
if ( pa_tagstruct_get_boolean ( t , & volume_set ) < 0 | |
pa_tagstruct_get_boolean ( t , & early_requests ) < 0 ) {
2008-08-18 17:49:18 +02:00
protocol_error ( c ) ;
pa_proplist_free ( p ) ;
return ;
}
}
2008-10-26 19:32:04 +01:00
if ( c - > version > = 15 ) {
if ( pa_tagstruct_get_boolean ( t , & muted_set ) < 0 | |
2009-02-03 02:23:46 +01:00
pa_tagstruct_get_boolean ( t , & dont_inhibit_auto_suspend ) < 0 | |
pa_tagstruct_get_boolean ( t , & fail_on_suspend ) < 0 ) {
2008-10-26 19:32:04 +01:00
protocol_error ( c ) ;
pa_proplist_free ( p ) ;
return ;
}
}
2007-11-21 01:30:40 +00:00
if ( ! pa_tagstruct_eof ( t ) ) {
2004-07-07 00:22:46 +00:00
protocol_error ( c ) ;
2008-05-15 23:34:41 +00:00
pa_proplist_free ( p ) ;
2004-07-07 00:22:46 +00:00
return ;
}
2004-06-20 01:12:13 +00:00
2006-08-19 23:06:45 +00:00
if ( sink_index ! = PA_INVALID_INDEX ) {
2008-05-15 23:34:41 +00:00
if ( ! ( sink = pa_idxset_get_by_index ( c - > protocol - > core - > sinks , sink_index ) ) ) {
pa_pstream_send_error ( c - > pstream , tag , PA_ERR_NOENTITY ) ;
pa_proplist_free ( p ) ;
return ;
}
2006-08-19 23:06:45 +00:00
} else if ( sink_name ) {
2008-05-15 23:34:41 +00:00
2009-01-15 20:07:13 +01:00
if ( ! ( sink = pa_namereg_get ( c - > protocol - > core , sink_name , PA_NAMEREG_SINK ) ) ) {
2008-05-15 23:34:41 +00:00
pa_pstream_send_error ( c - > pstream , tag , PA_ERR_NOENTITY ) ;
pa_proplist_free ( p ) ;
return ;
}
2006-08-19 23:06:45 +00:00
}
2006-02-22 18:54:21 +00:00
2007-11-21 01:30:40 +00:00
flags =
( corked ? PA_SINK_INPUT_START_CORKED : 0 ) |
( no_remap ? PA_SINK_INPUT_NO_REMAP : 0 ) |
( no_remix ? PA_SINK_INPUT_NO_REMIX : 0 ) |
( fix_format ? PA_SINK_INPUT_FIX_FORMAT : 0 ) |
( fix_rate ? PA_SINK_INPUT_FIX_RATE : 0 ) |
( fix_channels ? PA_SINK_INPUT_FIX_CHANNELS : 0 ) |
( no_move ? PA_SINK_INPUT_DONT_MOVE : 0 ) |
2008-10-26 19:32:04 +01:00
( variable_rate ? PA_SINK_INPUT_VARIABLE_RATE : 0 ) |
2009-02-03 02:23:46 +01:00
( dont_inhibit_auto_suspend ? PA_SINK_INPUT_DONT_INHIBIT_AUTO_SUSPEND : 0 ) |
2009-08-15 00:12:53 +02:00
( fail_on_suspend ? PA_SINK_INPUT_NO_CREATE_ON_SUSPEND | PA_SINK_INPUT_KILL_ON_SUSPEND : 0 ) ;
2008-10-26 19:32:04 +01:00
/* Only since protocol version 15 there's a seperate muted_set
* flag . For older versions we synthesize it here */
muted_set = muted_set | | muted ;
2007-11-21 01:30:40 +00:00
2009-03-30 18:46:12 +02:00
s = playback_stream_new ( c , sink , & ss , & map , & attr , volume_set ? & volume : NULL , muted , muted_set , syncid , & missing , flags , p , adjust_latency , early_requests , & ret ) ;
2008-05-15 23:34:41 +00:00
pa_proplist_free ( p ) ;
2009-02-03 03:14:20 +01:00
CHECK_VALIDITY ( c - > pstream , s , tag , ret ) ;
2004-09-26 17:02:26 +00:00
2006-02-22 18:54:21 +00:00
reply = reply_new ( tag ) ;
2004-07-03 23:35:12 +00:00
pa_tagstruct_putu32 ( reply , s - > index ) ;
2007-10-28 19:13:50 +00:00
pa_assert ( s - > sink_input ) ;
2004-07-03 23:35:12 +00:00
pa_tagstruct_putu32 ( reply , s - > sink_input - > index ) ;
2007-10-28 19:13:50 +00:00
pa_tagstruct_putu32 ( reply , missing ) ;
/* pa_log("initial request is %u", missing); */
2006-05-25 23:20:28 +00:00
if ( c - > version > = 9 ) {
2007-11-21 01:30:40 +00:00
/* Since 0.9.0 we support sending the buffer metrics back to the client */
2006-05-25 23:20:28 +00:00
2009-03-30 18:46:12 +02:00
pa_tagstruct_putu32 ( reply , ( uint32_t ) s - > buffer_attr . maxlength ) ;
pa_tagstruct_putu32 ( reply , ( uint32_t ) s - > buffer_attr . tlength ) ;
pa_tagstruct_putu32 ( reply , ( uint32_t ) s - > buffer_attr . prebuf ) ;
pa_tagstruct_putu32 ( reply , ( uint32_t ) s - > buffer_attr . minreq ) ;
2006-05-25 23:20:28 +00:00
}
2007-01-04 13:43:45 +00:00
2007-11-21 01:30:40 +00:00
if ( c - > version > = 12 ) {
/* Since 0.9.8 we support sending the chosen sample
* spec / channel map / device / suspend status back to the
* client */
pa_tagstruct_put_sample_spec ( reply , & ss ) ;
pa_tagstruct_put_channel_map ( reply , & map ) ;
pa_tagstruct_putu32 ( reply , s - > sink_input - > sink - > index ) ;
pa_tagstruct_puts ( reply , s - > sink_input - > sink - > name ) ;
pa_tagstruct_put_boolean ( reply , pa_sink_get_state ( s - > sink_input - > sink ) = = PA_SINK_SUSPENDED ) ;
}
2008-05-15 23:34:41 +00:00
if ( c - > version > = 13 )
2009-04-05 02:59:02 +02:00
pa_tagstruct_put_usec ( reply , s - > configured_sink_latency ) ;
2008-05-15 23:34:41 +00:00
2004-07-03 23:35:12 +00:00
pa_pstream_send_tagstruct ( c - > pstream , reply ) ;
2004-06-20 01:12:13 +00:00
}
2008-08-09 16:20:29 +02:00
static void command_delete_stream ( pa_pdispatch * pd , uint32_t command , uint32_t tag , pa_tagstruct * t , void * userdata ) {
2008-08-04 18:58:29 +02:00
pa_native_connection * c = PA_NATIVE_CONNECTION ( userdata ) ;
2004-06-20 01:12:13 +00:00
uint32_t channel ;
2007-10-28 19:13:50 +00:00
2008-08-04 18:58:29 +02:00
pa_native_connection_assert_ref ( c ) ;
2007-10-28 19:13:50 +00:00
pa_assert ( t ) ;
2007-01-04 13:43:45 +00:00
2004-07-03 23:35:12 +00:00
if ( pa_tagstruct_getu32 ( t , & channel ) < 0 | |
2004-07-07 00:22:46 +00:00
! pa_tagstruct_eof ( t ) ) {
protocol_error ( c ) ;
return ;
}
2004-06-20 01:12:13 +00:00
2006-02-22 18:54:21 +00:00
CHECK_VALIDITY ( c - > pstream , c - > authorized , tag , PA_ERR_ACCESS ) ;
2004-06-20 01:12:13 +00:00
2007-10-28 19:13:50 +00:00
switch ( command ) {
case PA_COMMAND_DELETE_PLAYBACK_STREAM : {
playback_stream * s ;
if ( ! ( s = pa_idxset_get_by_index ( c - > output_streams , channel ) ) | | ! playback_stream_isinstance ( s ) ) {
pa_pstream_send_error ( c - > pstream , tag , PA_ERR_EXIST ) ;
return ;
}
playback_stream_unlink ( s ) ;
break ;
2004-08-03 19:26:56 +00:00
}
2007-10-28 19:13:50 +00:00
case PA_COMMAND_DELETE_RECORD_STREAM : {
record_stream * s ;
if ( ! ( s = pa_idxset_get_by_index ( c - > record_streams , channel ) ) ) {
pa_pstream_send_error ( c - > pstream , tag , PA_ERR_EXIST ) ;
return ;
}
record_stream_unlink ( s ) ;
break ;
2004-08-03 19:26:56 +00:00
}
2007-10-28 19:13:50 +00:00
case PA_COMMAND_DELETE_UPLOAD_STREAM : {
upload_stream * s ;
if ( ! ( s = pa_idxset_get_by_index ( c - > output_streams , channel ) ) | | ! upload_stream_isinstance ( s ) ) {
pa_pstream_send_error ( c - > pstream , tag , PA_ERR_EXIST ) ;
return ;
}
upload_stream_unlink ( s ) ;
break ;
2004-08-03 19:26:56 +00:00
}
2007-10-28 19:13:50 +00:00
default :
pa_assert_not_reached ( ) ;
2004-08-03 19:26:56 +00:00
}
2007-01-04 13:43:45 +00:00
2004-07-10 16:50:22 +00:00
pa_pstream_send_simple_ack ( c - > pstream , tag ) ;
}
2008-08-09 16:20:29 +02:00
static void command_create_record_stream ( pa_pdispatch * pd , uint32_t command , uint32_t tag , pa_tagstruct * t , void * userdata ) {
2008-08-04 18:58:29 +02:00
pa_native_connection * c = PA_NATIVE_CONNECTION ( userdata ) ;
2007-10-28 19:13:50 +00:00
record_stream * s ;
2009-03-30 18:46:12 +02:00
pa_buffer_attr attr ;
2004-07-10 16:50:22 +00:00
uint32_t source_index ;
2008-06-13 21:56:19 +00:00
const char * name = NULL , * source_name ;
2006-01-11 01:17:39 +00:00
pa_sample_spec ss ;
2006-01-27 16:25:31 +00:00
pa_channel_map map ;
2006-01-11 01:17:39 +00:00
pa_tagstruct * reply ;
2006-08-19 23:06:45 +00:00
pa_source * source = NULL ;
2008-05-15 23:34:41 +00:00
pa_bool_t
corked = FALSE ,
no_remap = FALSE ,
no_remix = FALSE ,
fix_format = FALSE ,
fix_rate = FALSE ,
fix_channels = FALSE ,
no_move = FALSE ,
variable_rate = FALSE ,
adjust_latency = FALSE ,
2008-09-03 18:31:46 +02:00
peak_detect = FALSE ,
2008-10-26 19:32:04 +01:00
early_requests = FALSE ,
2009-02-03 02:23:46 +01:00
dont_inhibit_auto_suspend = FALSE ,
fail_on_suspend = FALSE ;
2007-11-21 01:30:40 +00:00
pa_source_output_flags_t flags = 0 ;
2008-05-15 23:34:41 +00:00
pa_proplist * p ;
2008-06-13 21:56:19 +00:00
uint32_t direct_on_input_idx = PA_INVALID_INDEX ;
pa_sink_input * direct_on_input = NULL ;
2009-02-03 03:14:20 +01:00
int ret = PA_ERR_INVALID ;
2007-10-28 19:13:50 +00:00
2008-08-04 18:58:29 +02:00
pa_native_connection_assert_ref ( c ) ;
2007-10-28 19:13:50 +00:00
pa_assert ( t ) ;
2007-01-04 13:43:45 +00:00
2009-03-30 18:46:12 +02:00
memset ( & attr , 0 , sizeof ( attr ) ) ;
2008-05-15 23:34:41 +00:00
if ( ( c - > version < 13 & & ( pa_tagstruct_gets ( t , & name ) < 0 | | ! name ) ) | |
2004-07-10 16:50:22 +00:00
pa_tagstruct_get_sample_spec ( t , & ss ) < 0 | |
2006-01-27 16:25:31 +00:00
pa_tagstruct_get_channel_map ( t , & map ) < 0 | |
2004-07-10 16:50:22 +00:00
pa_tagstruct_getu32 ( t , & source_index ) < 0 | |
2004-08-03 19:26:56 +00:00
pa_tagstruct_gets ( t , & source_name ) < 0 | |
2009-03-30 18:46:12 +02:00
pa_tagstruct_getu32 ( t , & attr . maxlength ) < 0 | |
2004-09-29 17:38:45 +00:00
pa_tagstruct_get_boolean ( t , & corked ) < 0 | |
2009-03-30 18:46:12 +02:00
pa_tagstruct_getu32 ( t , & attr . fragsize ) < 0 ) {
2004-07-10 16:50:22 +00:00
protocol_error ( c ) ;
return ;
}
2008-05-15 23:34:41 +00:00
CHECK_VALIDITY ( c - > pstream , c - > authorized , tag , PA_ERR_ACCESS ) ;
2008-08-18 17:48:04 +02:00
CHECK_VALIDITY ( c - > pstream , ! source_name | | pa_namereg_is_valid_name ( source_name ) , tag , PA_ERR_INVALID ) ;
CHECK_VALIDITY ( c - > pstream , source_index = = PA_INVALID_INDEX | | ! source_name , tag , PA_ERR_INVALID ) ;
CHECK_VALIDITY ( c - > pstream , ! source_name | | source_index = = PA_INVALID_INDEX , tag , PA_ERR_INVALID ) ;
2008-05-15 23:34:41 +00:00
CHECK_VALIDITY ( c - > pstream , pa_sample_spec_valid ( & ss ) , tag , PA_ERR_INVALID ) ;
CHECK_VALIDITY ( c - > pstream , pa_channel_map_valid ( & map ) , tag , PA_ERR_INVALID ) ;
CHECK_VALIDITY ( c - > pstream , map . channels = = ss . channels , tag , PA_ERR_INVALID ) ;
p = pa_proplist_new ( ) ;
if ( name )
pa_proplist_sets ( p , PA_PROP_MEDIA_NAME , name ) ;
2007-11-21 01:30:40 +00:00
if ( c - > version > = 12 ) {
/* Since 0.9.8 the user can ask for a couple of additional flags */
if ( pa_tagstruct_get_boolean ( t , & no_remap ) < 0 | |
pa_tagstruct_get_boolean ( t , & no_remix ) < 0 | |
pa_tagstruct_get_boolean ( t , & fix_format ) < 0 | |
pa_tagstruct_get_boolean ( t , & fix_rate ) < 0 | |
pa_tagstruct_get_boolean ( t , & fix_channels ) < 0 | |
pa_tagstruct_get_boolean ( t , & no_move ) < 0 | |
pa_tagstruct_get_boolean ( t , & variable_rate ) < 0 ) {
2008-05-15 23:34:41 +00:00
2007-11-21 01:30:40 +00:00
protocol_error ( c ) ;
2008-05-15 23:34:41 +00:00
pa_proplist_free ( p ) ;
return ;
}
}
if ( c - > version > = 13 ) {
if ( pa_tagstruct_get_boolean ( t , & peak_detect ) < 0 | |
pa_tagstruct_get_boolean ( t , & adjust_latency ) < 0 | |
2008-06-13 21:56:19 +00:00
pa_tagstruct_get_proplist ( t , p ) < 0 | |
pa_tagstruct_getu32 ( t , & direct_on_input_idx ) < 0 ) {
2008-05-15 23:34:41 +00:00
protocol_error ( c ) ;
pa_proplist_free ( p ) ;
2007-11-21 01:30:40 +00:00
return ;
}
}
2008-09-03 18:31:46 +02:00
if ( c - > version > = 14 ) {
if ( pa_tagstruct_get_boolean ( t , & early_requests ) < 0 ) {
protocol_error ( c ) ;
pa_proplist_free ( p ) ;
return ;
}
}
2008-10-26 19:32:04 +01:00
if ( c - > version > = 15 ) {
2009-02-03 02:23:46 +01:00
if ( pa_tagstruct_get_boolean ( t , & dont_inhibit_auto_suspend ) < 0 | |
pa_tagstruct_get_boolean ( t , & fail_on_suspend ) < 0 ) {
2008-10-26 19:32:04 +01:00
protocol_error ( c ) ;
pa_proplist_free ( p ) ;
return ;
}
}
2007-11-21 01:30:40 +00:00
if ( ! pa_tagstruct_eof ( t ) ) {
protocol_error ( c ) ;
2008-05-15 23:34:41 +00:00
pa_proplist_free ( p ) ;
2007-11-21 01:30:40 +00:00
return ;
}
2008-05-15 23:34:41 +00:00
if ( source_index ! = PA_INVALID_INDEX ) {
if ( ! ( source = pa_idxset_get_by_index ( c - > protocol - > core - > sources , source_index ) ) ) {
pa_pstream_send_error ( c - > pstream , tag , PA_ERR_NOENTITY ) ;
pa_proplist_free ( p ) ;
return ;
}
} else if ( source_name ) {
2009-01-15 20:07:13 +01:00
if ( ! ( source = pa_namereg_get ( c - > protocol - > core , source_name , PA_NAMEREG_SOURCE ) ) ) {
2008-05-15 23:34:41 +00:00
pa_pstream_send_error ( c - > pstream , tag , PA_ERR_NOENTITY ) ;
pa_proplist_free ( p ) ;
return ;
}
}
2008-06-13 21:56:19 +00:00
if ( direct_on_input_idx ! = PA_INVALID_INDEX ) {
if ( ! ( direct_on_input = pa_idxset_get_by_index ( c - > protocol - > core - > sink_inputs , direct_on_input_idx ) ) ) {
pa_pstream_send_error ( c - > pstream , tag , PA_ERR_NOENTITY ) ;
pa_proplist_free ( p ) ;
return ;
}
}
2007-11-21 01:30:40 +00:00
flags =
( corked ? PA_SOURCE_OUTPUT_START_CORKED : 0 ) |
( no_remap ? PA_SOURCE_OUTPUT_NO_REMAP : 0 ) |
( no_remix ? PA_SOURCE_OUTPUT_NO_REMIX : 0 ) |
( fix_format ? PA_SOURCE_OUTPUT_FIX_FORMAT : 0 ) |
( fix_rate ? PA_SOURCE_OUTPUT_FIX_RATE : 0 ) |
( fix_channels ? PA_SOURCE_OUTPUT_FIX_CHANNELS : 0 ) |
( no_move ? PA_SOURCE_OUTPUT_DONT_MOVE : 0 ) |
2008-10-26 19:32:04 +01:00
( variable_rate ? PA_SOURCE_OUTPUT_VARIABLE_RATE : 0 ) |
2009-02-03 02:23:46 +01:00
( dont_inhibit_auto_suspend ? PA_SOURCE_OUTPUT_DONT_INHIBIT_AUTO_SUSPEND : 0 ) |
2009-08-15 00:12:53 +02:00
( fail_on_suspend ? PA_SOURCE_OUTPUT_NO_CREATE_ON_SUSPEND | PA_SOURCE_OUTPUT_KILL_ON_SUSPEND : 0 ) ;
2007-11-21 01:30:40 +00:00
2009-03-30 18:46:12 +02:00
s = record_stream_new ( c , source , & ss , & map , peak_detect , & attr , flags , p , adjust_latency , direct_on_input , early_requests , & ret ) ;
2008-05-15 23:34:41 +00:00
pa_proplist_free ( p ) ;
2007-01-04 13:43:45 +00:00
2009-02-03 03:14:20 +01:00
CHECK_VALIDITY ( c - > pstream , s , tag , ret ) ;
2007-01-04 13:43:45 +00:00
2006-02-22 18:54:21 +00:00
reply = reply_new ( tag ) ;
2004-07-10 16:50:22 +00:00
pa_tagstruct_putu32 ( reply , s - > index ) ;
2007-10-28 19:13:50 +00:00
pa_assert ( s - > source_output ) ;
2004-07-10 16:50:22 +00:00
pa_tagstruct_putu32 ( reply , s - > source_output - > index ) ;
2006-05-25 23:20:28 +00:00
if ( c - > version > = 9 ) {
/* Since 0.9 we support sending the buffer metrics back to the client */
2009-03-30 18:46:12 +02:00
pa_tagstruct_putu32 ( reply , ( uint32_t ) s - > buffer_attr . maxlength ) ;
pa_tagstruct_putu32 ( reply , ( uint32_t ) s - > buffer_attr . fragsize ) ;
2006-05-25 23:20:28 +00:00
}
2007-01-04 13:43:45 +00:00
2007-11-21 01:30:40 +00:00
if ( c - > version > = 12 ) {
/* Since 0.9.8 we support sending the chosen sample
* spec / channel map / device / suspend status back to the
* client */
pa_tagstruct_put_sample_spec ( reply , & ss ) ;
pa_tagstruct_put_channel_map ( reply , & map ) ;
pa_tagstruct_putu32 ( reply , s - > source_output - > source - > index ) ;
pa_tagstruct_puts ( reply , s - > source_output - > source - > name ) ;
pa_tagstruct_put_boolean ( reply , pa_source_get_state ( s - > source_output - > source ) = = PA_SOURCE_SUSPENDED ) ;
}
2008-05-15 23:34:41 +00:00
if ( c - > version > = 13 )
2009-04-05 02:59:02 +02:00
pa_tagstruct_put_usec ( reply , s - > configured_source_latency ) ;
2008-05-15 23:34:41 +00:00
2004-07-10 16:50:22 +00:00
pa_pstream_send_tagstruct ( c - > pstream , reply ) ;
}
2008-08-09 16:20:29 +02:00
static void command_exit ( pa_pdispatch * pd , uint32_t command , uint32_t tag , pa_tagstruct * t , void * userdata ) {
2008-08-04 18:58:29 +02:00
pa_native_connection * c = PA_NATIVE_CONNECTION ( userdata ) ;
2008-08-06 19:39:12 +02:00
int ret ;
2007-10-28 19:13:50 +00:00
2008-08-04 18:58:29 +02:00
pa_native_connection_assert_ref ( c ) ;
2007-10-28 19:13:50 +00:00
pa_assert ( t ) ;
2007-01-04 13:43:45 +00:00
2004-07-07 00:22:46 +00:00
if ( ! pa_tagstruct_eof ( t ) ) {
protocol_error ( c ) ;
return ;
}
2004-06-20 01:12:13 +00:00
2006-02-22 18:54:21 +00:00
CHECK_VALIDITY ( c - > pstream , c - > authorized , tag , PA_ERR_ACCESS ) ;
2008-08-06 19:39:12 +02:00
ret = pa_core_exit ( c - > protocol - > core , FALSE , 0 ) ;
CHECK_VALIDITY ( c - > pstream , ret > = 0 , tag , PA_ERR_ACCESS ) ;
2007-01-04 13:43:45 +00:00
2004-07-03 23:35:12 +00:00
pa_pstream_send_simple_ack ( c - > pstream , tag ) ; /* nonsense */
2004-06-20 01:12:13 +00:00
}
2008-08-09 16:20:29 +02:00
static void command_auth ( pa_pdispatch * pd , uint32_t command , uint32_t tag , pa_tagstruct * t , void * userdata ) {
2008-08-04 18:58:29 +02:00
pa_native_connection * c = PA_NATIVE_CONNECTION ( userdata ) ;
2004-07-06 00:08:44 +00:00
const void * cookie ;
2006-03-02 21:56:15 +00:00
pa_tagstruct * reply ;
2008-09-03 18:31:46 +02:00
pa_bool_t shm_on_remote = FALSE , do_shm ;
2007-10-28 19:13:50 +00:00
2008-08-04 18:58:29 +02:00
pa_native_connection_assert_ref ( c ) ;
2007-10-28 19:13:50 +00:00
pa_assert ( t ) ;
2004-07-06 00:08:44 +00:00
2006-03-02 21:56:15 +00:00
if ( pa_tagstruct_getu32 ( t , & c - > version ) < 0 | |
pa_tagstruct_get_arbitrary ( t , & cookie , PA_NATIVE_COOKIE_LENGTH ) < 0 | |
2004-07-07 00:22:46 +00:00
! pa_tagstruct_eof ( t ) ) {
protocol_error ( c ) ;
return ;
}
2004-09-12 23:40:53 +00:00
2006-03-02 21:56:15 +00:00
/* Minimum supported version */
if ( c - > version < 8 ) {
pa_pstream_send_error ( c - > pstream , tag , PA_ERR_VERSION ) ;
return ;
}
2008-06-17 18:29:00 +00:00
/* Starting with protocol version 13 the MSB of the version tag
2008-08-04 18:58:29 +02:00
reflects if shm is available for this pa_native_connection or
2008-06-17 18:29:00 +00:00
not . */
if ( c - > version > = 13 ) {
shm_on_remote = ! ! ( c - > version & 0x80000000U ) ;
c - > version & = 0x7FFFFFFFU ;
}
pa_log_debug ( " Protocol version: remote %u, local %u " , c - > version , PA_PROTOCOL_VERSION ) ;
pa_proplist_setf ( c - > client - > proplist , " native-protocol.version " , " %u " , c - > version ) ;
2008-05-15 23:34:41 +00:00
2004-09-12 23:40:53 +00:00
if ( ! c - > authorized ) {
2008-05-15 23:34:41 +00:00
pa_bool_t success = FALSE ;
2007-01-04 13:43:45 +00:00
2006-07-19 21:48:35 +00:00
# ifdef HAVE_CREDS
const pa_creds * creds ;
2006-02-24 15:12:42 +00:00
2006-07-19 21:48:35 +00:00
if ( ( creds = pa_pdispatch_creds ( pd ) ) ) {
if ( creds - > uid = = getuid ( ) )
2008-05-15 23:34:41 +00:00
success = TRUE ;
2008-08-03 16:44:38 +02:00
else if ( c - > options - > auth_group ) {
2006-02-24 17:14:23 +00:00
int r ;
2006-07-19 21:48:35 +00:00
gid_t gid ;
2008-08-03 16:44:38 +02:00
if ( ( gid = pa_get_gid_of_group ( c - > options - > auth_group ) ) = = ( gid_t ) - 1 )
pa_log_warn ( " Failed to get GID of group '%s' " , c - > options - > auth_group ) ;
2006-07-19 21:48:35 +00:00
else if ( gid = = creds - > gid )
2008-05-15 23:34:41 +00:00
success = TRUE ;
2007-01-04 13:43:45 +00:00
2006-07-19 21:48:35 +00:00
if ( ! success ) {
2008-08-03 16:44:38 +02:00
if ( ( r = pa_uid_in_group ( creds - > uid , c - > options - > auth_group ) ) < 0 )
2008-05-15 23:34:41 +00:00
pa_log_warn ( " Failed to check group membership. " ) ;
2006-07-19 21:48:35 +00:00
else if ( r > 0 )
2008-05-15 23:34:41 +00:00
success = TRUE ;
2006-07-19 21:48:35 +00:00
}
2006-02-24 17:14:23 +00:00
}
2007-01-04 13:43:45 +00:00
2006-08-18 21:38:40 +00:00
pa_log_info ( " Got credentials: uid=%lu gid=%lu success=%i " ,
2006-07-19 21:48:35 +00:00
( unsigned long ) creds - > uid ,
( unsigned long ) creds - > gid ,
2008-06-17 18:29:00 +00:00
( int ) success ) ;
2006-02-24 15:12:42 +00:00
}
# endif
2008-08-03 16:44:38 +02:00
if ( ! success & & c - > options - > auth_cookie ) {
const uint8_t * ac ;
if ( ( ac = pa_auth_cookie_read ( c - > options - > auth_cookie , PA_NATIVE_COOKIE_LENGTH ) ) )
if ( memcmp ( ac , cookie , PA_NATIVE_COOKIE_LENGTH ) = = 0 )
success = TRUE ;
}
2006-02-24 15:12:42 +00:00
if ( ! success ) {
2006-08-18 21:38:40 +00:00
pa_log_warn ( " Denied access to client with invalid authorization data. " ) ;
2006-02-20 04:05:16 +00:00
pa_pstream_send_error ( c - > pstream , tag , PA_ERR_ACCESS ) ;
2004-09-12 23:40:53 +00:00
return ;
}
2007-01-04 13:43:45 +00:00
2008-05-15 23:34:41 +00:00
c - > authorized = TRUE ;
2004-11-18 00:28:26 +00:00
if ( c - > auth_timeout_event ) {
c - > protocol - > core - > mainloop - > time_free ( c - > auth_timeout_event ) ;
c - > auth_timeout_event = NULL ;
}
2004-07-06 00:08:44 +00:00
}
2006-03-02 21:56:15 +00:00
2008-06-17 18:29:00 +00:00
/* Enable shared memory support if possible */
do_shm =
pa_mempool_is_shared ( c - > protocol - > core - > mempool ) & &
c - > is_local ;
pa_log_debug ( " SHM possible: %s " , pa_yes_no ( do_shm ) ) ;
if ( do_shm )
if ( c - > version < 10 | | ( c - > version > = 13 & & ! shm_on_remote ) )
do_shm = FALSE ;
2008-10-01 01:31:56 +02:00
# ifdef HAVE_CREDS
2008-06-17 18:29:00 +00:00
if ( do_shm ) {
/* Only enable SHM if both sides are owned by the same
* user . This is a security measure because otherwise data
* private to the user might leak . */
const pa_creds * creds ;
if ( ! ( creds = pa_pdispatch_creds ( pd ) ) | | getuid ( ) ! = creds - > uid )
do_shm = FALSE ;
}
2008-10-01 01:31:56 +02:00
# endif
2008-06-17 18:29:00 +00:00
pa_log_debug ( " Negotiated SHM: %s " , pa_yes_no ( do_shm ) ) ;
pa_pstream_enable_shm ( c - > pstream , do_shm ) ;
2006-03-02 21:56:15 +00:00
reply = reply_new ( tag ) ;
2008-06-17 18:29:00 +00:00
pa_tagstruct_putu32 ( reply , PA_PROTOCOL_VERSION | ( do_shm ? 0x80000000 : 0 ) ) ;
2006-08-18 23:44:35 +00:00
# ifdef HAVE_CREDS
{
/* SHM support is only enabled after both sides made sure they are the same user. */
2007-01-04 13:43:45 +00:00
2006-08-18 23:44:35 +00:00
pa_creds ucred ;
ucred . uid = getuid ( ) ;
ucred . gid = getgid ( ) ;
2007-01-04 13:43:45 +00:00
2006-08-18 23:44:35 +00:00
pa_pstream_send_tagstruct_with_creds ( c - > pstream , reply , & ucred ) ;
}
# else
2006-03-02 21:56:15 +00:00
pa_pstream_send_tagstruct ( c - > pstream , reply ) ;
2006-08-18 23:44:35 +00:00
# endif
2004-07-06 00:08:44 +00:00
}
2008-08-09 16:20:29 +02:00
static void command_set_client_name ( pa_pdispatch * pd , uint32_t command , uint32_t tag , pa_tagstruct * t , void * userdata ) {
2008-08-04 18:58:29 +02:00
pa_native_connection * c = PA_NATIVE_CONNECTION ( userdata ) ;
2008-05-15 23:34:41 +00:00
const char * name = NULL ;
pa_proplist * p ;
pa_tagstruct * reply ;
2007-10-28 19:13:50 +00:00
2008-08-04 18:58:29 +02:00
pa_native_connection_assert_ref ( c ) ;
2007-10-28 19:13:50 +00:00
pa_assert ( t ) ;
2004-07-06 00:08:44 +00:00
2008-05-15 23:34:41 +00:00
p = pa_proplist_new ( ) ;
if ( ( c - > version < 13 & & pa_tagstruct_gets ( t , & name ) < 0 ) | |
( c - > version > = 13 & & pa_tagstruct_get_proplist ( t , p ) < 0 ) | |
2004-07-07 00:22:46 +00:00
! pa_tagstruct_eof ( t ) ) {
2008-05-15 23:34:41 +00:00
2004-07-07 00:22:46 +00:00
protocol_error ( c ) ;
2008-05-15 23:34:41 +00:00
pa_proplist_free ( p ) ;
2004-07-07 00:22:46 +00:00
return ;
}
2004-07-06 00:08:44 +00:00
2008-05-15 23:34:41 +00:00
if ( name )
if ( pa_proplist_sets ( p , PA_PROP_APPLICATION_NAME , name ) < 0 ) {
pa_pstream_send_error ( c - > pstream , tag , PA_ERR_INVALID ) ;
pa_proplist_free ( p ) ;
return ;
}
2007-01-04 13:43:45 +00:00
2009-02-05 04:10:08 +01:00
pa_client_update_proplist ( c - > client , PA_UPDATE_REPLACE , p ) ;
2008-05-15 23:34:41 +00:00
pa_proplist_free ( p ) ;
reply = reply_new ( tag ) ;
if ( c - > version > = 13 )
pa_tagstruct_putu32 ( reply , c - > client - > index ) ;
pa_pstream_send_tagstruct ( c - > pstream , reply ) ;
2004-07-07 00:22:46 +00:00
}
2008-08-09 16:20:29 +02:00
static void command_lookup ( pa_pdispatch * pd , uint32_t command , uint32_t tag , pa_tagstruct * t , void * userdata ) {
2008-08-04 18:58:29 +02:00
pa_native_connection * c = PA_NATIVE_CONNECTION ( userdata ) ;
2004-07-07 00:22:46 +00:00
const char * name ;
2006-01-11 01:17:39 +00:00
uint32_t idx = PA_IDXSET_INVALID ;
2007-10-28 19:13:50 +00:00
2008-08-04 18:58:29 +02:00
pa_native_connection_assert_ref ( c ) ;
2007-10-28 19:13:50 +00:00
pa_assert ( t ) ;
2004-07-07 00:22:46 +00:00
2006-02-22 18:54:21 +00:00
if ( pa_tagstruct_gets ( t , & name ) < 0 | |
2004-07-07 00:22:46 +00:00
! pa_tagstruct_eof ( t ) ) {
protocol_error ( c ) ;
return ;
}
2006-02-22 18:54:21 +00:00
CHECK_VALIDITY ( c - > pstream , c - > authorized , tag , PA_ERR_ACCESS ) ;
2008-08-18 17:48:04 +02:00
CHECK_VALIDITY ( c - > pstream , name & & pa_namereg_is_valid_name ( name ) , tag , PA_ERR_INVALID ) ;
2004-07-07 22:02:15 +00:00
2004-07-07 00:22:46 +00:00
if ( command = = PA_COMMAND_LOOKUP_SINK ) {
2006-01-11 01:17:39 +00:00
pa_sink * sink ;
2009-01-15 20:07:13 +01:00
if ( ( sink = pa_namereg_get ( c - > protocol - > core , name , PA_NAMEREG_SINK ) ) )
2006-01-11 01:17:39 +00:00
idx = sink - > index ;
2004-07-07 00:22:46 +00:00
} else {
2006-01-11 01:17:39 +00:00
pa_source * source ;
2007-10-28 19:13:50 +00:00
pa_assert ( command = = PA_COMMAND_LOOKUP_SOURCE ) ;
2009-01-15 20:07:13 +01:00
if ( ( source = pa_namereg_get ( c - > protocol - > core , name , PA_NAMEREG_SOURCE ) ) )
2006-01-11 01:17:39 +00:00
idx = source - > index ;
2004-07-07 00:22:46 +00:00
}
2006-01-11 01:17:39 +00:00
if ( idx = = PA_IDXSET_INVALID )
2006-02-20 04:05:16 +00:00
pa_pstream_send_error ( c - > pstream , tag , PA_ERR_NOENTITY ) ;
2004-07-07 00:22:46 +00:00
else {
2006-01-11 01:17:39 +00:00
pa_tagstruct * reply ;
2006-02-22 18:54:21 +00:00
reply = reply_new ( tag ) ;
2006-01-11 01:17:39 +00:00
pa_tagstruct_putu32 ( reply , idx ) ;
2004-07-07 00:22:46 +00:00
pa_pstream_send_tagstruct ( c - > pstream , reply ) ;
}
2004-07-06 00:08:44 +00:00
}
2008-08-09 16:20:29 +02:00
static void command_drain_playback_stream ( pa_pdispatch * pd , uint32_t command , uint32_t tag , pa_tagstruct * t , void * userdata ) {
2008-08-04 18:58:29 +02:00
pa_native_connection * c = PA_NATIVE_CONNECTION ( userdata ) ;
2006-01-11 01:17:39 +00:00
uint32_t idx ;
2007-10-28 19:13:50 +00:00
playback_stream * s ;
2008-08-04 18:58:29 +02:00
pa_native_connection_assert_ref ( c ) ;
2007-10-28 19:13:50 +00:00
pa_assert ( t ) ;
2004-07-07 22:02:15 +00:00
2006-01-11 01:17:39 +00:00
if ( pa_tagstruct_getu32 ( t , & idx ) < 0 | |
2004-07-07 22:02:15 +00:00
! pa_tagstruct_eof ( t ) ) {
protocol_error ( c ) ;
return ;
}
2006-02-22 18:54:21 +00:00
CHECK_VALIDITY ( c - > pstream , c - > authorized , tag , PA_ERR_ACCESS ) ;
s = pa_idxset_get_by_index ( c - > output_streams , idx ) ;
CHECK_VALIDITY ( c - > pstream , s , tag , PA_ERR_NOENTITY ) ;
2007-10-28 19:13:50 +00:00
CHECK_VALIDITY ( c - > pstream , playback_stream_isinstance ( s ) , tag , PA_ERR_NOENTITY ) ;
2007-01-04 13:43:45 +00:00
2007-10-28 19:13:50 +00:00
pa_asyncmsgq_post ( s - > sink_input - > sink - > asyncmsgq , PA_MSGOBJECT ( s - > sink_input ) , SINK_INPUT_MESSAGE_DRAIN , PA_UINT_TO_PTR ( tag ) , 0 , NULL , NULL ) ;
2007-01-04 13:43:45 +00:00
}
2004-07-07 22:02:15 +00:00
2008-08-09 16:20:29 +02:00
static void command_stat ( pa_pdispatch * pd , uint32_t command , uint32_t tag , pa_tagstruct * t , void * userdata ) {
2008-08-04 18:58:29 +02:00
pa_native_connection * c = PA_NATIVE_CONNECTION ( userdata ) ;
2006-01-11 01:17:39 +00:00
pa_tagstruct * reply ;
2006-08-18 19:55:18 +00:00
const pa_mempool_stat * stat ;
2007-10-28 19:13:50 +00:00
2008-08-04 18:58:29 +02:00
pa_native_connection_assert_ref ( c ) ;
2007-10-28 19:13:50 +00:00
pa_assert ( t ) ;
2004-07-15 20:51:55 +00:00
if ( ! pa_tagstruct_eof ( t ) ) {
protocol_error ( c ) ;
return ;
}
2006-02-22 18:54:21 +00:00
CHECK_VALIDITY ( c - > pstream , c - > authorized , tag , PA_ERR_ACCESS ) ;
2004-07-15 20:51:55 +00:00
2006-08-18 19:55:18 +00:00
stat = pa_mempool_get_stat ( c - > protocol - > core - > mempool ) ;
2007-01-04 13:43:45 +00:00
2006-02-22 18:54:21 +00:00
reply = reply_new ( tag ) ;
2007-05-27 20:38:14 +00:00
pa_tagstruct_putu32 ( reply , ( uint32_t ) pa_atomic_load ( & stat - > n_allocated ) ) ;
pa_tagstruct_putu32 ( reply , ( uint32_t ) pa_atomic_load ( & stat - > allocated_size ) ) ;
pa_tagstruct_putu32 ( reply , ( uint32_t ) pa_atomic_load ( & stat - > n_accumulated ) ) ;
pa_tagstruct_putu32 ( reply , ( uint32_t ) pa_atomic_load ( & stat - > accumulated_size ) ) ;
2008-08-19 22:39:54 +02:00
pa_tagstruct_putu32 ( reply , ( uint32_t ) pa_scache_total_size ( c - > protocol - > core ) ) ;
2004-07-15 20:51:55 +00:00
pa_pstream_send_tagstruct ( c - > pstream , reply ) ;
}
2008-08-09 16:20:29 +02:00
static void command_get_playback_latency ( pa_pdispatch * pd , uint32_t command , uint32_t tag , pa_tagstruct * t , void * userdata ) {
2008-08-04 18:58:29 +02:00
pa_native_connection * c = PA_NATIVE_CONNECTION ( userdata ) ;
2006-01-11 01:17:39 +00:00
pa_tagstruct * reply ;
2007-10-28 19:13:50 +00:00
playback_stream * s ;
2004-09-10 22:35:12 +00:00
struct timeval tv , now ;
2006-01-11 01:17:39 +00:00
uint32_t idx ;
2007-10-28 19:13:50 +00:00
2008-08-04 18:58:29 +02:00
pa_native_connection_assert_ref ( c ) ;
2007-10-28 19:13:50 +00:00
pa_assert ( t ) ;
2007-01-04 13:43:45 +00:00
2006-01-11 01:17:39 +00:00
if ( pa_tagstruct_getu32 ( t , & idx ) < 0 | |
2004-09-10 22:35:12 +00:00
pa_tagstruct_get_timeval ( t , & tv ) < 0 | |
2004-07-15 21:18:18 +00:00
! pa_tagstruct_eof ( t ) ) {
protocol_error ( c ) ;
return ;
}
2006-02-22 18:54:21 +00:00
CHECK_VALIDITY ( c - > pstream , c - > authorized , tag , PA_ERR_ACCESS ) ;
s = pa_idxset_get_by_index ( c - > output_streams , idx ) ;
CHECK_VALIDITY ( c - > pstream , s , tag , PA_ERR_NOENTITY ) ;
2007-10-28 19:13:50 +00:00
CHECK_VALIDITY ( c - > pstream , playback_stream_isinstance ( s ) , tag , PA_ERR_NOENTITY ) ;
2006-04-13 18:27:35 +00:00
2009-04-05 02:59:02 +02:00
/* Get an atomic snapshot of all timing parameters */
pa_assert_se ( pa_asyncmsgq_send ( s - > sink_input - > sink - > asyncmsgq , PA_MSGOBJECT ( s - > sink_input ) , SINK_INPUT_MESSAGE_UPDATE_LATENCY , s , 0 , NULL ) = = 0 ) ;
2007-01-04 13:43:45 +00:00
2009-04-05 02:59:02 +02:00
reply = reply_new ( tag ) ;
pa_tagstruct_put_usec ( reply ,
s - > current_sink_latency +
2009-07-23 13:40:23 +02:00
pa_bytes_to_usec ( s - > render_memblockq_length , & s - > sink_input - > sink - > sample_spec ) ) ;
2004-09-16 00:05:56 +00:00
pa_tagstruct_put_usec ( reply , 0 ) ;
2009-04-05 02:59:02 +02:00
pa_tagstruct_put_boolean ( reply ,
s - > playing_for > 0 & &
pa_sink_get_state ( s - > sink_input - > sink ) = = PA_SINK_RUNNING & &
pa_sink_input_get_state ( s - > sink_input ) = = PA_SINK_INPUT_RUNNING ) ;
2004-09-10 22:35:12 +00:00
pa_tagstruct_put_timeval ( reply , & tv ) ;
2006-04-07 00:23:38 +00:00
pa_tagstruct_put_timeval ( reply , pa_gettimeofday ( & now ) ) ;
2007-10-28 19:13:50 +00:00
pa_tagstruct_puts64 ( reply , s - > write_index ) ;
pa_tagstruct_puts64 ( reply , s - > read_index ) ;
2008-05-15 23:34:41 +00:00
if ( c - > version > = 13 ) {
2009-04-05 02:59:02 +02:00
pa_tagstruct_putu64 ( reply , s - > underrun_for ) ;
pa_tagstruct_putu64 ( reply , s - > playing_for ) ;
2008-05-15 23:34:41 +00:00
}
2004-07-15 21:18:18 +00:00
pa_pstream_send_tagstruct ( c - > pstream , reply ) ;
}
2008-08-09 16:20:29 +02:00
static void command_get_record_latency ( pa_pdispatch * pd , uint32_t command , uint32_t tag , pa_tagstruct * t , void * userdata ) {
2008-08-04 18:58:29 +02:00
pa_native_connection * c = PA_NATIVE_CONNECTION ( userdata ) ;
2006-01-11 01:17:39 +00:00
pa_tagstruct * reply ;
2007-10-28 19:13:50 +00:00
record_stream * s ;
2004-09-16 00:05:56 +00:00
struct timeval tv , now ;
2006-01-11 01:17:39 +00:00
uint32_t idx ;
2007-10-28 19:13:50 +00:00
2008-08-04 18:58:29 +02:00
pa_native_connection_assert_ref ( c ) ;
2007-10-28 19:13:50 +00:00
pa_assert ( t ) ;
2004-09-16 00:05:56 +00:00
2006-01-11 01:17:39 +00:00
if ( pa_tagstruct_getu32 ( t , & idx ) < 0 | |
2004-09-16 00:05:56 +00:00
pa_tagstruct_get_timeval ( t , & tv ) < 0 | |
! pa_tagstruct_eof ( t ) ) {
protocol_error ( c ) ;
return ;
}
2006-02-22 18:54:21 +00:00
CHECK_VALIDITY ( c - > pstream , c - > authorized , tag , PA_ERR_ACCESS ) ;
s = pa_idxset_get_by_index ( c - > record_streams , idx ) ;
CHECK_VALIDITY ( c - > pstream , s , tag , PA_ERR_NOENTITY ) ;
2004-09-16 00:05:56 +00:00
2009-04-05 02:59:02 +02:00
/* Get an atomic snapshot of all timing parameters */
pa_assert_se ( pa_asyncmsgq_send ( s - > source_output - > source - > asyncmsgq , PA_MSGOBJECT ( s - > source_output ) , SOURCE_OUTPUT_MESSAGE_UPDATE_LATENCY , s , 0 , NULL ) = = 0 ) ;
2006-02-22 18:54:21 +00:00
reply = reply_new ( tag ) ;
2009-04-05 02:59:02 +02:00
pa_tagstruct_put_usec ( reply , s - > current_monitor_latency ) ;
pa_tagstruct_put_usec ( reply ,
s - > current_source_latency +
pa_bytes_to_usec ( s - > on_the_fly_snapshot , & s - > source_output - > sample_spec ) ) ;
pa_tagstruct_put_boolean ( reply ,
pa_source_get_state ( s - > source_output - > source ) = = PA_SOURCE_RUNNING & &
pa_source_output_get_state ( s - > source_output ) = = PA_SOURCE_OUTPUT_RUNNING ) ;
2004-09-16 00:05:56 +00:00
pa_tagstruct_put_timeval ( reply , & tv ) ;
2006-04-07 00:23:38 +00:00
pa_tagstruct_put_timeval ( reply , pa_gettimeofday ( & now ) ) ;
2006-03-02 14:22:25 +00:00
pa_tagstruct_puts64 ( reply , pa_memblockq_get_write_index ( s - > memblockq ) ) ;
pa_tagstruct_puts64 ( reply , pa_memblockq_get_read_index ( s - > memblockq ) ) ;
2004-09-16 00:05:56 +00:00
pa_pstream_send_tagstruct ( c - > pstream , reply ) ;
}
2008-08-09 16:20:29 +02:00
static void command_create_upload_stream ( pa_pdispatch * pd , uint32_t command , uint32_t tag , pa_tagstruct * t , void * userdata ) {
2008-08-04 18:58:29 +02:00
pa_native_connection * c = PA_NATIVE_CONNECTION ( userdata ) ;
2007-10-28 19:13:50 +00:00
upload_stream * s ;
2006-02-27 09:09:15 +00:00
uint32_t length ;
2008-05-15 23:34:41 +00:00
const char * name = NULL ;
2006-01-11 01:17:39 +00:00
pa_sample_spec ss ;
2006-01-27 16:25:31 +00:00
pa_channel_map map ;
2006-01-11 01:17:39 +00:00
pa_tagstruct * reply ;
2008-05-15 23:34:41 +00:00
pa_proplist * p ;
2007-10-28 19:13:50 +00:00
2008-08-04 18:58:29 +02:00
pa_native_connection_assert_ref ( c ) ;
2007-10-28 19:13:50 +00:00
pa_assert ( t ) ;
2007-01-04 13:43:45 +00:00
2008-05-27 22:07:27 +00:00
if ( pa_tagstruct_gets ( t , & name ) < 0 | |
2004-08-03 19:26:56 +00:00
pa_tagstruct_get_sample_spec ( t , & ss ) < 0 | |
2006-01-27 16:25:31 +00:00
pa_tagstruct_get_channel_map ( t , & map ) < 0 | |
2008-05-15 23:34:41 +00:00
pa_tagstruct_getu32 ( t , & length ) < 0 ) {
2004-08-03 19:26:56 +00:00
protocol_error ( c ) ;
return ;
}
2006-02-22 18:54:21 +00:00
CHECK_VALIDITY ( c - > pstream , c - > authorized , tag , PA_ERR_ACCESS ) ;
2006-04-23 21:01:44 +00:00
CHECK_VALIDITY ( c - > pstream , pa_sample_spec_valid ( & ss ) , tag , PA_ERR_INVALID ) ;
CHECK_VALIDITY ( c - > pstream , pa_channel_map_valid ( & map ) , tag , PA_ERR_INVALID ) ;
CHECK_VALIDITY ( c - > pstream , map . channels = = ss . channels , tag , PA_ERR_INVALID ) ;
2006-02-22 18:54:21 +00:00
CHECK_VALIDITY ( c - > pstream , ( length % pa_frame_size ( & ss ) ) = = 0 & & length > 0 , tag , PA_ERR_INVALID ) ;
2006-04-23 21:01:44 +00:00
CHECK_VALIDITY ( c - > pstream , length < = PA_SCACHE_ENTRY_SIZE_MAX , tag , PA_ERR_TOOLARGE ) ;
2007-01-04 13:43:45 +00:00
2008-05-15 23:34:41 +00:00
p = pa_proplist_new ( ) ;
2009-01-20 02:15:43 +01:00
if ( ( c - > version > = 13 & & pa_tagstruct_get_proplist ( t , p ) < 0 ) | |
! pa_tagstruct_eof ( t ) ) {
2008-05-15 23:34:41 +00:00
protocol_error ( c ) ;
pa_proplist_free ( p ) ;
return ;
}
if ( c - > version < 13 )
pa_proplist_sets ( p , PA_PROP_MEDIA_NAME , name ) ;
2008-05-27 22:07:27 +00:00
else if ( ! name )
if ( ! ( name = pa_proplist_gets ( p , PA_PROP_EVENT_ID ) ) )
name = pa_proplist_gets ( p , PA_PROP_MEDIA_NAME ) ;
2009-02-18 20:00:57 +02:00
if ( ! name | | ! pa_namereg_is_valid_name ( name ) ) {
pa_proplist_free ( p ) ;
CHECK_VALIDITY ( c - > pstream , FALSE , tag , PA_ERR_INVALID ) ;
}
2008-05-15 23:34:41 +00:00
s = upload_stream_new ( c , & ss , & map , name , length , p ) ;
pa_proplist_free ( p ) ;
2006-02-22 18:54:21 +00:00
CHECK_VALIDITY ( c - > pstream , s , tag , PA_ERR_INVALID ) ;
2007-01-04 13:43:45 +00:00
2006-02-22 18:54:21 +00:00
reply = reply_new ( tag ) ;
2004-08-03 19:26:56 +00:00
pa_tagstruct_putu32 ( reply , s - > index ) ;
pa_tagstruct_putu32 ( reply , length ) ;
pa_pstream_send_tagstruct ( c - > pstream , reply ) ;
}
2008-08-09 16:20:29 +02:00
static void command_finish_upload_stream ( pa_pdispatch * pd , uint32_t command , uint32_t tag , pa_tagstruct * t , void * userdata ) {
2008-08-04 18:58:29 +02:00
pa_native_connection * c = PA_NATIVE_CONNECTION ( userdata ) ;
2004-08-03 19:26:56 +00:00
uint32_t channel ;
2007-10-28 19:13:50 +00:00
upload_stream * s ;
2006-01-11 01:17:39 +00:00
uint32_t idx ;
2007-10-28 19:13:50 +00:00
2008-08-04 18:58:29 +02:00
pa_native_connection_assert_ref ( c ) ;
2007-10-28 19:13:50 +00:00
pa_assert ( t ) ;
2007-01-04 13:43:45 +00:00
2004-08-03 19:26:56 +00:00
if ( pa_tagstruct_getu32 ( t , & channel ) < 0 | |
! pa_tagstruct_eof ( t ) ) {
protocol_error ( c ) ;
return ;
}
2006-02-22 18:54:21 +00:00
CHECK_VALIDITY ( c - > pstream , c - > authorized , tag , PA_ERR_ACCESS ) ;
2004-08-03 19:26:56 +00:00
2006-02-22 18:54:21 +00:00
s = pa_idxset_get_by_index ( c - > output_streams , channel ) ;
CHECK_VALIDITY ( c - > pstream , s , tag , PA_ERR_NOENTITY ) ;
2007-10-28 19:13:50 +00:00
CHECK_VALIDITY ( c - > pstream , upload_stream_isinstance ( s ) , tag , PA_ERR_NOENTITY ) ;
2004-08-03 19:26:56 +00:00
2009-07-01 14:25:13 +02:00
if ( ! s - > memchunk . memblock )
pa_pstream_send_error ( c - > pstream , tag , PA_ERR_TOOLARGE ) ;
else if ( pa_scache_add_item ( c - > protocol - > core , s - > name , & s - > sample_spec , & s - > channel_map , & s - > memchunk , s - > proplist , & idx ) < 0 )
2006-04-23 21:01:44 +00:00
pa_pstream_send_error ( c - > pstream , tag , PA_ERR_INTERNAL ) ;
else
pa_pstream_send_simple_ack ( c - > pstream , tag ) ;
2007-01-04 13:43:45 +00:00
2007-10-28 19:13:50 +00:00
upload_stream_unlink ( s ) ;
2004-08-03 19:26:56 +00:00
}
2008-08-09 16:20:29 +02:00
static void command_play_sample ( pa_pdispatch * pd , uint32_t command , uint32_t tag , pa_tagstruct * t , void * userdata ) {
2008-08-04 18:58:29 +02:00
pa_native_connection * c = PA_NATIVE_CONNECTION ( userdata ) ;
2006-01-27 16:25:31 +00:00
uint32_t sink_index ;
2006-04-23 19:49:01 +00:00
pa_volume_t volume ;
2006-01-11 01:17:39 +00:00
pa_sink * sink ;
2004-08-03 19:26:56 +00:00
const char * name , * sink_name ;
2008-05-15 23:34:41 +00:00
uint32_t idx ;
pa_proplist * p ;
pa_tagstruct * reply ;
2007-10-28 19:13:50 +00:00
2008-08-04 18:58:29 +02:00
pa_native_connection_assert_ref ( c ) ;
2007-10-28 19:13:50 +00:00
pa_assert ( t ) ;
2004-08-03 19:26:56 +00:00
2008-05-15 23:34:41 +00:00
CHECK_VALIDITY ( c - > pstream , c - > authorized , tag , PA_ERR_ACCESS ) ;
2004-08-03 19:26:56 +00:00
if ( pa_tagstruct_getu32 ( t , & sink_index ) < 0 | |
pa_tagstruct_gets ( t , & sink_name ) < 0 | |
2006-04-23 19:49:01 +00:00
pa_tagstruct_getu32 ( t , & volume ) < 0 | |
2008-05-15 23:34:41 +00:00
pa_tagstruct_gets ( t , & name ) < 0 ) {
2004-08-03 19:26:56 +00:00
protocol_error ( c ) ;
return ;
}
2007-01-04 13:43:45 +00:00
2008-08-18 17:48:04 +02:00
CHECK_VALIDITY ( c - > pstream , ! sink_name | | pa_namereg_is_valid_name ( sink_name ) , tag , PA_ERR_INVALID ) ;
CHECK_VALIDITY ( c - > pstream , sink_index = = PA_INVALID_INDEX | | ! sink_name , tag , PA_ERR_INVALID ) ;
CHECK_VALIDITY ( c - > pstream , ! sink_name | | sink_index = = PA_INVALID_INDEX , tag , PA_ERR_INVALID ) ;
CHECK_VALIDITY ( c - > pstream , name & & pa_namereg_is_valid_name ( name ) , tag , PA_ERR_INVALID ) ;
2004-08-03 19:26:56 +00:00
2006-02-22 18:54:21 +00:00
if ( sink_index ! = PA_INVALID_INDEX )
2004-08-03 19:26:56 +00:00
sink = pa_idxset_get_by_index ( c - > protocol - > core - > sinks , sink_index ) ;
else
2009-01-15 20:07:13 +01:00
sink = pa_namereg_get ( c - > protocol - > core , sink_name , PA_NAMEREG_SINK ) ;
2004-08-03 19:26:56 +00:00
2006-02-22 18:54:21 +00:00
CHECK_VALIDITY ( c - > pstream , sink , tag , PA_ERR_NOENTITY ) ;
2004-08-03 19:26:56 +00:00
2008-05-15 23:34:41 +00:00
p = pa_proplist_new ( ) ;
if ( ( c - > version > = 13 & & pa_tagstruct_get_proplist ( t , p ) < 0 ) | |
! pa_tagstruct_eof ( t ) ) {
protocol_error ( c ) ;
pa_proplist_free ( p ) ;
return ;
}
2008-08-04 23:32:52 +02:00
pa_proplist_update ( p , PA_UPDATE_MERGE , c - > client - > proplist ) ;
2008-05-15 23:34:41 +00:00
if ( pa_scache_play_item ( c - > protocol - > core , name , sink , volume , p , & idx ) < 0 ) {
2006-02-20 04:05:16 +00:00
pa_pstream_send_error ( c - > pstream , tag , PA_ERR_NOENTITY ) ;
2008-05-15 23:34:41 +00:00
pa_proplist_free ( p ) ;
2004-08-03 19:26:56 +00:00
return ;
}
2008-05-15 23:34:41 +00:00
pa_proplist_free ( p ) ;
reply = reply_new ( tag ) ;
if ( c - > version > = 13 )
pa_tagstruct_putu32 ( reply , idx ) ;
pa_pstream_send_tagstruct ( c - > pstream , reply ) ;
2004-08-03 19:26:56 +00:00
}
2008-08-09 16:20:29 +02:00
static void command_remove_sample ( pa_pdispatch * pd , uint32_t command , uint32_t tag , pa_tagstruct * t , void * userdata ) {
2008-08-04 18:58:29 +02:00
pa_native_connection * c = PA_NATIVE_CONNECTION ( userdata ) ;
2004-08-03 19:26:56 +00:00
const char * name ;
2007-10-28 19:13:50 +00:00
2008-08-04 18:58:29 +02:00
pa_native_connection_assert_ref ( c ) ;
2007-10-28 19:13:50 +00:00
pa_assert ( t ) ;
2004-08-03 19:26:56 +00:00
2006-02-22 18:54:21 +00:00
if ( pa_tagstruct_gets ( t , & name ) < 0 | |
2004-08-03 19:26:56 +00:00
! pa_tagstruct_eof ( t ) ) {
protocol_error ( c ) ;
return ;
}
2006-02-22 18:54:21 +00:00
CHECK_VALIDITY ( c - > pstream , c - > authorized , tag , PA_ERR_ACCESS ) ;
2008-08-18 17:48:04 +02:00
CHECK_VALIDITY ( c - > pstream , name & & pa_namereg_is_valid_name ( name ) , tag , PA_ERR_INVALID ) ;
2004-08-03 19:26:56 +00:00
if ( pa_scache_remove_item ( c - > protocol - > core , name ) < 0 ) {
2006-02-20 04:05:16 +00:00
pa_pstream_send_error ( c - > pstream , tag , PA_ERR_NOENTITY ) ;
2004-08-03 19:26:56 +00:00
return ;
}
pa_pstream_send_simple_ack ( c - > pstream , tag ) ;
}
2008-08-04 18:58:29 +02:00
static void fixup_sample_spec ( pa_native_connection * c , pa_sample_spec * fixed , const pa_sample_spec * original ) {
2007-11-21 22:55:28 +00:00
pa_assert ( c ) ;
pa_assert ( fixed ) ;
pa_assert ( original ) ;
* fixed = * original ;
if ( c - > version < 12 ) {
/* Before protocol version 12 we didn't support S32 samples,
* so we need to lie about this to the client */
if ( fixed - > format = = PA_SAMPLE_S32LE )
fixed - > format = PA_SAMPLE_FLOAT32LE ;
if ( fixed - > format = = PA_SAMPLE_S32BE )
fixed - > format = PA_SAMPLE_FLOAT32BE ;
}
2009-01-16 03:15:39 +01:00
if ( c - > version < 15 ) {
2009-01-16 18:39:36 +01:00
if ( fixed - > format = = PA_SAMPLE_S24LE | | fixed - > format = = PA_SAMPLE_S24_32LE )
2009-01-16 03:15:39 +01:00
fixed - > format = PA_SAMPLE_FLOAT32LE ;
2009-01-16 18:39:36 +01:00
if ( fixed - > format = = PA_SAMPLE_S24BE | | fixed - > format = = PA_SAMPLE_S24_32BE )
2009-01-16 03:15:39 +01:00
fixed - > format = PA_SAMPLE_FLOAT32BE ;
}
2007-11-21 22:55:28 +00:00
}
2008-08-04 18:58:29 +02:00
static void sink_fill_tagstruct ( pa_native_connection * c , pa_tagstruct * t , pa_sink * sink ) {
2007-11-21 22:55:28 +00:00
pa_sample_spec fixed_ss ;
2007-10-28 19:13:50 +00:00
pa_assert ( t ) ;
pa_sink_assert_ref ( sink ) ;
2007-11-21 22:55:28 +00:00
fixup_sample_spec ( c , & fixed_ss , & sink - > sample_spec ) ;
2006-01-28 01:07:09 +00:00
pa_tagstruct_put (
t ,
PA_TAG_U32 , sink - > index ,
PA_TAG_STRING , sink - > name ,
2008-05-15 23:34:41 +00:00
PA_TAG_STRING , pa_strnull ( pa_proplist_gets ( sink - > proplist , PA_PROP_DEVICE_DESCRIPTION ) ) ,
2007-11-21 22:55:28 +00:00
PA_TAG_SAMPLE_SPEC , & fixed_ss ,
2006-01-28 01:07:09 +00:00
PA_TAG_CHANNEL_MAP , & sink - > channel_map ,
2007-10-28 19:13:50 +00:00
PA_TAG_U32 , sink - > module ? sink - > module - > index : PA_INVALID_INDEX ,
2009-04-13 22:50:24 +02:00
PA_TAG_CVOLUME , pa_sink_get_volume ( sink , FALSE , FALSE ) ,
2008-08-13 13:59:50 +02:00
PA_TAG_BOOLEAN , pa_sink_get_mute ( sink , FALSE ) ,
2006-08-12 17:06:39 +00:00
PA_TAG_U32 , sink - > monitor_source ? sink - > monitor_source - > index : PA_INVALID_INDEX ,
PA_TAG_STRING , sink - > monitor_source ? sink - > monitor_source - > name : NULL ,
2006-01-28 01:07:09 +00:00
PA_TAG_USEC , pa_sink_get_latency ( sink ) ,
PA_TAG_STRING , sink - > driver ,
2007-10-28 19:13:50 +00:00
PA_TAG_U32 , sink - > flags ,
2006-01-28 01:07:09 +00:00
PA_TAG_INVALID ) ;
2008-05-15 23:34:41 +00:00
if ( c - > version > = 13 ) {
pa_tagstruct_put_proplist ( t , sink - > proplist ) ;
pa_tagstruct_put_usec ( t , pa_sink_get_requested_latency ( sink ) ) ;
}
2008-12-24 00:49:43 +01:00
2009-01-15 17:16:31 +02:00
if ( c - > version > = 15 ) {
2008-12-24 00:49:43 +01:00
pa_tagstruct_put_volume ( t , sink - > base_volume ) ;
2009-01-15 17:16:31 +02:00
if ( PA_UNLIKELY ( pa_sink_get_state ( sink ) = = PA_SINK_INVALID_STATE ) )
pa_log_error ( " Internal sink state is invalid. " ) ;
pa_tagstruct_putu32 ( t , pa_sink_get_state ( sink ) ) ;
2009-01-27 04:39:07 +01:00
pa_tagstruct_putu32 ( t , sink - > n_volume_steps ) ;
2009-02-18 22:11:50 +01:00
pa_tagstruct_putu32 ( t , sink - > card ? sink - > card - > index : PA_INVALID_INDEX ) ;
2009-01-15 17:16:31 +02:00
}
2009-06-17 23:17:37 +02:00
if ( c - > version > = 16 ) {
pa_tagstruct_putu32 ( t , sink - > ports ? pa_hashmap_size ( sink - > ports ) : 0 ) ;
if ( sink - > ports ) {
void * state ;
pa_device_port * p ;
PA_HASHMAP_FOREACH ( p , sink - > ports , state ) {
pa_tagstruct_puts ( t , p - > name ) ;
pa_tagstruct_puts ( t , p - > description ) ;
pa_tagstruct_putu32 ( t , p - > priority ) ;
}
}
pa_tagstruct_puts ( t , sink - > active_port ? sink - > active_port - > name : NULL ) ;
}
2004-08-05 19:53:57 +00:00
}
2008-08-04 18:58:29 +02:00
static void source_fill_tagstruct ( pa_native_connection * c , pa_tagstruct * t , pa_source * source ) {
2007-11-21 22:55:28 +00:00
pa_sample_spec fixed_ss ;
2007-10-28 19:13:50 +00:00
pa_assert ( t ) ;
pa_source_assert_ref ( source ) ;
2007-11-21 22:55:28 +00:00
fixup_sample_spec ( c , & fixed_ss , & source - > sample_spec ) ;
2006-02-22 14:11:23 +00:00
pa_tagstruct_put (
t ,
PA_TAG_U32 , source - > index ,
PA_TAG_STRING , source - > name ,
2008-05-15 23:34:41 +00:00
PA_TAG_STRING , pa_strnull ( pa_proplist_gets ( source - > proplist , PA_PROP_DEVICE_DESCRIPTION ) ) ,
2007-11-21 22:55:28 +00:00
PA_TAG_SAMPLE_SPEC , & fixed_ss ,
2006-02-22 14:11:23 +00:00
PA_TAG_CHANNEL_MAP , & source - > channel_map ,
2007-10-28 19:13:50 +00:00
PA_TAG_U32 , source - > module ? source - > module - > index : PA_INVALID_INDEX ,
2008-08-13 13:59:50 +02:00
PA_TAG_CVOLUME , pa_source_get_volume ( source , FALSE ) ,
PA_TAG_BOOLEAN , pa_source_get_mute ( source , FALSE ) ,
2006-02-22 14:11:23 +00:00
PA_TAG_U32 , source - > monitor_of ? source - > monitor_of - > index : PA_INVALID_INDEX ,
PA_TAG_STRING , source - > monitor_of ? source - > monitor_of - > name : NULL ,
PA_TAG_USEC , pa_source_get_latency ( source ) ,
PA_TAG_STRING , source - > driver ,
2007-10-28 19:13:50 +00:00
PA_TAG_U32 , source - > flags ,
2006-02-22 14:11:23 +00:00
PA_TAG_INVALID ) ;
2008-05-15 23:34:41 +00:00
if ( c - > version > = 13 ) {
pa_tagstruct_put_proplist ( t , source - > proplist ) ;
pa_tagstruct_put_usec ( t , pa_source_get_requested_latency ( source ) ) ;
}
2004-08-05 19:53:57 +00:00
2009-01-15 17:16:31 +02:00
if ( c - > version > = 15 ) {
2008-12-24 00:49:43 +01:00
pa_tagstruct_put_volume ( t , source - > base_volume ) ;
2009-01-15 17:16:31 +02:00
if ( PA_UNLIKELY ( pa_source_get_state ( source ) = = PA_SOURCE_INVALID_STATE ) )
pa_log_error ( " Internal source state is invalid. " ) ;
pa_tagstruct_putu32 ( t , pa_source_get_state ( source ) ) ;
2009-01-27 04:39:07 +01:00
pa_tagstruct_putu32 ( t , source - > n_volume_steps ) ;
2009-02-18 22:11:50 +01:00
pa_tagstruct_putu32 ( t , source - > card ? source - > card - > index : PA_INVALID_INDEX ) ;
2009-01-15 17:16:31 +02:00
}
2009-06-17 23:17:37 +02:00
if ( c - > version > = 16 ) {
pa_tagstruct_putu32 ( t , source - > ports ? pa_hashmap_size ( source - > ports ) : 0 ) ;
if ( source - > ports ) {
void * state ;
pa_device_port * p ;
PA_HASHMAP_FOREACH ( p , source - > ports , state ) {
pa_tagstruct_puts ( t , p - > name ) ;
pa_tagstruct_puts ( t , p - > description ) ;
pa_tagstruct_putu32 ( t , p - > priority ) ;
}
}
pa_tagstruct_puts ( t , source - > active_port ? source - > active_port - > name : NULL ) ;
}
2008-12-24 00:49:43 +01:00
}
2008-05-15 23:34:41 +00:00
2008-08-04 18:58:29 +02:00
static void client_fill_tagstruct ( pa_native_connection * c , pa_tagstruct * t , pa_client * client ) {
2007-10-28 19:13:50 +00:00
pa_assert ( t ) ;
pa_assert ( client ) ;
2004-08-12 23:25:28 +00:00
pa_tagstruct_putu32 ( t , client - > index ) ;
2008-05-15 23:34:41 +00:00
pa_tagstruct_puts ( t , pa_strnull ( pa_proplist_gets ( client - > proplist , PA_PROP_APPLICATION_NAME ) ) ) ;
pa_tagstruct_putu32 ( t , client - > module ? client - > module - > index : PA_INVALID_INDEX ) ;
2006-01-27 16:25:31 +00:00
pa_tagstruct_puts ( t , client - > driver ) ;
2008-05-15 23:34:41 +00:00
if ( c - > version > = 13 )
pa_tagstruct_put_proplist ( t , client - > proplist ) ;
2004-08-12 23:25:28 +00:00
}
2009-01-20 03:25:29 +01:00
static void card_fill_tagstruct ( pa_native_connection * c , pa_tagstruct * t , pa_card * card ) {
void * state = NULL ;
pa_card_profile * p ;
pa_assert ( t ) ;
pa_assert ( card ) ;
pa_tagstruct_putu32 ( t , card - > index ) ;
pa_tagstruct_puts ( t , card - > name ) ;
pa_tagstruct_putu32 ( t , card - > module ? card - > module - > index : PA_INVALID_INDEX ) ;
pa_tagstruct_puts ( t , card - > driver ) ;
pa_tagstruct_putu32 ( t , card - > profiles ? pa_hashmap_size ( card - > profiles ) : 0 ) ;
if ( card - > profiles ) {
while ( ( p = pa_hashmap_iterate ( card - > profiles , & state , NULL ) ) ) {
pa_tagstruct_puts ( t , p - > name ) ;
pa_tagstruct_puts ( t , p - > description ) ;
2009-02-18 22:11:50 +01:00
pa_tagstruct_putu32 ( t , p - > n_sinks ) ;
pa_tagstruct_putu32 ( t , p - > n_sources ) ;
2009-03-03 00:32:10 +01:00
pa_tagstruct_putu32 ( t , p - > priority ) ;
2009-01-20 03:25:29 +01:00
}
}
pa_tagstruct_puts ( t , card - > active_profile ? card - > active_profile - > name : NULL ) ;
pa_tagstruct_put_proplist ( t , card - > proplist ) ;
}
2009-01-19 22:02:28 +01:00
static void module_fill_tagstruct ( pa_native_connection * c , pa_tagstruct * t , pa_module * module ) {
2007-10-28 19:13:50 +00:00
pa_assert ( t ) ;
pa_assert ( module ) ;
2004-08-12 23:25:28 +00:00
pa_tagstruct_putu32 ( t , module - > index ) ;
pa_tagstruct_puts ( t , module - > name ) ;
2004-09-19 23:12:41 +00:00
pa_tagstruct_puts ( t , module - > argument ) ;
2009-01-15 20:49:12 +01:00
pa_tagstruct_putu32 ( t , ( uint32_t ) pa_module_get_n_used ( module ) ) ;
2009-01-19 22:02:28 +01:00
if ( c - > version < 15 )
pa_tagstruct_put_boolean ( t , FALSE ) ; /* autoload is obsolete */
if ( c - > version > = 15 )
pa_tagstruct_put_proplist ( t , module - > proplist ) ;
2004-08-12 23:25:28 +00:00
}
2008-08-04 18:58:29 +02:00
static void sink_input_fill_tagstruct ( pa_native_connection * c , pa_tagstruct * t , pa_sink_input * s ) {
2007-11-21 22:55:28 +00:00
pa_sample_spec fixed_ss ;
2008-06-20 22:32:41 +02:00
pa_usec_t sink_latency ;
2009-04-13 22:50:24 +02:00
pa_cvolume v ;
2007-11-21 22:55:28 +00:00
2007-10-28 19:13:50 +00:00
pa_assert ( t ) ;
pa_sink_input_assert_ref ( s ) ;
2007-11-21 22:55:28 +00:00
fixup_sample_spec ( c , & fixed_ss , & s - > sample_spec ) ;
2004-08-16 19:55:02 +00:00
pa_tagstruct_putu32 ( t , s - > index ) ;
2008-05-15 23:34:41 +00:00
pa_tagstruct_puts ( t , pa_strnull ( pa_proplist_gets ( s - > proplist , PA_PROP_MEDIA_NAME ) ) ) ;
2006-08-13 16:19:56 +00:00
pa_tagstruct_putu32 ( t , s - > module ? s - > module - > index : PA_INVALID_INDEX ) ;
2006-02-22 18:54:21 +00:00
pa_tagstruct_putu32 ( t , s - > client ? s - > client - > index : PA_INVALID_INDEX ) ;
2004-08-16 19:55:02 +00:00
pa_tagstruct_putu32 ( t , s - > sink - > index ) ;
2007-11-21 22:55:28 +00:00
pa_tagstruct_put_sample_spec ( t , & fixed_ss ) ;
2006-01-27 16:25:31 +00:00
pa_tagstruct_put_channel_map ( t , & s - > channel_map ) ;
2009-04-13 22:50:24 +02:00
pa_tagstruct_put_cvolume ( t , pa_sink_input_get_volume ( s , & v , TRUE ) ) ;
2008-06-20 22:32:41 +02:00
pa_tagstruct_put_usec ( t , pa_sink_input_get_latency ( s , & sink_latency ) ) ;
pa_tagstruct_put_usec ( t , sink_latency ) ;
2004-11-20 16:23:53 +00:00
pa_tagstruct_puts ( t , pa_resample_method_to_string ( pa_sink_input_get_resample_method ( s ) ) ) ;
2006-01-27 16:25:31 +00:00
pa_tagstruct_puts ( t , s - > driver ) ;
2007-10-28 19:13:50 +00:00
if ( c - > version > = 11 )
pa_tagstruct_put_boolean ( t , pa_sink_input_get_mute ( s ) ) ;
2008-05-15 23:34:41 +00:00
if ( c - > version > = 13 )
pa_tagstruct_put_proplist ( t , s - > proplist ) ;
2004-08-16 19:55:02 +00:00
}
2008-08-04 18:58:29 +02:00
static void source_output_fill_tagstruct ( pa_native_connection * c , pa_tagstruct * t , pa_source_output * s ) {
2007-11-21 22:55:28 +00:00
pa_sample_spec fixed_ss ;
2008-06-20 22:32:41 +02:00
pa_usec_t source_latency ;
2007-11-21 22:55:28 +00:00
2007-10-28 19:13:50 +00:00
pa_assert ( t ) ;
pa_source_output_assert_ref ( s ) ;
2007-11-21 22:55:28 +00:00
fixup_sample_spec ( c , & fixed_ss , & s - > sample_spec ) ;
2004-08-16 19:55:02 +00:00
pa_tagstruct_putu32 ( t , s - > index ) ;
2008-05-15 23:34:41 +00:00
pa_tagstruct_puts ( t , pa_strnull ( pa_proplist_gets ( s - > proplist , PA_PROP_MEDIA_NAME ) ) ) ;
2006-08-13 19:55:17 +00:00
pa_tagstruct_putu32 ( t , s - > module ? s - > module - > index : PA_INVALID_INDEX ) ;
2006-02-22 18:54:21 +00:00
pa_tagstruct_putu32 ( t , s - > client ? s - > client - > index : PA_INVALID_INDEX ) ;
2004-08-16 19:55:02 +00:00
pa_tagstruct_putu32 ( t , s - > source - > index ) ;
2007-11-21 22:55:28 +00:00
pa_tagstruct_put_sample_spec ( t , & fixed_ss ) ;
2006-01-27 16:25:31 +00:00
pa_tagstruct_put_channel_map ( t , & s - > channel_map ) ;
2008-06-20 22:32:41 +02:00
pa_tagstruct_put_usec ( t , pa_source_output_get_latency ( s , & source_latency ) ) ;
pa_tagstruct_put_usec ( t , source_latency ) ;
2004-11-20 16:23:53 +00:00
pa_tagstruct_puts ( t , pa_resample_method_to_string ( pa_source_output_get_resample_method ( s ) ) ) ;
2006-01-27 16:25:31 +00:00
pa_tagstruct_puts ( t , s - > driver ) ;
2008-05-15 23:34:41 +00:00
if ( c - > version > = 13 )
pa_tagstruct_put_proplist ( t , s - > proplist ) ;
2004-08-16 19:55:02 +00:00
}
2008-08-04 18:58:29 +02:00
static void scache_fill_tagstruct ( pa_native_connection * c , pa_tagstruct * t , pa_scache_entry * e ) {
2007-11-21 22:55:28 +00:00
pa_sample_spec fixed_ss ;
2009-01-27 03:05:40 +01:00
pa_cvolume v ;
2007-11-21 22:55:28 +00:00
2007-10-28 19:13:50 +00:00
pa_assert ( t ) ;
pa_assert ( e ) ;
2008-06-14 21:33:21 +00:00
if ( e - > memchunk . memblock )
fixup_sample_spec ( c , & fixed_ss , & e - > sample_spec ) ;
else
memset ( & fixed_ss , 0 , sizeof ( fixed_ss ) ) ;
2007-11-21 22:55:28 +00:00
2004-08-19 23:14:59 +00:00
pa_tagstruct_putu32 ( t , e - > index ) ;
pa_tagstruct_puts ( t , e - > name ) ;
2009-01-27 03:05:40 +01:00
if ( e - > volume_is_set )
v = e - > volume ;
else
pa_cvolume_init ( & v ) ;
pa_tagstruct_put_cvolume ( t , & v ) ;
2008-06-17 18:29:00 +00:00
pa_tagstruct_put_usec ( t , e - > memchunk . memblock ? pa_bytes_to_usec ( e - > memchunk . length , & e - > sample_spec ) : 0 ) ;
2007-11-21 22:55:28 +00:00
pa_tagstruct_put_sample_spec ( t , & fixed_ss ) ;
2006-01-27 16:25:31 +00:00
pa_tagstruct_put_channel_map ( t , & e - > channel_map ) ;
2008-08-19 22:39:54 +02:00
pa_tagstruct_putu32 ( t , ( uint32_t ) e - > memchunk . length ) ;
2004-09-15 19:16:57 +00:00
pa_tagstruct_put_boolean ( t , e - > lazy ) ;
pa_tagstruct_puts ( t , e - > filename ) ;
2008-05-15 23:34:41 +00:00
if ( c - > version > = 13 )
pa_tagstruct_put_proplist ( t , e - > proplist ) ;
2004-08-19 23:14:59 +00:00
}
2008-08-09 16:20:29 +02:00
static void command_get_info ( pa_pdispatch * pd , uint32_t command , uint32_t tag , pa_tagstruct * t , void * userdata ) {
2008-08-04 18:58:29 +02:00
pa_native_connection * c = PA_NATIVE_CONNECTION ( userdata ) ;
2006-01-11 01:17:39 +00:00
uint32_t idx ;
pa_sink * sink = NULL ;
pa_source * source = NULL ;
pa_client * client = NULL ;
2009-01-20 03:25:29 +01:00
pa_card * card = NULL ;
2006-01-11 01:17:39 +00:00
pa_module * module = NULL ;
pa_sink_input * si = NULL ;
pa_source_output * so = NULL ;
pa_scache_entry * sce = NULL ;
2008-09-01 16:00:08 +03:00
const char * name = NULL ;
2006-01-11 01:17:39 +00:00
pa_tagstruct * reply ;
2007-10-28 19:13:50 +00:00
2008-08-04 18:58:29 +02:00
pa_native_connection_assert_ref ( c ) ;
2007-10-28 19:13:50 +00:00
pa_assert ( t ) ;
2004-08-05 19:53:57 +00:00
2006-01-11 01:17:39 +00:00
if ( pa_tagstruct_getu32 ( t , & idx ) < 0 | |
2004-08-16 19:55:02 +00:00
( command ! = PA_COMMAND_GET_CLIENT_INFO & &
command ! = PA_COMMAND_GET_MODULE_INFO & &
command ! = PA_COMMAND_GET_SINK_INPUT_INFO & &
command ! = PA_COMMAND_GET_SOURCE_OUTPUT_INFO & &
pa_tagstruct_gets ( t , & name ) < 0 ) | |
2004-08-05 19:53:57 +00:00
! pa_tagstruct_eof ( t ) ) {
protocol_error ( c ) ;
return ;
}
2006-02-22 18:54:21 +00:00
CHECK_VALIDITY ( c - > pstream , c - > authorized , tag , PA_ERR_ACCESS ) ;
2008-08-18 17:48:04 +02:00
CHECK_VALIDITY ( c - > pstream , ! name | | pa_namereg_is_valid_name ( name ) , tag , PA_ERR_INVALID ) ;
CHECK_VALIDITY ( c - > pstream , idx ! = PA_INVALID_INDEX | | name , tag , PA_ERR_INVALID ) ;
CHECK_VALIDITY ( c - > pstream , idx = = PA_INVALID_INDEX | | ! name , tag , PA_ERR_INVALID ) ;
CHECK_VALIDITY ( c - > pstream , ! name | | idx = = PA_INVALID_INDEX , tag , PA_ERR_INVALID ) ;
2004-08-05 19:53:57 +00:00
if ( command = = PA_COMMAND_GET_SINK_INFO ) {
2006-02-22 18:54:21 +00:00
if ( idx ! = PA_INVALID_INDEX )
2006-01-11 01:17:39 +00:00
sink = pa_idxset_get_by_index ( c - > protocol - > core - > sinks , idx ) ;
2004-08-05 19:53:57 +00:00
else
2009-01-15 20:07:13 +01:00
sink = pa_namereg_get ( c - > protocol - > core , name , PA_NAMEREG_SINK ) ;
2004-08-12 23:25:28 +00:00
} else if ( command = = PA_COMMAND_GET_SOURCE_INFO ) {
2006-02-22 18:54:21 +00:00
if ( idx ! = PA_INVALID_INDEX )
2006-01-11 01:17:39 +00:00
source = pa_idxset_get_by_index ( c - > protocol - > core - > sources , idx ) ;
2004-08-05 19:53:57 +00:00
else
2009-01-15 20:07:13 +01:00
source = pa_namereg_get ( c - > protocol - > core , name , PA_NAMEREG_SOURCE ) ;
2009-01-20 03:25:29 +01:00
} else if ( command = = PA_COMMAND_GET_CARD_INFO ) {
if ( idx ! = PA_INVALID_INDEX )
card = pa_idxset_get_by_index ( c - > protocol - > core - > cards , idx ) ;
else
card = pa_namereg_get ( c - > protocol - > core , name , PA_NAMEREG_CARD ) ;
2004-08-12 23:25:28 +00:00
} else if ( command = = PA_COMMAND_GET_CLIENT_INFO )
2006-01-11 01:17:39 +00:00
client = pa_idxset_get_by_index ( c - > protocol - > core - > clients , idx ) ;
2007-01-04 13:43:45 +00:00
else if ( command = = PA_COMMAND_GET_MODULE_INFO )
2006-01-11 01:17:39 +00:00
module = pa_idxset_get_by_index ( c - > protocol - > core - > modules , idx ) ;
2004-08-16 19:55:02 +00:00
else if ( command = = PA_COMMAND_GET_SINK_INPUT_INFO )
2006-01-11 01:17:39 +00:00
si = pa_idxset_get_by_index ( c - > protocol - > core - > sink_inputs , idx ) ;
2004-08-19 23:14:59 +00:00
else if ( command = = PA_COMMAND_GET_SOURCE_OUTPUT_INFO )
2006-01-11 01:17:39 +00:00
so = pa_idxset_get_by_index ( c - > protocol - > core - > source_outputs , idx ) ;
2004-08-19 23:14:59 +00:00
else {
2007-10-28 19:13:50 +00:00
pa_assert ( command = = PA_COMMAND_GET_SAMPLE_INFO ) ;
2006-02-22 18:54:21 +00:00
if ( idx ! = PA_INVALID_INDEX )
2006-01-11 01:17:39 +00:00
sce = pa_idxset_get_by_index ( c - > protocol - > core - > scache , idx ) ;
2004-08-19 23:14:59 +00:00
else
2009-01-15 20:07:13 +01:00
sce = pa_namereg_get ( c - > protocol - > core , name , PA_NAMEREG_SAMPLE ) ;
2004-08-05 19:53:57 +00:00
}
2007-01-04 13:43:45 +00:00
2009-01-20 03:25:29 +01:00
if ( ! sink & & ! source & & ! client & & ! card & & ! module & & ! si & & ! so & & ! sce ) {
2006-02-20 04:05:16 +00:00
pa_pstream_send_error ( c - > pstream , tag , PA_ERR_NOENTITY ) ;
2004-08-05 19:53:57 +00:00
return ;
}
2006-02-22 18:54:21 +00:00
reply = reply_new ( tag ) ;
2004-08-05 19:53:57 +00:00
if ( sink )
2007-11-21 22:55:28 +00:00
sink_fill_tagstruct ( c , reply , sink ) ;
2004-08-12 23:25:28 +00:00
else if ( source )
2007-11-21 22:55:28 +00:00
source_fill_tagstruct ( c , reply , source ) ;
2004-08-12 23:25:28 +00:00
else if ( client )
2008-05-15 23:34:41 +00:00
client_fill_tagstruct ( c , reply , client ) ;
2009-02-17 20:18:56 +02:00
else if ( card )
2009-01-20 03:25:29 +01:00
card_fill_tagstruct ( c , reply , card ) ;
2004-08-16 19:55:02 +00:00
else if ( module )
2009-01-19 22:02:28 +01:00
module_fill_tagstruct ( c , reply , module ) ;
2004-08-16 19:55:02 +00:00
else if ( si )
2007-10-28 19:13:50 +00:00
sink_input_fill_tagstruct ( c , reply , si ) ;
2004-08-19 23:14:59 +00:00
else if ( so )
2007-11-21 22:55:28 +00:00
source_output_fill_tagstruct ( c , reply , so ) ;
2004-08-19 23:14:59 +00:00
else
2007-11-21 22:55:28 +00:00
scache_fill_tagstruct ( c , reply , sce ) ;
2004-08-05 19:53:57 +00:00
pa_pstream_send_tagstruct ( c - > pstream , reply ) ;
}
2008-08-09 16:20:29 +02:00
static void command_get_info_list ( pa_pdispatch * pd , uint32_t command , uint32_t tag , pa_tagstruct * t , void * userdata ) {
2008-08-04 18:58:29 +02:00
pa_native_connection * c = PA_NATIVE_CONNECTION ( userdata ) ;
2006-01-11 01:17:39 +00:00
pa_idxset * i ;
uint32_t idx ;
2004-08-05 19:53:57 +00:00
void * p ;
2006-01-11 01:17:39 +00:00
pa_tagstruct * reply ;
2007-10-28 19:13:50 +00:00
2008-08-04 18:58:29 +02:00
pa_native_connection_assert_ref ( c ) ;
2007-10-28 19:13:50 +00:00
pa_assert ( t ) ;
2004-08-05 19:53:57 +00:00
if ( ! pa_tagstruct_eof ( t ) ) {
protocol_error ( c ) ;
return ;
}
2006-02-22 18:54:21 +00:00
CHECK_VALIDITY ( c - > pstream , c - > authorized , tag , PA_ERR_ACCESS ) ;
reply = reply_new ( tag ) ;
2004-08-05 19:53:57 +00:00
if ( command = = PA_COMMAND_GET_SINK_INFO_LIST )
i = c - > protocol - > core - > sinks ;
2004-08-12 23:25:28 +00:00
else if ( command = = PA_COMMAND_GET_SOURCE_INFO_LIST )
2004-08-05 19:53:57 +00:00
i = c - > protocol - > core - > sources ;
2004-08-12 23:25:28 +00:00
else if ( command = = PA_COMMAND_GET_CLIENT_INFO_LIST )
i = c - > protocol - > core - > clients ;
2009-01-20 03:25:29 +01:00
else if ( command = = PA_COMMAND_GET_CARD_INFO_LIST )
i = c - > protocol - > core - > cards ;
2004-08-16 19:55:02 +00:00
else if ( command = = PA_COMMAND_GET_MODULE_INFO_LIST )
2004-08-12 23:25:28 +00:00
i = c - > protocol - > core - > modules ;
2004-08-16 19:55:02 +00:00
else if ( command = = PA_COMMAND_GET_SINK_INPUT_INFO_LIST )
i = c - > protocol - > core - > sink_inputs ;
2004-08-19 23:14:59 +00:00
else if ( command = = PA_COMMAND_GET_SOURCE_OUTPUT_INFO_LIST )
2004-08-16 19:55:02 +00:00
i = c - > protocol - > core - > source_outputs ;
2004-08-19 23:14:59 +00:00
else {
2007-10-28 19:13:50 +00:00
pa_assert ( command = = PA_COMMAND_GET_SAMPLE_INFO_LIST ) ;
2004-08-19 23:14:59 +00:00
i = c - > protocol - > core - > scache ;
2004-08-05 19:53:57 +00:00
}
2004-08-20 10:54:31 +00:00
if ( i ) {
2006-01-11 01:17:39 +00:00
for ( p = pa_idxset_first ( i , & idx ) ; p ; p = pa_idxset_next ( i , & idx ) ) {
2004-08-20 10:54:31 +00:00
if ( command = = PA_COMMAND_GET_SINK_INFO_LIST )
2007-11-21 22:55:28 +00:00
sink_fill_tagstruct ( c , reply , p ) ;
2004-08-20 10:54:31 +00:00
else if ( command = = PA_COMMAND_GET_SOURCE_INFO_LIST )
2007-11-21 22:55:28 +00:00
source_fill_tagstruct ( c , reply , p ) ;
2004-08-20 10:54:31 +00:00
else if ( command = = PA_COMMAND_GET_CLIENT_INFO_LIST )
2008-05-15 23:34:41 +00:00
client_fill_tagstruct ( c , reply , p ) ;
2009-01-20 03:25:29 +01:00
else if ( command = = PA_COMMAND_GET_CARD_INFO_LIST )
card_fill_tagstruct ( c , reply , p ) ;
2004-08-20 10:54:31 +00:00
else if ( command = = PA_COMMAND_GET_MODULE_INFO_LIST )
2009-01-19 22:02:28 +01:00
module_fill_tagstruct ( c , reply , p ) ;
2004-08-20 10:54:31 +00:00
else if ( command = = PA_COMMAND_GET_SINK_INPUT_INFO_LIST )
2007-10-28 19:13:50 +00:00
sink_input_fill_tagstruct ( c , reply , p ) ;
2007-01-04 13:43:45 +00:00
else if ( command = = PA_COMMAND_GET_SOURCE_OUTPUT_INFO_LIST )
2007-11-21 22:55:28 +00:00
source_output_fill_tagstruct ( c , reply , p ) ;
2004-08-20 10:54:31 +00:00
else {
2007-10-28 19:13:50 +00:00
pa_assert ( command = = PA_COMMAND_GET_SAMPLE_INFO_LIST ) ;
2007-11-21 22:55:28 +00:00
scache_fill_tagstruct ( c , reply , p ) ;
2004-08-20 10:54:31 +00:00
}
2004-08-05 19:53:57 +00:00
}
2004-08-20 10:54:31 +00:00
}
2007-01-04 13:43:45 +00:00
2004-08-05 19:53:57 +00:00
pa_pstream_send_tagstruct ( c - > pstream , reply ) ;
}
2008-08-09 16:20:29 +02:00
static void command_get_server_info ( pa_pdispatch * pd , uint32_t command , uint32_t tag , pa_tagstruct * t , void * userdata ) {
2008-08-04 18:58:29 +02:00
pa_native_connection * c = PA_NATIVE_CONNECTION ( userdata ) ;
2006-01-11 01:17:39 +00:00
pa_tagstruct * reply ;
2009-01-28 01:46:27 +01:00
pa_sink * def_sink ;
pa_source * def_source ;
2007-11-21 22:55:28 +00:00
pa_sample_spec fixed_ss ;
2009-04-29 01:56:02 +02:00
char * h , * u ;
2007-10-28 19:13:50 +00:00
2008-08-04 18:58:29 +02:00
pa_native_connection_assert_ref ( c ) ;
2007-10-28 19:13:50 +00:00
pa_assert ( t ) ;
2004-08-10 13:00:12 +00:00
if ( ! pa_tagstruct_eof ( t ) ) {
protocol_error ( c ) ;
return ;
}
2007-01-04 13:43:45 +00:00
2006-02-22 18:54:21 +00:00
CHECK_VALIDITY ( c - > pstream , c - > authorized , tag , PA_ERR_ACCESS ) ;
2004-08-10 13:00:12 +00:00
2006-02-22 18:54:21 +00:00
reply = reply_new ( tag ) ;
2004-08-10 13:00:12 +00:00
pa_tagstruct_puts ( reply , PACKAGE_NAME ) ;
pa_tagstruct_puts ( reply , PACKAGE_VERSION ) ;
2009-04-29 01:56:02 +02:00
u = pa_get_user_name_malloc ( ) ;
pa_tagstruct_puts ( reply , u ) ;
pa_xfree ( u ) ;
h = pa_get_host_name_malloc ( ) ;
pa_tagstruct_puts ( reply , h ) ;
pa_xfree ( h ) ;
2007-11-21 22:55:28 +00:00
fixup_sample_spec ( c , & fixed_ss , & c - > protocol - > core - > default_sample_spec ) ;
pa_tagstruct_put_sample_spec ( reply , & fixed_ss ) ;
2004-09-07 14:58:42 +00:00
2009-01-28 01:46:27 +01:00
def_sink = pa_namereg_get_default_sink ( c - > protocol - > core ) ;
pa_tagstruct_puts ( reply , def_sink ? def_sink - > name : NULL ) ;
def_source = pa_namereg_get_default_source ( c - > protocol - > core ) ;
pa_tagstruct_puts ( reply , def_source ? def_source - > name : NULL ) ;
2004-12-12 22:58:53 +00:00
pa_tagstruct_putu32 ( reply , c - > protocol - > core - > cookie ) ;
2007-01-04 13:43:45 +00:00
2009-02-21 16:32:42 +01:00
if ( c - > version > = 15 )
pa_tagstruct_put_channel_map ( reply , & c - > protocol - > core - > default_channel_map ) ;
2004-08-10 13:00:12 +00:00
pa_pstream_send_tagstruct ( c - > pstream , reply ) ;
}
2006-01-27 16:25:31 +00:00
static void subscription_cb ( pa_core * core , pa_subscription_event_type_t e , uint32_t idx , void * userdata ) {
2006-01-11 01:17:39 +00:00
pa_tagstruct * t ;
2008-08-04 18:58:29 +02:00
pa_native_connection * c = PA_NATIVE_CONNECTION ( userdata ) ;
2007-10-28 19:13:50 +00:00
2008-08-04 18:58:29 +02:00
pa_native_connection_assert_ref ( c ) ;
2004-08-11 15:11:26 +00:00
t = pa_tagstruct_new ( NULL , 0 ) ;
pa_tagstruct_putu32 ( t , PA_COMMAND_SUBSCRIBE_EVENT ) ;
pa_tagstruct_putu32 ( t , ( uint32_t ) - 1 ) ;
pa_tagstruct_putu32 ( t , e ) ;
2006-01-11 01:17:39 +00:00
pa_tagstruct_putu32 ( t , idx ) ;
2004-08-11 15:11:26 +00:00
pa_pstream_send_tagstruct ( c - > pstream , t ) ;
}
2008-08-09 16:20:29 +02:00
static void command_subscribe ( pa_pdispatch * pd , uint32_t command , uint32_t tag , pa_tagstruct * t , void * userdata ) {
2008-08-04 18:58:29 +02:00
pa_native_connection * c = PA_NATIVE_CONNECTION ( userdata ) ;
2006-01-27 16:25:31 +00:00
pa_subscription_mask_t m ;
2007-10-28 19:13:50 +00:00
2008-08-04 18:58:29 +02:00
pa_native_connection_assert_ref ( c ) ;
2007-10-28 19:13:50 +00:00
pa_assert ( t ) ;
2004-08-11 15:11:26 +00:00
if ( pa_tagstruct_getu32 ( t , & m ) < 0 | |
! pa_tagstruct_eof ( t ) ) {
protocol_error ( c ) ;
return ;
}
2006-02-22 18:54:21 +00:00
CHECK_VALIDITY ( c - > pstream , c - > authorized , tag , PA_ERR_ACCESS ) ;
CHECK_VALIDITY ( c - > pstream , ( m & ~ PA_SUBSCRIPTION_MASK_ALL ) = = 0 , tag , PA_ERR_INVALID ) ;
2007-01-04 13:43:45 +00:00
2004-08-11 15:11:26 +00:00
if ( c - > subscription )
pa_subscription_free ( c - > subscription ) ;
if ( m ! = 0 ) {
c - > subscription = pa_subscription_new ( c - > protocol - > core , m , subscription_cb , c ) ;
2007-10-28 19:13:50 +00:00
pa_assert ( c - > subscription ) ;
2004-08-11 15:11:26 +00:00
} else
c - > subscription = NULL ;
pa_pstream_send_simple_ack ( c - > pstream , tag ) ;
2004-08-15 13:15:51 +00:00
}
2006-02-22 18:54:21 +00:00
static void command_set_volume (
2008-08-09 16:20:29 +02:00
pa_pdispatch * pd ,
2006-02-22 18:54:21 +00:00
uint32_t command ,
uint32_t tag ,
pa_tagstruct * t ,
void * userdata ) {
2007-01-04 13:43:45 +00:00
2008-08-04 18:58:29 +02:00
pa_native_connection * c = PA_NATIVE_CONNECTION ( userdata ) ;
2006-01-27 16:25:31 +00:00
uint32_t idx ;
pa_cvolume volume ;
2006-01-11 01:17:39 +00:00
pa_sink * sink = NULL ;
2006-02-22 14:11:23 +00:00
pa_source * source = NULL ;
2006-01-11 01:17:39 +00:00
pa_sink_input * si = NULL ;
2004-08-15 13:15:51 +00:00
const char * name = NULL ;
2009-08-14 19:31:05 +02:00
const char * client_name ;
2007-10-28 19:13:50 +00:00
2008-08-04 18:58:29 +02:00
pa_native_connection_assert_ref ( c ) ;
2007-10-28 19:13:50 +00:00
pa_assert ( t ) ;
2004-08-15 13:15:51 +00:00
2006-01-11 01:17:39 +00:00
if ( pa_tagstruct_getu32 ( t , & idx ) < 0 | |
2004-08-15 13:15:51 +00:00
( command = = PA_COMMAND_SET_SINK_VOLUME & & pa_tagstruct_gets ( t , & name ) < 0 ) | |
2006-02-22 14:11:23 +00:00
( command = = PA_COMMAND_SET_SOURCE_VOLUME & & pa_tagstruct_gets ( t , & name ) < 0 ) | |
2006-01-27 16:25:31 +00:00
pa_tagstruct_get_cvolume ( t , & volume ) | |
2004-08-15 13:15:51 +00:00
! pa_tagstruct_eof ( t ) ) {
protocol_error ( c ) ;
return ;
}
2007-01-04 13:43:45 +00:00
2006-02-22 18:54:21 +00:00
CHECK_VALIDITY ( c - > pstream , c - > authorized , tag , PA_ERR_ACCESS ) ;
2008-08-18 17:48:04 +02:00
CHECK_VALIDITY ( c - > pstream , ! name | | pa_namereg_is_valid_name ( name ) , tag , PA_ERR_INVALID ) ;
CHECK_VALIDITY ( c - > pstream , idx ! = PA_INVALID_INDEX | | name , tag , PA_ERR_INVALID ) ;
CHECK_VALIDITY ( c - > pstream , idx = = PA_INVALID_INDEX | | ! name , tag , PA_ERR_INVALID ) ;
CHECK_VALIDITY ( c - > pstream , ! name | | idx = = PA_INVALID_INDEX , tag , PA_ERR_INVALID ) ;
2006-04-23 21:01:44 +00:00
CHECK_VALIDITY ( c - > pstream , pa_cvolume_valid ( & volume ) , tag , PA_ERR_INVALID ) ;
2004-08-15 13:15:51 +00:00
2007-10-28 19:13:50 +00:00
switch ( command ) {
case PA_COMMAND_SET_SINK_VOLUME :
if ( idx ! = PA_INVALID_INDEX )
sink = pa_idxset_get_by_index ( c - > protocol - > core - > sinks , idx ) ;
else
2009-01-15 20:07:13 +01:00
sink = pa_namereg_get ( c - > protocol - > core , name , PA_NAMEREG_SINK ) ;
2007-10-28 19:13:50 +00:00
break ;
case PA_COMMAND_SET_SOURCE_VOLUME :
if ( idx ! = PA_INVALID_INDEX )
source = pa_idxset_get_by_index ( c - > protocol - > core - > sources , idx ) ;
else
2009-01-15 20:07:13 +01:00
source = pa_namereg_get ( c - > protocol - > core , name , PA_NAMEREG_SOURCE ) ;
2007-10-28 19:13:50 +00:00
break ;
case PA_COMMAND_SET_SINK_INPUT_VOLUME :
si = pa_idxset_get_by_index ( c - > protocol - > core - > sink_inputs , idx ) ;
break ;
default :
pa_assert_not_reached ( ) ;
2004-08-15 13:15:51 +00:00
}
2006-02-22 18:54:21 +00:00
CHECK_VALIDITY ( c - > pstream , si | | sink | | source , tag , PA_ERR_NOENTITY ) ;
2004-08-15 13:15:51 +00:00
2009-08-14 19:31:05 +02:00
client_name = pa_strnull ( pa_proplist_gets ( c - > client - > proplist , PA_PROP_APPLICATION_PROCESS_BINARY ) ) ;
if ( sink ) {
pa_log ( " Client %s changes volume of sink %s. " , client_name , sink - > name ) ;
2009-06-17 03:45:14 +02:00
pa_sink_set_volume ( sink , & volume , TRUE , TRUE , TRUE , TRUE ) ;
2009-08-14 19:31:05 +02:00
} else if ( source ) {
pa_log ( " Client %s changes volume of sink %s. " , client_name , source - > name ) ;
2009-06-17 03:45:14 +02:00
pa_source_set_volume ( source , & volume , TRUE ) ;
2009-08-14 19:31:05 +02:00
} else if ( si ) {
pa_log ( " Client %s changes volume of sink %s. " ,
client_name ,
pa_strnull ( pa_proplist_gets ( si - > proplist , PA_PROP_MEDIA_NAME ) ) ) ;
2009-04-13 22:50:24 +02:00
pa_sink_input_set_volume ( si , & volume , TRUE , TRUE ) ;
2009-08-14 19:31:05 +02:00
}
2004-08-15 13:15:51 +00:00
pa_pstream_send_simple_ack ( c - > pstream , tag ) ;
2004-08-11 15:11:26 +00:00
}
2006-02-23 12:04:31 +00:00
static void command_set_mute (
2008-08-09 16:20:29 +02:00
pa_pdispatch * pd ,
2006-02-23 12:04:31 +00:00
uint32_t command ,
uint32_t tag ,
pa_tagstruct * t ,
void * userdata ) {
2007-01-04 13:43:45 +00:00
2008-08-04 18:58:29 +02:00
pa_native_connection * c = PA_NATIVE_CONNECTION ( userdata ) ;
2006-02-23 12:04:31 +00:00
uint32_t idx ;
2008-05-15 23:34:41 +00:00
pa_bool_t mute ;
2006-02-23 12:04:31 +00:00
pa_sink * sink = NULL ;
pa_source * source = NULL ;
2007-10-28 19:13:50 +00:00
pa_sink_input * si = NULL ;
2006-02-23 12:04:31 +00:00
const char * name = NULL ;
2007-10-28 19:13:50 +00:00
2008-08-04 18:58:29 +02:00
pa_native_connection_assert_ref ( c ) ;
2007-10-28 19:13:50 +00:00
pa_assert ( t ) ;
2006-02-23 12:04:31 +00:00
if ( pa_tagstruct_getu32 ( t , & idx ) < 0 | |
2007-10-28 19:13:50 +00:00
( command = = PA_COMMAND_SET_SINK_MUTE & & pa_tagstruct_gets ( t , & name ) < 0 ) | |
( command = = PA_COMMAND_SET_SOURCE_MUTE & & pa_tagstruct_gets ( t , & name ) < 0 ) | |
2006-02-23 12:04:31 +00:00
pa_tagstruct_get_boolean ( t , & mute ) | |
! pa_tagstruct_eof ( t ) ) {
protocol_error ( c ) ;
return ;
}
2007-01-04 13:43:45 +00:00
2006-02-23 12:04:31 +00:00
CHECK_VALIDITY ( c - > pstream , c - > authorized , tag , PA_ERR_ACCESS ) ;
2008-08-18 17:48:04 +02:00
CHECK_VALIDITY ( c - > pstream , ! name | | pa_namereg_is_valid_name ( name ) , tag , PA_ERR_INVALID ) ;
CHECK_VALIDITY ( c - > pstream , idx ! = PA_INVALID_INDEX | | name , tag , PA_ERR_INVALID ) ;
CHECK_VALIDITY ( c - > pstream , idx = = PA_INVALID_INDEX | | ! name , tag , PA_ERR_INVALID ) ;
CHECK_VALIDITY ( c - > pstream , ! name | | idx = = PA_INVALID_INDEX , tag , PA_ERR_INVALID ) ;
2006-02-23 12:04:31 +00:00
2007-10-28 19:13:50 +00:00
switch ( command ) {
case PA_COMMAND_SET_SINK_MUTE :
if ( idx ! = PA_INVALID_INDEX )
sink = pa_idxset_get_by_index ( c - > protocol - > core - > sinks , idx ) ;
else
2009-01-15 20:07:13 +01:00
sink = pa_namereg_get ( c - > protocol - > core , name , PA_NAMEREG_SINK ) ;
2007-10-28 19:13:50 +00:00
break ;
case PA_COMMAND_SET_SOURCE_MUTE :
if ( idx ! = PA_INVALID_INDEX )
source = pa_idxset_get_by_index ( c - > protocol - > core - > sources , idx ) ;
else
2009-01-15 20:07:13 +01:00
source = pa_namereg_get ( c - > protocol - > core , name , PA_NAMEREG_SOURCE ) ;
2007-10-28 19:13:50 +00:00
break ;
case PA_COMMAND_SET_SINK_INPUT_MUTE :
si = pa_idxset_get_by_index ( c - > protocol - > core - > sink_inputs , idx ) ;
break ;
default :
pa_assert_not_reached ( ) ;
2006-02-23 12:04:31 +00:00
}
2007-10-28 19:13:50 +00:00
CHECK_VALIDITY ( c - > pstream , si | | sink | | source , tag , PA_ERR_NOENTITY ) ;
2006-02-23 12:04:31 +00:00
if ( sink )
2009-06-17 03:45:14 +02:00
pa_sink_set_mute ( sink , mute , TRUE ) ;
2006-02-23 12:04:31 +00:00
else if ( source )
2009-06-17 03:45:14 +02:00
pa_source_set_mute ( source , mute , TRUE ) ;
2007-10-28 19:13:50 +00:00
else if ( si )
2009-01-27 23:35:55 +01:00
pa_sink_input_set_mute ( si , mute , TRUE ) ;
2006-02-23 12:04:31 +00:00
pa_pstream_send_simple_ack ( c - > pstream , tag ) ;
}
2008-08-09 16:20:29 +02:00
static void command_cork_playback_stream ( pa_pdispatch * pd , uint32_t command , uint32_t tag , pa_tagstruct * t , void * userdata ) {
2008-08-04 18:58:29 +02:00
pa_native_connection * c = PA_NATIVE_CONNECTION ( userdata ) ;
2006-01-11 01:17:39 +00:00
uint32_t idx ;
2008-05-15 23:34:41 +00:00
pa_bool_t b ;
2007-10-28 19:13:50 +00:00
playback_stream * s ;
2008-08-04 18:58:29 +02:00
pa_native_connection_assert_ref ( c ) ;
2007-10-28 19:13:50 +00:00
pa_assert ( t ) ;
2004-08-22 21:13:58 +00:00
2006-01-11 01:17:39 +00:00
if ( pa_tagstruct_getu32 ( t , & idx ) < 0 | |
2004-09-26 17:02:26 +00:00
pa_tagstruct_get_boolean ( t , & b ) < 0 | |
2004-08-22 21:13:58 +00:00
! pa_tagstruct_eof ( t ) ) {
protocol_error ( c ) ;
return ;
}
2006-02-22 18:54:21 +00:00
CHECK_VALIDITY ( c - > pstream , c - > authorized , tag , PA_ERR_ACCESS ) ;
CHECK_VALIDITY ( c - > pstream , idx ! = PA_INVALID_INDEX , tag , PA_ERR_INVALID ) ;
s = pa_idxset_get_by_index ( c - > output_streams , idx ) ;
CHECK_VALIDITY ( c - > pstream , s , tag , PA_ERR_NOENTITY ) ;
2007-10-28 19:13:50 +00:00
CHECK_VALIDITY ( c - > pstream , playback_stream_isinstance ( s ) , tag , PA_ERR_NOENTITY ) ;
2006-02-20 04:05:16 +00:00
2004-08-22 21:13:58 +00:00
pa_sink_input_cork ( s - > sink_input , b ) ;
2008-10-06 02:26:08 +02:00
if ( b )
s - > is_underrun = TRUE ;
2006-02-20 04:05:16 +00:00
pa_pstream_send_simple_ack ( c - > pstream , tag ) ;
2007-01-04 13:43:45 +00:00
}
2006-02-20 04:05:16 +00:00
2008-08-09 16:20:29 +02:00
static void command_trigger_or_flush_or_prebuf_playback_stream ( pa_pdispatch * pd , uint32_t command , uint32_t tag , pa_tagstruct * t , void * userdata ) {
2008-08-04 18:58:29 +02:00
pa_native_connection * c = PA_NATIVE_CONNECTION ( userdata ) ;
2006-02-20 04:05:16 +00:00
uint32_t idx ;
2007-10-28 19:13:50 +00:00
playback_stream * s ;
2007-01-04 13:43:45 +00:00
2008-08-04 18:58:29 +02:00
pa_native_connection_assert_ref ( c ) ;
2007-10-28 19:13:50 +00:00
pa_assert ( t ) ;
2004-08-22 21:13:58 +00:00
2006-01-11 01:17:39 +00:00
if ( pa_tagstruct_getu32 ( t , & idx ) < 0 | |
2004-08-22 21:13:58 +00:00
! pa_tagstruct_eof ( t ) ) {
protocol_error ( c ) ;
return ;
}
2006-02-22 18:54:21 +00:00
CHECK_VALIDITY ( c - > pstream , c - > authorized , tag , PA_ERR_ACCESS ) ;
CHECK_VALIDITY ( c - > pstream , idx ! = PA_INVALID_INDEX , tag , PA_ERR_INVALID ) ;
s = pa_idxset_get_by_index ( c - > output_streams , idx ) ;
CHECK_VALIDITY ( c - > pstream , s , tag , PA_ERR_NOENTITY ) ;
2007-10-28 19:13:50 +00:00
CHECK_VALIDITY ( c - > pstream , playback_stream_isinstance ( s ) , tag , PA_ERR_NOENTITY ) ;
2004-08-22 21:13:58 +00:00
2006-02-20 04:05:16 +00:00
switch ( command ) {
2007-10-28 19:13:50 +00:00
case PA_COMMAND_FLUSH_PLAYBACK_STREAM :
pa_asyncmsgq_send ( s - > sink_input - > sink - > asyncmsgq , PA_MSGOBJECT ( s - > sink_input ) , SINK_INPUT_MESSAGE_FLUSH , NULL , 0 , NULL ) ;
break ;
2006-02-20 04:05:16 +00:00
case PA_COMMAND_PREBUF_PLAYBACK_STREAM :
2007-10-28 19:13:50 +00:00
pa_asyncmsgq_send ( s - > sink_input - > sink - > asyncmsgq , PA_MSGOBJECT ( s - > sink_input ) , SINK_INPUT_MESSAGE_PREBUF_FORCE , NULL , 0 , NULL ) ;
2006-02-20 04:05:16 +00:00
break ;
2007-01-04 13:43:45 +00:00
2006-02-20 04:05:16 +00:00
case PA_COMMAND_TRIGGER_PLAYBACK_STREAM :
2007-10-28 19:13:50 +00:00
pa_asyncmsgq_send ( s - > sink_input - > sink - > asyncmsgq , PA_MSGOBJECT ( s - > sink_input ) , SINK_INPUT_MESSAGE_TRIGGER , NULL , 0 , NULL ) ;
2006-02-20 04:05:16 +00:00
break ;
2007-01-04 13:43:45 +00:00
2006-02-20 04:05:16 +00:00
default :
2007-10-28 19:13:50 +00:00
pa_assert_not_reached ( ) ;
2004-08-27 01:29:49 +00:00
}
2004-08-22 21:13:58 +00:00
pa_pstream_send_simple_ack ( c - > pstream , tag ) ;
}
2004-08-15 13:15:51 +00:00
2008-08-09 16:20:29 +02:00
static void command_cork_record_stream ( pa_pdispatch * pd , uint32_t command , uint32_t tag , pa_tagstruct * t , void * userdata ) {
2008-08-04 18:58:29 +02:00
pa_native_connection * c = PA_NATIVE_CONNECTION ( userdata ) ;
2006-01-11 01:17:39 +00:00
uint32_t idx ;
2007-10-28 19:13:50 +00:00
record_stream * s ;
2008-05-15 23:34:41 +00:00
pa_bool_t b ;
2007-10-28 19:13:50 +00:00
2008-08-04 18:58:29 +02:00
pa_native_connection_assert_ref ( c ) ;
2007-10-28 19:13:50 +00:00
pa_assert ( t ) ;
2004-09-26 17:02:26 +00:00
2006-01-11 01:17:39 +00:00
if ( pa_tagstruct_getu32 ( t , & idx ) < 0 | |
2004-09-26 17:02:26 +00:00
pa_tagstruct_get_boolean ( t , & b ) < 0 | |
! pa_tagstruct_eof ( t ) ) {
protocol_error ( c ) ;
return ;
}
2006-02-22 18:54:21 +00:00
CHECK_VALIDITY ( c - > pstream , c - > authorized , tag , PA_ERR_ACCESS ) ;
s = pa_idxset_get_by_index ( c - > record_streams , idx ) ;
CHECK_VALIDITY ( c - > pstream , s , tag , PA_ERR_NOENTITY ) ;
2004-09-26 17:02:26 +00:00
pa_source_output_cork ( s - > source_output , b ) ;
2006-02-20 04:05:16 +00:00
pa_memblockq_prebuf_force ( s - > memblockq ) ;
2004-09-26 17:02:26 +00:00
pa_pstream_send_simple_ack ( c - > pstream , tag ) ;
}
2008-08-09 16:20:29 +02:00
static void command_flush_record_stream ( pa_pdispatch * pd , uint32_t command , uint32_t tag , pa_tagstruct * t , void * userdata ) {
2008-08-04 18:58:29 +02:00
pa_native_connection * c = PA_NATIVE_CONNECTION ( userdata ) ;
2006-01-11 01:17:39 +00:00
uint32_t idx ;
2007-10-28 19:13:50 +00:00
record_stream * s ;
2008-08-04 18:58:29 +02:00
pa_native_connection_assert_ref ( c ) ;
2007-10-28 19:13:50 +00:00
pa_assert ( t ) ;
2004-09-26 17:02:26 +00:00
2006-01-11 01:17:39 +00:00
if ( pa_tagstruct_getu32 ( t , & idx ) < 0 | |
2004-09-26 17:02:26 +00:00
! pa_tagstruct_eof ( t ) ) {
protocol_error ( c ) ;
return ;
}
2006-02-22 18:54:21 +00:00
CHECK_VALIDITY ( c - > pstream , c - > authorized , tag , PA_ERR_ACCESS ) ;
s = pa_idxset_get_by_index ( c - > record_streams , idx ) ;
CHECK_VALIDITY ( c - > pstream , s , tag , PA_ERR_NOENTITY ) ;
2004-09-26 17:02:26 +00:00
2008-06-26 00:39:31 +02:00
pa_memblockq_flush_read ( s - > memblockq ) ;
2004-09-26 17:02:26 +00:00
pa_pstream_send_simple_ack ( c - > pstream , tag ) ;
}
2007-11-21 01:30:40 +00:00
static void command_set_stream_buffer_attr ( pa_pdispatch * pd , uint32_t command , uint32_t tag , pa_tagstruct * t , void * userdata ) {
2008-08-04 18:58:29 +02:00
pa_native_connection * c = PA_NATIVE_CONNECTION ( userdata ) ;
2007-11-21 01:30:40 +00:00
uint32_t idx ;
2009-03-30 18:46:12 +02:00
pa_buffer_attr a ;
2007-11-21 01:30:40 +00:00
pa_tagstruct * reply ;
2008-08-04 18:58:29 +02:00
pa_native_connection_assert_ref ( c ) ;
2007-11-21 01:30:40 +00:00
pa_assert ( t ) ;
2009-03-30 18:46:12 +02:00
memset ( & a , 0 , sizeof ( a ) ) ;
2007-11-21 01:30:40 +00:00
if ( pa_tagstruct_getu32 ( t , & idx ) < 0 ) {
protocol_error ( c ) ;
return ;
}
CHECK_VALIDITY ( c - > pstream , c - > authorized , tag , PA_ERR_ACCESS ) ;
if ( command = = PA_COMMAND_SET_PLAYBACK_STREAM_BUFFER_ATTR ) {
playback_stream * s ;
2008-09-03 18:31:46 +02:00
pa_bool_t adjust_latency = FALSE , early_requests = FALSE ;
2007-11-21 01:30:40 +00:00
s = pa_idxset_get_by_index ( c - > output_streams , idx ) ;
CHECK_VALIDITY ( c - > pstream , s , tag , PA_ERR_NOENTITY ) ;
CHECK_VALIDITY ( c - > pstream , playback_stream_isinstance ( s ) , tag , PA_ERR_NOENTITY ) ;
if ( pa_tagstruct_get (
t ,
2009-03-30 18:46:12 +02:00
PA_TAG_U32 , & a . maxlength ,
PA_TAG_U32 , & a . tlength ,
PA_TAG_U32 , & a . prebuf ,
PA_TAG_U32 , & a . minreq ,
2007-11-21 01:30:40 +00:00
PA_TAG_INVALID ) < 0 | |
2008-05-15 23:34:41 +00:00
( c - > version > = 13 & & pa_tagstruct_get_boolean ( t , & adjust_latency ) < 0 ) | |
2008-09-03 18:31:46 +02:00
( c - > version > = 14 & & pa_tagstruct_get_boolean ( t , & early_requests ) < 0 ) | |
2007-11-21 01:30:40 +00:00
! pa_tagstruct_eof ( t ) ) {
protocol_error ( c ) ;
return ;
}
2009-03-30 18:46:12 +02:00
s - > adjust_latency = adjust_latency ;
s - > early_requests = early_requests ;
s - > buffer_attr = a ;
fix_playback_buffer_attr ( s ) ;
pa_assert_se ( pa_asyncmsgq_send ( s - > sink_input - > sink - > asyncmsgq , PA_MSGOBJECT ( s - > sink_input ) , SINK_INPUT_MESSAGE_UPDATE_BUFFER_ATTR , NULL , 0 , NULL ) = = 0 ) ;
2007-11-21 01:30:40 +00:00
reply = reply_new ( tag ) ;
2009-03-30 18:46:12 +02:00
pa_tagstruct_putu32 ( reply , s - > buffer_attr . maxlength ) ;
pa_tagstruct_putu32 ( reply , s - > buffer_attr . tlength ) ;
pa_tagstruct_putu32 ( reply , s - > buffer_attr . prebuf ) ;
pa_tagstruct_putu32 ( reply , s - > buffer_attr . minreq ) ;
2008-05-15 23:34:41 +00:00
if ( c - > version > = 13 )
2009-04-05 02:59:02 +02:00
pa_tagstruct_put_usec ( reply , s - > configured_sink_latency ) ;
2007-11-21 01:30:40 +00:00
} else {
record_stream * s ;
2008-09-03 18:31:46 +02:00
pa_bool_t adjust_latency = FALSE , early_requests = FALSE ;
2007-11-21 01:30:40 +00:00
pa_assert ( command = = PA_COMMAND_SET_RECORD_STREAM_BUFFER_ATTR ) ;
s = pa_idxset_get_by_index ( c - > record_streams , idx ) ;
CHECK_VALIDITY ( c - > pstream , s , tag , PA_ERR_NOENTITY ) ;
if ( pa_tagstruct_get (
t ,
2009-03-30 18:46:12 +02:00
PA_TAG_U32 , & a . maxlength ,
PA_TAG_U32 , & a . fragsize ,
2007-11-21 01:30:40 +00:00
PA_TAG_INVALID ) < 0 | |
2008-05-15 23:34:41 +00:00
( c - > version > = 13 & & pa_tagstruct_get_boolean ( t , & adjust_latency ) < 0 ) | |
2008-09-03 18:31:46 +02:00
( c - > version > = 14 & & pa_tagstruct_get_boolean ( t , & early_requests ) < 0 ) | |
2007-11-21 01:30:40 +00:00
! pa_tagstruct_eof ( t ) ) {
protocol_error ( c ) ;
return ;
}
2009-03-30 18:46:12 +02:00
s - > adjust_latency = adjust_latency ;
s - > early_requests = early_requests ;
s - > buffer_attr = a ;
fix_record_buffer_attr_pre ( s ) ;
pa_memblockq_set_maxlength ( s - > memblockq , s - > buffer_attr . maxlength ) ;
pa_memblockq_get_attr ( s - > memblockq , & s - > buffer_attr ) ;
fix_record_buffer_attr_post ( s ) ;
2007-11-21 01:30:40 +00:00
reply = reply_new ( tag ) ;
2009-03-30 18:46:12 +02:00
pa_tagstruct_putu32 ( reply , s - > buffer_attr . maxlength ) ;
pa_tagstruct_putu32 ( reply , s - > buffer_attr . fragsize ) ;
2008-05-15 23:34:41 +00:00
if ( c - > version > = 13 )
2009-04-05 02:59:02 +02:00
pa_tagstruct_put_usec ( reply , s - > configured_source_latency ) ;
2007-11-21 01:30:40 +00:00
}
pa_pstream_send_tagstruct ( c - > pstream , reply ) ;
}
static void command_update_stream_sample_rate ( pa_pdispatch * pd , uint32_t command , uint32_t tag , pa_tagstruct * t , void * userdata ) {
2008-08-04 18:58:29 +02:00
pa_native_connection * c = PA_NATIVE_CONNECTION ( userdata ) ;
2007-11-21 01:30:40 +00:00
uint32_t idx ;
uint32_t rate ;
2008-08-04 18:58:29 +02:00
pa_native_connection_assert_ref ( c ) ;
2007-11-21 01:30:40 +00:00
pa_assert ( t ) ;
if ( pa_tagstruct_getu32 ( t , & idx ) < 0 | |
pa_tagstruct_getu32 ( t , & rate ) < 0 | |
! pa_tagstruct_eof ( t ) ) {
protocol_error ( c ) ;
return ;
}
CHECK_VALIDITY ( c - > pstream , c - > authorized , tag , PA_ERR_ACCESS ) ;
CHECK_VALIDITY ( c - > pstream , rate > 0 & & rate < = PA_RATE_MAX , tag , PA_ERR_INVALID ) ;
if ( command = = PA_COMMAND_UPDATE_PLAYBACK_STREAM_SAMPLE_RATE ) {
playback_stream * s ;
s = pa_idxset_get_by_index ( c - > output_streams , idx ) ;
CHECK_VALIDITY ( c - > pstream , s , tag , PA_ERR_NOENTITY ) ;
CHECK_VALIDITY ( c - > pstream , playback_stream_isinstance ( s ) , tag , PA_ERR_NOENTITY ) ;
pa_sink_input_set_rate ( s - > sink_input , rate ) ;
} else {
record_stream * s ;
pa_assert ( command = = PA_COMMAND_UPDATE_RECORD_STREAM_SAMPLE_RATE ) ;
s = pa_idxset_get_by_index ( c - > record_streams , idx ) ;
CHECK_VALIDITY ( c - > pstream , s , tag , PA_ERR_NOENTITY ) ;
pa_source_output_set_rate ( s - > source_output , rate ) ;
}
pa_pstream_send_simple_ack ( c - > pstream , tag ) ;
}
2008-05-15 23:34:41 +00:00
static void command_update_proplist ( pa_pdispatch * pd , uint32_t command , uint32_t tag , pa_tagstruct * t , void * userdata ) {
2008-08-04 18:58:29 +02:00
pa_native_connection * c = PA_NATIVE_CONNECTION ( userdata ) ;
2008-05-15 23:34:41 +00:00
uint32_t idx ;
uint32_t mode ;
pa_proplist * p ;
2008-08-04 18:58:29 +02:00
pa_native_connection_assert_ref ( c ) ;
2008-05-15 23:34:41 +00:00
pa_assert ( t ) ;
CHECK_VALIDITY ( c - > pstream , c - > authorized , tag , PA_ERR_ACCESS ) ;
p = pa_proplist_new ( ) ;
if ( command = = PA_COMMAND_UPDATE_CLIENT_PROPLIST ) {
if ( pa_tagstruct_getu32 ( t , & mode ) < 0 | |
pa_tagstruct_get_proplist ( t , p ) < 0 | |
! pa_tagstruct_eof ( t ) ) {
protocol_error ( c ) ;
pa_proplist_free ( p ) ;
return ;
}
} else {
if ( pa_tagstruct_getu32 ( t , & idx ) < 0 | |
pa_tagstruct_getu32 ( t , & mode ) < 0 | |
pa_tagstruct_get_proplist ( t , p ) < 0 | |
! pa_tagstruct_eof ( t ) ) {
protocol_error ( c ) ;
pa_proplist_free ( p ) ;
return ;
}
}
2009-02-18 20:00:57 +02:00
if ( ! ( mode = = PA_UPDATE_SET | | mode = = PA_UPDATE_MERGE | | mode = = PA_UPDATE_REPLACE ) ) {
pa_proplist_free ( p ) ;
CHECK_VALIDITY ( c - > pstream , FALSE , tag , PA_ERR_INVALID ) ;
}
2008-05-15 23:34:41 +00:00
if ( command = = PA_COMMAND_UPDATE_PLAYBACK_STREAM_PROPLIST ) {
playback_stream * s ;
s = pa_idxset_get_by_index ( c - > output_streams , idx ) ;
2009-02-18 20:00:57 +02:00
if ( ! s | | ! playback_stream_isinstance ( s ) ) {
pa_proplist_free ( p ) ;
CHECK_VALIDITY ( c - > pstream , FALSE , tag , PA_ERR_NOENTITY ) ;
}
2009-02-05 04:10:08 +01:00
pa_sink_input_update_proplist ( s - > sink_input , mode , p ) ;
2008-05-15 23:34:41 +00:00
} else if ( command = = PA_COMMAND_UPDATE_RECORD_STREAM_PROPLIST ) {
record_stream * s ;
2009-02-18 20:00:57 +02:00
if ( ! ( s = pa_idxset_get_by_index ( c - > record_streams , idx ) ) ) {
pa_proplist_free ( p ) ;
CHECK_VALIDITY ( c - > pstream , FALSE , tag , PA_ERR_NOENTITY ) ;
}
2009-02-05 04:10:08 +01:00
pa_source_output_update_proplist ( s - > source_output , mode , p ) ;
2009-02-18 20:00:57 +02:00
2008-05-15 23:34:41 +00:00
} else {
pa_assert ( command = = PA_COMMAND_UPDATE_CLIENT_PROPLIST ) ;
2009-02-05 04:10:08 +01:00
pa_client_update_proplist ( c - > client , mode , p ) ;
2008-05-15 23:34:41 +00:00
}
pa_pstream_send_simple_ack ( c - > pstream , tag ) ;
2009-02-18 20:00:57 +02:00
pa_proplist_free ( p ) ;
2008-05-15 23:34:41 +00:00
}
static void command_remove_proplist ( pa_pdispatch * pd , uint32_t command , uint32_t tag , pa_tagstruct * t , void * userdata ) {
2008-08-04 18:58:29 +02:00
pa_native_connection * c = PA_NATIVE_CONNECTION ( userdata ) ;
2008-05-15 23:34:41 +00:00
uint32_t idx ;
unsigned changed = 0 ;
pa_proplist * p ;
pa_strlist * l = NULL ;
2008-08-04 18:58:29 +02:00
pa_native_connection_assert_ref ( c ) ;
2008-05-15 23:34:41 +00:00
pa_assert ( t ) ;
CHECK_VALIDITY ( c - > pstream , c - > authorized , tag , PA_ERR_ACCESS ) ;
if ( command ! = PA_COMMAND_REMOVE_CLIENT_PROPLIST ) {
if ( pa_tagstruct_getu32 ( t , & idx ) < 0 ) {
protocol_error ( c ) ;
return ;
}
}
if ( command = = PA_COMMAND_REMOVE_PLAYBACK_STREAM_PROPLIST ) {
playback_stream * s ;
s = pa_idxset_get_by_index ( c - > output_streams , idx ) ;
CHECK_VALIDITY ( c - > pstream , s , tag , PA_ERR_NOENTITY ) ;
CHECK_VALIDITY ( c - > pstream , playback_stream_isinstance ( s ) , tag , PA_ERR_NOENTITY ) ;
p = s - > sink_input - > proplist ;
} else if ( command = = PA_COMMAND_REMOVE_RECORD_STREAM_PROPLIST ) {
record_stream * s ;
s = pa_idxset_get_by_index ( c - > record_streams , idx ) ;
CHECK_VALIDITY ( c - > pstream , s , tag , PA_ERR_NOENTITY ) ;
p = s - > source_output - > proplist ;
} else {
pa_assert ( command = = PA_COMMAND_REMOVE_CLIENT_PROPLIST ) ;
p = c - > client - > proplist ;
}
for ( ; ; ) {
const char * k ;
if ( pa_tagstruct_gets ( t , & k ) < 0 ) {
protocol_error ( c ) ;
pa_strlist_free ( l ) ;
return ;
}
if ( ! k )
break ;
l = pa_strlist_prepend ( l , k ) ;
}
if ( ! pa_tagstruct_eof ( t ) ) {
protocol_error ( c ) ;
pa_strlist_free ( l ) ;
return ;
}
for ( ; ; ) {
char * z ;
l = pa_strlist_pop ( l , & z ) ;
if ( ! z )
break ;
2008-08-19 22:39:54 +02:00
changed + = ( unsigned ) ( pa_proplist_unset ( p , z ) > = 0 ) ;
2008-05-15 23:34:41 +00:00
pa_xfree ( z ) ;
}
pa_pstream_send_simple_ack ( c - > pstream , tag ) ;
if ( changed ) {
if ( command = = PA_COMMAND_REMOVE_PLAYBACK_STREAM_PROPLIST ) {
playback_stream * s ;
s = pa_idxset_get_by_index ( c - > output_streams , idx ) ;
pa_subscription_post ( c - > protocol - > core , PA_SUBSCRIPTION_EVENT_SINK_INPUT | PA_SUBSCRIPTION_EVENT_CHANGE , s - > sink_input - > index ) ;
} else if ( command = = PA_COMMAND_REMOVE_RECORD_STREAM_PROPLIST ) {
record_stream * s ;
s = pa_idxset_get_by_index ( c - > record_streams , idx ) ;
pa_subscription_post ( c - > protocol - > core , PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT | PA_SUBSCRIPTION_EVENT_CHANGE , s - > source_output - > index ) ;
} else {
pa_assert ( command = = PA_COMMAND_REMOVE_CLIENT_PROPLIST ) ;
pa_subscription_post ( c - > protocol - > core , PA_SUBSCRIPTION_EVENT_CLIENT | PA_SUBSCRIPTION_EVENT_CHANGE , c - > client - > index ) ;
}
}
}
2008-08-09 16:20:29 +02:00
static void command_set_default_sink_or_source ( pa_pdispatch * pd , uint32_t command , uint32_t tag , pa_tagstruct * t , void * userdata ) {
2008-08-04 18:58:29 +02:00
pa_native_connection * c = PA_NATIVE_CONNECTION ( userdata ) ;
2004-09-06 21:55:09 +00:00
const char * s ;
2007-10-28 19:13:50 +00:00
2008-08-04 18:58:29 +02:00
pa_native_connection_assert_ref ( c ) ;
2007-10-28 19:13:50 +00:00
pa_assert ( t ) ;
2004-09-06 21:55:09 +00:00
2006-02-22 18:54:21 +00:00
if ( pa_tagstruct_gets ( t , & s ) < 0 | |
2004-09-06 21:55:09 +00:00
! pa_tagstruct_eof ( t ) ) {
protocol_error ( c ) ;
return ;
}
2006-02-22 18:54:21 +00:00
CHECK_VALIDITY ( c - > pstream , c - > authorized , tag , PA_ERR_ACCESS ) ;
2008-08-18 17:48:04 +02:00
CHECK_VALIDITY ( c - > pstream , ! s | | pa_namereg_is_valid_name ( s ) , tag , PA_ERR_INVALID ) ;
2004-09-06 21:55:09 +00:00
2009-01-28 01:46:27 +01:00
if ( command = = PA_COMMAND_SET_DEFAULT_SOURCE ) {
pa_source * source ;
source = pa_namereg_get ( c - > protocol - > core , s , PA_NAMEREG_SOURCE ) ;
CHECK_VALIDITY ( c - > pstream , source , tag , PA_ERR_NOENTITY ) ;
pa_namereg_set_default_source ( c - > protocol - > core , source ) ;
} else {
pa_sink * sink ;
pa_assert ( command = = PA_COMMAND_SET_DEFAULT_SINK ) ;
sink = pa_namereg_get ( c - > protocol - > core , s , PA_NAMEREG_SINK ) ;
CHECK_VALIDITY ( c - > pstream , sink , tag , PA_ERR_NOENTITY ) ;
pa_namereg_set_default_sink ( c - > protocol - > core , sink ) ;
}
2004-09-06 21:55:09 +00:00
pa_pstream_send_simple_ack ( c - > pstream , tag ) ;
}
2008-08-09 16:20:29 +02:00
static void command_set_stream_name ( pa_pdispatch * pd , uint32_t command , uint32_t tag , pa_tagstruct * t , void * userdata ) {
2008-08-04 18:58:29 +02:00
pa_native_connection * c = PA_NATIVE_CONNECTION ( userdata ) ;
2006-01-11 01:17:39 +00:00
uint32_t idx ;
2004-09-15 19:16:57 +00:00
const char * name ;
2007-10-28 19:13:50 +00:00
2008-08-04 18:58:29 +02:00
pa_native_connection_assert_ref ( c ) ;
2007-10-28 19:13:50 +00:00
pa_assert ( t ) ;
2004-09-15 19:16:57 +00:00
2006-01-11 01:17:39 +00:00
if ( pa_tagstruct_getu32 ( t , & idx ) < 0 | |
2006-02-22 18:54:21 +00:00
pa_tagstruct_gets ( t , & name ) < 0 | |
2004-09-15 19:16:57 +00:00
! pa_tagstruct_eof ( t ) ) {
protocol_error ( c ) ;
return ;
}
2007-01-04 13:43:45 +00:00
2006-02-22 18:54:21 +00:00
CHECK_VALIDITY ( c - > pstream , c - > authorized , tag , PA_ERR_ACCESS ) ;
2006-05-14 16:02:40 +00:00
CHECK_VALIDITY ( c - > pstream , name & & pa_utf8_valid ( name ) , tag , PA_ERR_INVALID ) ;
2004-09-15 19:16:57 +00:00
if ( command = = PA_COMMAND_SET_PLAYBACK_STREAM_NAME ) {
2007-10-28 19:13:50 +00:00
playback_stream * s ;
2007-01-04 13:43:45 +00:00
2006-02-22 18:54:21 +00:00
s = pa_idxset_get_by_index ( c - > output_streams , idx ) ;
CHECK_VALIDITY ( c - > pstream , s , tag , PA_ERR_NOENTITY ) ;
2007-10-28 19:13:50 +00:00
CHECK_VALIDITY ( c - > pstream , playback_stream_isinstance ( s ) , tag , PA_ERR_NOENTITY ) ;
2004-09-15 19:16:57 +00:00
pa_sink_input_set_name ( s - > sink_input , name ) ;
2007-01-04 13:43:45 +00:00
2004-09-15 19:16:57 +00:00
} else {
2007-10-28 19:13:50 +00:00
record_stream * s ;
2007-11-21 01:30:40 +00:00
pa_assert ( command = = PA_COMMAND_SET_RECORD_STREAM_NAME ) ;
2007-01-04 13:43:45 +00:00
2006-02-22 18:54:21 +00:00
s = pa_idxset_get_by_index ( c - > record_streams , idx ) ;
CHECK_VALIDITY ( c - > pstream , s , tag , PA_ERR_NOENTITY ) ;
2004-09-15 19:16:57 +00:00
pa_source_output_set_name ( s - > source_output , name ) ;
}
pa_pstream_send_simple_ack ( c - > pstream , tag ) ;
}
2008-08-09 16:20:29 +02:00
static void command_kill ( pa_pdispatch * pd , uint32_t command , uint32_t tag , pa_tagstruct * t , void * userdata ) {
2008-08-04 18:58:29 +02:00
pa_native_connection * c = PA_NATIVE_CONNECTION ( userdata ) ;
2006-01-11 01:17:39 +00:00
uint32_t idx ;
2007-10-28 19:13:50 +00:00
2008-08-04 18:58:29 +02:00
pa_native_connection_assert_ref ( c ) ;
2007-10-28 19:13:50 +00:00
pa_assert ( t ) ;
2004-09-15 19:16:57 +00:00
2006-01-11 01:17:39 +00:00
if ( pa_tagstruct_getu32 ( t , & idx ) < 0 | |
2004-09-15 19:16:57 +00:00
! pa_tagstruct_eof ( t ) ) {
protocol_error ( c ) ;
return ;
}
2006-02-22 18:54:21 +00:00
CHECK_VALIDITY ( c - > pstream , c - > authorized , tag , PA_ERR_ACCESS ) ;
2004-09-15 19:16:57 +00:00
if ( command = = PA_COMMAND_KILL_CLIENT ) {
2006-01-11 01:17:39 +00:00
pa_client * client ;
2007-01-04 13:43:45 +00:00
2006-02-22 18:54:21 +00:00
client = pa_idxset_get_by_index ( c - > protocol - > core - > clients , idx ) ;
CHECK_VALIDITY ( c - > pstream , client , tag , PA_ERR_NOENTITY ) ;
2007-10-28 19:13:50 +00:00
2008-08-04 18:58:29 +02:00
pa_native_connection_ref ( c ) ;
2004-09-15 19:16:57 +00:00
pa_client_kill ( client ) ;
2007-01-04 13:43:45 +00:00
2004-09-15 19:16:57 +00:00
} else if ( command = = PA_COMMAND_KILL_SINK_INPUT ) {
2006-01-11 01:17:39 +00:00
pa_sink_input * s ;
2007-01-04 13:43:45 +00:00
2006-02-22 18:54:21 +00:00
s = pa_idxset_get_by_index ( c - > protocol - > core - > sink_inputs , idx ) ;
CHECK_VALIDITY ( c - > pstream , s , tag , PA_ERR_NOENTITY ) ;
2004-09-15 19:16:57 +00:00
2008-08-04 18:58:29 +02:00
pa_native_connection_ref ( c ) ;
2004-09-15 19:16:57 +00:00
pa_sink_input_kill ( s ) ;
} else {
2006-01-11 01:17:39 +00:00
pa_source_output * s ;
2004-09-15 19:16:57 +00:00
2007-10-28 19:13:50 +00:00
pa_assert ( command = = PA_COMMAND_KILL_SOURCE_OUTPUT ) ;
2007-01-04 13:43:45 +00:00
2006-02-22 18:54:21 +00:00
s = pa_idxset_get_by_index ( c - > protocol - > core - > source_outputs , idx ) ;
CHECK_VALIDITY ( c - > pstream , s , tag , PA_ERR_NOENTITY ) ;
2004-09-15 19:16:57 +00:00
2008-08-04 18:58:29 +02:00
pa_native_connection_ref ( c ) ;
2004-09-15 19:16:57 +00:00
pa_source_output_kill ( s ) ;
}
pa_pstream_send_simple_ack ( c - > pstream , tag ) ;
2008-08-04 18:58:29 +02:00
pa_native_connection_unref ( c ) ;
2004-09-15 19:16:57 +00:00
}
2008-08-09 16:20:29 +02:00
static void command_load_module ( pa_pdispatch * pd , uint32_t command , uint32_t tag , pa_tagstruct * t , void * userdata ) {
2008-08-04 18:58:29 +02:00
pa_native_connection * c = PA_NATIVE_CONNECTION ( userdata ) ;
2006-01-11 01:17:39 +00:00
pa_module * m ;
2004-09-15 19:16:57 +00:00
const char * name , * argument ;
2006-01-11 01:17:39 +00:00
pa_tagstruct * reply ;
2007-10-28 19:13:50 +00:00
2008-08-04 18:58:29 +02:00
pa_native_connection_assert_ref ( c ) ;
2007-10-28 19:13:50 +00:00
pa_assert ( t ) ;
2004-09-15 19:16:57 +00:00
2006-02-22 18:54:21 +00:00
if ( pa_tagstruct_gets ( t , & name ) < 0 | |
2004-09-15 19:16:57 +00:00
pa_tagstruct_gets ( t , & argument ) < 0 | |
! pa_tagstruct_eof ( t ) ) {
protocol_error ( c ) ;
return ;
}
2006-02-22 18:54:21 +00:00
CHECK_VALIDITY ( c - > pstream , c - > authorized , tag , PA_ERR_ACCESS ) ;
2006-05-14 16:02:40 +00:00
CHECK_VALIDITY ( c - > pstream , name & & * name & & pa_utf8_valid ( name ) & & ! strchr ( name , ' / ' ) , tag , PA_ERR_INVALID ) ;
CHECK_VALIDITY ( c - > pstream , ! argument | | pa_utf8_valid ( argument ) , tag , PA_ERR_INVALID ) ;
2007-01-04 13:43:45 +00:00
2004-09-15 19:16:57 +00:00
if ( ! ( m = pa_module_load ( c - > protocol - > core , name , argument ) ) ) {
2006-02-20 04:05:16 +00:00
pa_pstream_send_error ( c - > pstream , tag , PA_ERR_MODINITFAILED ) ;
2004-09-15 19:16:57 +00:00
return ;
}
2006-02-22 18:54:21 +00:00
reply = reply_new ( tag ) ;
2004-09-15 19:16:57 +00:00
pa_tagstruct_putu32 ( reply , m - > index ) ;
pa_pstream_send_tagstruct ( c - > pstream , reply ) ;
}
2008-08-09 16:20:29 +02:00
static void command_unload_module ( pa_pdispatch * pd , uint32_t command , uint32_t tag , pa_tagstruct * t , void * userdata ) {
2008-08-04 18:58:29 +02:00
pa_native_connection * c = PA_NATIVE_CONNECTION ( userdata ) ;
2006-01-11 01:17:39 +00:00
uint32_t idx ;
pa_module * m ;
2007-10-28 19:13:50 +00:00
2008-08-04 18:58:29 +02:00
pa_native_connection_assert_ref ( c ) ;
2007-10-28 19:13:50 +00:00
pa_assert ( t ) ;
2004-09-15 19:16:57 +00:00
2006-01-11 01:17:39 +00:00
if ( pa_tagstruct_getu32 ( t , & idx ) < 0 | |
2004-09-15 19:16:57 +00:00
! pa_tagstruct_eof ( t ) ) {
protocol_error ( c ) ;
return ;
}
2007-01-04 13:43:45 +00:00
2006-02-22 18:54:21 +00:00
CHECK_VALIDITY ( c - > pstream , c - > authorized , tag , PA_ERR_ACCESS ) ;
m = pa_idxset_get_by_index ( c - > protocol - > core - > modules , idx ) ;
CHECK_VALIDITY ( c - > pstream , m , tag , PA_ERR_NOENTITY ) ;
2004-09-15 19:16:57 +00:00
2008-08-05 23:56:25 +02:00
pa_module_unload_request ( m , FALSE ) ;
2004-09-15 19:16:57 +00:00
pa_pstream_send_simple_ack ( c - > pstream , tag ) ;
}
2006-07-31 21:54:46 +00:00
static void command_move_stream ( pa_pdispatch * pd , uint32_t command , uint32_t tag , pa_tagstruct * t , void * userdata ) {
2008-08-04 18:58:29 +02:00
pa_native_connection * c = PA_NATIVE_CONNECTION ( userdata ) ;
2006-07-31 21:54:46 +00:00
uint32_t idx = PA_INVALID_INDEX , idx_device = PA_INVALID_INDEX ;
2008-08-18 17:48:04 +02:00
const char * name_device = NULL ;
2007-01-04 13:43:45 +00:00
2008-08-04 18:58:29 +02:00
pa_native_connection_assert_ref ( c ) ;
2007-10-28 19:13:50 +00:00
pa_assert ( t ) ;
2006-07-31 21:54:46 +00:00
if ( pa_tagstruct_getu32 ( t , & idx ) < 0 | |
pa_tagstruct_getu32 ( t , & idx_device ) < 0 | |
2008-08-18 17:48:04 +02:00
pa_tagstruct_gets ( t , & name_device ) < 0 | |
2006-07-31 21:54:46 +00:00
! pa_tagstruct_eof ( t ) ) {
protocol_error ( c ) ;
return ;
}
2007-01-04 13:43:45 +00:00
2006-07-31 21:54:46 +00:00
CHECK_VALIDITY ( c - > pstream , c - > authorized , tag , PA_ERR_ACCESS ) ;
CHECK_VALIDITY ( c - > pstream , idx ! = PA_INVALID_INDEX , tag , PA_ERR_INVALID ) ;
2008-08-18 17:48:04 +02:00
CHECK_VALIDITY ( c - > pstream , ! name_device | | pa_namereg_is_valid_name ( name_device ) , tag , PA_ERR_INVALID ) ;
CHECK_VALIDITY ( c - > pstream , idx_device ! = PA_INVALID_INDEX | | name_device , tag , PA_ERR_INVALID ) ;
CHECK_VALIDITY ( c - > pstream , idx_device = = PA_INVALID_INDEX | | ! name_device , tag , PA_ERR_INVALID ) ;
CHECK_VALIDITY ( c - > pstream , ! name_device | | idx_device = = PA_INVALID_INDEX , tag , PA_ERR_INVALID ) ;
2006-07-31 21:54:46 +00:00
2006-08-03 22:32:23 +00:00
if ( command = = PA_COMMAND_MOVE_SINK_INPUT ) {
pa_sink_input * si = NULL ;
pa_sink * sink = NULL ;
2006-07-31 21:54:46 +00:00
2006-08-03 22:32:23 +00:00
si = pa_idxset_get_by_index ( c - > protocol - > core - > sink_inputs , idx ) ;
2007-01-04 13:43:45 +00:00
2006-08-03 22:32:23 +00:00
if ( idx_device ! = PA_INVALID_INDEX )
sink = pa_idxset_get_by_index ( c - > protocol - > core - > sinks , idx_device ) ;
else
2009-01-15 20:07:13 +01:00
sink = pa_namereg_get ( c - > protocol - > core , name_device , PA_NAMEREG_SINK ) ;
2006-08-03 22:32:23 +00:00
CHECK_VALIDITY ( c - > pstream , si & & sink , tag , PA_ERR_NOENTITY ) ;
2009-01-27 23:35:55 +01:00
if ( pa_sink_input_move_to ( si , sink , TRUE ) < 0 ) {
2006-08-03 22:32:23 +00:00
pa_pstream_send_error ( c - > pstream , tag , PA_ERR_INVALID ) ;
return ;
}
} else {
pa_source_output * so = NULL ;
pa_source * source ;
2007-10-28 19:13:50 +00:00
pa_assert ( command = = PA_COMMAND_MOVE_SOURCE_OUTPUT ) ;
2006-08-03 22:32:23 +00:00
so = pa_idxset_get_by_index ( c - > protocol - > core - > source_outputs , idx ) ;
2007-01-04 13:43:45 +00:00
2006-08-03 22:32:23 +00:00
if ( idx_device ! = PA_INVALID_INDEX )
source = pa_idxset_get_by_index ( c - > protocol - > core - > sources , idx_device ) ;
else
2009-01-15 20:07:13 +01:00
source = pa_namereg_get ( c - > protocol - > core , name_device , PA_NAMEREG_SOURCE ) ;
2006-08-03 22:32:23 +00:00
CHECK_VALIDITY ( c - > pstream , so & & source , tag , PA_ERR_NOENTITY ) ;
2006-07-31 21:54:46 +00:00
2009-01-27 23:35:55 +01:00
if ( pa_source_output_move_to ( so , source , TRUE ) < 0 ) {
2006-08-03 22:32:23 +00:00
pa_pstream_send_error ( c - > pstream , tag , PA_ERR_INVALID ) ;
return ;
}
}
2007-01-04 13:43:45 +00:00
2006-07-31 21:54:46 +00:00
pa_pstream_send_simple_ack ( c - > pstream , tag ) ;
2007-10-28 19:13:50 +00:00
}
static void command_suspend ( pa_pdispatch * pd , uint32_t command , uint32_t tag , pa_tagstruct * t , void * userdata ) {
2008-08-04 18:58:29 +02:00
pa_native_connection * c = PA_NATIVE_CONNECTION ( userdata ) ;
2007-10-28 19:13:50 +00:00
uint32_t idx = PA_INVALID_INDEX ;
const char * name = NULL ;
2008-05-15 23:34:41 +00:00
pa_bool_t b ;
2007-10-28 19:13:50 +00:00
2008-08-04 18:58:29 +02:00
pa_native_connection_assert_ref ( c ) ;
2007-10-28 19:13:50 +00:00
pa_assert ( t ) ;
if ( pa_tagstruct_getu32 ( t , & idx ) < 0 | |
pa_tagstruct_gets ( t , & name ) < 0 | |
pa_tagstruct_get_boolean ( t , & b ) < 0 | |
! pa_tagstruct_eof ( t ) ) {
protocol_error ( c ) ;
return ;
}
CHECK_VALIDITY ( c - > pstream , c - > authorized , tag , PA_ERR_ACCESS ) ;
2009-01-12 19:44:21 +01:00
CHECK_VALIDITY ( c - > pstream , ! name | | pa_namereg_is_valid_name ( name ) | | * name = = 0 , tag , PA_ERR_INVALID ) ;
2008-08-18 17:48:04 +02:00
CHECK_VALIDITY ( c - > pstream , idx ! = PA_INVALID_INDEX | | name , tag , PA_ERR_INVALID ) ;
CHECK_VALIDITY ( c - > pstream , idx = = PA_INVALID_INDEX | | ! name , tag , PA_ERR_INVALID ) ;
CHECK_VALIDITY ( c - > pstream , ! name | | idx = = PA_INVALID_INDEX , tag , PA_ERR_INVALID ) ;
2007-01-04 13:43:45 +00:00
2007-10-28 19:13:50 +00:00
if ( command = = PA_COMMAND_SUSPEND_SINK ) {
if ( idx = = PA_INVALID_INDEX & & name & & ! * name ) {
2009-01-12 19:44:21 +01:00
pa_log_debug ( " %s all sinks " , b ? " Suspending " : " Resuming " ) ;
2009-06-05 19:05:07 +02:00
if ( pa_sink_suspend_all ( c - > protocol - > core , b , PA_SUSPEND_USER ) < 0 ) {
2007-10-28 19:13:50 +00:00
pa_pstream_send_error ( c - > pstream , tag , PA_ERR_INVALID ) ;
return ;
}
} else {
pa_sink * sink = NULL ;
if ( idx ! = PA_INVALID_INDEX )
sink = pa_idxset_get_by_index ( c - > protocol - > core - > sinks , idx ) ;
else
2009-01-15 20:07:13 +01:00
sink = pa_namereg_get ( c - > protocol - > core , name , PA_NAMEREG_SINK ) ;
2007-10-28 19:13:50 +00:00
CHECK_VALIDITY ( c - > pstream , sink , tag , PA_ERR_NOENTITY ) ;
2009-06-05 19:05:07 +02:00
if ( pa_sink_suspend ( sink , b , PA_SUSPEND_USER ) < 0 ) {
2007-10-28 19:13:50 +00:00
pa_pstream_send_error ( c - > pstream , tag , PA_ERR_INVALID ) ;
return ;
}
}
} else {
pa_assert ( command = = PA_COMMAND_SUSPEND_SOURCE ) ;
if ( idx = = PA_INVALID_INDEX & & name & & ! * name ) {
2009-01-12 19:44:21 +01:00
pa_log_debug ( " %s all sources " , b ? " Suspending " : " Resuming " ) ;
2009-06-05 19:05:07 +02:00
if ( pa_source_suspend_all ( c - > protocol - > core , b , PA_SUSPEND_USER ) < 0 ) {
2007-10-28 19:13:50 +00:00
pa_pstream_send_error ( c - > pstream , tag , PA_ERR_INVALID ) ;
return ;
}
} else {
pa_source * source ;
if ( idx ! = PA_INVALID_INDEX )
source = pa_idxset_get_by_index ( c - > protocol - > core - > sources , idx ) ;
else
2009-01-15 20:07:13 +01:00
source = pa_namereg_get ( c - > protocol - > core , name , PA_NAMEREG_SOURCE ) ;
2007-10-28 19:13:50 +00:00
CHECK_VALIDITY ( c - > pstream , source , tag , PA_ERR_NOENTITY ) ;
2009-06-05 19:05:07 +02:00
if ( pa_source_suspend ( source , b , PA_SUSPEND_USER ) < 0 ) {
2007-10-28 19:13:50 +00:00
pa_pstream_send_error ( c - > pstream , tag , PA_ERR_INVALID ) ;
return ;
}
}
}
pa_pstream_send_simple_ack ( c - > pstream , tag ) ;
2006-07-31 21:54:46 +00:00
}
2008-08-03 18:56:10 +02:00
static void command_extension ( pa_pdispatch * pd , uint32_t command , uint32_t tag , pa_tagstruct * t , void * userdata ) {
2008-08-04 18:58:29 +02:00
pa_native_connection * c = PA_NATIVE_CONNECTION ( userdata ) ;
2008-08-03 18:56:10 +02:00
uint32_t idx = PA_INVALID_INDEX ;
const char * name = NULL ;
pa_module * m ;
pa_native_protocol_ext_cb_t cb ;
2008-08-04 18:58:29 +02:00
pa_native_connection_assert_ref ( c ) ;
2008-08-03 18:56:10 +02:00
pa_assert ( t ) ;
if ( pa_tagstruct_getu32 ( t , & idx ) < 0 | |
pa_tagstruct_gets ( t , & name ) < 0 ) {
protocol_error ( c ) ;
return ;
}
CHECK_VALIDITY ( c - > pstream , c - > authorized , tag , PA_ERR_ACCESS ) ;
2008-08-18 17:48:04 +02:00
CHECK_VALIDITY ( c - > pstream , ! name | | pa_utf8_valid ( name ) , tag , PA_ERR_INVALID ) ;
CHECK_VALIDITY ( c - > pstream , idx ! = PA_INVALID_INDEX | | name , tag , PA_ERR_INVALID ) ;
CHECK_VALIDITY ( c - > pstream , idx = = PA_INVALID_INDEX | | ! name , tag , PA_ERR_INVALID ) ;
CHECK_VALIDITY ( c - > pstream , ! name | | idx = = PA_INVALID_INDEX , tag , PA_ERR_INVALID ) ;
2008-08-03 18:56:10 +02:00
if ( idx ! = PA_INVALID_INDEX )
m = pa_idxset_get_by_index ( c - > protocol - > core - > modules , idx ) ;
else {
for ( m = pa_idxset_first ( c - > protocol - > core - > modules , & idx ) ; m ; m = pa_idxset_next ( c - > protocol - > core - > modules , & idx ) )
if ( strcmp ( name , m - > name ) = = 0 )
break ;
}
CHECK_VALIDITY ( c - > pstream , m , tag , PA_ERR_NOEXTENSION ) ;
CHECK_VALIDITY ( c - > pstream , m - > load_once | | idx ! = PA_INVALID_INDEX , tag , PA_ERR_INVALID ) ;
2009-01-22 00:22:46 +01:00
cb = ( pa_native_protocol_ext_cb_t ) ( unsigned long ) pa_hashmap_get ( c - > protocol - > extensions , m ) ;
2009-02-17 22:32:40 +02:00
CHECK_VALIDITY ( c - > pstream , cb , tag , PA_ERR_NOEXTENSION ) ;
2008-08-03 18:56:10 +02:00
2008-08-04 18:58:29 +02:00
if ( cb ( c - > protocol , m , c , tag , t ) < 0 )
protocol_error ( c ) ;
2008-08-03 18:56:10 +02:00
}
2009-01-21 03:04:04 +01:00
static void command_set_card_profile ( pa_pdispatch * pd , uint32_t command , uint32_t tag , pa_tagstruct * t , void * userdata ) {
pa_native_connection * c = PA_NATIVE_CONNECTION ( userdata ) ;
uint32_t idx = PA_INVALID_INDEX ;
const char * name = NULL , * profile = NULL ;
pa_card * card = NULL ;
2009-06-17 04:52:41 +02:00
int ret ;
2009-01-21 03:04:04 +01:00
pa_native_connection_assert_ref ( c ) ;
pa_assert ( t ) ;
if ( pa_tagstruct_getu32 ( t , & idx ) < 0 | |
pa_tagstruct_gets ( t , & name ) < 0 | |
pa_tagstruct_gets ( t , & profile ) < 0 | |
! pa_tagstruct_eof ( t ) ) {
protocol_error ( c ) ;
return ;
}
CHECK_VALIDITY ( c - > pstream , c - > authorized , tag , PA_ERR_ACCESS ) ;
CHECK_VALIDITY ( c - > pstream , ! name | | pa_namereg_is_valid_name ( name ) , tag , PA_ERR_INVALID ) ;
CHECK_VALIDITY ( c - > pstream , idx ! = PA_INVALID_INDEX | | name , tag , PA_ERR_INVALID ) ;
CHECK_VALIDITY ( c - > pstream , idx = = PA_INVALID_INDEX | | ! name , tag , PA_ERR_INVALID ) ;
CHECK_VALIDITY ( c - > pstream , ! name | | idx = = PA_INVALID_INDEX , tag , PA_ERR_INVALID ) ;
if ( idx ! = PA_INVALID_INDEX )
card = pa_idxset_get_by_index ( c - > protocol - > core - > cards , idx ) ;
else
card = pa_namereg_get ( c - > protocol - > core , name , PA_NAMEREG_CARD ) ;
CHECK_VALIDITY ( c - > pstream , card , tag , PA_ERR_NOENTITY ) ;
2009-06-17 04:52:41 +02:00
if ( ( ret = pa_card_set_profile ( card , profile , TRUE ) ) < 0 ) {
pa_pstream_send_error ( c - > pstream , tag , - ret ) ;
return ;
}
pa_pstream_send_simple_ack ( c - > pstream , tag ) ;
}
static void command_set_sink_or_source_port ( pa_pdispatch * pd , uint32_t command , uint32_t tag , pa_tagstruct * t , void * userdata ) {
pa_native_connection * c = PA_NATIVE_CONNECTION ( userdata ) ;
uint32_t idx = PA_INVALID_INDEX ;
const char * name = NULL , * port = NULL ;
int ret ;
pa_native_connection_assert_ref ( c ) ;
pa_assert ( t ) ;
if ( pa_tagstruct_getu32 ( t , & idx ) < 0 | |
pa_tagstruct_gets ( t , & name ) < 0 | |
pa_tagstruct_gets ( t , & port ) < 0 | |
! pa_tagstruct_eof ( t ) ) {
protocol_error ( c ) ;
2009-01-21 03:04:04 +01:00
return ;
}
2009-06-17 04:52:41 +02:00
CHECK_VALIDITY ( c - > pstream , c - > authorized , tag , PA_ERR_ACCESS ) ;
CHECK_VALIDITY ( c - > pstream , ! name | | pa_namereg_is_valid_name ( name ) , tag , PA_ERR_INVALID ) ;
CHECK_VALIDITY ( c - > pstream , idx ! = PA_INVALID_INDEX | | name , tag , PA_ERR_INVALID ) ;
CHECK_VALIDITY ( c - > pstream , idx = = PA_INVALID_INDEX | | ! name , tag , PA_ERR_INVALID ) ;
CHECK_VALIDITY ( c - > pstream , ! name | | idx = = PA_INVALID_INDEX , tag , PA_ERR_INVALID ) ;
if ( command = = PA_COMMAND_SET_SINK_PORT ) {
pa_sink * sink ;
if ( idx ! = PA_INVALID_INDEX )
sink = pa_idxset_get_by_index ( c - > protocol - > core - > sinks , idx ) ;
else
sink = pa_namereg_get ( c - > protocol - > core , name , PA_NAMEREG_SINK ) ;
CHECK_VALIDITY ( c - > pstream , sink , tag , PA_ERR_NOENTITY ) ;
if ( ( ret = pa_sink_set_port ( sink , port , TRUE ) ) < 0 ) {
pa_pstream_send_error ( c - > pstream , tag , - ret ) ;
return ;
}
} else {
pa_source * source ;
pa_assert ( command = PA_COMMAND_SET_SOURCE_PORT ) ;
if ( idx ! = PA_INVALID_INDEX )
source = pa_idxset_get_by_index ( c - > protocol - > core - > sources , idx ) ;
else
source = pa_namereg_get ( c - > protocol - > core , name , PA_NAMEREG_SOURCE ) ;
CHECK_VALIDITY ( c - > pstream , source , tag , PA_ERR_NOENTITY ) ;
if ( ( ret = pa_source_set_port ( source , port , TRUE ) ) < 0 ) {
pa_pstream_send_error ( c - > pstream , tag , - ret ) ;
return ;
}
}
2009-01-21 03:04:04 +01:00
pa_pstream_send_simple_ack ( c - > pstream , tag ) ;
}
2008-08-03 18:56:10 +02:00
2004-06-23 23:17:30 +00:00
/*** pstream callbacks ***/
2006-07-19 21:48:35 +00:00
static void pstream_packet_callback ( pa_pstream * p , pa_packet * packet , const pa_creds * creds , void * userdata ) {
2008-08-04 18:58:29 +02:00
pa_native_connection * c = PA_NATIVE_CONNECTION ( userdata ) ;
2007-10-28 19:13:50 +00:00
pa_assert ( p ) ;
pa_assert ( packet ) ;
2008-08-04 18:58:29 +02:00
pa_native_connection_assert_ref ( c ) ;
2004-06-20 01:12:13 +00:00
2006-02-24 15:12:42 +00:00
if ( pa_pdispatch_run ( c - > pdispatch , packet , creds , c ) < 0 ) {
2006-08-18 21:38:40 +00:00
pa_log ( " invalid packet. " ) ;
2008-08-04 18:58:29 +02:00
native_connection_unlink ( c ) ;
2004-06-23 23:17:30 +00:00
}
2004-06-20 01:12:13 +00:00
}
2006-02-20 04:05:16 +00:00
static void pstream_memblock_callback ( pa_pstream * p , uint32_t channel , int64_t offset , pa_seek_mode_t seek , const pa_memchunk * chunk , void * userdata ) {
2008-08-04 18:58:29 +02:00
pa_native_connection * c = PA_NATIVE_CONNECTION ( userdata ) ;
2007-10-28 19:13:50 +00:00
output_stream * stream ;
pa_assert ( p ) ;
pa_assert ( chunk ) ;
2008-08-04 18:58:29 +02:00
pa_native_connection_assert_ref ( c ) ;
2007-01-04 13:43:45 +00:00
2007-10-28 19:13:50 +00:00
if ( ! ( stream = OUTPUT_STREAM ( pa_idxset_get_by_index ( c - > output_streams , channel ) ) ) ) {
2009-04-10 01:16:59 +02:00
pa_log_debug ( " Client sent block for invalid stream. " ) ;
2006-08-13 17:31:58 +00:00
/* Ignoring */
2004-07-07 00:22:46 +00:00
return ;
2004-06-20 01:12:13 +00:00
}
2008-09-03 18:31:46 +02:00
/* pa_log("got %lu bytes", (unsigned long) chunk->length); */
2007-10-28 19:13:50 +00:00
if ( playback_stream_isinstance ( stream ) ) {
playback_stream * ps = PLAYBACK_STREAM ( stream ) ;
2006-02-20 04:05:16 +00:00
2009-02-18 21:55:55 +01:00
if ( chunk - > memblock ) {
if ( seek ! = PA_SEEK_RELATIVE | | offset ! = 0 )
pa_asyncmsgq_post ( ps - > sink_input - > sink - > asyncmsgq , PA_MSGOBJECT ( ps - > sink_input ) , SINK_INPUT_MESSAGE_SEEK , PA_UINT_TO_PTR ( seek ) , offset , NULL , NULL ) ;
2006-02-20 04:05:16 +00:00
2009-02-18 21:55:55 +01:00
pa_asyncmsgq_post ( ps - > sink_input - > sink - > asyncmsgq , PA_MSGOBJECT ( ps - > sink_input ) , SINK_INPUT_MESSAGE_POST_DATA , NULL , 0 , chunk , NULL ) ;
} else
pa_asyncmsgq_post ( ps - > sink_input - > sink - > asyncmsgq , PA_MSGOBJECT ( ps - > sink_input ) , SINK_INPUT_MESSAGE_SEEK , PA_UINT_TO_PTR ( seek ) , offset + chunk - > length , NULL , NULL ) ;
2004-08-27 01:29:49 +00:00
2004-08-03 19:26:56 +00:00
} else {
2007-10-28 19:13:50 +00:00
upload_stream * u = UPLOAD_STREAM ( stream ) ;
2004-08-03 19:26:56 +00:00
size_t l ;
if ( ! u - > memchunk . memblock ) {
2009-02-18 21:55:55 +01:00
if ( u - > length = = chunk - > length & & chunk - > memblock ) {
2004-08-03 19:26:56 +00:00
u - > memchunk = * chunk ;
pa_memblock_ref ( u - > memchunk . memblock ) ;
u - > length = 0 ;
} else {
2006-08-18 19:55:18 +00:00
u - > memchunk . memblock = pa_memblock_new ( c - > protocol - > core - > mempool , u - > length ) ;
2004-08-03 19:26:56 +00:00
u - > memchunk . index = u - > memchunk . length = 0 ;
}
}
2007-01-04 13:43:45 +00:00
2007-10-28 19:13:50 +00:00
pa_assert ( u - > memchunk . memblock ) ;
2007-01-04 13:43:45 +00:00
l = u - > length ;
2004-08-03 19:26:56 +00:00
if ( l > chunk - > length )
l = chunk - > length ;
if ( l > 0 ) {
2009-02-18 21:55:55 +01:00
void * dst ;
2007-10-28 19:13:50 +00:00
dst = pa_memblock_acquire ( u - > memchunk . memblock ) ;
2009-02-18 21:55:55 +01:00
if ( chunk - > memblock ) {
void * src ;
src = pa_memblock_acquire ( chunk - > memblock ) ;
memcpy ( ( uint8_t * ) dst + u - > memchunk . index + u - > memchunk . length ,
( uint8_t * ) src + chunk - > index , l ) ;
pa_memblock_release ( chunk - > memblock ) ;
} else
pa_silence_memory ( ( uint8_t * ) dst + u - > memchunk . index + u - > memchunk . length , l , & u - > sample_spec ) ;
2007-10-28 19:13:50 +00:00
pa_memblock_release ( u - > memchunk . memblock ) ;
2004-08-03 19:26:56 +00:00
u - > memchunk . length + = l ;
u - > length - = l ;
}
}
2004-06-20 01:12:13 +00:00
}
2006-01-11 01:17:39 +00:00
static void pstream_die_callback ( pa_pstream * p , void * userdata ) {
2008-08-04 18:58:29 +02:00
pa_native_connection * c = PA_NATIVE_CONNECTION ( userdata ) ;
2004-06-20 01:12:13 +00:00
2007-10-28 19:13:50 +00:00
pa_assert ( p ) ;
2008-08-04 18:58:29 +02:00
pa_native_connection_assert_ref ( c ) ;
2004-06-08 23:54:24 +00:00
2008-08-04 18:58:29 +02:00
native_connection_unlink ( c ) ;
pa_log_info ( " Connection died. " ) ;
2007-10-28 19:13:50 +00:00
}
2004-07-10 16:50:22 +00:00
2006-01-11 01:17:39 +00:00
static void pstream_drain_callback ( pa_pstream * p , void * userdata ) {
2008-08-04 18:58:29 +02:00
pa_native_connection * c = PA_NATIVE_CONNECTION ( userdata ) ;
2007-10-28 19:13:50 +00:00
pa_assert ( p ) ;
2008-08-04 18:58:29 +02:00
pa_native_connection_assert_ref ( c ) ;
2004-07-10 16:50:22 +00:00
2008-08-04 18:58:29 +02:00
native_connection_send_memblock ( c ) ;
2004-07-10 16:50:22 +00:00
}
2007-10-28 19:13:50 +00:00
static void pstream_revoke_callback ( pa_pstream * p , uint32_t block_id , void * userdata ) {
pa_thread_mq * q ;
if ( ! ( q = pa_thread_mq_get ( ) ) )
pa_pstream_send_revoke ( p , block_id ) ;
else
pa_asyncmsgq_post ( q - > outq , PA_MSGOBJECT ( userdata ) , CONNECTION_MESSAGE_REVOKE , PA_UINT_TO_PTR ( block_id ) , 0 , NULL , NULL ) ;
}
static void pstream_release_callback ( pa_pstream * p , uint32_t block_id , void * userdata ) {
pa_thread_mq * q ;
if ( ! ( q = pa_thread_mq_get ( ) ) )
pa_pstream_send_release ( p , block_id ) ;
else
pa_asyncmsgq_post ( q - > outq , PA_MSGOBJECT ( userdata ) , CONNECTION_MESSAGE_RELEASE , PA_UINT_TO_PTR ( block_id ) , 0 , NULL , NULL ) ;
}
2004-07-06 00:08:44 +00:00
/*** client callbacks ***/
2006-01-11 01:17:39 +00:00
static void client_kill_cb ( pa_client * c ) {
2007-10-28 19:13:50 +00:00
pa_assert ( c ) ;
2008-08-04 18:58:29 +02:00
native_connection_unlink ( PA_NATIVE_CONNECTION ( c - > userdata ) ) ;
pa_log_info ( " Connection killed. " ) ;
2004-07-06 00:08:44 +00:00
}
2009-02-12 03:18:05 +01:00
static void client_send_event_cb ( pa_client * client , const char * event , pa_proplist * pl ) {
pa_tagstruct * t ;
pa_native_connection * c ;
pa_assert ( client ) ;
c = PA_NATIVE_CONNECTION ( client - > userdata ) ;
pa_native_connection_assert_ref ( c ) ;
if ( c - > version < 15 )
return ;
t = pa_tagstruct_new ( NULL , 0 ) ;
pa_tagstruct_putu32 ( t , PA_COMMAND_CLIENT_EVENT ) ;
pa_tagstruct_putu32 ( t , ( uint32_t ) - 1 ) ; /* tag */
pa_tagstruct_puts ( t , event ) ;
pa_tagstruct_put_proplist ( t , pl ) ;
pa_pstream_send_tagstruct ( c - > pstream , t ) ;
}
2008-08-03 16:44:38 +02:00
/*** module entry points ***/
2004-06-20 01:12:13 +00:00
2009-04-05 02:13:43 +03:00
static void auth_timeout ( pa_mainloop_api * m , pa_time_event * e , const struct timeval * t , void * userdata ) {
2008-08-04 18:58:29 +02:00
pa_native_connection * c = PA_NATIVE_CONNECTION ( userdata ) ;
2007-10-28 19:13:50 +00:00
pa_assert ( m ) ;
2008-08-04 18:58:29 +02:00
pa_native_connection_assert_ref ( c ) ;
2007-10-28 19:13:50 +00:00
pa_assert ( c - > auth_timeout_event = = e ) ;
2004-11-18 00:28:26 +00:00
2008-08-04 18:58:29 +02:00
if ( ! c - > authorized ) {
native_connection_unlink ( c ) ;
pa_log_info ( " Connection terminated due to authentication timeout. " ) ;
}
2004-11-18 00:28:26 +00:00
}
2008-08-03 16:44:38 +02:00
void pa_native_protocol_connect ( pa_native_protocol * p , pa_iochannel * io , pa_native_options * o ) {
2008-08-04 18:58:29 +02:00
pa_native_connection * c ;
2009-01-15 17:52:29 +01:00
char pname [ 128 ] ;
pa_client * client ;
pa_client_new_data data ;
2007-10-28 19:13:50 +00:00
pa_assert ( p ) ;
2008-08-03 16:44:38 +02:00
pa_assert ( io ) ;
pa_assert ( o ) ;
2004-06-20 01:12:13 +00:00
2006-01-11 01:17:39 +00:00
if ( pa_idxset_size ( p - > connections ) + 1 > MAX_CONNECTIONS ) {
2006-08-18 21:38:40 +00:00
pa_log_warn ( " Warning! Too many connections (%u), dropping incoming connection. " , MAX_CONNECTIONS ) ;
2004-11-18 00:28:26 +00:00
pa_iochannel_free ( io ) ;
return ;
}
2009-01-15 17:52:29 +01:00
pa_client_new_data_init ( & data ) ;
data . module = o - > module ;
data . driver = __FILE__ ;
pa_iochannel_socket_peer_to_string ( io , pname , sizeof ( pname ) ) ;
pa_proplist_setf ( data . proplist , PA_PROP_APPLICATION_NAME , " Native client (%s) " , pname ) ;
pa_proplist_sets ( data . proplist , " native-protocol.peer " , pname ) ;
client = pa_client_new ( p - > core , & data ) ;
pa_client_new_data_done ( & data ) ;
if ( ! client )
return ;
2008-08-04 18:58:29 +02:00
c = pa_msgobject_new ( pa_native_connection ) ;
c - > parent . parent . free = native_connection_free ;
c - > parent . process_msg = native_connection_process_msg ;
2008-08-03 16:44:38 +02:00
c - > protocol = p ;
c - > options = pa_native_options_ref ( o ) ;
c - > authorized = FALSE ;
if ( o - > auth_anonymous ) {
pa_log_info ( " Client authenticated anonymously. " ) ;
c - > authorized = TRUE ;
}
2004-09-14 23:08:39 +00:00
2008-08-03 16:44:38 +02:00
if ( ! c - > authorized & &
o - > auth_ip_acl & &
pa_ip_acl_check ( o - > auth_ip_acl , pa_iochannel_get_recv_fd ( io ) ) > 0 ) {
2004-11-18 00:28:26 +00:00
2006-08-18 21:38:40 +00:00
pa_log_info ( " Client authenticated by IP ACL. " ) ;
2008-05-15 23:34:41 +00:00
c - > authorized = TRUE ;
2006-07-20 18:43:20 +00:00
}
2007-01-04 13:43:45 +00:00
2009-04-05 02:13:43 +03:00
if ( ! c - > authorized )
c - > auth_timeout_event = pa_core_rttime_new ( p - > core , pa_rtclock_now ( ) + AUTH_TIMEOUT , auth_timeout , c ) ;
else
2004-11-18 00:28:26 +00:00
c - > auth_timeout_event = NULL ;
2006-05-25 23:20:28 +00:00
2008-06-17 18:29:00 +00:00
c - > is_local = pa_iochannel_socket_is_local ( io ) ;
2006-05-25 23:20:28 +00:00
c - > version = 8 ;
2008-08-03 16:44:38 +02:00
2009-01-15 17:52:29 +01:00
c - > client = client ;
2004-07-06 00:08:44 +00:00
c - > client - > kill = client_kill_cb ;
2009-02-12 03:18:05 +01:00
c - > client - > send_event = client_send_event_cb ;
2004-07-06 00:08:44 +00:00
c - > client - > userdata = c ;
2007-01-04 13:43:45 +00:00
2006-08-18 19:55:18 +00:00
c - > pstream = pa_pstream_new ( p - > core - > mainloop , io , p - > core - > mempool ) ;
2004-07-10 16:50:22 +00:00
pa_pstream_set_recieve_packet_callback ( c - > pstream , pstream_packet_callback , c ) ;
pa_pstream_set_recieve_memblock_callback ( c - > pstream , pstream_memblock_callback , c ) ;
pa_pstream_set_die_callback ( c - > pstream , pstream_die_callback , c ) ;
pa_pstream_set_drain_callback ( c - > pstream , pstream_drain_callback , c ) ;
2007-10-28 19:13:50 +00:00
pa_pstream_set_revoke_callback ( c - > pstream , pstream_revoke_callback , c ) ;
pa_pstream_set_release_callback ( c - > pstream , pstream_release_callback , c ) ;
2004-06-20 01:12:13 +00:00
2009-04-05 02:13:43 +03:00
c - > pdispatch = pa_pdispatch_new ( p - > core - > mainloop , TRUE , command_table , PA_COMMAND_MAX ) ;
2004-06-23 23:17:30 +00:00
2004-07-03 23:35:12 +00:00
c - > record_streams = pa_idxset_new ( NULL , NULL ) ;
2004-08-03 19:26:56 +00:00
c - > output_streams = pa_idxset_new ( NULL , NULL ) ;
2004-06-20 01:12:13 +00:00
2004-07-10 16:50:22 +00:00
c - > rrobin_index = PA_IDXSET_INVALID ;
2004-08-11 15:11:26 +00:00
c - > subscription = NULL ;
2004-07-10 16:50:22 +00:00
2004-07-03 23:35:12 +00:00
pa_idxset_put ( p - > connections , c , NULL ) ;
2006-02-24 15:12:42 +00:00
2006-07-19 21:48:35 +00:00
# ifdef HAVE_CREDS
2006-02-24 15:12:42 +00:00
if ( pa_iochannel_creds_supported ( io ) )
pa_iochannel_creds_enable ( io ) ;
# endif
2008-08-04 18:58:29 +02:00
pa_hook_fire ( & p - > hooks [ PA_NATIVE_HOOK_CONNECTION_PUT ] , c ) ;
2004-06-20 01:12:13 +00:00
}
2008-08-03 16:44:38 +02:00
void pa_native_protocol_disconnect ( pa_native_protocol * p , pa_module * m ) {
2008-08-04 18:58:29 +02:00
pa_native_connection * c ;
2008-08-03 16:44:38 +02:00
void * state = NULL ;
2004-06-20 01:12:13 +00:00
2007-10-28 19:13:50 +00:00
pa_assert ( p ) ;
2008-08-03 16:44:38 +02:00
pa_assert ( m ) ;
2004-11-07 20:48:46 +00:00
2008-08-03 16:44:38 +02:00
while ( ( c = pa_idxset_iterate ( p - > connections , & state , NULL ) ) )
if ( c - > options - > module = = m )
2008-08-04 18:58:29 +02:00
native_connection_unlink ( c ) ;
2008-08-03 16:44:38 +02:00
}
2007-01-04 13:43:45 +00:00
2008-08-03 16:44:38 +02:00
static pa_native_protocol * native_protocol_new ( pa_core * c ) {
pa_native_protocol * p ;
2008-08-04 18:58:29 +02:00
pa_native_hook_t h ;
2007-01-04 13:43:45 +00:00
2008-08-03 16:44:38 +02:00
pa_assert ( c ) ;
2004-11-07 20:48:46 +00:00
2008-08-03 16:44:38 +02:00
p = pa_xnew ( pa_native_protocol , 1 ) ;
PA_REFCNT_INIT ( p ) ;
p - > core = c ;
p - > connections = pa_idxset_new ( NULL , NULL ) ;
2004-11-07 20:48:46 +00:00
2008-08-03 16:44:38 +02:00
p - > servers = NULL ;
2008-08-04 18:58:29 +02:00
p - > extensions = pa_hashmap_new ( pa_idxset_trivial_hash_func , pa_idxset_trivial_compare_func ) ;
for ( h = 0 ; h < PA_NATIVE_HOOK_MAX ; h + + )
pa_hook_init ( & p - > hooks [ h ] , p ) ;
2004-11-07 20:48:46 +00:00
2008-08-03 16:44:38 +02:00
pa_assert_se ( pa_shared_set ( c , " native-protocol " , p ) > = 0 ) ;
2007-01-04 13:43:45 +00:00
2008-08-03 16:44:38 +02:00
return p ;
2004-11-07 20:48:46 +00:00
}
2008-08-03 16:44:38 +02:00
pa_native_protocol * pa_native_protocol_get ( pa_core * c ) {
pa_native_protocol * p ;
2007-01-04 13:43:45 +00:00
2008-08-03 16:44:38 +02:00
if ( ( p = pa_shared_get ( c , " native-protocol " ) ) )
return pa_native_protocol_ref ( p ) ;
2004-06-08 23:54:24 +00:00
2008-08-03 16:44:38 +02:00
return native_protocol_new ( c ) ;
}
2007-01-04 13:43:45 +00:00
2008-08-03 16:44:38 +02:00
pa_native_protocol * pa_native_protocol_ref ( pa_native_protocol * p ) {
pa_assert ( p ) ;
pa_assert ( PA_REFCNT_VALUE ( p ) > = 1 ) ;
2007-01-04 13:43:45 +00:00
2008-08-03 16:44:38 +02:00
PA_REFCNT_INC ( p ) ;
2006-07-19 21:48:35 +00:00
2008-08-03 16:44:38 +02:00
return p ;
}
2006-07-20 18:43:20 +00:00
2008-08-03 16:44:38 +02:00
void pa_native_protocol_unref ( pa_native_protocol * p ) {
2008-08-04 18:58:29 +02:00
pa_native_connection * c ;
pa_native_hook_t h ;
2008-08-03 16:44:38 +02:00
pa_assert ( p ) ;
pa_assert ( PA_REFCNT_VALUE ( p ) > = 1 ) ;
2006-07-20 18:43:20 +00:00
2008-08-03 16:44:38 +02:00
if ( PA_REFCNT_DEC ( p ) > 0 )
return ;
2006-07-20 18:43:20 +00:00
2008-08-03 16:44:38 +02:00
while ( ( c = pa_idxset_first ( p - > connections , NULL ) ) )
2008-08-04 18:58:29 +02:00
native_connection_unlink ( c ) ;
2004-07-10 20:56:38 +00:00
2008-08-03 16:44:38 +02:00
pa_idxset_free ( p - > connections , NULL , NULL ) ;
2006-07-20 18:43:20 +00:00
2008-08-03 16:44:38 +02:00
pa_strlist_free ( p - > servers ) ;
2008-08-04 18:58:29 +02:00
for ( h = 0 ; h < PA_NATIVE_HOOK_MAX ; h + + )
pa_hook_done ( & p - > hooks [ h ] ) ;
pa_hashmap_free ( p - > extensions , NULL , NULL ) ;
2004-06-08 23:54:24 +00:00
2008-08-03 16:44:38 +02:00
pa_assert_se ( pa_shared_remove ( p - > core , " native-protocol " ) > = 0 ) ;
2006-07-20 18:43:20 +00:00
pa_xfree ( p ) ;
2004-09-01 21:12:27 +00:00
}
2008-08-03 16:44:38 +02:00
void pa_native_protocol_add_server_string ( pa_native_protocol * p , const char * name ) {
pa_assert ( p ) ;
pa_assert ( PA_REFCNT_VALUE ( p ) > = 1 ) ;
pa_assert ( name ) ;
2004-09-01 21:12:27 +00:00
2008-08-03 16:44:38 +02:00
p - > servers = pa_strlist_prepend ( p - > servers , name ) ;
2007-01-04 13:43:45 +00:00
2008-08-04 18:58:29 +02:00
pa_hook_fire ( & p - > hooks [ PA_NATIVE_HOOK_SERVERS_CHANGED ] , p - > servers ) ;
2008-08-03 16:44:38 +02:00
}
2004-11-11 21:18:33 +00:00
2008-08-03 16:44:38 +02:00
void pa_native_protocol_remove_server_string ( pa_native_protocol * p , const char * name ) {
pa_assert ( p ) ;
pa_assert ( PA_REFCNT_VALUE ( p ) > = 1 ) ;
pa_assert ( name ) ;
2007-01-04 13:43:45 +00:00
2008-08-03 16:44:38 +02:00
p - > servers = pa_strlist_remove ( p - > servers , name ) ;
2008-08-04 18:58:29 +02:00
pa_hook_fire ( & p - > hooks [ PA_NATIVE_HOOK_SERVERS_CHANGED ] , p - > servers ) ;
2004-06-08 23:54:24 +00:00
}
2008-08-04 18:58:29 +02:00
pa_hook * pa_native_protocol_hooks ( pa_native_protocol * p ) {
2007-10-28 19:13:50 +00:00
pa_assert ( p ) ;
2008-08-03 16:44:38 +02:00
pa_assert ( PA_REFCNT_VALUE ( p ) > = 1 ) ;
2004-06-08 23:54:24 +00:00
2008-08-04 18:58:29 +02:00
return p - > hooks ;
2008-08-03 16:44:38 +02:00
}
pa_strlist * pa_native_protocol_servers ( pa_native_protocol * p ) {
pa_assert ( p ) ;
pa_assert ( PA_REFCNT_VALUE ( p ) > = 1 ) ;
2004-09-01 21:12:27 +00:00
2008-08-03 16:44:38 +02:00
return p - > servers ;
}
2007-01-04 13:43:45 +00:00
2008-08-03 18:56:10 +02:00
int pa_native_protocol_install_ext ( pa_native_protocol * p , pa_module * m , pa_native_protocol_ext_cb_t cb ) {
pa_assert ( p ) ;
pa_assert ( PA_REFCNT_VALUE ( p ) > = 1 ) ;
pa_assert ( m ) ;
pa_assert ( cb ) ;
pa_assert ( ! pa_hashmap_get ( p - > extensions , m ) ) ;
2007-01-04 13:43:45 +00:00
2009-01-22 00:22:46 +01:00
pa_assert_se ( pa_hashmap_put ( p - > extensions , m , ( void * ) ( unsigned long ) cb ) = = 0 ) ;
2008-08-03 18:56:10 +02:00
return 0 ;
}
2008-08-03 16:44:38 +02:00
2008-08-03 18:56:10 +02:00
void pa_native_protocol_remove_ext ( pa_native_protocol * p , pa_module * m ) {
pa_assert ( p ) ;
pa_assert ( PA_REFCNT_VALUE ( p ) > = 1 ) ;
pa_assert ( m ) ;
2008-08-03 16:44:38 +02:00
2008-08-03 18:56:10 +02:00
pa_assert_se ( pa_hashmap_remove ( p - > extensions , m ) ) ;
}
2008-08-03 16:44:38 +02:00
pa_native_options * pa_native_options_new ( void ) {
pa_native_options * o ;
o = pa_xnew0 ( pa_native_options , 1 ) ;
PA_REFCNT_INIT ( o ) ;
return o ;
}
pa_native_options * pa_native_options_ref ( pa_native_options * o ) {
pa_assert ( o ) ;
pa_assert ( PA_REFCNT_VALUE ( o ) > = 1 ) ;
PA_REFCNT_INC ( o ) ;
return o ;
}
void pa_native_options_unref ( pa_native_options * o ) {
pa_assert ( o ) ;
pa_assert ( PA_REFCNT_VALUE ( o ) > = 1 ) ;
if ( PA_REFCNT_DEC ( o ) > 0 )
return ;
pa_xfree ( o - > auth_group ) ;
if ( o - > auth_ip_acl )
pa_ip_acl_free ( o - > auth_ip_acl ) ;
if ( o - > auth_cookie )
pa_auth_cookie_unref ( o - > auth_cookie ) ;
pa_xfree ( o ) ;
}
int pa_native_options_parse ( pa_native_options * o , pa_core * c , pa_modargs * ma ) {
pa_bool_t enabled ;
const char * acl ;
pa_assert ( o ) ;
pa_assert ( PA_REFCNT_VALUE ( o ) > = 1 ) ;
pa_assert ( ma ) ;
if ( pa_modargs_get_value_boolean ( ma , " auth-anonymous " , & o - > auth_anonymous ) < 0 ) {
pa_log ( " auth-anonymous= expects a boolean argument. " ) ;
return - 1 ;
2004-11-11 21:18:33 +00:00
}
2004-11-07 20:48:46 +00:00
2008-08-03 16:44:38 +02:00
enabled = TRUE ;
if ( pa_modargs_get_value_boolean ( ma , " auth-group-enabled " , & enabled ) < 0 ) {
pa_log ( " auth-group-enabled= expects a boolean argument. " ) ;
return - 1 ;
}
2004-11-11 21:18:33 +00:00
2008-08-03 16:44:38 +02:00
pa_xfree ( o - > auth_group ) ;
o - > auth_group = enabled ? pa_xstrdup ( pa_modargs_get_value ( ma , " auth-group " , pa_in_system_mode ( ) ? PA_ACCESS_GROUP : NULL ) ) : NULL ;
2007-01-04 13:43:45 +00:00
2008-08-03 16:44:38 +02:00
# ifndef HAVE_CREDS
if ( o - > auth_group )
pa_log_warn ( " Authentication group configured, but not available on local system. Ignoring. " ) ;
2006-02-24 17:14:23 +00:00
# endif
2004-09-01 21:12:27 +00:00
2008-08-03 16:44:38 +02:00
if ( ( acl = pa_modargs_get_value ( ma , " auth-ip-acl " , NULL ) ) ) {
pa_ip_acl * ipa ;
2007-10-28 19:13:50 +00:00
2008-08-11 19:46:28 +02:00
if ( ! ( ipa = pa_ip_acl_new ( acl ) ) ) {
2008-08-03 16:44:38 +02:00
pa_log ( " Failed to parse IP ACL '%s' " , acl ) ;
return - 1 ;
}
2004-09-01 21:12:27 +00:00
2008-08-03 16:44:38 +02:00
if ( o - > auth_ip_acl )
pa_ip_acl_free ( o - > auth_ip_acl ) ;
2004-09-01 21:12:27 +00:00
2008-08-03 16:44:38 +02:00
o - > auth_ip_acl = ipa ;
}
2007-01-04 13:43:45 +00:00
2008-08-03 16:44:38 +02:00
enabled = TRUE ;
if ( pa_modargs_get_value_boolean ( ma , " auth-cookie-enabled " , & enabled ) < 0 ) {
pa_log ( " auth-cookie-enabled= expects a boolean argument. " ) ;
return - 1 ;
}
if ( o - > auth_cookie )
pa_auth_cookie_unref ( o - > auth_cookie ) ;
if ( enabled ) {
const char * cn ;
/* The new name for this is 'auth-cookie', for compat reasons
* we check the old name too */
if ( ! ( cn = pa_modargs_get_value ( ma , " auth-cookie " , NULL ) ) )
if ( ! ( cn = pa_modargs_get_value ( ma , " cookie " , NULL ) ) )
cn = PA_NATIVE_COOKIE_FILE ;
if ( ! ( o - > auth_cookie = pa_auth_cookie_get ( c , cn , PA_NATIVE_COOKIE_LENGTH ) ) )
return - 1 ;
} else
o - > auth_cookie = NULL ;
return 0 ;
2004-09-01 21:12:27 +00:00
}
2008-08-04 18:58:29 +02:00
pa_pstream * pa_native_connection_get_pstream ( pa_native_connection * c ) {
pa_native_connection_assert_ref ( c ) ;
return c - > pstream ;
}