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