1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
|
/*
* PCM - Direct Stream Mixing
* Copyright (c) 2003 by Jaroslav Kysela <perex@suse.cz>
*
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#include "pcm_local.h"
#define DIRECT_IPC_SEMS 1
#define DIRECT_IPC_SEM_CLIENT 0
typedef void (mix_areas1_t)(unsigned int size,
volatile signed short *dst, signed short *src,
volatile signed int *sum, size_t dst_step,
size_t src_step, size_t sum_step);
typedef void (mix_areas2_t)(unsigned int size,
volatile signed int *dst, signed int *src,
volatile signed int *sum, size_t dst_step,
size_t src_step, size_t sum_step);
typedef void (mix_areas3_t)(unsigned int size,
volatile unsigned char *dst, unsigned char *src,
volatile signed int *sum, size_t dst_step,
size_t src_step, size_t sum_step);
struct slave_params {
snd_pcm_format_t format;
int rate;
int channels;
int period_time;
int buffer_time;
snd_pcm_sframes_t period_size;
snd_pcm_sframes_t buffer_size;
unsigned int periods;
};
typedef struct {
char socket_name[256]; /* name of communication socket */
snd_pcm_type_t type; /* PCM type (currently only hw) */
struct {
unsigned int format;
snd_interval_t rate;
snd_interval_t buffer_size;
snd_interval_t buffer_time;
snd_interval_t period_size;
snd_interval_t period_time;
snd_interval_t periods;
} hw;
struct {
unsigned int buffer_size;
unsigned int period_size;
unsigned long long boundary;
unsigned int channels;
unsigned int sample_bits;
unsigned int rate;
snd_pcm_format_t format;
unsigned int info;
unsigned int msbits;
} s;
union {
struct {
unsigned long long chn_mask;
} dshare;
} u;
} snd_pcm_direct_share_t;
typedef struct snd_pcm_direct snd_pcm_direct_t;
struct snd_pcm_direct {
snd_pcm_type_t type; /* type (dmix, dsnoop, dshare) */
key_t ipc_key; /* IPC key for semaphore and memory */
mode_t ipc_perm; /* IPC socket permissions */
int ipc_gid; /* IPC socket gid */
int semid; /* IPC global semaphore identification */
int shmid; /* IPC global shared memory identification */
snd_pcm_direct_share_t *shmptr; /* pointer to shared memory area */
snd_pcm_t *spcm; /* slave PCM handle */
snd_pcm_uframes_t appl_ptr;
snd_pcm_uframes_t last_appl_ptr;
snd_pcm_uframes_t hw_ptr;
snd_pcm_uframes_t avail_max;
snd_pcm_uframes_t slave_appl_ptr;
snd_pcm_uframes_t slave_hw_ptr;
snd_pcm_uframes_t slave_period_size;
snd_pcm_uframes_t slave_buffer_size;
snd_pcm_uframes_t slave_boundary;
int (*sync_ptr)(snd_pcm_t *pcm);
snd_pcm_state_t state;
snd_htimestamp_t trigger_tstamp;
int server, client;
int comm_fd; /* communication file descriptor (socket) */
int hw_fd; /* hardware file descriptor */
struct pollfd timer_fd;
int poll_fd;
int tread;
int timer_need_poll;
unsigned int timer_event_suspend;
unsigned int timer_event_resume;
int server_fd;
pid_t server_pid;
snd_timer_t *timer; /* timer used as poll_fd */
int interleaved; /* we have interleaved buffer */
int slowptr; /* use slow but more precise ptr updates */
int variable_buffer_size; /* allow the variable buffer size */
unsigned int channels; /* client's channels */
unsigned int *bindings;
union {
struct {
int shmid_sum; /* IPC global sum ring buffer memory identification */
signed int *sum_buffer; /* shared sum buffer */
mix_areas1_t *mix_areas1;
mix_areas2_t *mix_areas2;
mix_areas3_t *mix_areas3;
} dmix;
struct {
} dsnoop;
struct {
unsigned long long chn_mask;
} dshare;
} u;
void (*server_free)(snd_pcm_direct_t *direct);
};
int snd_pcm_direct_semaphore_create_or_connect(snd_pcm_direct_t *dmix);
static inline int snd_pcm_direct_semaphore_discard(snd_pcm_direct_t *dmix)
{
if (dmix->semid >= 0) {
if (semctl(dmix->semid, 0, IPC_RMID, NULL) < 0)
return -errno;
dmix->semid = -1;
}
return 0;
}
static inline int snd_pcm_direct_semaphore_down(snd_pcm_direct_t *dmix, int sem_num)
{
struct sembuf op[2] = { { sem_num, 0, 0 }, { sem_num, 1, SEM_UNDO } };
return semop(dmix->semid, op, 2);
}
static inline int snd_pcm_direct_semaphore_up(snd_pcm_direct_t *dmix, int sem_num)
{
struct sembuf op = { sem_num, -1, SEM_UNDO | IPC_NOWAIT };
return semop(dmix->semid, &op, 1);
}
int snd_pcm_direct_shm_create_or_connect(snd_pcm_direct_t *dmix);
int snd_pcm_direct_shm_discard(snd_pcm_direct_t *dmix);
int snd_pcm_direct_server_create(snd_pcm_direct_t *dmix);
int snd_pcm_direct_server_discard(snd_pcm_direct_t *dmix);
int snd_pcm_direct_client_connect(snd_pcm_direct_t *dmix);
int snd_pcm_direct_client_discard(snd_pcm_direct_t *dmix);
int snd_pcm_direct_initialize_slave(snd_pcm_direct_t *dmix, snd_pcm_t *spcm, struct slave_params *params);
int snd_pcm_direct_initialize_poll_fd(snd_pcm_direct_t *dmix);
int snd_pcm_direct_check_interleave(snd_pcm_direct_t *dmix, snd_pcm_t *pcm);
int snd_pcm_direct_parse_bindings(snd_pcm_direct_t *dmix, snd_config_t *cfg);
int snd_pcm_direct_nonblock(snd_pcm_t *pcm, int nonblock);
int snd_pcm_direct_async(snd_pcm_t *pcm, int sig, pid_t pid);
int snd_pcm_direct_poll_revents(snd_pcm_t *pcm, struct pollfd *pfds, unsigned int nfds, unsigned short *revents);
int snd_pcm_direct_info(snd_pcm_t *pcm, snd_pcm_info_t * info);
int snd_pcm_direct_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params);
int snd_pcm_direct_hw_params(snd_pcm_t *pcm, snd_pcm_hw_params_t * params);
int snd_pcm_direct_hw_free(snd_pcm_t *pcm);
int snd_pcm_direct_sw_params(snd_pcm_t *pcm, snd_pcm_sw_params_t * params);
int snd_pcm_direct_channel_info(snd_pcm_t *pcm, snd_pcm_channel_info_t * info);
int snd_pcm_direct_mmap(snd_pcm_t *pcm);
int snd_pcm_direct_munmap(snd_pcm_t *pcm);
int snd_pcm_direct_resume(snd_pcm_t *pcm);
int snd_pcm_direct_timer_stop(snd_pcm_direct_t *dmix);
void snd_pcm_direct_clear_timer_queue(snd_pcm_direct_t *dmix);
int snd_pcm_direct_set_timer_params(snd_pcm_direct_t *dmix);
int snd_pcm_direct_open_secondary_client(snd_pcm_t **spcmp, snd_pcm_direct_t *dmix, const char *client_name);
int snd_pcm_direct_get_slave_ipc_offset(snd_config_t *root, snd_config_t *sconf, int direction);
int snd_timer_async(snd_timer_t *timer, int sig, pid_t pid);
struct timespec snd_pcm_hw_fast_tstamp(snd_pcm_t *pcm);
struct snd_pcm_direct_open_conf {
key_t ipc_key;
mode_t ipc_perm;
int ipc_gid;
int slowptr;
int variable_buffer_size;
snd_config_t *slave;
snd_config_t *bindings;
};
int snd_pcm_direct_parse_open_conf(snd_config_t *conf, struct snd_pcm_direct_open_conf *rec);
|