Home | History | Annotate | Download | only in pcm
      1 /*
      2  *  PCM - Direct Stream Mixing
      3  *  Copyright (c) 2003 by Jaroslav Kysela <perex (at) perex.cz>
      4  *
      5  *
      6  *   This library is free software; you can redistribute it and/or modify
      7  *   it under the terms of the GNU Lesser General Public License as
      8  *   published by the Free Software Foundation; either version 2.1 of
      9  *   the License, or (at your option) any later version.
     10  *
     11  *   This program is distributed in the hope that it will be useful,
     12  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
     13  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     14  *   GNU Lesser General Public License for more details.
     15  *
     16  *   You should have received a copy of the GNU Lesser General Public
     17  *   License along with this library; if not, write to the Free Software
     18  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
     19  *
     20  */
     21 
     22 #include "pcm_local.h"
     23 
     24 #define DIRECT_IPC_SEMS         1
     25 #define DIRECT_IPC_SEM_CLIENT   0
     26 
     27 typedef void (mix_areas_t)(unsigned int size,
     28 			   volatile void *dst, void *src,
     29 			   volatile signed int *sum, size_t dst_step,
     30 			   size_t src_step, size_t sum_step);
     31 
     32 typedef void (mix_areas_16_t)(unsigned int size,
     33 			      volatile signed short *dst, signed short *src,
     34 			      volatile signed int *sum, size_t dst_step,
     35 			      size_t src_step, size_t sum_step);
     36 
     37 typedef void (mix_areas_32_t)(unsigned int size,
     38 			      volatile signed int *dst, signed int *src,
     39 			      volatile signed int *sum, size_t dst_step,
     40 			      size_t src_step, size_t sum_step);
     41 
     42 typedef void (mix_areas_24_t)(unsigned int size,
     43 			      volatile unsigned char *dst, unsigned char *src,
     44 			      volatile signed int *sum, size_t dst_step,
     45 			      size_t src_step, size_t sum_step);
     46 
     47 typedef void (mix_areas_u8_t)(unsigned int size,
     48 			      volatile unsigned char *dst, unsigned char *src,
     49 			      volatile signed int *sum, size_t dst_step,
     50 			      size_t src_step, size_t sum_step);
     51 
     52 struct slave_params {
     53 	snd_pcm_format_t format;
     54 	int rate;
     55 	int channels;
     56 	int period_time;
     57 	int buffer_time;
     58 	snd_pcm_sframes_t period_size;
     59 	snd_pcm_sframes_t buffer_size;
     60 	unsigned int periods;
     61 };
     62 
     63 /* shared among direct plugin clients - be careful to be 32/64bit compatible! */
     64 typedef struct {
     65 	unsigned int magic;			/* magic number */
     66 	char socket_name[256];			/* name of communication socket */
     67 	snd_pcm_type_t type;			/* PCM type (currently only hw) */
     68 	int use_server;
     69 	struct {
     70 		unsigned int format;
     71 		snd_interval_t rate;
     72 		snd_interval_t buffer_size;
     73 		snd_interval_t buffer_time;
     74 		snd_interval_t period_size;
     75 		snd_interval_t period_time;
     76 		snd_interval_t periods;
     77 	} hw;
     78 	struct {
     79 		/* copied to slave PCMs */
     80 		snd_pcm_access_t access;
     81 		snd_pcm_format_t format;
     82 		snd_pcm_subformat_t subformat;
     83 		unsigned int channels;
     84 		unsigned int rate;
     85 		unsigned int period_size;
     86 		unsigned int period_time;
     87 		snd_interval_t periods;
     88 		unsigned int monotonic;
     89 		snd_pcm_tstamp_t tstamp_mode;
     90 		unsigned int period_step;
     91 		unsigned int sleep_min; /* not used */
     92 		unsigned int avail_min;
     93 		unsigned int start_threshold;
     94 		unsigned int stop_threshold;
     95 		unsigned int silence_threshold;
     96 		unsigned int silence_size;
     97 		unsigned int xfer_align; /* not used */
     98 		unsigned long long boundary;
     99 		unsigned int info;
    100 		unsigned int msbits;
    101 		unsigned int rate_num;
    102 		unsigned int rate_den;
    103 		unsigned int hw_flags;
    104 		unsigned int fifo_size;
    105 		unsigned int buffer_size;
    106 		snd_interval_t buffer_time;
    107 		unsigned int sample_bits;
    108 		unsigned int frame_bits;
    109 	} s;
    110 	union {
    111 		struct {
    112 			unsigned long long chn_mask;
    113 		} dshare;
    114 	} u;
    115 } snd_pcm_direct_share_t;
    116 
    117 typedef struct snd_pcm_direct snd_pcm_direct_t;
    118 
    119 struct snd_pcm_direct {
    120 	snd_pcm_type_t type;		/* type (dmix, dsnoop, dshare) */
    121 	key_t ipc_key;			/* IPC key for semaphore and memory */
    122 	mode_t ipc_perm;		/* IPC socket permissions */
    123 	int ipc_gid;			/* IPC socket gid */
    124 	int semid;			/* IPC global semaphore identification */
    125 	int shmid;			/* IPC global shared memory identification */
    126 	snd_pcm_direct_share_t *shmptr;	/* pointer to shared memory area */
    127 	snd_pcm_t *spcm; 		/* slave PCM handle */
    128 	snd_pcm_uframes_t appl_ptr;
    129 	snd_pcm_uframes_t last_appl_ptr;
    130 	snd_pcm_uframes_t hw_ptr;
    131 	snd_pcm_uframes_t avail_max;
    132 	snd_pcm_uframes_t slave_appl_ptr;
    133 	snd_pcm_uframes_t slave_hw_ptr;
    134 	snd_pcm_uframes_t slave_period_size;
    135 	snd_pcm_uframes_t slave_buffer_size;
    136 	snd_pcm_uframes_t slave_boundary;
    137 	int (*sync_ptr)(snd_pcm_t *pcm);
    138 	snd_pcm_state_t state;
    139 	snd_htimestamp_t trigger_tstamp;
    140 	int server, client;
    141 	int comm_fd;			/* communication file descriptor (socket) */
    142 	int hw_fd;			/* hardware file descriptor */
    143 	struct pollfd timer_fd;
    144 	int poll_fd;
    145 	int tread;
    146 	int timer_need_poll;
    147 	unsigned int timer_event_suspend;
    148 	unsigned int timer_event_resume;
    149 	int server_fd;
    150 	pid_t server_pid;
    151 	snd_timer_t *timer; 		/* timer used as poll_fd */
    152 	int interleaved;	 	/* we have interleaved buffer */
    153 	int slowptr;			/* use slow but more precise ptr updates */
    154 	int max_periods;		/* max periods (-1 = fixed periods, 0 = max buffer size) */
    155 	unsigned int channels;		/* client's channels */
    156 	unsigned int *bindings;
    157 	union {
    158 		struct {
    159 			int shmid_sum;			/* IPC global sum ring buffer memory identification */
    160 			signed int *sum_buffer;		/* shared sum buffer */
    161 			mix_areas_16_t *mix_areas_16;
    162 			mix_areas_32_t *mix_areas_32;
    163 			mix_areas_24_t *mix_areas_24;
    164 			mix_areas_u8_t *mix_areas_u8;
    165 			mix_areas_16_t *remix_areas_16;
    166 			mix_areas_32_t *remix_areas_32;
    167 			mix_areas_24_t *remix_areas_24;
    168 			mix_areas_u8_t *remix_areas_u8;
    169 		} dmix;
    170 		struct {
    171 		} dsnoop;
    172 		struct {
    173 			unsigned long long chn_mask;
    174 		} dshare;
    175 	} u;
    176 	void (*server_free)(snd_pcm_direct_t *direct);
    177 };
    178 
    179 /* make local functions really local */
    180 #define snd_pcm_direct_semaphore_create_or_connect \
    181 	snd1_pcm_direct_semaphore_create_or_connect
    182 #define snd_pcm_direct_shm_create_or_connect \
    183 	snd1_pcm_direct_shm_create_or_connect
    184 #define snd_pcm_direct_shm_discard \
    185 	snd1_pcm_direct_shm_discard
    186 #define snd_pcm_direct_server_create \
    187 	snd1_pcm_direct_server_create
    188 #define snd_pcm_direct_server_discard \
    189 	snd1_pcm_direct_server_discard
    190 #define snd_pcm_direct_client_connect \
    191 	snd1_pcm_direct_client_connect
    192 #define snd_pcm_direct_client_discard \
    193 	snd1_pcm_direct_client_discard
    194 #define snd_pcm_direct_initialize_slave \
    195 	snd1_pcm_direct_initialize_slave
    196 #define snd_pcm_direct_initialize_secondary_slave \
    197 	snd1_pcm_direct_initialize_secondary_slave
    198 #define snd_pcm_direct_initialize_poll_fd \
    199 	snd1_pcm_direct_initialize_poll_fd
    200 #define snd_pcm_direct_check_interleave \
    201 	snd1_pcm_direct_check_interleave
    202 #define snd_pcm_direct_parse_bindings \
    203 	snd1_pcm_direct_parse_bindings
    204 #define snd_pcm_direct_nonblock \
    205 	snd1_pcm_direct_nonblock
    206 #define snd_pcm_direct_async \
    207 	snd1_pcm_direct_async
    208 #define snd_pcm_direct_poll_revents \
    209 	snd1_pcm_direct_poll_revents
    210 #define snd_pcm_direct_info \
    211 	snd1_pcm_direct_info
    212 #define snd_pcm_direct_hw_refine \
    213 	snd1_pcm_direct_hw_refine
    214 #define snd_pcm_direct_hw_params \
    215 	snd1_pcm_direct_hw_params
    216 #define snd_pcm_direct_hw_free \
    217 	snd1_pcm_direct_hw_free
    218 #define snd_pcm_direct_sw_params \
    219 	snd1_pcm_direct_sw_params
    220 #define snd_pcm_direct_channel_info \
    221 	snd1_pcm_direct_channel_info
    222 #define snd_pcm_direct_mmap \
    223 	snd1_pcm_direct_mmap
    224 #define snd_pcm_direct_munmap \
    225 	snd1_pcm_direct_munmap
    226 #define snd_pcm_direct_resume \
    227 	snd1_pcm_direct_resume
    228 #define snd_pcm_direct_timer_stop \
    229 	snd1_pcm_direct_timer_stop
    230 #define snd_pcm_direct_clear_timer_queue \
    231 	snd1_pcm_direct_clear_timer_queue
    232 #define snd_pcm_direct_set_timer_params \
    233 	snd1_pcm_direct_set_timer_params
    234 #define snd_pcm_direct_open_secondary_client \
    235 	snd1_pcm_direct_open_secondary_client
    236 #define snd_pcm_direct_parse_open_conf \
    237 	snd1_pcm_direct_parse_open_conf
    238 
    239 int snd_pcm_direct_semaphore_create_or_connect(snd_pcm_direct_t *dmix);
    240 
    241 static inline int snd_pcm_direct_semaphore_discard(snd_pcm_direct_t *dmix)
    242 {
    243 	if (dmix->semid >= 0) {
    244 		if (semctl(dmix->semid, 0, IPC_RMID, NULL) < 0)
    245 			return -errno;
    246 		dmix->semid = -1;
    247 	}
    248 	return 0;
    249 }
    250 
    251 static inline int snd_pcm_direct_semaphore_down(snd_pcm_direct_t *dmix, int sem_num)
    252 {
    253 	struct sembuf op[2] = { { sem_num, 0, 0 }, { sem_num, 1, SEM_UNDO } };
    254 	return semop(dmix->semid, op, 2);
    255 }
    256 
    257 static inline int snd_pcm_direct_semaphore_up(snd_pcm_direct_t *dmix, int sem_num)
    258 {
    259 	struct sembuf op = { sem_num, -1, SEM_UNDO | IPC_NOWAIT };
    260 	return semop(dmix->semid, &op, 1);
    261 }
    262 
    263 int snd_pcm_direct_shm_create_or_connect(snd_pcm_direct_t *dmix);
    264 int snd_pcm_direct_shm_discard(snd_pcm_direct_t *dmix);
    265 int snd_pcm_direct_server_create(snd_pcm_direct_t *dmix);
    266 int snd_pcm_direct_server_discard(snd_pcm_direct_t *dmix);
    267 int snd_pcm_direct_client_connect(snd_pcm_direct_t *dmix);
    268 int snd_pcm_direct_client_discard(snd_pcm_direct_t *dmix);
    269 int snd_pcm_direct_initialize_slave(snd_pcm_direct_t *dmix, snd_pcm_t *spcm, struct slave_params *params);
    270 int snd_pcm_direct_initialize_secondary_slave(snd_pcm_direct_t *dmix, snd_pcm_t *spcm, struct slave_params *params);
    271 int snd_pcm_direct_initialize_poll_fd(snd_pcm_direct_t *dmix);
    272 int snd_pcm_direct_check_interleave(snd_pcm_direct_t *dmix, snd_pcm_t *pcm);
    273 int snd_pcm_direct_parse_bindings(snd_pcm_direct_t *dmix,
    274 				  struct slave_params *params,
    275 				  snd_config_t *cfg);
    276 int snd_pcm_direct_nonblock(snd_pcm_t *pcm, int nonblock);
    277 int snd_pcm_direct_async(snd_pcm_t *pcm, int sig, pid_t pid);
    278 int snd_pcm_direct_poll_revents(snd_pcm_t *pcm, struct pollfd *pfds, unsigned int nfds, unsigned short *revents);
    279 int snd_pcm_direct_info(snd_pcm_t *pcm, snd_pcm_info_t * info);
    280 int snd_pcm_direct_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params);
    281 int snd_pcm_direct_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params);
    282 int snd_pcm_direct_hw_free(snd_pcm_t *pcm);
    283 int snd_pcm_direct_sw_params(snd_pcm_t *pcm, snd_pcm_sw_params_t * params);
    284 int snd_pcm_direct_channel_info(snd_pcm_t *pcm, snd_pcm_channel_info_t * info);
    285 int snd_pcm_direct_mmap(snd_pcm_t *pcm);
    286 int snd_pcm_direct_munmap(snd_pcm_t *pcm);
    287 int snd_pcm_direct_resume(snd_pcm_t *pcm);
    288 int snd_pcm_direct_timer_stop(snd_pcm_direct_t *dmix);
    289 void snd_pcm_direct_clear_timer_queue(snd_pcm_direct_t *dmix);
    290 int snd_pcm_direct_set_timer_params(snd_pcm_direct_t *dmix);
    291 int snd_pcm_direct_open_secondary_client(snd_pcm_t **spcmp, snd_pcm_direct_t *dmix, const char *client_name);
    292 
    293 int snd_timer_async(snd_timer_t *timer, int sig, pid_t pid);
    294 struct timespec snd_pcm_hw_fast_tstamp(snd_pcm_t *pcm);
    295 
    296 struct snd_pcm_direct_open_conf {
    297 	key_t ipc_key;
    298 	mode_t ipc_perm;
    299 	int ipc_gid;
    300 	int slowptr;
    301 	int max_periods;
    302 	snd_config_t *slave;
    303 	snd_config_t *bindings;
    304 };
    305 
    306 int snd_pcm_direct_parse_open_conf(snd_config_t *root, snd_config_t *conf, int stream, struct snd_pcm_direct_open_conf *rec);
    307