mirror of
				https://github.com/alsa-project/alsa-lib.git
				synced 2025-11-03 09:01:52 -05:00 
			
		
		
		
	Fixed mmap wrt shm. Renamed pcm_client, control_client to shm. More error messages. Implemented asoundrc as documented.
This commit is contained in:
		
							parent
							
								
									dcc88ffaa7
								
							
						
					
					
						commit
						e5e1ca14d4
					
				
					 30 changed files with 1642 additions and 2555 deletions
				
			
		
							
								
								
									
										1
									
								
								TODO
									
										
									
									
									
								
							
							
						
						
									
										1
									
								
								TODO
									
										
									
									
									
								
							| 
						 | 
					@ -1,3 +1,2 @@
 | 
				
			||||||
H solve multi/server mmap'ing problem
 | 
					 | 
				
			||||||
M add abstraction layer to timer, rawmidi, hwdep, seq
 | 
					M add abstraction layer to timer, rawmidi, hwdep, seq
 | 
				
			||||||
L move OSS emulation to user space? (pseudo device driver and daemon)
 | 
					L move OSS emulation to user space? (pseudo device driver and daemon)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -31,29 +31,29 @@
 | 
				
			||||||
#include <stddef.h>
 | 
					#include <stddef.h>
 | 
				
			||||||
#include <getopt.h>
 | 
					#include <getopt.h>
 | 
				
			||||||
#include <netinet/in.h>
 | 
					#include <netinet/in.h>
 | 
				
			||||||
 | 
					#include <netdb.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "asoundlib.h"
 | 
					#include "asoundlib.h"
 | 
				
			||||||
#include "pcm_local.h"
 | 
					 | 
				
			||||||
#include "aserver.h"
 | 
					#include "aserver.h"
 | 
				
			||||||
#include "list.h"
 | 
					#include "list.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
char *command;
 | 
					char *command;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 95)
 | 
					#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 95)
 | 
				
			||||||
#define error(...) do {\
 | 
					#define ERROR(...) do {\
 | 
				
			||||||
	fprintf(stderr, "%s: %s:%d: ", command, __FUNCTION__, __LINE__); \
 | 
						fprintf(stderr, "%s %s:%i:(%s) ", command, __FILE__, __LINE__, __FUNCTION__); \
 | 
				
			||||||
	fprintf(stderr, __VA_ARGS__); \
 | 
						fprintf(stderr, __VA_ARGS__); \
 | 
				
			||||||
	putc('\n', stderr); \
 | 
						putc('\n', stderr); \
 | 
				
			||||||
} while (0)
 | 
					} while (0)
 | 
				
			||||||
#else
 | 
					#else
 | 
				
			||||||
#define error(args...) do {\
 | 
					#define ERROR(args...) do {\
 | 
				
			||||||
	fprintf(stderr, "%s: %s:%d: ", command, __FUNCTION__, __LINE__); \
 | 
						fprintf(stderr, "%s %s:%i:(%s) ", command, __FILE__, __LINE__, __FUNCTION__); \
 | 
				
			||||||
	fprintf(stderr, ##args); \
 | 
						fprintf(stderr, ##args); \
 | 
				
			||||||
	putc('\n', stderr); \
 | 
						putc('\n', stderr); \
 | 
				
			||||||
} while (0)
 | 
					} while (0)
 | 
				
			||||||
#endif	
 | 
					#endif	
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define perrno(string) error("%s", strerror(errno))
 | 
					#define SYSERR(string) ERROR(string ": %s", strerror(errno))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int make_local_socket(const char *filename)
 | 
					int make_local_socket(const char *filename)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
| 
						 | 
					@ -65,7 +65,7 @@ int make_local_socket(const char *filename)
 | 
				
			||||||
	sock = socket(PF_LOCAL, SOCK_STREAM, 0);
 | 
						sock = socket(PF_LOCAL, SOCK_STREAM, 0);
 | 
				
			||||||
	if (sock < 0) {
 | 
						if (sock < 0) {
 | 
				
			||||||
		int result = -errno;
 | 
							int result = -errno;
 | 
				
			||||||
		perrno("socket");
 | 
							SYSERR("socket");
 | 
				
			||||||
		return result;
 | 
							return result;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
| 
						 | 
					@ -76,7 +76,7 @@ int make_local_socket(const char *filename)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (bind(sock, (struct sockaddr *) addr, size) < 0) {
 | 
						if (bind(sock, (struct sockaddr *) addr, size) < 0) {
 | 
				
			||||||
		int result = -errno;
 | 
							int result = -errno;
 | 
				
			||||||
		perrno("bind");
 | 
							SYSERR("bind");
 | 
				
			||||||
		return result;
 | 
							return result;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -91,7 +91,7 @@ int make_inet_socket(int port)
 | 
				
			||||||
	sock = socket(PF_INET, SOCK_STREAM, 0);
 | 
						sock = socket(PF_INET, SOCK_STREAM, 0);
 | 
				
			||||||
	if (sock < 0) {
 | 
						if (sock < 0) {
 | 
				
			||||||
		int result = -errno;
 | 
							int result = -errno;
 | 
				
			||||||
		perrno("socket");
 | 
							SYSERR("socket");
 | 
				
			||||||
		return result;
 | 
							return result;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
| 
						 | 
					@ -101,7 +101,7 @@ int make_inet_socket(int port)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (bind(sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
 | 
						if (bind(sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
 | 
				
			||||||
		int result = -errno;
 | 
							int result = -errno;
 | 
				
			||||||
		perrno("bind");
 | 
							SYSERR("bind");
 | 
				
			||||||
		return result;
 | 
							return result;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -135,7 +135,7 @@ int send_fd(int socket, void *data, size_t len, int fd)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ret = sendmsg(socket, &msghdr, 0 );
 | 
					    ret = sendmsg(socket, &msghdr, 0 );
 | 
				
			||||||
    if (ret < 0) {
 | 
					    if (ret < 0) {
 | 
				
			||||||
	    perrno("sendmsg");
 | 
						    SYSERR("sendmsg");
 | 
				
			||||||
	    return -errno;
 | 
						    return -errno;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    return ret;
 | 
					    return ret;
 | 
				
			||||||
| 
						 | 
					@ -182,13 +182,6 @@ void del_waiter(int fd)
 | 
				
			||||||
	memmove(&pollfds[k], &pollfds[k + 1], pollfds_count - k);
 | 
						memmove(&pollfds[k], &pollfds[k + 1], pollfds_count - k);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef struct {
 | 
					 | 
				
			||||||
	struct list_head list;
 | 
					 | 
				
			||||||
	int fd;
 | 
					 | 
				
			||||||
	int local;
 | 
					 | 
				
			||||||
} master_t;
 | 
					 | 
				
			||||||
LIST_HEAD(masters);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
typedef struct client client_t;
 | 
					typedef struct client client_t;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef struct {
 | 
					typedef struct {
 | 
				
			||||||
| 
						 | 
					@ -199,10 +192,9 @@ typedef struct {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct client {
 | 
					struct client {
 | 
				
			||||||
	struct list_head list;
 | 
						struct list_head list;
 | 
				
			||||||
	struct socket {
 | 
						int poll_fd;
 | 
				
			||||||
		int fd;
 | 
						int ctrl_fd;
 | 
				
			||||||
		int local;
 | 
						int local;
 | 
				
			||||||
	} data, ctrl;
 | 
					 | 
				
			||||||
	int transport_type;
 | 
						int transport_type;
 | 
				
			||||||
	int dev_type;
 | 
						int dev_type;
 | 
				
			||||||
	char name[256];
 | 
						char name[256];
 | 
				
			||||||
| 
						 | 
					@ -250,9 +242,8 @@ typedef struct {
 | 
				
			||||||
	struct list_head list;
 | 
						struct list_head list;
 | 
				
			||||||
	int fd;
 | 
						int fd;
 | 
				
			||||||
	uint32_t cookie;
 | 
						uint32_t cookie;
 | 
				
			||||||
	int local;
 | 
					} inet_pending_t;
 | 
				
			||||||
} pending_t;
 | 
					LIST_HEAD(inet_pendings);
 | 
				
			||||||
LIST_HEAD(pendings);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
int pcm_handler(waiter_t *waiter, unsigned short events)
 | 
					int pcm_handler(waiter_t *waiter, unsigned short events)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
| 
						 | 
					@ -260,15 +251,15 @@ int pcm_handler(waiter_t *waiter, unsigned short events)
 | 
				
			||||||
	char buf[1];
 | 
						char buf[1];
 | 
				
			||||||
	ssize_t n;
 | 
						ssize_t n;
 | 
				
			||||||
	if (events & POLLIN) {
 | 
						if (events & POLLIN) {
 | 
				
			||||||
		n = write(client->data.fd, buf, 1);
 | 
							n = write(client->poll_fd, buf, 1);
 | 
				
			||||||
		if (n != 1) {
 | 
							if (n != 1) {
 | 
				
			||||||
			perrno("write");
 | 
								SYSERR("write");
 | 
				
			||||||
			return -errno;
 | 
								return -errno;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	} else if (events & POLLOUT) {
 | 
						} else if (events & POLLOUT) {
 | 
				
			||||||
		n = read(client->data.fd, buf, 1);
 | 
							n = read(client->poll_fd, buf, 1);
 | 
				
			||||||
		if (n != 1) {
 | 
							if (n != 1) {
 | 
				
			||||||
			perrno("read");
 | 
								SYSERR("read");
 | 
				
			||||||
			return -errno;
 | 
								return -errno;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -283,7 +274,7 @@ int pcm_shm_open(client_t *client, int *cookie)
 | 
				
			||||||
	snd_pcm_t *pcm;
 | 
						snd_pcm_t *pcm;
 | 
				
			||||||
	int err;
 | 
						int err;
 | 
				
			||||||
	int result;
 | 
						int result;
 | 
				
			||||||
	err = snd_pcm_open(&pcm, client->name, client->stream, client->mode);
 | 
						err = snd_pcm_open(&pcm, client->name, client->stream, SND_PCM_NONBLOCK);
 | 
				
			||||||
	if (err < 0)
 | 
						if (err < 0)
 | 
				
			||||||
		return err;
 | 
							return err;
 | 
				
			||||||
	client->device.pcm.handle = pcm;
 | 
						client->device.pcm.handle = pcm;
 | 
				
			||||||
| 
						 | 
					@ -292,7 +283,7 @@ int pcm_shm_open(client_t *client, int *cookie)
 | 
				
			||||||
	shmid = shmget(IPC_PRIVATE, PCM_SHM_SIZE, 0666);
 | 
						shmid = shmget(IPC_PRIVATE, PCM_SHM_SIZE, 0666);
 | 
				
			||||||
	if (shmid < 0) {
 | 
						if (shmid < 0) {
 | 
				
			||||||
		result = -errno;
 | 
							result = -errno;
 | 
				
			||||||
		perrno("shmget");
 | 
							SYSERR("shmget");
 | 
				
			||||||
		goto _err;
 | 
							goto _err;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	client->transport.shm.ctrl_id = shmid;
 | 
						client->transport.shm.ctrl_id = shmid;
 | 
				
			||||||
| 
						 | 
					@ -300,7 +291,7 @@ int pcm_shm_open(client_t *client, int *cookie)
 | 
				
			||||||
	if (!client->transport.shm.ctrl) {
 | 
						if (!client->transport.shm.ctrl) {
 | 
				
			||||||
		result = -errno;
 | 
							result = -errno;
 | 
				
			||||||
		shmctl(shmid, IPC_RMID, 0);
 | 
							shmctl(shmid, IPC_RMID, 0);
 | 
				
			||||||
		perrno("shmat");
 | 
							SYSERR("shmat");
 | 
				
			||||||
		goto _err;
 | 
							goto _err;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	*cookie = shmid;
 | 
						*cookie = shmid;
 | 
				
			||||||
| 
						 | 
					@ -315,38 +306,66 @@ int pcm_shm_open(client_t *client, int *cookie)
 | 
				
			||||||
int pcm_shm_close(client_t *client)
 | 
					int pcm_shm_close(client_t *client)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int err;
 | 
						int err;
 | 
				
			||||||
	snd_pcm_client_shm_t *ctrl = client->transport.shm.ctrl;
 | 
						snd_pcm_shm_ctrl_t *ctrl = client->transport.shm.ctrl;
 | 
				
			||||||
	if (client->polling) {
 | 
						if (client->polling) {
 | 
				
			||||||
		del_waiter(client->device.pcm.fd);
 | 
							del_waiter(client->device.pcm.fd);
 | 
				
			||||||
		client->polling = 0;
 | 
							client->polling = 0;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	/* FIXME: blocking */
 | 
					 | 
				
			||||||
	err = snd_pcm_close(client->device.pcm.handle);
 | 
						err = snd_pcm_close(client->device.pcm.handle);
 | 
				
			||||||
	ctrl->result = err;
 | 
						ctrl->result = err;
 | 
				
			||||||
	if (err < 0) 
 | 
						if (err < 0) 
 | 
				
			||||||
		perrno("snd_pcm_close");
 | 
							SYSERR("snd_pcm_close");
 | 
				
			||||||
	if (client->transport.shm.ctrl) {
 | 
						if (client->transport.shm.ctrl) {
 | 
				
			||||||
		err = shmdt((void *)client->transport.shm.ctrl);
 | 
							err = shmdt((void *)client->transport.shm.ctrl);
 | 
				
			||||||
		if (err < 0)
 | 
							if (err < 0)
 | 
				
			||||||
			perrno("shmdt");
 | 
								SYSERR("shmdt");
 | 
				
			||||||
		err = shmctl(client->transport.shm.ctrl_id, IPC_RMID, 0);
 | 
							err = shmctl(client->transport.shm.ctrl_id, IPC_RMID, 0);
 | 
				
			||||||
		if (err < 0)
 | 
							if (err < 0)
 | 
				
			||||||
			perrno("shmctl");
 | 
								SYSERR("shmctl");
 | 
				
			||||||
		client->transport.shm.ctrl = 0;
 | 
							client->transport.shm.ctrl = 0;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	client->open = 0;
 | 
						client->open = 0;
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int shm_ack(client_t *client)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct pollfd pfd;
 | 
				
			||||||
 | 
						int err;
 | 
				
			||||||
 | 
						char buf[1];
 | 
				
			||||||
 | 
						pfd.fd = client->ctrl_fd;
 | 
				
			||||||
 | 
						pfd.events = POLLHUP;
 | 
				
			||||||
 | 
						if (poll(&pfd, 1, 0) == 1)
 | 
				
			||||||
 | 
							return -EBADFD;
 | 
				
			||||||
 | 
						err = write(client->ctrl_fd, buf, 1);
 | 
				
			||||||
 | 
						if (err != 1)
 | 
				
			||||||
 | 
							return -EBADFD;
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int shm_ack_fd(client_t *client, int fd)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct pollfd pfd;
 | 
				
			||||||
 | 
						int err;
 | 
				
			||||||
 | 
						char buf[1];
 | 
				
			||||||
 | 
						pfd.fd = client->ctrl_fd;
 | 
				
			||||||
 | 
						pfd.events = POLLHUP;
 | 
				
			||||||
 | 
						if (poll(&pfd, 1, 0) == 1)
 | 
				
			||||||
 | 
							return -EBADFD;
 | 
				
			||||||
 | 
						err = send_fd(client->ctrl_fd, buf, 1, fd);
 | 
				
			||||||
 | 
						if (err != 1)
 | 
				
			||||||
 | 
							return -EBADFD;
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int pcm_shm_cmd(client_t *client)
 | 
					int pcm_shm_cmd(client_t *client)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	snd_pcm_client_shm_t *ctrl = client->transport.shm.ctrl;
 | 
						snd_pcm_shm_ctrl_t *ctrl = client->transport.shm.ctrl;
 | 
				
			||||||
	struct pollfd pfd;
 | 
					 | 
				
			||||||
	char buf[1];
 | 
						char buf[1];
 | 
				
			||||||
	int err;
 | 
						int err;
 | 
				
			||||||
	int cmd;
 | 
						int cmd;
 | 
				
			||||||
	snd_pcm_t *pcm;
 | 
						snd_pcm_t *pcm;
 | 
				
			||||||
	err = read(client->ctrl.fd, buf, 1);
 | 
						err = read(client->ctrl_fd, buf, 1);
 | 
				
			||||||
	if (err != 1)
 | 
						if (err != 1)
 | 
				
			||||||
		return -EBADFD;
 | 
							return -EBADFD;
 | 
				
			||||||
	cmd = ctrl->cmd;
 | 
						cmd = ctrl->cmd;
 | 
				
			||||||
| 
						 | 
					@ -409,63 +428,74 @@ int pcm_shm_cmd(client_t *client)
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	case SND_PCM_IOCTL_LINK:
 | 
						case SND_PCM_IOCTL_LINK:
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		struct list_head *item;
 | 
							/* FIXME */
 | 
				
			||||||
		list_for_each(item, &clients) {
 | 
							ctrl->result = -ENOSYS;
 | 
				
			||||||
			client_t *client = list_entry(item, client_t, list);
 | 
					 | 
				
			||||||
			if (!client->open)
 | 
					 | 
				
			||||||
				continue;
 | 
					 | 
				
			||||||
			if (client->data.fd == ctrl->u.link) {
 | 
					 | 
				
			||||||
				ctrl->result = snd_pcm_link(pcm, client->device.pcm.handle);
 | 
					 | 
				
			||||||
				break;
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		ctrl->result = -EBADFD;
 | 
					 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	case SND_PCM_IOCTL_UNLINK:
 | 
						case SND_PCM_IOCTL_UNLINK:
 | 
				
			||||||
		ctrl->result = snd_pcm_unlink(pcm);
 | 
							ctrl->result = snd_pcm_unlink(pcm);
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	case SND_PCM_IOCTL_MMAP_DATA:
 | 
						case SND_PCM_IOCTL_MMAP:
 | 
				
			||||||
	case SND_PCM_IOCTL_MMAP_CONTROL:
 | 
					 | 
				
			||||||
	case SND_PCM_IOCTL_MMAP_STATUS:
 | 
					 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		pfd.fd = client->ctrl.fd;
 | 
							err = snd_pcm_mmap(pcm);
 | 
				
			||||||
		pfd.events = POLLHUP;
 | 
							if (err < 0)
 | 
				
			||||||
		if (poll(&pfd, 1, 0) == 1)
 | 
								ctrl->result = err;
 | 
				
			||||||
			return -EBADFD;
 | 
							else
 | 
				
			||||||
		err = send_fd(client->ctrl.fd, buf, 1, client->device.pcm.fd);
 | 
								ctrl->result = pcm->mmap_info_count;
 | 
				
			||||||
		if (err != 1)
 | 
					 | 
				
			||||||
			return -EBADFD;
 | 
					 | 
				
			||||||
		ctrl->result = 0;
 | 
					 | 
				
			||||||
		return 0;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	case SND_PCM_IOCTL_MUNMAP_DATA:
 | 
					 | 
				
			||||||
	case SND_PCM_IOCTL_MUNMAP_CONTROL:
 | 
					 | 
				
			||||||
	case SND_PCM_IOCTL_MUNMAP_STATUS:
 | 
					 | 
				
			||||||
		ctrl->result = 0;
 | 
					 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						case SND_PCM_IOCTL_MMAP_INFO:
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							snd_pcm_mmap_info_t *i;
 | 
				
			||||||
 | 
							unsigned int index = ctrl->u.mmap_info.index;
 | 
				
			||||||
 | 
							if (index >= pcm->mmap_info_count) {
 | 
				
			||||||
 | 
								ctrl->result = -EINVAL;
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							i = &pcm->mmap_info[index];
 | 
				
			||||||
 | 
							if (i->type == SND_PCM_MMAP_USER) {
 | 
				
			||||||
 | 
								i->u.user.shmid = shmget(IPC_PRIVATE, i->size, 0666);
 | 
				
			||||||
 | 
								if (i->u.user.shmid < 0) {
 | 
				
			||||||
 | 
									SYSERR("shmget");
 | 
				
			||||||
 | 
									return -EINVAL;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							ctrl->u.mmap_info = *i;
 | 
				
			||||||
 | 
							ctrl->u.mmap_info.index = index;
 | 
				
			||||||
 | 
							ctrl->result = 0;
 | 
				
			||||||
 | 
							if (i->type == SND_PCM_MMAP_USER)
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							return shm_ack_fd(client, i->u.kernel.fd);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						case SND_PCM_IOCTL_MUNMAP:
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							size_t k;
 | 
				
			||||||
 | 
							ctrl->result = snd_pcm_munmap(pcm);
 | 
				
			||||||
 | 
							if (ctrl->result < 0)
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							for (k = 0; k < pcm->mmap_info_count; ++k) {
 | 
				
			||||||
 | 
								snd_pcm_mmap_info_t *i = &pcm->mmap_info[k];
 | 
				
			||||||
 | 
								if (i->type == SND_PCM_MMAP_USER) {
 | 
				
			||||||
 | 
									int err = shmdt(i->addr);
 | 
				
			||||||
 | 
									assert(err >= 0);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	case SND_PCM_IOCTL_MMAP_FORWARD:
 | 
						case SND_PCM_IOCTL_MMAP_FORWARD:
 | 
				
			||||||
		ctrl->result = snd_pcm_mmap_forward(pcm, ctrl->u.mmap_forward);
 | 
							ctrl->result = snd_pcm_mmap_forward(pcm, ctrl->u.mmap_forward);
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
 | 
						case SND_PCM_IOCTL_POLL_DESCRIPTOR:
 | 
				
			||||||
 | 
							ctrl->result = 0;
 | 
				
			||||||
 | 
							return shm_ack_fd(client, snd_pcm_poll_descriptor(pcm));
 | 
				
			||||||
	case SND_PCM_IOCTL_CLOSE:
 | 
						case SND_PCM_IOCTL_CLOSE:
 | 
				
			||||||
		client->ops->close(client);
 | 
							client->ops->close(client);
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	default:
 | 
						default:
 | 
				
			||||||
		fprintf(stderr, "Bogus cmd: %x\n", ctrl->cmd);
 | 
							ERROR("Bogus cmd: %x", ctrl->cmd);
 | 
				
			||||||
		ctrl->result = -ENOSYS;
 | 
							ctrl->result = -ENOSYS;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	pfd.fd = client->ctrl.fd;
 | 
						return shm_ack(client);
 | 
				
			||||||
	pfd.events = POLLHUP;
 | 
					 | 
				
			||||||
	if (poll(&pfd, 1, 0) == 1)
 | 
					 | 
				
			||||||
		return -EBADFD;
 | 
					 | 
				
			||||||
	err = write(client->ctrl.fd, buf, 1);
 | 
					 | 
				
			||||||
	if (err != 1)
 | 
					 | 
				
			||||||
		return -EBADFD;
 | 
					 | 
				
			||||||
	if (!client->polling) {
 | 
					 | 
				
			||||||
		add_waiter(client->device.pcm.fd, POLLIN | POLLOUT, pcm_handler, client);
 | 
					 | 
				
			||||||
		client->polling = 1;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
transport_ops_t pcm_shm_ops = {
 | 
					transport_ops_t pcm_shm_ops = {
 | 
				
			||||||
| 
						 | 
					@ -480,9 +510,9 @@ int ctl_handler(waiter_t *waiter, unsigned short events)
 | 
				
			||||||
	char buf[1];
 | 
						char buf[1];
 | 
				
			||||||
	ssize_t n;
 | 
						ssize_t n;
 | 
				
			||||||
	if (events & POLLIN) {
 | 
						if (events & POLLIN) {
 | 
				
			||||||
		n = write(client->data.fd, buf, 1);
 | 
							n = write(client->poll_fd, buf, 1);
 | 
				
			||||||
		if (n != 1) {
 | 
							if (n != 1) {
 | 
				
			||||||
			perrno("write");
 | 
								SYSERR("write");
 | 
				
			||||||
			return -errno;
 | 
								return -errno;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -506,7 +536,7 @@ int ctl_shm_open(client_t *client, int *cookie)
 | 
				
			||||||
	shmid = shmget(IPC_PRIVATE, CTL_SHM_SIZE, 0666);
 | 
						shmid = shmget(IPC_PRIVATE, CTL_SHM_SIZE, 0666);
 | 
				
			||||||
	if (shmid < 0) {
 | 
						if (shmid < 0) {
 | 
				
			||||||
		result = -errno;
 | 
							result = -errno;
 | 
				
			||||||
		perrno("shmget");
 | 
							SYSERR("shmget");
 | 
				
			||||||
		goto _err;
 | 
							goto _err;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	client->transport.shm.ctrl_id = shmid;
 | 
						client->transport.shm.ctrl_id = shmid;
 | 
				
			||||||
| 
						 | 
					@ -514,7 +544,7 @@ int ctl_shm_open(client_t *client, int *cookie)
 | 
				
			||||||
	if (!client->transport.shm.ctrl) {
 | 
						if (!client->transport.shm.ctrl) {
 | 
				
			||||||
		result = -errno;
 | 
							result = -errno;
 | 
				
			||||||
		shmctl(shmid, IPC_RMID, 0);
 | 
							shmctl(shmid, IPC_RMID, 0);
 | 
				
			||||||
		perrno("shmat");
 | 
							SYSERR("shmat");
 | 
				
			||||||
		goto _err;
 | 
							goto _err;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	*cookie = shmid;
 | 
						*cookie = shmid;
 | 
				
			||||||
| 
						 | 
					@ -531,23 +561,22 @@ int ctl_shm_open(client_t *client, int *cookie)
 | 
				
			||||||
int ctl_shm_close(client_t *client)
 | 
					int ctl_shm_close(client_t *client)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int err;
 | 
						int err;
 | 
				
			||||||
	snd_ctl_client_shm_t *ctrl = client->transport.shm.ctrl;
 | 
						snd_ctl_shm_ctrl_t *ctrl = client->transport.shm.ctrl;
 | 
				
			||||||
	if (client->polling) {
 | 
						if (client->polling) {
 | 
				
			||||||
		del_waiter(client->device.control.fd);
 | 
							del_waiter(client->device.control.fd);
 | 
				
			||||||
		client->polling = 0;
 | 
							client->polling = 0;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	/* FIXME: blocking */
 | 
					 | 
				
			||||||
	err = snd_ctl_close(client->device.control.handle);
 | 
						err = snd_ctl_close(client->device.control.handle);
 | 
				
			||||||
	ctrl->result = err;
 | 
						ctrl->result = err;
 | 
				
			||||||
	if (err < 0) 
 | 
						if (err < 0) 
 | 
				
			||||||
		perrno("snd_ctl_close");
 | 
							SYSERR("snd_ctl_close");
 | 
				
			||||||
	if (client->transport.shm.ctrl) {
 | 
						if (client->transport.shm.ctrl) {
 | 
				
			||||||
		err = shmdt((void *)client->transport.shm.ctrl);
 | 
							err = shmdt((void *)client->transport.shm.ctrl);
 | 
				
			||||||
		if (err < 0)
 | 
							if (err < 0)
 | 
				
			||||||
			perrno("shmdt");
 | 
								SYSERR("shmdt");
 | 
				
			||||||
		err = shmctl(client->transport.shm.ctrl_id, IPC_RMID, 0);
 | 
							err = shmctl(client->transport.shm.ctrl_id, IPC_RMID, 0);
 | 
				
			||||||
		if (err < 0)
 | 
							if (err < 0)
 | 
				
			||||||
			perrno("shmctl");
 | 
								SYSERR("shmctl");
 | 
				
			||||||
		client->transport.shm.ctrl = 0;
 | 
							client->transport.shm.ctrl = 0;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	client->open = 0;
 | 
						client->open = 0;
 | 
				
			||||||
| 
						 | 
					@ -558,13 +587,12 @@ extern int snd_ctl_read1(snd_ctl_t *ctl, snd_ctl_event_t *event);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int ctl_shm_cmd(client_t *client)
 | 
					int ctl_shm_cmd(client_t *client)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	snd_ctl_client_shm_t *ctrl = client->transport.shm.ctrl;
 | 
						snd_ctl_shm_ctrl_t *ctrl = client->transport.shm.ctrl;
 | 
				
			||||||
	struct pollfd pfd;
 | 
					 | 
				
			||||||
	char buf[1];
 | 
						char buf[1];
 | 
				
			||||||
	int err;
 | 
						int err;
 | 
				
			||||||
	int cmd;
 | 
						int cmd;
 | 
				
			||||||
	snd_ctl_t *ctl;
 | 
						snd_ctl_t *ctl;
 | 
				
			||||||
	err = read(client->ctrl.fd, buf, 1);
 | 
						err = read(client->ctrl_fd, buf, 1);
 | 
				
			||||||
	if (err != 1)
 | 
						if (err != 1)
 | 
				
			||||||
		return -EBADFD;
 | 
							return -EBADFD;
 | 
				
			||||||
	cmd = ctrl->cmd;
 | 
						cmd = ctrl->cmd;
 | 
				
			||||||
| 
						 | 
					@ -612,22 +640,14 @@ int ctl_shm_cmd(client_t *client)
 | 
				
			||||||
	case SND_CTL_IOCTL_CLOSE:
 | 
						case SND_CTL_IOCTL_CLOSE:
 | 
				
			||||||
		client->ops->close(client);
 | 
							client->ops->close(client);
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
 | 
						case SND_PCM_IOCTL_POLL_DESCRIPTOR:
 | 
				
			||||||
 | 
							ctrl->result = 0;
 | 
				
			||||||
 | 
							return shm_ack_fd(client, snd_ctl_poll_descriptor(ctl));
 | 
				
			||||||
	default:
 | 
						default:
 | 
				
			||||||
		fprintf(stderr, "Bogus cmd: %x\n", ctrl->cmd);
 | 
							ERROR("Bogus cmd: %x", ctrl->cmd);
 | 
				
			||||||
		ctrl->result = -ENOSYS;
 | 
							ctrl->result = -ENOSYS;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	pfd.fd = client->ctrl.fd;
 | 
						return shm_ack(client);
 | 
				
			||||||
	pfd.events = POLLHUP;
 | 
					 | 
				
			||||||
	if (poll(&pfd, 1, 0) == 1)
 | 
					 | 
				
			||||||
		return -EBADFD;
 | 
					 | 
				
			||||||
	err = write(client->ctrl.fd, buf, 1);
 | 
					 | 
				
			||||||
	if (err != 1)
 | 
					 | 
				
			||||||
		return -EBADFD;
 | 
					 | 
				
			||||||
	if (!client->polling) {
 | 
					 | 
				
			||||||
		add_waiter(client->device.control.fd, POLLIN, ctl_handler, client);
 | 
					 | 
				
			||||||
		client->polling = 1;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
transport_ops_t ctl_shm_ops = {
 | 
					transport_ops_t ctl_shm_ops = {
 | 
				
			||||||
| 
						 | 
					@ -643,9 +663,9 @@ int snd_client_open(client_t *client)
 | 
				
			||||||
	snd_client_open_answer_t ans;
 | 
						snd_client_open_answer_t ans;
 | 
				
			||||||
	char *name;
 | 
						char *name;
 | 
				
			||||||
	memset(&ans, 0, sizeof(ans));
 | 
						memset(&ans, 0, sizeof(ans));
 | 
				
			||||||
	err = read(client->ctrl.fd, &req, sizeof(req));
 | 
						err = read(client->ctrl_fd, &req, sizeof(req));
 | 
				
			||||||
	if (err < 0) {
 | 
						if (err < 0) {
 | 
				
			||||||
		perrno("read");
 | 
							SYSERR("read");
 | 
				
			||||||
		exit(1);
 | 
							exit(1);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if (err != sizeof(req)) {
 | 
						if (err != sizeof(req)) {
 | 
				
			||||||
| 
						 | 
					@ -653,9 +673,9 @@ int snd_client_open(client_t *client)
 | 
				
			||||||
		goto _answer;
 | 
							goto _answer;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	name = alloca(req.namelen);
 | 
						name = alloca(req.namelen);
 | 
				
			||||||
	err = read(client->ctrl.fd, name, req.namelen);
 | 
						err = read(client->ctrl_fd, name, req.namelen);
 | 
				
			||||||
	if (err < 0) {
 | 
						if (err < 0) {
 | 
				
			||||||
		perrno("read");
 | 
							SYSERR("read");
 | 
				
			||||||
		exit(1);
 | 
							exit(1);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if (err != req.namelen) {
 | 
						if (err != req.namelen) {
 | 
				
			||||||
| 
						 | 
					@ -663,20 +683,17 @@ int snd_client_open(client_t *client)
 | 
				
			||||||
		goto _answer;
 | 
							goto _answer;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	switch (req.dev_type) {
 | 
						switch (req.transport_type) {
 | 
				
			||||||
	case SND_DEV_TYPE_PCM:
 | 
						case SND_TRANSPORT_TYPE_SHM:
 | 
				
			||||||
		switch (req.transport_type) {
 | 
							if (!client->local) {
 | 
				
			||||||
		case SND_TRANSPORT_TYPE_SHM:
 | 
					 | 
				
			||||||
			client->ops = &pcm_shm_ops;
 | 
					 | 
				
			||||||
			break;
 | 
					 | 
				
			||||||
		default:
 | 
					 | 
				
			||||||
			ans.result = -EINVAL;
 | 
								ans.result = -EINVAL;
 | 
				
			||||||
			goto _answer;
 | 
								goto _answer;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		break;
 | 
							switch (req.dev_type) {
 | 
				
			||||||
	case SND_DEV_TYPE_CONTROL:
 | 
							case SND_DEV_TYPE_PCM:
 | 
				
			||||||
		switch (req.transport_type) {
 | 
								client->ops = &pcm_shm_ops;
 | 
				
			||||||
		case SND_TRANSPORT_TYPE_SHM:
 | 
								break;
 | 
				
			||||||
 | 
							case SND_DEV_TYPE_CONTROL:
 | 
				
			||||||
			client->ops = &ctl_shm_ops;
 | 
								client->ops = &ctl_shm_ops;
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		default:
 | 
							default:
 | 
				
			||||||
| 
						 | 
					@ -701,27 +718,27 @@ int snd_client_open(client_t *client)
 | 
				
			||||||
		ans.result = err;
 | 
							ans.result = err;
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		client->open = 1;
 | 
							client->open = 1;
 | 
				
			||||||
		ans.result = client->data.fd;
 | 
							ans.result = 0;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 _answer:
 | 
					 _answer:
 | 
				
			||||||
	err = write(client->ctrl.fd, &ans, sizeof(ans));
 | 
						err = write(client->ctrl_fd, &ans, sizeof(ans));
 | 
				
			||||||
	if (err != sizeof(ans)) {
 | 
						if (err != sizeof(ans)) {
 | 
				
			||||||
		perrno("write");
 | 
							SYSERR("write");
 | 
				
			||||||
		exit(1);
 | 
							exit(1);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int client_data_handler(waiter_t *waiter, unsigned short events ATTRIBUTE_UNUSED)
 | 
					int client_poll_handler(waiter_t *waiter, unsigned short events ATTRIBUTE_UNUSED)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	client_t *client = waiter->private_data;
 | 
						client_t *client = waiter->private_data;
 | 
				
			||||||
	if (client->open)
 | 
						if (client->open)
 | 
				
			||||||
		client->ops->close(client);
 | 
							client->ops->close(client);
 | 
				
			||||||
	close(client->data.fd);
 | 
						close(client->poll_fd);
 | 
				
			||||||
	close(client->ctrl.fd);
 | 
						close(client->ctrl_fd);
 | 
				
			||||||
	del_waiter(client->data.fd);
 | 
						del_waiter(client->poll_fd);
 | 
				
			||||||
	del_waiter(client->ctrl.fd);
 | 
						del_waiter(client->ctrl_fd);
 | 
				
			||||||
	list_del(&client->list);
 | 
						list_del(&client->list);
 | 
				
			||||||
	free(client);
 | 
						free(client);
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
| 
						 | 
					@ -730,18 +747,25 @@ int client_data_handler(waiter_t *waiter, unsigned short events ATTRIBUTE_UNUSED
 | 
				
			||||||
int client_ctrl_handler(waiter_t *waiter, unsigned short events)
 | 
					int client_ctrl_handler(waiter_t *waiter, unsigned short events)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	client_t *client = waiter->private_data;
 | 
						client_t *client = waiter->private_data;
 | 
				
			||||||
	if (events & POLLHUP)
 | 
						if (events & POLLHUP) {
 | 
				
			||||||
		return client_data_handler(waiter, events);
 | 
							if (client->open)
 | 
				
			||||||
 | 
								client->ops->close(client);
 | 
				
			||||||
 | 
							close(client->ctrl_fd);
 | 
				
			||||||
 | 
							del_waiter(client->ctrl_fd);
 | 
				
			||||||
 | 
							list_del(&client->list);
 | 
				
			||||||
 | 
							free(client);
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	if (client->open)
 | 
						if (client->open)
 | 
				
			||||||
		return client->ops->cmd(client);
 | 
							return client->ops->cmd(client);
 | 
				
			||||||
	else
 | 
						else
 | 
				
			||||||
		return snd_client_open(client);
 | 
							return snd_client_open(client);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int pending_handler(waiter_t *waiter, unsigned short events)
 | 
					int inet_pending_handler(waiter_t *waiter, unsigned short events)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	pending_t *pending = waiter->private_data;
 | 
						inet_pending_t *pending = waiter->private_data;
 | 
				
			||||||
	pending_t *pdata;
 | 
						inet_pending_t *pdata;
 | 
				
			||||||
	client_t *client;
 | 
						client_t *client;
 | 
				
			||||||
	uint32_t cookie;
 | 
						uint32_t cookie;
 | 
				
			||||||
	struct list_head *item;
 | 
						struct list_head *item;
 | 
				
			||||||
| 
						 | 
					@ -766,8 +790,8 @@ int pending_handler(waiter_t *waiter, unsigned short events)
 | 
				
			||||||
		return 0;
 | 
							return 0;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	list_for_each(item, &pendings) {
 | 
						list_for_each(item, &inet_pendings) {
 | 
				
			||||||
		pdata = list_entry(item, pending_t, list);
 | 
							pdata = list_entry(item, inet_pending_t, list);
 | 
				
			||||||
		if (pdata->cookie == cookie)
 | 
							if (pdata->cookie == cookie)
 | 
				
			||||||
			goto found;
 | 
								goto found;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -775,13 +799,12 @@ int pending_handler(waiter_t *waiter, unsigned short events)
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 found:
 | 
					 found:
 | 
				
			||||||
	client = calloc(sizeof(*client), 1);
 | 
						client = calloc(1, sizeof(*client));
 | 
				
			||||||
	client->data.fd = pdata->fd;
 | 
						client->local = 0;
 | 
				
			||||||
	client->data.local = pdata->local;
 | 
						client->poll_fd = pdata->fd;
 | 
				
			||||||
	client->ctrl.fd = waiter->fd;
 | 
						client->ctrl_fd = waiter->fd;
 | 
				
			||||||
	client->ctrl.local = pending->local;
 | 
						add_waiter(client->ctrl_fd, POLLIN | POLLHUP, client_ctrl_handler, client);
 | 
				
			||||||
	add_waiter(client->ctrl.fd, POLLIN | POLLHUP, client_ctrl_handler, client);
 | 
						add_waiter(client->poll_fd, POLLHUP, client_poll_handler, client);
 | 
				
			||||||
	add_waiter(client->data.fd, POLLHUP, client_data_handler, client);
 | 
					 | 
				
			||||||
	client->open = 0;
 | 
						client->open = 0;
 | 
				
			||||||
	list_add_tail(&client->list, &clients);
 | 
						list_add_tail(&client->list, &clients);
 | 
				
			||||||
	list_del(&pending->list);
 | 
						list_del(&pending->list);
 | 
				
			||||||
| 
						 | 
					@ -791,70 +814,81 @@ int pending_handler(waiter_t *waiter, unsigned short events)
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int master_handler(waiter_t *waiter, unsigned short events ATTRIBUTE_UNUSED)
 | 
					int local_handler(waiter_t *waiter, unsigned short events ATTRIBUTE_UNUSED)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	master_t *master = waiter->private_data;
 | 
					 | 
				
			||||||
	int sock;
 | 
						int sock;
 | 
				
			||||||
	sock = accept(waiter->fd, 0, 0);
 | 
						sock = accept(waiter->fd, 0, 0);
 | 
				
			||||||
	if (sock < 0) {
 | 
						if (sock < 0) {
 | 
				
			||||||
		int result = -errno;
 | 
							int result = -errno;
 | 
				
			||||||
		perrno("accept");
 | 
							SYSERR("accept");
 | 
				
			||||||
		return result;
 | 
							return result;
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		pending_t *pending = calloc(sizeof(*pending), 1);
 | 
							client_t *client = calloc(1, sizeof(*client));
 | 
				
			||||||
 | 
							client->ctrl_fd = sock;
 | 
				
			||||||
 | 
							client->local = 1;
 | 
				
			||||||
 | 
							client->open = 0;
 | 
				
			||||||
 | 
							add_waiter(sock, POLLIN | POLLHUP, client_ctrl_handler, client);
 | 
				
			||||||
 | 
							list_add_tail(&client->list, &clients);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int inet_handler(waiter_t *waiter, unsigned short events ATTRIBUTE_UNUSED)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int sock;
 | 
				
			||||||
 | 
						sock = accept(waiter->fd, 0, 0);
 | 
				
			||||||
 | 
						if (sock < 0) {
 | 
				
			||||||
 | 
							int result = -errno;
 | 
				
			||||||
 | 
							SYSERR("accept");
 | 
				
			||||||
 | 
							return result;
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							inet_pending_t *pending = calloc(1, sizeof(*pending));
 | 
				
			||||||
		pending->fd = sock;
 | 
							pending->fd = sock;
 | 
				
			||||||
		pending->local = master->local;
 | 
					 | 
				
			||||||
		pending->cookie = 0;
 | 
							pending->cookie = 0;
 | 
				
			||||||
		add_waiter(sock, POLLIN, pending_handler, pending);
 | 
							add_waiter(sock, POLLIN, inet_pending_handler, pending);
 | 
				
			||||||
		list_add_tail(&pending->list, &pendings);
 | 
							list_add_tail(&pending->list, &inet_pendings);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int server(char *sockname, int port)
 | 
					int server(char *sockname, int port)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct list_head *item;
 | 
					 | 
				
			||||||
	int err;
 | 
						int err;
 | 
				
			||||||
	unsigned int k;
 | 
						unsigned int k;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!sockname && port < 0)
 | 
				
			||||||
 | 
							return -EINVAL;
 | 
				
			||||||
	if (sockname) {
 | 
						if (sockname) {
 | 
				
			||||||
		int sock = make_local_socket(sockname);
 | 
							int sock = make_local_socket(sockname);
 | 
				
			||||||
		master_t *master;
 | 
					 | 
				
			||||||
		if (sock < 0)
 | 
							if (sock < 0)
 | 
				
			||||||
			return sock;
 | 
								return sock;
 | 
				
			||||||
		master = calloc(sizeof(*master), 1);
 | 
							if (fcntl(sock, F_SETFL, O_NONBLOCK) < 0) {
 | 
				
			||||||
		master->fd = sock;
 | 
								int result = -errno;
 | 
				
			||||||
		master->local = 1;
 | 
								SYSERR("fcntl");
 | 
				
			||||||
		add_waiter(sock, POLLIN, master_handler, master);
 | 
								return result;
 | 
				
			||||||
		list_add_tail(&master->list, &masters);
 | 
							}
 | 
				
			||||||
 | 
							if (listen(sock, 4) < 0) {
 | 
				
			||||||
 | 
								int result = -errno;
 | 
				
			||||||
 | 
								SYSERR("listen");
 | 
				
			||||||
 | 
								return result;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							add_waiter(sock, POLLIN, local_handler, NULL);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if (port >= 0) {
 | 
						if (port >= 0) {
 | 
				
			||||||
		int sock = make_inet_socket(port);
 | 
							int sock = make_inet_socket(port);
 | 
				
			||||||
		master_t *master;
 | 
					 | 
				
			||||||
		if (sock < 0)
 | 
							if (sock < 0)
 | 
				
			||||||
			return sock;
 | 
								return sock;
 | 
				
			||||||
		master = calloc(sizeof(*master), 1);
 | 
							if (fcntl(sock, F_SETFL, O_NONBLOCK) < 0) {
 | 
				
			||||||
		master->fd = sock;
 | 
					 | 
				
			||||||
		master->local = 0;
 | 
					 | 
				
			||||||
		add_waiter(sock, POLLIN, master_handler, master);
 | 
					 | 
				
			||||||
		list_add_tail(&master->list, &masters);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (list_empty(&masters))
 | 
					 | 
				
			||||||
		return -EINVAL;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	list_for_each(item, &masters) {
 | 
					 | 
				
			||||||
		master_t *master = list_entry(item, master_t, list);
 | 
					 | 
				
			||||||
		if (fcntl(master->fd, F_SETFL, O_NONBLOCK) < 0) {
 | 
					 | 
				
			||||||
			int result = -errno;
 | 
								int result = -errno;
 | 
				
			||||||
			perrno("fcntl");
 | 
								SYSERR("fcntl");
 | 
				
			||||||
			return result;
 | 
								return result;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if (listen(master->fd, 4) < 0) {
 | 
							if (listen(sock, 4) < 0) {
 | 
				
			||||||
			int result = -errno;
 | 
								int result = -errno;
 | 
				
			||||||
			perrno("listen");
 | 
								SYSERR("listen");
 | 
				
			||||||
			return result;
 | 
								return result;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
							add_waiter(sock, POLLIN, inet_handler, NULL);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	while (1) {
 | 
						while (1) {
 | 
				
			||||||
| 
						 | 
					@ -864,7 +898,7 @@ int server(char *sockname, int port)
 | 
				
			||||||
			err = poll(pollfds, pollfds_count, 1000);
 | 
								err = poll(pollfds, pollfds_count, 1000);
 | 
				
			||||||
		} while (err == 0);
 | 
							} while (err == 0);
 | 
				
			||||||
		if (err < 0) {
 | 
							if (err < 0) {
 | 
				
			||||||
			perrno("poll");
 | 
								SYSERR("poll");
 | 
				
			||||||
			continue;
 | 
								continue;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -878,7 +912,7 @@ int server(char *sockname, int port)
 | 
				
			||||||
					continue;
 | 
										continue;
 | 
				
			||||||
				err = w->handler(w, pfd->revents);
 | 
									err = w->handler(w, pfd->revents);
 | 
				
			||||||
				if (err < 0)
 | 
									if (err < 0)
 | 
				
			||||||
					perrno("handler");
 | 
										SYSERR("handler");
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -889,47 +923,102 @@ int server(char *sockname, int port)
 | 
				
			||||||
void usage()
 | 
					void usage()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	fprintf(stderr, "\
 | 
						fprintf(stderr, "\
 | 
				
			||||||
Usage: %s [OPTIONS]
 | 
					Usage: %s [OPTIONS] server
 | 
				
			||||||
 | 
					
 | 
				
			||||||
--help			help
 | 
					--help			help
 | 
				
			||||||
--version		print current version
 | 
					 | 
				
			||||||
-l,--local SOCKNAME	local socket name
 | 
					 | 
				
			||||||
-p,--port PORT		port number
 | 
					 | 
				
			||||||
", command);
 | 
					", command);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern int is_local(struct hostent *hent);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int main(int argc, char **argv)
 | 
					int main(int argc, char **argv)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	static struct option long_options[] = {
 | 
						static struct option long_options[] = {
 | 
				
			||||||
		{"local", 1, 0, 'l'},
 | 
					 | 
				
			||||||
		{"port", 1, 0, 'p'},
 | 
					 | 
				
			||||||
		{"help", 0, 0, 'h'}
 | 
							{"help", 0, 0, 'h'}
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
	int c;
 | 
						int c;
 | 
				
			||||||
	char *local = NULL;
 | 
						snd_config_t *conf;
 | 
				
			||||||
	int port = -1;
 | 
						snd_config_iterator_t i;
 | 
				
			||||||
 | 
						char *socket = NULL;
 | 
				
			||||||
 | 
						char *host = NULL;
 | 
				
			||||||
 | 
						long port = -1;
 | 
				
			||||||
 | 
						int err;
 | 
				
			||||||
 | 
						char *srvname;
 | 
				
			||||||
 | 
						struct hostent *h;
 | 
				
			||||||
	command = argv[0];
 | 
						command = argv[0];
 | 
				
			||||||
	while ((c = getopt_long(argc, argv, "hl:p:", long_options, 0)) != -1) {
 | 
						while ((c = getopt_long(argc, argv, "h", long_options, 0)) != -1) {
 | 
				
			||||||
		switch (c) {
 | 
							switch (c) {
 | 
				
			||||||
		case 'h':
 | 
							case 'h':
 | 
				
			||||||
			usage();
 | 
								usage();
 | 
				
			||||||
			return 0;
 | 
								return 0;
 | 
				
			||||||
		case 'l':
 | 
					 | 
				
			||||||
			local = optarg;
 | 
					 | 
				
			||||||
			break;
 | 
					 | 
				
			||||||
		case 'p':
 | 
					 | 
				
			||||||
			port = atoi(optarg);
 | 
					 | 
				
			||||||
			break;
 | 
					 | 
				
			||||||
		default:
 | 
							default:
 | 
				
			||||||
			fprintf(stderr, "Try `%s --help' for more information\n", command);
 | 
								fprintf(stderr, "Try `%s --help' for more information\n", command);
 | 
				
			||||||
			return 1;
 | 
								return 1;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if (!local && port == -1) {
 | 
						if (argc - optind != 1) {
 | 
				
			||||||
		fprintf(stderr, "%s: you need to specify at least one master socket\n", command);
 | 
							ERROR("you need to specify server name");
 | 
				
			||||||
		return 1;
 | 
							return 1;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						err = snd_config_update();
 | 
				
			||||||
	server(local, port);
 | 
						if (err < 0) {
 | 
				
			||||||
 | 
							ERROR("cannot read configuration file");
 | 
				
			||||||
 | 
							return 1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						srvname = argv[optind];
 | 
				
			||||||
 | 
						err = snd_config_searchv(snd_config, &conf, "server", srvname, 0);
 | 
				
			||||||
 | 
						if (err < 0) {
 | 
				
			||||||
 | 
							ERROR("unknown server %s", srvname);
 | 
				
			||||||
 | 
							return 1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						snd_config_foreach(i, conf) {
 | 
				
			||||||
 | 
							snd_config_t *n = snd_config_entry(i);
 | 
				
			||||||
 | 
							if (strcmp(n->id, "comment") == 0)
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
							if (strcmp(n->id, "host") == 0) {
 | 
				
			||||||
 | 
								err = snd_config_string_get(n, &host);
 | 
				
			||||||
 | 
								if (err < 0) {
 | 
				
			||||||
 | 
									ERROR("Invalid type for host");
 | 
				
			||||||
 | 
									return 1;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if (strcmp(n->id, "socket") == 0) {
 | 
				
			||||||
 | 
								err = snd_config_string_get(n, &socket);
 | 
				
			||||||
 | 
								if (err < 0) {
 | 
				
			||||||
 | 
									ERROR("Invalid type for socket");
 | 
				
			||||||
 | 
									return 1;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if (strcmp(n->id, "port") == 0) {
 | 
				
			||||||
 | 
								err = snd_config_integer_get(n, &port);
 | 
				
			||||||
 | 
								if (err < 0) {
 | 
				
			||||||
 | 
									ERROR("Invalid type for port");
 | 
				
			||||||
 | 
									return 1;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							ERROR("Unknown field: %s", n->id);
 | 
				
			||||||
 | 
							return 1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (!host) {
 | 
				
			||||||
 | 
							ERROR("host is not defined");
 | 
				
			||||||
 | 
							return 1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						h = gethostbyname(host);
 | 
				
			||||||
 | 
						if (!h) {
 | 
				
			||||||
 | 
							ERROR("Cannot resolve %s", host);
 | 
				
			||||||
 | 
							return 1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (!is_local(h)) {
 | 
				
			||||||
 | 
							ERROR("%s is not the local host", host);
 | 
				
			||||||
 | 
							return 1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (!socket && port < 0) {
 | 
				
			||||||
 | 
							ERROR("either socket or port need to be defined");
 | 
				
			||||||
 | 
							return 1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						server(socket, port);
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -19,17 +19,17 @@
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
  
 | 
					  
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "../src/pcm/pcm_local.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define SND_PCM_IOCTL_STATE		_IO ('A', 0xf0)
 | 
					#define SND_PCM_IOCTL_STATE		_IO ('A', 0xf0)
 | 
				
			||||||
#define SND_PCM_IOCTL_MMAP_DATA		_IO ('A', 0xf1)
 | 
					#define SND_PCM_IOCTL_MMAP		_IO ('A', 0xf1)
 | 
				
			||||||
#define SND_PCM_IOCTL_MMAP_CONTROL	_IO ('A', 0xf2)
 | 
					#define SND_PCM_IOCTL_MUNMAP		_IO ('A', 0xf4)
 | 
				
			||||||
#define SND_PCM_IOCTL_MMAP_STATUS	_IO ('A', 0xf3)
 | 
					 | 
				
			||||||
#define SND_PCM_IOCTL_MUNMAP_DATA	_IO ('A', 0xf4)
 | 
					 | 
				
			||||||
#define SND_PCM_IOCTL_MUNMAP_CONTROL	_IO ('A', 0xf5)
 | 
					 | 
				
			||||||
#define SND_PCM_IOCTL_MUNMAP_STATUS	_IO ('A', 0xf6)
 | 
					 | 
				
			||||||
#define SND_PCM_IOCTL_MMAP_FORWARD	_IO ('A', 0xf7)
 | 
					#define SND_PCM_IOCTL_MMAP_FORWARD	_IO ('A', 0xf7)
 | 
				
			||||||
#define SND_PCM_IOCTL_AVAIL_UPDATE	_IO ('A', 0xf8)
 | 
					#define SND_PCM_IOCTL_AVAIL_UPDATE	_IO ('A', 0xf8)
 | 
				
			||||||
#define SND_PCM_IOCTL_ASYNC		_IO ('A', 0xf9)
 | 
					#define SND_PCM_IOCTL_ASYNC		_IO ('A', 0xf9)
 | 
				
			||||||
#define SND_PCM_IOCTL_CLOSE		_IO ('A', 0xfa)
 | 
					#define SND_PCM_IOCTL_CLOSE		_IO ('A', 0xfa)
 | 
				
			||||||
 | 
					#define SND_PCM_IOCTL_MMAP_INFO		_IO ('A', 0xfb)
 | 
				
			||||||
 | 
					#define SND_PCM_IOCTL_POLL_DESCRIPTOR	_IO ('A', 0xfc)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef struct {
 | 
					typedef struct {
 | 
				
			||||||
	long result;
 | 
						long result;
 | 
				
			||||||
| 
						 | 
					@ -39,6 +39,7 @@ typedef struct {
 | 
				
			||||||
			int sig;
 | 
								int sig;
 | 
				
			||||||
			pid_t pid;
 | 
								pid_t pid;
 | 
				
			||||||
		} async;
 | 
							} async;
 | 
				
			||||||
 | 
							snd_pcm_mmap_info_t mmap_info;
 | 
				
			||||||
		snd_pcm_info_t info;
 | 
							snd_pcm_info_t info;
 | 
				
			||||||
		snd_pcm_params_t params;
 | 
							snd_pcm_params_t params;
 | 
				
			||||||
		snd_pcm_params_info_t params_info;
 | 
							snd_pcm_params_info_t params_info;
 | 
				
			||||||
| 
						 | 
					@ -54,13 +55,13 @@ typedef struct {
 | 
				
			||||||
		size_t mmap_forward;
 | 
							size_t mmap_forward;
 | 
				
			||||||
	} u;
 | 
						} u;
 | 
				
			||||||
	char data[0];
 | 
						char data[0];
 | 
				
			||||||
} snd_pcm_client_shm_t;
 | 
					} snd_pcm_shm_ctrl_t;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define PCM_SHM_SIZE 65536
 | 
					#define PCM_SHM_SIZE sizeof(snd_pcm_shm_ctrl_t)
 | 
				
			||||||
#define PCM_SHM_DATA_MAXLEN (PCM_SHM_SIZE - offsetof(snd_pcm_client_shm_t, data))
 | 
					 | 
				
			||||||
		
 | 
							
 | 
				
			||||||
#define SND_CTL_IOCTL_READ		_IOR('U', 0xf0, snd_ctl_event_t)
 | 
					#define SND_CTL_IOCTL_READ		_IOR('U', 0xf0, snd_ctl_event_t)
 | 
				
			||||||
#define SND_CTL_IOCTL_CLOSE		_IO ('U', 0xf1)
 | 
					#define SND_CTL_IOCTL_CLOSE		_IO ('U', 0xf1)
 | 
				
			||||||
 | 
					#define SND_CTL_IOCTL_POLL_DESCRIPTOR	_IO ('U', 0xf2)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef struct {
 | 
					typedef struct {
 | 
				
			||||||
	int result;
 | 
						int result;
 | 
				
			||||||
| 
						 | 
					@ -78,10 +79,10 @@ typedef struct {
 | 
				
			||||||
		snd_ctl_event_t read;
 | 
							snd_ctl_event_t read;
 | 
				
			||||||
	} u;
 | 
						} u;
 | 
				
			||||||
	char data[0];
 | 
						char data[0];
 | 
				
			||||||
} snd_ctl_client_shm_t;
 | 
					} snd_ctl_shm_ctrl_t;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define CTL_SHM_SIZE 65536
 | 
					#define CTL_SHM_SIZE 65536
 | 
				
			||||||
#define CTL_SHM_DATA_MAXLEN (CTL_SHM_SIZE - offsetof(snd_ctl_client_shm_t, data))
 | 
					#define CTL_SHM_DATA_MAXLEN (CTL_SHM_SIZE - offsetof(snd_ctl_shm_ctrl_t, data))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef struct {
 | 
					typedef struct {
 | 
				
			||||||
	unsigned char dev_type;
 | 
						unsigned char dev_type;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -7,7 +7,10 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef struct snd_ctl snd_ctl_t;
 | 
					typedef struct snd_ctl snd_ctl_t;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef enum { SND_CTL_TYPE_HW, SND_CTL_TYPE_CLIENT } snd_ctl_type_t;
 | 
					typedef enum { SND_CTL_TYPE_HW,
 | 
				
			||||||
 | 
						       SND_CTL_TYPE_SHM,
 | 
				
			||||||
 | 
						       SND_CTL_TYPE_INET
 | 
				
			||||||
 | 
					 } snd_ctl_type_t;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef struct snd_ctl_callbacks {
 | 
					typedef struct snd_ctl_callbacks {
 | 
				
			||||||
	void *private_data;	/* may be used by an application */
 | 
						void *private_data;	/* may be used by an application */
 | 
				
			||||||
| 
						 | 
					@ -37,8 +40,8 @@ int snd_defaults_pcm_device(void);
 | 
				
			||||||
int snd_defaults_rawmidi_card(void);
 | 
					int snd_defaults_rawmidi_card(void);
 | 
				
			||||||
int snd_defaults_rawmidi_device(void);
 | 
					int snd_defaults_rawmidi_device(void);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int snd_ctl_hw_open(snd_ctl_t **handle, int card);
 | 
					int snd_ctl_hw_open(snd_ctl_t **handle, char *name, int card);
 | 
				
			||||||
int snd_ctl_client_open(snd_ctl_t **handlep, char *host, int port, int transport, char *name);
 | 
					int snd_ctl_shm_open(snd_ctl_t **handlep, char *name, char *socket, char *sname);
 | 
				
			||||||
snd_ctl_type_t snd_ctl_type(snd_ctl_t *handle);
 | 
					snd_ctl_type_t snd_ctl_type(snd_ctl_t *handle);
 | 
				
			||||||
int snd_ctl_open(snd_ctl_t **handle, char *name);
 | 
					int snd_ctl_open(snd_ctl_t **handle, char *name);
 | 
				
			||||||
int snd_ctl_close(snd_ctl_t *handle);
 | 
					int snd_ctl_close(snd_ctl_t *handle);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -104,7 +104,8 @@ typedef enum {
 | 
				
			||||||
	SND_PCM_TYPE_MULTI,
 | 
						SND_PCM_TYPE_MULTI,
 | 
				
			||||||
	SND_PCM_TYPE_FILE,
 | 
						SND_PCM_TYPE_FILE,
 | 
				
			||||||
	SND_PCM_TYPE_NULL,
 | 
						SND_PCM_TYPE_NULL,
 | 
				
			||||||
	SND_PCM_TYPE_CLIENT,
 | 
						SND_PCM_TYPE_SHM,
 | 
				
			||||||
 | 
						SND_PCM_TYPE_INET,
 | 
				
			||||||
	SND_PCM_TYPE_LINEAR,
 | 
						SND_PCM_TYPE_LINEAR,
 | 
				
			||||||
	SND_PCM_TYPE_ALAW,
 | 
						SND_PCM_TYPE_ALAW,
 | 
				
			||||||
	SND_PCM_TYPE_MULAW,
 | 
						SND_PCM_TYPE_MULAW,
 | 
				
			||||||
| 
						 | 
					@ -118,16 +119,16 @@ typedef enum {
 | 
				
			||||||
	SND_PCM_TYPE_LBSERVER,
 | 
						SND_PCM_TYPE_LBSERVER,
 | 
				
			||||||
} snd_pcm_type_t;
 | 
					} snd_pcm_type_t;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
extern void (*snd_pcm_error)(const char *file, int line, const char *function, const char *fmt, ...);
 | 
					extern void snd_pcm_error(const char *file, int line, const char *function, const char *fmt, ...)  __attribute__ ((weak, format (printf, 4, 5)));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int snd_pcm_open(snd_pcm_t **handle, char *name, 
 | 
					int snd_pcm_open(snd_pcm_t **pcm, char *name, 
 | 
				
			||||||
		 int stream, int mode);
 | 
							 int stream, int mode);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Obsolete functions */
 | 
					/* Obsolete functions */
 | 
				
			||||||
int snd_pcm_hw_open_subdevice(snd_pcm_t **handle, int card, int device, int subdevice, int stream, int mode);
 | 
					int snd_pcm_hw_open_subdevice(snd_pcm_t **pcm, int card, int device, int subdevice, int stream, int mode);
 | 
				
			||||||
int snd_pcm_hw_open_device(snd_pcm_t **handle, int card, int device, int stream, int mode);
 | 
					int snd_pcm_hw_open_device(snd_pcm_t **pcm, int card, int device, int stream, int mode);
 | 
				
			||||||
int snd_pcm_plug_open_subdevice(snd_pcm_t **handle, int card, int device, int subdevice, int stream, int mode);
 | 
					int snd_pcm_plug_open_subdevice(snd_pcm_t **pcm, int card, int device, int subdevice, int stream, int mode);
 | 
				
			||||||
int snd_pcm_plug_open_device(snd_pcm_t **handle, int card, int device, int stream, int mode);
 | 
					int snd_pcm_plug_open_device(snd_pcm_t **pcm, int card, int device, int stream, int mode);
 | 
				
			||||||
#define snd_pcm_write snd_pcm_writei
 | 
					#define snd_pcm_write snd_pcm_writei
 | 
				
			||||||
#define snd_pcm_read snd_pcm_readi
 | 
					#define snd_pcm_read snd_pcm_readi
 | 
				
			||||||
ssize_t snd_pcm_writev(snd_pcm_t *pcm, const struct iovec *vector, int count);
 | 
					ssize_t snd_pcm_writev(snd_pcm_t *pcm, const struct iovec *vector, int count);
 | 
				
			||||||
| 
						 | 
					@ -171,7 +172,7 @@ ssize_t snd_pcm_avail_update(snd_pcm_t *pcm);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* mmap */
 | 
					/* mmap */
 | 
				
			||||||
int snd_pcm_mmap(snd_pcm_t *pcm, void **buffer);
 | 
					int snd_pcm_mmap(snd_pcm_t *pcm);
 | 
				
			||||||
int snd_pcm_munmap(snd_pcm_t *pcm);
 | 
					int snd_pcm_munmap(snd_pcm_t *pcm);
 | 
				
			||||||
snd_pcm_channel_area_t *snd_pcm_mmap_areas(snd_pcm_t *pcm);
 | 
					snd_pcm_channel_area_t *snd_pcm_mmap_areas(snd_pcm_t *pcm);
 | 
				
			||||||
int snd_pcm_mmap_get_areas(snd_pcm_t *pcm, snd_pcm_channel_area_t *stopped_areas, snd_pcm_channel_area_t *running_areas);
 | 
					int snd_pcm_mmap_get_areas(snd_pcm_t *pcm, snd_pcm_channel_area_t *stopped_areas, snd_pcm_channel_area_t *running_areas);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,7 +1,7 @@
 | 
				
			||||||
EXTRA_LTLIBRARIES = libcontrol.la
 | 
					EXTRA_LTLIBRARIES = libcontrol.la
 | 
				
			||||||
 | 
					
 | 
				
			||||||
libcontrol_la_SOURCES = cards.c controls.c bag.c defaults.c \
 | 
					libcontrol_la_SOURCES = cards.c controls.c bag.c defaults.c \
 | 
				
			||||||
                        control.c control_hw.c control_client.c
 | 
					                        control.c control_hw.c control_shm.c
 | 
				
			||||||
 | 
					
 | 
				
			||||||
all: libcontrol.la
 | 
					all: libcontrol.la
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -106,7 +106,7 @@ int snd_card_get_index(const char *string)
 | 
				
			||||||
	for (card = 0; card < 32; card++) {
 | 
						for (card = 0; card < 32; card++) {
 | 
				
			||||||
		if (snd_card_load(card) < 0)
 | 
							if (snd_card_load(card) < 0)
 | 
				
			||||||
			continue;
 | 
								continue;
 | 
				
			||||||
		if (snd_ctl_hw_open(&handle, card) < 0)
 | 
							if (snd_ctl_hw_open(&handle, NULL, card) < 0)
 | 
				
			||||||
			continue;
 | 
								continue;
 | 
				
			||||||
		if (snd_ctl_hw_info(handle, &info) < 0) {
 | 
							if (snd_ctl_hw_info(handle, &info) < 0) {
 | 
				
			||||||
			snd_ctl_close(handle);
 | 
								snd_ctl_close(handle);
 | 
				
			||||||
| 
						 | 
					@ -127,7 +127,7 @@ int snd_card_get_name(int card, char **name)
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
	if (name == NULL)
 | 
						if (name == NULL)
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
	if ((err = snd_ctl_hw_open(&handle, card)) < 0)
 | 
						if ((err = snd_ctl_hw_open(&handle, NULL, card)) < 0)
 | 
				
			||||||
		return err;
 | 
							return err;
 | 
				
			||||||
	if ((err = snd_ctl_hw_info(handle, &info)) < 0) {
 | 
						if ((err = snd_ctl_hw_info(handle, &info)) < 0) {
 | 
				
			||||||
		snd_ctl_close(handle);
 | 
							snd_ctl_close(handle);
 | 
				
			||||||
| 
						 | 
					@ -148,7 +148,7 @@ int snd_card_get_longname(int card, char **name)
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
	if (name == NULL)
 | 
						if (name == NULL)
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
	if ((err = snd_ctl_hw_open(&handle, card)) < 0)
 | 
						if ((err = snd_ctl_hw_open(&handle, NULL, card)) < 0)
 | 
				
			||||||
		return err;
 | 
							return err;
 | 
				
			||||||
	if ((err = snd_ctl_hw_info(handle, &info)) < 0) {
 | 
						if ((err = snd_ctl_hw_info(handle, &info)) < 0) {
 | 
				
			||||||
		snd_ctl_close(handle);
 | 
							snd_ctl_close(handle);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -26,6 +26,7 @@
 | 
				
			||||||
#include <errno.h>
 | 
					#include <errno.h>
 | 
				
			||||||
#include <fcntl.h>
 | 
					#include <fcntl.h>
 | 
				
			||||||
#include <assert.h>
 | 
					#include <assert.h>
 | 
				
			||||||
 | 
					#include <dlfcn.h>
 | 
				
			||||||
#include "asoundlib.h"
 | 
					#include "asoundlib.h"
 | 
				
			||||||
#include "control_local.h"
 | 
					#include "control_local.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -148,106 +149,22 @@ int snd_ctl_read(snd_ctl_t *ctl, snd_ctl_callbacks_t * callbacks)
 | 
				
			||||||
	return result >= 0 ? count : -errno;
 | 
						return result >= 0 ? count : -errno;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int _snd_ctl_open_hw(snd_ctl_t **handlep, snd_config_t *conf)
 | 
					int snd_ctl_open(snd_ctl_t **ctlp, char *name)
 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	snd_config_iterator_t i;
 | 
					 | 
				
			||||||
	long card = -1;
 | 
					 | 
				
			||||||
	char *str;
 | 
					 | 
				
			||||||
	int err;
 | 
					 | 
				
			||||||
	snd_config_foreach(i, conf) {
 | 
					 | 
				
			||||||
		snd_config_t *n = snd_config_entry(i);
 | 
					 | 
				
			||||||
		if (strcmp(n->id, "comment") == 0)
 | 
					 | 
				
			||||||
			continue;
 | 
					 | 
				
			||||||
		if (strcmp(n->id, "type") == 0)
 | 
					 | 
				
			||||||
			continue;
 | 
					 | 
				
			||||||
		if (strcmp(n->id, "card") == 0) {
 | 
					 | 
				
			||||||
			err = snd_config_integer_get(n, &card);
 | 
					 | 
				
			||||||
			if (err < 0) {
 | 
					 | 
				
			||||||
				err = snd_config_string_get(n, &str);
 | 
					 | 
				
			||||||
				if (err < 0)
 | 
					 | 
				
			||||||
					return -EINVAL;
 | 
					 | 
				
			||||||
				card = snd_card_get_index(str);
 | 
					 | 
				
			||||||
				if (card < 0)
 | 
					 | 
				
			||||||
					return card;
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			continue;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		return -EINVAL;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if (card < 0)
 | 
					 | 
				
			||||||
		return -EINVAL;
 | 
					 | 
				
			||||||
	return snd_ctl_hw_open(handlep, card);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
				
 | 
					 | 
				
			||||||
static int _snd_ctl_open_client(snd_ctl_t **handlep, snd_config_t *conf)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	snd_config_iterator_t i;
 | 
					 | 
				
			||||||
	char *socket = NULL;
 | 
					 | 
				
			||||||
	char *name = NULL;
 | 
					 | 
				
			||||||
	char *host = NULL;
 | 
					 | 
				
			||||||
	long port = -1;
 | 
					 | 
				
			||||||
	int err;
 | 
					 | 
				
			||||||
	snd_config_foreach(i, conf) {
 | 
					 | 
				
			||||||
		snd_config_t *n = snd_config_entry(i);
 | 
					 | 
				
			||||||
		if (strcmp(n->id, "comment") == 0)
 | 
					 | 
				
			||||||
			continue;
 | 
					 | 
				
			||||||
		if (strcmp(n->id, "type") == 0)
 | 
					 | 
				
			||||||
			continue;
 | 
					 | 
				
			||||||
		if (strcmp(n->id, "socket") == 0) {
 | 
					 | 
				
			||||||
			err = snd_config_string_get(n, &socket);
 | 
					 | 
				
			||||||
			if (err < 0)
 | 
					 | 
				
			||||||
				return -EINVAL;
 | 
					 | 
				
			||||||
			continue;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		if (strcmp(n->id, "host") == 0) {
 | 
					 | 
				
			||||||
			err = snd_config_string_get(n, &host);
 | 
					 | 
				
			||||||
			if (err < 0)
 | 
					 | 
				
			||||||
				return -EINVAL;
 | 
					 | 
				
			||||||
			continue;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		if (strcmp(n->id, "port") == 0) {
 | 
					 | 
				
			||||||
			err = snd_config_integer_get(n, &port);
 | 
					 | 
				
			||||||
			if (err < 0)
 | 
					 | 
				
			||||||
				return -EINVAL;
 | 
					 | 
				
			||||||
			continue;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		if (strcmp(n->id, "name") == 0) {
 | 
					 | 
				
			||||||
			err = snd_config_string_get(n, &name);
 | 
					 | 
				
			||||||
			if (err < 0)
 | 
					 | 
				
			||||||
				return -EINVAL;
 | 
					 | 
				
			||||||
			continue;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		return -EINVAL;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if (!name)
 | 
					 | 
				
			||||||
		return -EINVAL;
 | 
					 | 
				
			||||||
	if (socket) {
 | 
					 | 
				
			||||||
		if (port >= 0 || host)
 | 
					 | 
				
			||||||
			return -EINVAL;
 | 
					 | 
				
			||||||
		return snd_ctl_client_open(handlep, socket, -1, SND_TRANSPORT_TYPE_SHM, name);
 | 
					 | 
				
			||||||
	} else  {
 | 
					 | 
				
			||||||
		if (port < 0 || !name)
 | 
					 | 
				
			||||||
			return -EINVAL;
 | 
					 | 
				
			||||||
		return snd_ctl_client_open(handlep, host, port, SND_TRANSPORT_TYPE_TCP, name);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
				
 | 
					 | 
				
			||||||
int snd_ctl_open(snd_ctl_t **handlep, char *name)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	char *str;
 | 
						char *str;
 | 
				
			||||||
	int err;
 | 
						int err;
 | 
				
			||||||
	snd_config_t *ctl_conf, *conf;
 | 
						snd_config_t *ctl_conf, *conf, *type_conf;
 | 
				
			||||||
	assert(handlep && name);
 | 
						snd_config_iterator_t i;
 | 
				
			||||||
 | 
						char *lib = NULL, *open = NULL;
 | 
				
			||||||
 | 
						int (*open_func)(snd_ctl_t **ctlp, char *name, snd_config_t *conf);
 | 
				
			||||||
 | 
						void *h;
 | 
				
			||||||
 | 
						assert(ctlp && name);
 | 
				
			||||||
	err = snd_config_update();
 | 
						err = snd_config_update();
 | 
				
			||||||
	if (err < 0)
 | 
						if (err < 0)
 | 
				
			||||||
		return err;
 | 
							return err;
 | 
				
			||||||
	err = snd_config_searchv(snd_config, &ctl_conf, "ctl", name, 0);
 | 
						err = snd_config_searchv(snd_config, &ctl_conf, "ctl", name, 0);
 | 
				
			||||||
	if (err < 0) {
 | 
						if (err < 0)
 | 
				
			||||||
		int idx = snd_card_get_index(name);
 | 
							return err;
 | 
				
			||||||
		if (idx < 0)
 | 
					 | 
				
			||||||
			return idx;
 | 
					 | 
				
			||||||
		return snd_ctl_hw_open(handlep, idx);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if (snd_config_type(ctl_conf) != SND_CONFIG_TYPE_COMPOUND)
 | 
						if (snd_config_type(ctl_conf) != SND_CONFIG_TYPE_COMPOUND)
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
	err = snd_config_search(ctl_conf, "type", &conf);
 | 
						err = snd_config_search(ctl_conf, "type", &conf);
 | 
				
			||||||
| 
						 | 
					@ -256,10 +173,37 @@ int snd_ctl_open(snd_ctl_t **handlep, char *name)
 | 
				
			||||||
	err = snd_config_string_get(conf, &str);
 | 
						err = snd_config_string_get(conf, &str);
 | 
				
			||||||
	if (err < 0)
 | 
						if (err < 0)
 | 
				
			||||||
		return err;
 | 
							return err;
 | 
				
			||||||
	if (strcmp(str, "hw") == 0)
 | 
						err = snd_config_searchv(snd_config, &type_conf, "ctltype", str, 0);
 | 
				
			||||||
		return _snd_ctl_open_hw(handlep, ctl_conf);
 | 
						if (err < 0)
 | 
				
			||||||
	else if (strcmp(str, "client") == 0)
 | 
							return err;
 | 
				
			||||||
		return _snd_ctl_open_client(handlep, ctl_conf);
 | 
						snd_config_foreach(i, type_conf) {
 | 
				
			||||||
	else
 | 
							snd_config_t *n = snd_config_entry(i);
 | 
				
			||||||
 | 
							if (strcmp(n->id, "comment") == 0)
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
							if (strcmp(n->id, "lib") == 0) {
 | 
				
			||||||
 | 
								err = snd_config_string_get(n, &lib);
 | 
				
			||||||
 | 
								if (err < 0)
 | 
				
			||||||
 | 
									return -EINVAL;
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if (strcmp(n->id, "open") == 0) {
 | 
				
			||||||
 | 
								err = snd_config_string_get(n, &open);
 | 
				
			||||||
 | 
								if (err < 0)
 | 
				
			||||||
 | 
									return -EINVAL;
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
								return -EINVAL;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (!open)
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
						if (!lib)
 | 
				
			||||||
 | 
							lib = "libasound.so";
 | 
				
			||||||
 | 
						h = dlopen(lib, RTLD_NOW);
 | 
				
			||||||
 | 
						if (!h)
 | 
				
			||||||
 | 
							return -ENOENT;
 | 
				
			||||||
 | 
						open_func = dlsym(h, open);
 | 
				
			||||||
 | 
						dlclose(h);
 | 
				
			||||||
 | 
						if (!open_func)
 | 
				
			||||||
 | 
							return -ENXIO;
 | 
				
			||||||
 | 
						return open_func(ctlp, name, ctl_conf);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,433 +0,0 @@
 | 
				
			||||||
/*
 | 
					 | 
				
			||||||
 *  Control - Client
 | 
					 | 
				
			||||||
 *  Copyright (c) 2000 by Abramo Bagnara <abramo@alsa-project.org>
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 *   This library is free software; you can redistribute it and/or modify
 | 
					 | 
				
			||||||
 *   it under the terms of the GNU Library General Public License as
 | 
					 | 
				
			||||||
 *   published by the Free Software Foundation; either version 2 of
 | 
					 | 
				
			||||||
 *   the License, or (at your option) any later version.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 *   This program is distributed in the hope that it will be useful,
 | 
					 | 
				
			||||||
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
					 | 
				
			||||||
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
					 | 
				
			||||||
 *   GNU Library General Public License for more details.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 *   You should have received a copy of the GNU Library General Public
 | 
					 | 
				
			||||||
 *   License along with this library; if not, write to the Free Software
 | 
					 | 
				
			||||||
 *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
  
 | 
					 | 
				
			||||||
#include <stdio.h>
 | 
					 | 
				
			||||||
#include <stdlib.h>
 | 
					 | 
				
			||||||
#include <stddef.h>
 | 
					 | 
				
			||||||
#include <unistd.h>
 | 
					 | 
				
			||||||
#include <string.h>
 | 
					 | 
				
			||||||
#include <errno.h>
 | 
					 | 
				
			||||||
#include <fcntl.h>
 | 
					 | 
				
			||||||
#include <sys/shm.h>
 | 
					 | 
				
			||||||
#include <sys/socket.h>
 | 
					 | 
				
			||||||
#include <sys/poll.h>
 | 
					 | 
				
			||||||
#include <sys/un.h>
 | 
					 | 
				
			||||||
#include <sys/uio.h>
 | 
					 | 
				
			||||||
#include <sys/mman.h>
 | 
					 | 
				
			||||||
#include <netinet/in.h>
 | 
					 | 
				
			||||||
#include <netdb.h>
 | 
					 | 
				
			||||||
#include "control_local.h"
 | 
					 | 
				
			||||||
#include "aserver.h"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
typedef struct {
 | 
					 | 
				
			||||||
	int data_fd;
 | 
					 | 
				
			||||||
	int ctrl_fd;
 | 
					 | 
				
			||||||
	union {
 | 
					 | 
				
			||||||
		struct {
 | 
					 | 
				
			||||||
			void *ctrl;
 | 
					 | 
				
			||||||
		} shm;
 | 
					 | 
				
			||||||
	} u;
 | 
					 | 
				
			||||||
} snd_ctl_client_t;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void clean_poll(snd_ctl_t *ctl)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	snd_ctl_client_t *client = ctl->private;
 | 
					 | 
				
			||||||
	struct pollfd pfd;
 | 
					 | 
				
			||||||
	int err;
 | 
					 | 
				
			||||||
	char buf[1];
 | 
					 | 
				
			||||||
	pfd.fd = client->data_fd;
 | 
					 | 
				
			||||||
	pfd.events = POLLIN;
 | 
					 | 
				
			||||||
	while (1) {
 | 
					 | 
				
			||||||
		err = poll(&pfd, 1, 0);
 | 
					 | 
				
			||||||
		if (err == 0)
 | 
					 | 
				
			||||||
			break;
 | 
					 | 
				
			||||||
		assert(err > 0);
 | 
					 | 
				
			||||||
		err = read(client->data_fd, buf, 1);
 | 
					 | 
				
			||||||
		assert(err == 1);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int snd_ctl_client_shm_action(snd_ctl_t *ctl)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	snd_ctl_client_t *client = ctl->private;
 | 
					 | 
				
			||||||
	int err;
 | 
					 | 
				
			||||||
	char buf[1];
 | 
					 | 
				
			||||||
	snd_ctl_client_shm_t *ctrl = client->u.shm.ctrl;
 | 
					 | 
				
			||||||
	clean_poll(ctl);
 | 
					 | 
				
			||||||
	err = write(client->ctrl_fd, buf, 1);
 | 
					 | 
				
			||||||
	if (err != 1)
 | 
					 | 
				
			||||||
		return -EBADFD;
 | 
					 | 
				
			||||||
	err = read(client->ctrl_fd, buf, 1);
 | 
					 | 
				
			||||||
	if (err != 1)
 | 
					 | 
				
			||||||
		return -EBADFD;
 | 
					 | 
				
			||||||
	if (ctrl->cmd) {
 | 
					 | 
				
			||||||
		fprintf(stderr, "Server has not done the cmd\n");
 | 
					 | 
				
			||||||
		return -EBADFD;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int snd_ctl_client_shm_close(snd_ctl_t *ctl)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	snd_ctl_client_t *client = ctl->private;
 | 
					 | 
				
			||||||
	snd_ctl_client_shm_t *ctrl = client->u.shm.ctrl;
 | 
					 | 
				
			||||||
	int result;
 | 
					 | 
				
			||||||
	ctrl->cmd = SND_CTL_IOCTL_CLOSE;
 | 
					 | 
				
			||||||
	result = snd_ctl_client_shm_action(ctl);
 | 
					 | 
				
			||||||
	if (result >= 0)
 | 
					 | 
				
			||||||
		result = ctrl->result;
 | 
					 | 
				
			||||||
	shmdt((void *)ctrl);
 | 
					 | 
				
			||||||
	close(client->data_fd);
 | 
					 | 
				
			||||||
	close(client->ctrl_fd);
 | 
					 | 
				
			||||||
	free(client);
 | 
					 | 
				
			||||||
	return result;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int snd_ctl_client_poll_descriptor(snd_ctl_t *ctl)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	snd_ctl_client_t *client = ctl->private;
 | 
					 | 
				
			||||||
	return client->data_fd;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int snd_ctl_client_shm_hw_info(snd_ctl_t *ctl, snd_ctl_hw_info_t *info)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	snd_ctl_client_t *client = ctl->private;
 | 
					 | 
				
			||||||
	snd_ctl_client_shm_t *ctrl = client->u.shm.ctrl;
 | 
					 | 
				
			||||||
	int err;
 | 
					 | 
				
			||||||
//	ctrl->u.hw_info = *info;
 | 
					 | 
				
			||||||
	ctrl->cmd = SND_CTL_IOCTL_HW_INFO;
 | 
					 | 
				
			||||||
	err = snd_ctl_client_shm_action(ctl);
 | 
					 | 
				
			||||||
	if (err < 0)
 | 
					 | 
				
			||||||
		return err;
 | 
					 | 
				
			||||||
	*info = ctrl->u.hw_info;
 | 
					 | 
				
			||||||
	return ctrl->result;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int snd_ctl_client_shm_clist(snd_ctl_t *ctl, snd_control_list_t *list)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	snd_ctl_client_t *client = ctl->private;
 | 
					 | 
				
			||||||
	snd_ctl_client_shm_t *ctrl = client->u.shm.ctrl;
 | 
					 | 
				
			||||||
	size_t maxsize = CTL_SHM_DATA_MAXLEN;
 | 
					 | 
				
			||||||
	size_t bytes = list->controls_request * sizeof(*list->pids);
 | 
					 | 
				
			||||||
	int err;
 | 
					 | 
				
			||||||
	snd_control_id_t *pids = list->pids;
 | 
					 | 
				
			||||||
	if (bytes > maxsize)
 | 
					 | 
				
			||||||
		return -EINVAL;
 | 
					 | 
				
			||||||
	ctrl->u.clist = *list;
 | 
					 | 
				
			||||||
	ctrl->cmd = SND_CTL_IOCTL_CONTROL_LIST;
 | 
					 | 
				
			||||||
	err = snd_ctl_client_shm_action(ctl);
 | 
					 | 
				
			||||||
	if (err < 0)
 | 
					 | 
				
			||||||
		return err;
 | 
					 | 
				
			||||||
	*list = ctrl->u.clist;
 | 
					 | 
				
			||||||
	list->pids = pids;
 | 
					 | 
				
			||||||
	memcpy(pids, ctrl->data, bytes);
 | 
					 | 
				
			||||||
	return ctrl->result;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int snd_ctl_client_shm_cinfo(snd_ctl_t *ctl, snd_control_info_t *info)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	snd_ctl_client_t *client = ctl->private;
 | 
					 | 
				
			||||||
	snd_ctl_client_shm_t *ctrl = client->u.shm.ctrl;
 | 
					 | 
				
			||||||
	int err;
 | 
					 | 
				
			||||||
	ctrl->u.cinfo = *info;
 | 
					 | 
				
			||||||
	ctrl->cmd = SND_CTL_IOCTL_CONTROL_INFO;
 | 
					 | 
				
			||||||
	err = snd_ctl_client_shm_action(ctl);
 | 
					 | 
				
			||||||
	if (err < 0)
 | 
					 | 
				
			||||||
		return err;
 | 
					 | 
				
			||||||
	*info = ctrl->u.cinfo;
 | 
					 | 
				
			||||||
	return ctrl->result;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int snd_ctl_client_shm_cread(snd_ctl_t *ctl, snd_control_t *control)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	snd_ctl_client_t *client = ctl->private;
 | 
					 | 
				
			||||||
	snd_ctl_client_shm_t *ctrl = client->u.shm.ctrl;
 | 
					 | 
				
			||||||
	int err;
 | 
					 | 
				
			||||||
	ctrl->u.cread = *control;
 | 
					 | 
				
			||||||
	ctrl->cmd = SND_CTL_IOCTL_CONTROL_READ;
 | 
					 | 
				
			||||||
	err = snd_ctl_client_shm_action(ctl);
 | 
					 | 
				
			||||||
	if (err < 0)
 | 
					 | 
				
			||||||
		return err;
 | 
					 | 
				
			||||||
	*control = ctrl->u.cread;
 | 
					 | 
				
			||||||
	return ctrl->result;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int snd_ctl_client_shm_cwrite(snd_ctl_t *ctl, snd_control_t *control)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	snd_ctl_client_t *client = ctl->private;
 | 
					 | 
				
			||||||
	snd_ctl_client_shm_t *ctrl = client->u.shm.ctrl;
 | 
					 | 
				
			||||||
	int err;
 | 
					 | 
				
			||||||
	ctrl->u.cwrite = *control;
 | 
					 | 
				
			||||||
	ctrl->cmd = SND_CTL_IOCTL_CONTROL_WRITE;
 | 
					 | 
				
			||||||
	err = snd_ctl_client_shm_action(ctl);
 | 
					 | 
				
			||||||
	if (err < 0)
 | 
					 | 
				
			||||||
		return err;
 | 
					 | 
				
			||||||
	*control = ctrl->u.cwrite;
 | 
					 | 
				
			||||||
	return ctrl->result;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int snd_ctl_client_shm_hwdep_info(snd_ctl_t *ctl, snd_hwdep_info_t * info)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	snd_ctl_client_t *client = ctl->private;
 | 
					 | 
				
			||||||
	snd_ctl_client_shm_t *ctrl = client->u.shm.ctrl;
 | 
					 | 
				
			||||||
	int err;
 | 
					 | 
				
			||||||
	ctrl->u.hwdep_info = *info;
 | 
					 | 
				
			||||||
	ctrl->cmd = SND_CTL_IOCTL_HWDEP_INFO;
 | 
					 | 
				
			||||||
	err = snd_ctl_client_shm_action(ctl);
 | 
					 | 
				
			||||||
	if (err < 0)
 | 
					 | 
				
			||||||
		return err;
 | 
					 | 
				
			||||||
	*info = ctrl->u.hwdep_info;
 | 
					 | 
				
			||||||
	return ctrl->result;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int snd_ctl_client_shm_pcm_info(snd_ctl_t *ctl, snd_pcm_info_t * info)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	snd_ctl_client_t *client = ctl->private;
 | 
					 | 
				
			||||||
	snd_ctl_client_shm_t *ctrl = client->u.shm.ctrl;
 | 
					 | 
				
			||||||
	int err;
 | 
					 | 
				
			||||||
	ctrl->u.pcm_info = *info;
 | 
					 | 
				
			||||||
	ctrl->cmd = SND_CTL_IOCTL_PCM_INFO;
 | 
					 | 
				
			||||||
	err = snd_ctl_client_shm_action(ctl);
 | 
					 | 
				
			||||||
	if (err < 0)
 | 
					 | 
				
			||||||
		return err;
 | 
					 | 
				
			||||||
	*info = ctrl->u.pcm_info;
 | 
					 | 
				
			||||||
	return ctrl->result;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int snd_ctl_client_shm_pcm_prefer_subdevice(snd_ctl_t *ctl, int subdev)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	snd_ctl_client_t *client = ctl->private;
 | 
					 | 
				
			||||||
	snd_ctl_client_shm_t *ctrl = client->u.shm.ctrl;
 | 
					 | 
				
			||||||
	int err;
 | 
					 | 
				
			||||||
	ctrl->u.pcm_prefer_subdevice = subdev;
 | 
					 | 
				
			||||||
	ctrl->cmd = SND_CTL_IOCTL_PCM_PREFER_SUBDEVICE;
 | 
					 | 
				
			||||||
	err = snd_ctl_client_shm_action(ctl);
 | 
					 | 
				
			||||||
	if (err < 0)
 | 
					 | 
				
			||||||
		return err;
 | 
					 | 
				
			||||||
	return ctrl->result;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int snd_ctl_client_shm_rawmidi_info(snd_ctl_t *ctl, snd_rawmidi_info_t * info)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	snd_ctl_client_t *client = ctl->private;
 | 
					 | 
				
			||||||
	snd_ctl_client_shm_t *ctrl = client->u.shm.ctrl;
 | 
					 | 
				
			||||||
	int err;
 | 
					 | 
				
			||||||
	ctrl->u.rawmidi_info = *info;
 | 
					 | 
				
			||||||
	ctrl->cmd = SND_CTL_IOCTL_RAWMIDI_INFO;
 | 
					 | 
				
			||||||
	err = snd_ctl_client_shm_action(ctl);
 | 
					 | 
				
			||||||
	if (err < 0)
 | 
					 | 
				
			||||||
		return err;
 | 
					 | 
				
			||||||
	*info = ctrl->u.rawmidi_info;
 | 
					 | 
				
			||||||
	return ctrl->result;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int snd_ctl_client_shm_read(snd_ctl_t *ctl, snd_ctl_event_t *event)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	snd_ctl_client_t *client = ctl->private;
 | 
					 | 
				
			||||||
	snd_ctl_client_shm_t *ctrl = client->u.shm.ctrl;
 | 
					 | 
				
			||||||
	int err;
 | 
					 | 
				
			||||||
	ctrl->u.read = *event;
 | 
					 | 
				
			||||||
	ctrl->cmd = SND_CTL_IOCTL_READ;
 | 
					 | 
				
			||||||
	err = snd_ctl_client_shm_action(ctl);
 | 
					 | 
				
			||||||
	if (err < 0)
 | 
					 | 
				
			||||||
		return err;
 | 
					 | 
				
			||||||
	*event = ctrl->u.read;
 | 
					 | 
				
			||||||
	return ctrl->result;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
struct snd_ctl_ops snd_ctl_client_ops = {
 | 
					 | 
				
			||||||
	close: snd_ctl_client_shm_close,
 | 
					 | 
				
			||||||
	poll_descriptor: snd_ctl_client_poll_descriptor,
 | 
					 | 
				
			||||||
	hw_info: snd_ctl_client_shm_hw_info,
 | 
					 | 
				
			||||||
	clist: snd_ctl_client_shm_clist,
 | 
					 | 
				
			||||||
	cinfo: snd_ctl_client_shm_cinfo,
 | 
					 | 
				
			||||||
	cread: snd_ctl_client_shm_cread,
 | 
					 | 
				
			||||||
	cwrite: snd_ctl_client_shm_cwrite,
 | 
					 | 
				
			||||||
	hwdep_info: snd_ctl_client_shm_hwdep_info,
 | 
					 | 
				
			||||||
	pcm_info: snd_ctl_client_shm_pcm_info,
 | 
					 | 
				
			||||||
	pcm_prefer_subdevice: snd_ctl_client_shm_pcm_prefer_subdevice,
 | 
					 | 
				
			||||||
	rawmidi_info: snd_ctl_client_shm_rawmidi_info,
 | 
					 | 
				
			||||||
	read: snd_ctl_client_shm_read,
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int make_local_socket(const char *filename)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	size_t l = strlen(filename);
 | 
					 | 
				
			||||||
	size_t size = offsetof(struct sockaddr_un, sun_path) + l;
 | 
					 | 
				
			||||||
	struct sockaddr_un *addr = alloca(size);
 | 
					 | 
				
			||||||
	int sock;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	sock = socket(PF_LOCAL, SOCK_STREAM, 0);
 | 
					 | 
				
			||||||
	if (sock < 0)
 | 
					 | 
				
			||||||
		return -errno;
 | 
					 | 
				
			||||||
	
 | 
					 | 
				
			||||||
	addr->sun_family = AF_LOCAL;
 | 
					 | 
				
			||||||
	memcpy(addr->sun_path, filename, l);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (connect(sock, (struct sockaddr *) addr, size) < 0)
 | 
					 | 
				
			||||||
		return -errno;
 | 
					 | 
				
			||||||
	return sock;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int make_inet_socket(const char *host, int port)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct sockaddr_in addr;
 | 
					 | 
				
			||||||
	int sock;
 | 
					 | 
				
			||||||
	struct hostent *h = gethostbyname(host);
 | 
					 | 
				
			||||||
	if (!h)
 | 
					 | 
				
			||||||
		return -ENOENT;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	sock = socket(PF_INET, SOCK_STREAM, 0);
 | 
					 | 
				
			||||||
	if (sock < 0)
 | 
					 | 
				
			||||||
		return -errno;
 | 
					 | 
				
			||||||
	
 | 
					 | 
				
			||||||
	addr.sin_family = AF_INET;
 | 
					 | 
				
			||||||
	addr.sin_port = htons(port);
 | 
					 | 
				
			||||||
	memcpy(&addr.sin_addr, h->h_addr_list[0], sizeof(struct in_addr));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (connect(sock, (struct sockaddr *) &addr, sizeof(addr)) < 0)
 | 
					 | 
				
			||||||
		return -errno;
 | 
					 | 
				
			||||||
	return sock;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* port == -1 -> PF_LOCAL and host is the socket name */
 | 
					 | 
				
			||||||
int snd_ctl_client_open(snd_ctl_t **handlep, char *host, int port, int transport, char *name)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	snd_ctl_t *ctl;
 | 
					 | 
				
			||||||
	snd_ctl_client_t *client;
 | 
					 | 
				
			||||||
	snd_client_open_request_t *req;
 | 
					 | 
				
			||||||
	snd_client_open_answer_t ans;
 | 
					 | 
				
			||||||
	size_t namelen, reqlen;
 | 
					 | 
				
			||||||
	int err;
 | 
					 | 
				
			||||||
	int result;
 | 
					 | 
				
			||||||
	int fds[2] = {-1, -1};
 | 
					 | 
				
			||||||
	int k;
 | 
					 | 
				
			||||||
	snd_ctl_client_shm_t *ctrl = NULL;
 | 
					 | 
				
			||||||
	uint32_t rcookie, scookie = getpid();
 | 
					 | 
				
			||||||
	namelen = strlen(name);
 | 
					 | 
				
			||||||
	if (namelen > 255)
 | 
					 | 
				
			||||||
		return -EINVAL;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	for (k = 0; k < 2; ++k) {
 | 
					 | 
				
			||||||
		if (port == -1)
 | 
					 | 
				
			||||||
			fds[k] = make_local_socket(host);
 | 
					 | 
				
			||||||
		else
 | 
					 | 
				
			||||||
			fds[k] = make_inet_socket(host, port);
 | 
					 | 
				
			||||||
		if (fds[k] < 0) {
 | 
					 | 
				
			||||||
			result = fds[k];
 | 
					 | 
				
			||||||
			goto _err;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		err = write(fds[k], &scookie, sizeof(scookie));
 | 
					 | 
				
			||||||
		if (err != sizeof(scookie)) {
 | 
					 | 
				
			||||||
			result = -EBADFD;
 | 
					 | 
				
			||||||
			goto _err;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		err = read(fds[k], &rcookie, sizeof(rcookie));
 | 
					 | 
				
			||||||
		if (err != sizeof(rcookie) ||
 | 
					 | 
				
			||||||
		    rcookie != scookie) {
 | 
					 | 
				
			||||||
			result = -EBADFD;
 | 
					 | 
				
			||||||
			goto _err;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	reqlen = sizeof(*req) + namelen;
 | 
					 | 
				
			||||||
	req = alloca(reqlen);
 | 
					 | 
				
			||||||
	memcpy(req->name, name, namelen);
 | 
					 | 
				
			||||||
	req->dev_type = SND_DEV_TYPE_CONTROL;
 | 
					 | 
				
			||||||
	req->transport_type = transport;
 | 
					 | 
				
			||||||
	req->stream = 0;
 | 
					 | 
				
			||||||
	req->mode = 0;
 | 
					 | 
				
			||||||
	req->namelen = namelen;
 | 
					 | 
				
			||||||
	err = write(fds[1], req, reqlen);
 | 
					 | 
				
			||||||
	if (err < 0) {
 | 
					 | 
				
			||||||
		result = -errno;
 | 
					 | 
				
			||||||
		goto _err;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if ((size_t) err != reqlen) {
 | 
					 | 
				
			||||||
		result = -EINVAL;
 | 
					 | 
				
			||||||
		goto _err;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	err = read(fds[1], &ans, sizeof(ans));
 | 
					 | 
				
			||||||
	if (err < 0) {
 | 
					 | 
				
			||||||
		result = -errno;
 | 
					 | 
				
			||||||
		goto _err;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if (err != sizeof(ans)) {
 | 
					 | 
				
			||||||
		result = -EINVAL;
 | 
					 | 
				
			||||||
		goto _err;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	result = ans.result;
 | 
					 | 
				
			||||||
	if (result < 0)
 | 
					 | 
				
			||||||
		goto _err;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	switch (transport) {
 | 
					 | 
				
			||||||
	case SND_TRANSPORT_TYPE_SHM:
 | 
					 | 
				
			||||||
		ctrl = shmat(ans.cookie, 0, 0);
 | 
					 | 
				
			||||||
		if (!ctrl) {
 | 
					 | 
				
			||||||
			result = -errno;
 | 
					 | 
				
			||||||
			goto _err;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		break;
 | 
					 | 
				
			||||||
	default:
 | 
					 | 
				
			||||||
		result = -ENOSYS;
 | 
					 | 
				
			||||||
		goto _err;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
		
 | 
					 | 
				
			||||||
	ctl = calloc(1, sizeof(snd_ctl_t));
 | 
					 | 
				
			||||||
	if (!ctl) {
 | 
					 | 
				
			||||||
		result = -ENOMEM;
 | 
					 | 
				
			||||||
		goto _err;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	client = calloc(1, sizeof(snd_ctl_client_t));
 | 
					 | 
				
			||||||
	if (!ctl) {
 | 
					 | 
				
			||||||
		free(ctl);
 | 
					 | 
				
			||||||
		result = -ENOMEM;
 | 
					 | 
				
			||||||
		goto _err;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	client->data_fd = fds[0];
 | 
					 | 
				
			||||||
	client->ctrl_fd = fds[1];
 | 
					 | 
				
			||||||
	switch (transport) {
 | 
					 | 
				
			||||||
	case SND_TRANSPORT_TYPE_SHM:
 | 
					 | 
				
			||||||
		client->u.shm.ctrl = ctrl;
 | 
					 | 
				
			||||||
		break;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	ctl->type = SND_CTL_TYPE_CLIENT;
 | 
					 | 
				
			||||||
	ctl->ops = &snd_ctl_client_ops;
 | 
					 | 
				
			||||||
	ctl->private = client;
 | 
					 | 
				
			||||||
	INIT_LIST_HEAD(&ctl->hlist);
 | 
					 | 
				
			||||||
	*handlep = ctl;
 | 
					 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 _err:
 | 
					 | 
				
			||||||
	if (fds[0] >= 0)
 | 
					 | 
				
			||||||
		close(fds[0]);
 | 
					 | 
				
			||||||
	if (fds[1] >= 0)
 | 
					 | 
				
			||||||
		close(fds[1]);
 | 
					 | 
				
			||||||
	switch (transport) {
 | 
					 | 
				
			||||||
	case SND_TRANSPORT_TYPE_SHM:
 | 
					 | 
				
			||||||
		if (ctrl)
 | 
					 | 
				
			||||||
			shmdt(ctrl);
 | 
					 | 
				
			||||||
		break;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return result;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
| 
						 | 
					@ -147,7 +147,7 @@ struct snd_ctl_ops snd_ctl_hw_ops = {
 | 
				
			||||||
	read: snd_ctl_hw_read,
 | 
						read: snd_ctl_hw_read,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int snd_ctl_hw_open(snd_ctl_t **handle, int card)
 | 
					int snd_ctl_hw_open(snd_ctl_t **handle, char *name, int card)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int fd, ver;
 | 
						int fd, ver;
 | 
				
			||||||
	char filename[32];
 | 
						char filename[32];
 | 
				
			||||||
| 
						 | 
					@ -185,6 +185,9 @@ int snd_ctl_hw_open(snd_ctl_t **handle, int card)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	hw->card = card;
 | 
						hw->card = card;
 | 
				
			||||||
	hw->fd = fd;
 | 
						hw->fd = fd;
 | 
				
			||||||
 | 
						if (name)
 | 
				
			||||||
 | 
							ctl->name = strdup(name);
 | 
				
			||||||
 | 
						ctl->type = SND_CTL_TYPE_HW;
 | 
				
			||||||
	ctl->ops = &snd_ctl_hw_ops;
 | 
						ctl->ops = &snd_ctl_hw_ops;
 | 
				
			||||||
	ctl->private = hw;
 | 
						ctl->private = hw;
 | 
				
			||||||
	INIT_LIST_HEAD(&ctl->hlist);
 | 
						INIT_LIST_HEAD(&ctl->hlist);
 | 
				
			||||||
| 
						 | 
					@ -192,3 +195,34 @@ int snd_ctl_hw_open(snd_ctl_t **handle, int card)
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int _snd_ctl_hw_open(snd_ctl_t **handlep, char *name, snd_config_t *conf)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						snd_config_iterator_t i;
 | 
				
			||||||
 | 
						long card = -1;
 | 
				
			||||||
 | 
						char *str;
 | 
				
			||||||
 | 
						int err;
 | 
				
			||||||
 | 
						snd_config_foreach(i, conf) {
 | 
				
			||||||
 | 
							snd_config_t *n = snd_config_entry(i);
 | 
				
			||||||
 | 
							if (strcmp(n->id, "comment") == 0)
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
							if (strcmp(n->id, "type") == 0)
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
							if (strcmp(n->id, "card") == 0) {
 | 
				
			||||||
 | 
								err = snd_config_integer_get(n, &card);
 | 
				
			||||||
 | 
								if (err < 0) {
 | 
				
			||||||
 | 
									err = snd_config_string_get(n, &str);
 | 
				
			||||||
 | 
									if (err < 0)
 | 
				
			||||||
 | 
										return -EINVAL;
 | 
				
			||||||
 | 
									card = snd_card_get_index(str);
 | 
				
			||||||
 | 
									if (card < 0)
 | 
				
			||||||
 | 
										return card;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (card < 0)
 | 
				
			||||||
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
						return snd_ctl_hw_open(handlep, name, card);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
									
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -40,6 +40,7 @@ struct snd_ctl_ops {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct snd_ctl {
 | 
					struct snd_ctl {
 | 
				
			||||||
 | 
						char *name;
 | 
				
			||||||
	snd_ctl_type_t type;
 | 
						snd_ctl_type_t type;
 | 
				
			||||||
	struct snd_ctl_ops *ops;
 | 
						struct snd_ctl_ops *ops;
 | 
				
			||||||
	void *private;
 | 
						void *private;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										512
									
								
								src/control/control_shm.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										512
									
								
								src/control/control_shm.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,512 @@
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 *  Control - SHM Client
 | 
				
			||||||
 | 
					 *  Copyright (c) 2000 by Abramo Bagnara <abramo@alsa-project.org>
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *   This library is free software; you can redistribute it and/or modify
 | 
				
			||||||
 | 
					 *   it under the terms of the GNU Library General Public License as
 | 
				
			||||||
 | 
					 *   published by the Free Software Foundation; either version 2 of
 | 
				
			||||||
 | 
					 *   the License, or (at your option) any later version.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *   This program is distributed in the hope that it will be useful,
 | 
				
			||||||
 | 
					 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
				
			||||||
 | 
					 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
				
			||||||
 | 
					 *   GNU Library General Public License for more details.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *   You should have received a copy of the GNU Library General Public
 | 
				
			||||||
 | 
					 *   License along with this library; if not, write to the Free Software
 | 
				
			||||||
 | 
					 *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					#include <stdio.h>
 | 
				
			||||||
 | 
					#include <stdlib.h>
 | 
				
			||||||
 | 
					#include <stddef.h>
 | 
				
			||||||
 | 
					#include <unistd.h>
 | 
				
			||||||
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					#include <errno.h>
 | 
				
			||||||
 | 
					#include <fcntl.h>
 | 
				
			||||||
 | 
					#include <sys/shm.h>
 | 
				
			||||||
 | 
					#include <sys/socket.h>
 | 
				
			||||||
 | 
					#include <sys/poll.h>
 | 
				
			||||||
 | 
					#include <sys/un.h>
 | 
				
			||||||
 | 
					#include <sys/uio.h>
 | 
				
			||||||
 | 
					#include <sys/mman.h>
 | 
				
			||||||
 | 
					#include <netinet/in.h>
 | 
				
			||||||
 | 
					#include <netdb.h>
 | 
				
			||||||
 | 
					#include "control_local.h"
 | 
				
			||||||
 | 
					#include "aserver.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef struct {
 | 
				
			||||||
 | 
						int socket;
 | 
				
			||||||
 | 
						void *ctrl;
 | 
				
			||||||
 | 
					} snd_ctl_shm_t;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern int receive_fd(int socket, void *data, size_t len, int *fd);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int snd_ctl_shm_action(snd_ctl_t *ctl)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						snd_ctl_shm_t *shm = ctl->private;
 | 
				
			||||||
 | 
						int err;
 | 
				
			||||||
 | 
						char buf[1];
 | 
				
			||||||
 | 
						snd_ctl_shm_ctrl_t *ctrl = shm->ctrl;
 | 
				
			||||||
 | 
						err = write(shm->socket, buf, 1);
 | 
				
			||||||
 | 
						if (err != 1)
 | 
				
			||||||
 | 
							return -EBADFD;
 | 
				
			||||||
 | 
						err = read(shm->socket, buf, 1);
 | 
				
			||||||
 | 
						if (err != 1)
 | 
				
			||||||
 | 
							return -EBADFD;
 | 
				
			||||||
 | 
						if (ctrl->cmd) {
 | 
				
			||||||
 | 
							fprintf(stderr, "Server has not done the cmd\n");
 | 
				
			||||||
 | 
							return -EBADFD;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return ctrl->result;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int snd_ctl_shm_action_fd(snd_ctl_t *ctl, int *fd)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						snd_ctl_shm_t *shm = ctl->private;
 | 
				
			||||||
 | 
						int err;
 | 
				
			||||||
 | 
						char buf[1];
 | 
				
			||||||
 | 
						snd_ctl_shm_ctrl_t *ctrl = shm->ctrl;
 | 
				
			||||||
 | 
						err = write(shm->socket, buf, 1);
 | 
				
			||||||
 | 
						if (err != 1)
 | 
				
			||||||
 | 
							return -EBADFD;
 | 
				
			||||||
 | 
						err = receive_fd(shm->socket, buf, 1, fd);
 | 
				
			||||||
 | 
						if (err != 1)
 | 
				
			||||||
 | 
							return -EBADFD;
 | 
				
			||||||
 | 
						if (ctrl->cmd) {
 | 
				
			||||||
 | 
							fprintf(stderr, "Server has not done the cmd\n");
 | 
				
			||||||
 | 
							return -EBADFD;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return ctrl->result;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int snd_ctl_shm_close(snd_ctl_t *ctl)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						snd_ctl_shm_t *shm = ctl->private;
 | 
				
			||||||
 | 
						snd_ctl_shm_ctrl_t *ctrl = shm->ctrl;
 | 
				
			||||||
 | 
						int result;
 | 
				
			||||||
 | 
						ctrl->cmd = SND_CTL_IOCTL_CLOSE;
 | 
				
			||||||
 | 
						result = snd_ctl_shm_action(ctl);
 | 
				
			||||||
 | 
						shmdt((void *)ctrl);
 | 
				
			||||||
 | 
						close(shm->socket);
 | 
				
			||||||
 | 
						free(shm);
 | 
				
			||||||
 | 
						return result;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int snd_ctl_shm_poll_descriptor(snd_ctl_t *ctl)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						snd_ctl_shm_t *shm = ctl->private;
 | 
				
			||||||
 | 
						snd_ctl_shm_ctrl_t *ctrl = shm->ctrl;
 | 
				
			||||||
 | 
						int fd, err;
 | 
				
			||||||
 | 
						ctrl->cmd = SND_CTL_IOCTL_POLL_DESCRIPTOR;
 | 
				
			||||||
 | 
						err = snd_ctl_shm_action_fd(ctl, &fd);
 | 
				
			||||||
 | 
						if (err < 0)
 | 
				
			||||||
 | 
							return err;
 | 
				
			||||||
 | 
						return fd;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int snd_ctl_shm_hw_info(snd_ctl_t *ctl, snd_ctl_hw_info_t *info)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						snd_ctl_shm_t *shm = ctl->private;
 | 
				
			||||||
 | 
						snd_ctl_shm_ctrl_t *ctrl = shm->ctrl;
 | 
				
			||||||
 | 
						int err;
 | 
				
			||||||
 | 
					//	ctrl->u.hw_info = *info;
 | 
				
			||||||
 | 
						ctrl->cmd = SND_CTL_IOCTL_HW_INFO;
 | 
				
			||||||
 | 
						err = snd_ctl_shm_action(ctl);
 | 
				
			||||||
 | 
						if (err < 0)
 | 
				
			||||||
 | 
							return err;
 | 
				
			||||||
 | 
						*info = ctrl->u.hw_info;
 | 
				
			||||||
 | 
						return err;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int snd_ctl_shm_clist(snd_ctl_t *ctl, snd_control_list_t *list)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						snd_ctl_shm_t *shm = ctl->private;
 | 
				
			||||||
 | 
						snd_ctl_shm_ctrl_t *ctrl = shm->ctrl;
 | 
				
			||||||
 | 
						size_t maxsize = CTL_SHM_DATA_MAXLEN;
 | 
				
			||||||
 | 
						size_t bytes = list->controls_request * sizeof(*list->pids);
 | 
				
			||||||
 | 
						int err;
 | 
				
			||||||
 | 
						snd_control_id_t *pids = list->pids;
 | 
				
			||||||
 | 
						if (bytes > maxsize)
 | 
				
			||||||
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
						ctrl->u.clist = *list;
 | 
				
			||||||
 | 
						ctrl->cmd = SND_CTL_IOCTL_CONTROL_LIST;
 | 
				
			||||||
 | 
						err = snd_ctl_shm_action(ctl);
 | 
				
			||||||
 | 
						if (err < 0)
 | 
				
			||||||
 | 
							return err;
 | 
				
			||||||
 | 
						*list = ctrl->u.clist;
 | 
				
			||||||
 | 
						list->pids = pids;
 | 
				
			||||||
 | 
						memcpy(pids, ctrl->data, bytes);
 | 
				
			||||||
 | 
						return err;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int snd_ctl_shm_cinfo(snd_ctl_t *ctl, snd_control_info_t *info)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						snd_ctl_shm_t *shm = ctl->private;
 | 
				
			||||||
 | 
						snd_ctl_shm_ctrl_t *ctrl = shm->ctrl;
 | 
				
			||||||
 | 
						int err;
 | 
				
			||||||
 | 
						ctrl->u.cinfo = *info;
 | 
				
			||||||
 | 
						ctrl->cmd = SND_CTL_IOCTL_CONTROL_INFO;
 | 
				
			||||||
 | 
						err = snd_ctl_shm_action(ctl);
 | 
				
			||||||
 | 
						if (err < 0)
 | 
				
			||||||
 | 
							return err;
 | 
				
			||||||
 | 
						*info = ctrl->u.cinfo;
 | 
				
			||||||
 | 
						return err;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int snd_ctl_shm_cread(snd_ctl_t *ctl, snd_control_t *control)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						snd_ctl_shm_t *shm = ctl->private;
 | 
				
			||||||
 | 
						snd_ctl_shm_ctrl_t *ctrl = shm->ctrl;
 | 
				
			||||||
 | 
						int err;
 | 
				
			||||||
 | 
						ctrl->u.cread = *control;
 | 
				
			||||||
 | 
						ctrl->cmd = SND_CTL_IOCTL_CONTROL_READ;
 | 
				
			||||||
 | 
						err = snd_ctl_shm_action(ctl);
 | 
				
			||||||
 | 
						if (err < 0)
 | 
				
			||||||
 | 
							return err;
 | 
				
			||||||
 | 
						*control = ctrl->u.cread;
 | 
				
			||||||
 | 
						return err;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int snd_ctl_shm_cwrite(snd_ctl_t *ctl, snd_control_t *control)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						snd_ctl_shm_t *shm = ctl->private;
 | 
				
			||||||
 | 
						snd_ctl_shm_ctrl_t *ctrl = shm->ctrl;
 | 
				
			||||||
 | 
						int err;
 | 
				
			||||||
 | 
						ctrl->u.cwrite = *control;
 | 
				
			||||||
 | 
						ctrl->cmd = SND_CTL_IOCTL_CONTROL_WRITE;
 | 
				
			||||||
 | 
						err = snd_ctl_shm_action(ctl);
 | 
				
			||||||
 | 
						if (err < 0)
 | 
				
			||||||
 | 
							return err;
 | 
				
			||||||
 | 
						*control = ctrl->u.cwrite;
 | 
				
			||||||
 | 
						return err;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int snd_ctl_shm_hwdep_info(snd_ctl_t *ctl, snd_hwdep_info_t * info)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						snd_ctl_shm_t *shm = ctl->private;
 | 
				
			||||||
 | 
						snd_ctl_shm_ctrl_t *ctrl = shm->ctrl;
 | 
				
			||||||
 | 
						int err;
 | 
				
			||||||
 | 
						ctrl->u.hwdep_info = *info;
 | 
				
			||||||
 | 
						ctrl->cmd = SND_CTL_IOCTL_HWDEP_INFO;
 | 
				
			||||||
 | 
						err = snd_ctl_shm_action(ctl);
 | 
				
			||||||
 | 
						if (err < 0)
 | 
				
			||||||
 | 
							return err;
 | 
				
			||||||
 | 
						*info = ctrl->u.hwdep_info;
 | 
				
			||||||
 | 
						return err;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int snd_ctl_shm_pcm_info(snd_ctl_t *ctl, snd_pcm_info_t * info)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						snd_ctl_shm_t *shm = ctl->private;
 | 
				
			||||||
 | 
						snd_ctl_shm_ctrl_t *ctrl = shm->ctrl;
 | 
				
			||||||
 | 
						int err;
 | 
				
			||||||
 | 
						ctrl->u.pcm_info = *info;
 | 
				
			||||||
 | 
						ctrl->cmd = SND_CTL_IOCTL_PCM_INFO;
 | 
				
			||||||
 | 
						err = snd_ctl_shm_action(ctl);
 | 
				
			||||||
 | 
						if (err < 0)
 | 
				
			||||||
 | 
							return err;
 | 
				
			||||||
 | 
						*info = ctrl->u.pcm_info;
 | 
				
			||||||
 | 
						return err;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int snd_ctl_shm_pcm_prefer_subdevice(snd_ctl_t *ctl, int subdev)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						snd_ctl_shm_t *shm = ctl->private;
 | 
				
			||||||
 | 
						snd_ctl_shm_ctrl_t *ctrl = shm->ctrl;
 | 
				
			||||||
 | 
						int err;
 | 
				
			||||||
 | 
						ctrl->u.pcm_prefer_subdevice = subdev;
 | 
				
			||||||
 | 
						ctrl->cmd = SND_CTL_IOCTL_PCM_PREFER_SUBDEVICE;
 | 
				
			||||||
 | 
						err = snd_ctl_shm_action(ctl);
 | 
				
			||||||
 | 
						if (err < 0)
 | 
				
			||||||
 | 
							return err;
 | 
				
			||||||
 | 
						return err;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int snd_ctl_shm_rawmidi_info(snd_ctl_t *ctl, snd_rawmidi_info_t * info)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						snd_ctl_shm_t *shm = ctl->private;
 | 
				
			||||||
 | 
						snd_ctl_shm_ctrl_t *ctrl = shm->ctrl;
 | 
				
			||||||
 | 
						int err;
 | 
				
			||||||
 | 
						ctrl->u.rawmidi_info = *info;
 | 
				
			||||||
 | 
						ctrl->cmd = SND_CTL_IOCTL_RAWMIDI_INFO;
 | 
				
			||||||
 | 
						err = snd_ctl_shm_action(ctl);
 | 
				
			||||||
 | 
						if (err < 0)
 | 
				
			||||||
 | 
							return err;
 | 
				
			||||||
 | 
						*info = ctrl->u.rawmidi_info;
 | 
				
			||||||
 | 
						return err;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int snd_ctl_shm_read(snd_ctl_t *ctl, snd_ctl_event_t *event)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						snd_ctl_shm_t *shm = ctl->private;
 | 
				
			||||||
 | 
						snd_ctl_shm_ctrl_t *ctrl = shm->ctrl;
 | 
				
			||||||
 | 
						int err;
 | 
				
			||||||
 | 
						ctrl->u.read = *event;
 | 
				
			||||||
 | 
						ctrl->cmd = SND_CTL_IOCTL_READ;
 | 
				
			||||||
 | 
						err = snd_ctl_shm_action(ctl);
 | 
				
			||||||
 | 
						if (err < 0)
 | 
				
			||||||
 | 
							return err;
 | 
				
			||||||
 | 
						*event = ctrl->u.read;
 | 
				
			||||||
 | 
						return err;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct snd_ctl_ops snd_ctl_shm_ops = {
 | 
				
			||||||
 | 
						close: snd_ctl_shm_close,
 | 
				
			||||||
 | 
						poll_descriptor: snd_ctl_shm_poll_descriptor,
 | 
				
			||||||
 | 
						hw_info: snd_ctl_shm_hw_info,
 | 
				
			||||||
 | 
						clist: snd_ctl_shm_clist,
 | 
				
			||||||
 | 
						cinfo: snd_ctl_shm_cinfo,
 | 
				
			||||||
 | 
						cread: snd_ctl_shm_cread,
 | 
				
			||||||
 | 
						cwrite: snd_ctl_shm_cwrite,
 | 
				
			||||||
 | 
						hwdep_info: snd_ctl_shm_hwdep_info,
 | 
				
			||||||
 | 
						pcm_info: snd_ctl_shm_pcm_info,
 | 
				
			||||||
 | 
						pcm_prefer_subdevice: snd_ctl_shm_pcm_prefer_subdevice,
 | 
				
			||||||
 | 
						rawmidi_info: snd_ctl_shm_rawmidi_info,
 | 
				
			||||||
 | 
						read: snd_ctl_shm_read,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int make_local_socket(const char *filename)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						size_t l = strlen(filename);
 | 
				
			||||||
 | 
						size_t size = offsetof(struct sockaddr_un, sun_path) + l;
 | 
				
			||||||
 | 
						struct sockaddr_un *addr = alloca(size);
 | 
				
			||||||
 | 
						int sock;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						sock = socket(PF_LOCAL, SOCK_STREAM, 0);
 | 
				
			||||||
 | 
						if (sock < 0)
 | 
				
			||||||
 | 
							return -errno;
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						addr->sun_family = AF_LOCAL;
 | 
				
			||||||
 | 
						memcpy(addr->sun_path, filename, l);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (connect(sock, (struct sockaddr *) addr, size) < 0)
 | 
				
			||||||
 | 
							return -errno;
 | 
				
			||||||
 | 
						return sock;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if 0
 | 
				
			||||||
 | 
					static int make_inet_socket(const char *host, int port)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct sockaddr_in addr;
 | 
				
			||||||
 | 
						int sock;
 | 
				
			||||||
 | 
						struct hostent *h = gethostbyname(host);
 | 
				
			||||||
 | 
						if (!h)
 | 
				
			||||||
 | 
							return -ENOENT;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						sock = socket(PF_INET, SOCK_STREAM, 0);
 | 
				
			||||||
 | 
						if (sock < 0)
 | 
				
			||||||
 | 
							return -errno;
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						addr.sin_family = AF_INET;
 | 
				
			||||||
 | 
						addr.sin_port = htons(port);
 | 
				
			||||||
 | 
						memcpy(&addr.sin_addr, h->h_addr_list[0], sizeof(struct in_addr));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (connect(sock, (struct sockaddr *) &addr, sizeof(addr)) < 0)
 | 
				
			||||||
 | 
							return -errno;
 | 
				
			||||||
 | 
						return sock;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int snd_ctl_shm_open(snd_ctl_t **handlep, char *name, char *socket, char *sname)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						snd_ctl_t *ctl;
 | 
				
			||||||
 | 
						snd_ctl_shm_t *shm = NULL;
 | 
				
			||||||
 | 
						snd_client_open_request_t *req;
 | 
				
			||||||
 | 
						snd_client_open_answer_t ans;
 | 
				
			||||||
 | 
						size_t snamelen, reqlen;
 | 
				
			||||||
 | 
						int err;
 | 
				
			||||||
 | 
						int result;
 | 
				
			||||||
 | 
						int sock = -1;
 | 
				
			||||||
 | 
						snd_ctl_shm_ctrl_t *ctrl = NULL;
 | 
				
			||||||
 | 
						snamelen = strlen(sname);
 | 
				
			||||||
 | 
						if (snamelen > 255)
 | 
				
			||||||
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						result = make_local_socket(socket);
 | 
				
			||||||
 | 
						if (result < 0) {
 | 
				
			||||||
 | 
							ERR("server for socket %s is not running", socket);
 | 
				
			||||||
 | 
							goto _err;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						sock = result;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						reqlen = sizeof(*req) + snamelen;
 | 
				
			||||||
 | 
						req = alloca(reqlen);
 | 
				
			||||||
 | 
						memcpy(req->name, sname, snamelen);
 | 
				
			||||||
 | 
						req->dev_type = SND_DEV_TYPE_CONTROL;
 | 
				
			||||||
 | 
						req->transport_type = SND_TRANSPORT_TYPE_SHM;
 | 
				
			||||||
 | 
						req->stream = 0;
 | 
				
			||||||
 | 
						req->mode = 0;
 | 
				
			||||||
 | 
						req->namelen = snamelen;
 | 
				
			||||||
 | 
						err = write(sock, req, reqlen);
 | 
				
			||||||
 | 
						if (err < 0) {
 | 
				
			||||||
 | 
							ERR("write error");
 | 
				
			||||||
 | 
							result = -errno;
 | 
				
			||||||
 | 
							goto _err;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if ((size_t) err != reqlen) {
 | 
				
			||||||
 | 
							ERR("write size error");
 | 
				
			||||||
 | 
							result = -EINVAL;
 | 
				
			||||||
 | 
							goto _err;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						err = read(sock, &ans, sizeof(ans));
 | 
				
			||||||
 | 
						if (err < 0) {
 | 
				
			||||||
 | 
							ERR("read error");
 | 
				
			||||||
 | 
							result = -errno;
 | 
				
			||||||
 | 
							goto _err;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (err != sizeof(ans)) {
 | 
				
			||||||
 | 
							ERR("read size error");
 | 
				
			||||||
 | 
							result = -EINVAL;
 | 
				
			||||||
 | 
							goto _err;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						result = ans.result;
 | 
				
			||||||
 | 
						if (result < 0)
 | 
				
			||||||
 | 
							goto _err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ctrl = shmat(ans.cookie, 0, 0);
 | 
				
			||||||
 | 
						if (!ctrl) {
 | 
				
			||||||
 | 
							result = -errno;
 | 
				
			||||||
 | 
							goto _err;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
						ctl = calloc(1, sizeof(snd_ctl_t));
 | 
				
			||||||
 | 
						if (!ctl) {
 | 
				
			||||||
 | 
							result = -ENOMEM;
 | 
				
			||||||
 | 
							goto _err;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						shm = calloc(1, sizeof(snd_ctl_shm_t));
 | 
				
			||||||
 | 
						if (!ctl) {
 | 
				
			||||||
 | 
							free(ctl);
 | 
				
			||||||
 | 
							result = -ENOMEM;
 | 
				
			||||||
 | 
							goto _err;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						shm->socket = sock;
 | 
				
			||||||
 | 
						shm->ctrl = ctrl;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (name)
 | 
				
			||||||
 | 
							ctl->name = strdup(name);
 | 
				
			||||||
 | 
						ctl->type = SND_CTL_TYPE_SHM;
 | 
				
			||||||
 | 
						ctl->ops = &snd_ctl_shm_ops;
 | 
				
			||||||
 | 
						ctl->private = shm;
 | 
				
			||||||
 | 
						INIT_LIST_HEAD(&ctl->hlist);
 | 
				
			||||||
 | 
						*handlep = ctl;
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 _err:
 | 
				
			||||||
 | 
						close(sock);
 | 
				
			||||||
 | 
						if (ctrl)
 | 
				
			||||||
 | 
							shmdt(ctrl);
 | 
				
			||||||
 | 
						if (shm)
 | 
				
			||||||
 | 
							free(shm);
 | 
				
			||||||
 | 
						return result;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern int is_local(struct hostent *hent);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int _snd_ctl_shm_open(snd_ctl_t **handlep, char *name, snd_config_t *conf)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						snd_config_iterator_t i;
 | 
				
			||||||
 | 
						char *server = NULL;
 | 
				
			||||||
 | 
						char *sname = NULL;
 | 
				
			||||||
 | 
						snd_config_t *sconfig;
 | 
				
			||||||
 | 
						char *host = NULL;
 | 
				
			||||||
 | 
						char *socket = NULL;
 | 
				
			||||||
 | 
						long port = -1;
 | 
				
			||||||
 | 
						int err;
 | 
				
			||||||
 | 
						int local;
 | 
				
			||||||
 | 
						struct hostent *h;
 | 
				
			||||||
 | 
						snd_config_foreach(i, conf) {
 | 
				
			||||||
 | 
							snd_config_t *n = snd_config_entry(i);
 | 
				
			||||||
 | 
							if (strcmp(n->id, "comment") == 0)
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
							if (strcmp(n->id, "type") == 0)
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
							if (strcmp(n->id, "server") == 0) {
 | 
				
			||||||
 | 
								err = snd_config_string_get(n, &server);
 | 
				
			||||||
 | 
								if (err < 0) {
 | 
				
			||||||
 | 
									ERR("Invalid type for server");
 | 
				
			||||||
 | 
									return -EINVAL;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if (strcmp(n->id, "sname") == 0) {
 | 
				
			||||||
 | 
								err = snd_config_string_get(n, &sname);
 | 
				
			||||||
 | 
								if (err < 0) {
 | 
				
			||||||
 | 
									ERR("Invalid type for sname");
 | 
				
			||||||
 | 
									return -EINVAL;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							ERR("Unknown field: %s", n->id);
 | 
				
			||||||
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (!sname) {
 | 
				
			||||||
 | 
							ERR("sname is not defined");
 | 
				
			||||||
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (!server) {
 | 
				
			||||||
 | 
							ERR("server is not defined");
 | 
				
			||||||
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						err = snd_config_searchv(snd_config, &sconfig, "server", server, 0);
 | 
				
			||||||
 | 
						if (err < 0) {
 | 
				
			||||||
 | 
							ERR("Unknown server %s", server);
 | 
				
			||||||
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						snd_config_foreach(i, conf) {
 | 
				
			||||||
 | 
							snd_config_t *n = snd_config_entry(i);
 | 
				
			||||||
 | 
							if (strcmp(n->id, "comment") == 0)
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
							if (strcmp(n->id, "host") == 0) {
 | 
				
			||||||
 | 
								err = snd_config_string_get(n, &host);
 | 
				
			||||||
 | 
								if (err < 0) {
 | 
				
			||||||
 | 
									ERR("Invalid type for host");
 | 
				
			||||||
 | 
									return -EINVAL;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if (strcmp(n->id, "socket") == 0) {
 | 
				
			||||||
 | 
								err = snd_config_string_get(n, &socket);
 | 
				
			||||||
 | 
								if (err < 0) {
 | 
				
			||||||
 | 
									ERR("Invalid type for socket");
 | 
				
			||||||
 | 
									return -EINVAL;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if (strcmp(n->id, "port") == 0) {
 | 
				
			||||||
 | 
								err = snd_config_integer_get(n, &port);
 | 
				
			||||||
 | 
								if (err < 0) {
 | 
				
			||||||
 | 
									ERR("Invalid type for port");
 | 
				
			||||||
 | 
									return -EINVAL;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							ERR("Unknown field: %s", n->id);
 | 
				
			||||||
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!host) {
 | 
				
			||||||
 | 
							ERR("host is not defined");
 | 
				
			||||||
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (!socket) {
 | 
				
			||||||
 | 
							ERR("socket is not defined");
 | 
				
			||||||
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						h = gethostbyname(host);
 | 
				
			||||||
 | 
						if (!h) {
 | 
				
			||||||
 | 
							ERR("Cannot resolve %s", host);
 | 
				
			||||||
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						local = is_local(h);
 | 
				
			||||||
 | 
						if (!local) {
 | 
				
			||||||
 | 
							ERR("%s is not the local host", host);
 | 
				
			||||||
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return snd_ctl_shm_open(handlep, name, socket, sname);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
									
 | 
				
			||||||
| 
						 | 
					@ -3,7 +3,7 @@ EXTRA_LTLIBRARIES = libpcm.la
 | 
				
			||||||
 | 
					
 | 
				
			||||||
libpcm_la_SOURCES = pcm.c pcm_hw.c pcm_plugin.c pcm_linear.c pcm_route.c \
 | 
					libpcm_la_SOURCES = pcm.c pcm_hw.c pcm_plugin.c pcm_linear.c pcm_route.c \
 | 
				
			||||||
		    pcm_mulaw.c pcm_alaw.c pcm_adpcm.c pcm_rate.c pcm_plug.c \
 | 
							    pcm_mulaw.c pcm_alaw.c pcm_adpcm.c pcm_rate.c pcm_plug.c \
 | 
				
			||||||
	            pcm_misc.c pcm_mmap.c pcm_multi.c pcm_client.c pcm_file.c \
 | 
						            pcm_misc.c pcm_mmap.c pcm_multi.c pcm_shm.c pcm_file.c \
 | 
				
			||||||
		    pcm_share.c
 | 
							    pcm_share.c
 | 
				
			||||||
noinst_HEADERS = pcm_local.h pcm_plugin.h
 | 
					noinst_HEADERS = pcm_local.h pcm_plugin.h
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										112
									
								
								src/pcm/pcm.c
									
										
									
									
									
								
							
							
						
						
									
										112
									
								
								src/pcm/pcm.c
									
										
									
									
									
								
							| 
						 | 
					@ -30,18 +30,6 @@
 | 
				
			||||||
#include "pcm_local.h"
 | 
					#include "pcm_local.h"
 | 
				
			||||||
#include "list.h"
 | 
					#include "list.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int snd_pcm_init(snd_pcm_t *pcm)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	int err;
 | 
					 | 
				
			||||||
	err = snd_pcm_mmap_status(pcm, NULL);
 | 
					 | 
				
			||||||
	if (err < 0)
 | 
					 | 
				
			||||||
		return err;
 | 
					 | 
				
			||||||
	err = snd_pcm_mmap_control(pcm, NULL);
 | 
					 | 
				
			||||||
	if (err < 0)
 | 
					 | 
				
			||||||
		return err;
 | 
					 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
snd_pcm_type_t snd_pcm_type(snd_pcm_t *pcm)
 | 
					snd_pcm_type_t snd_pcm_type(snd_pcm_t *pcm)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	assert(pcm);
 | 
						assert(pcm);
 | 
				
			||||||
| 
						 | 
					@ -59,16 +47,8 @@ int snd_pcm_close(snd_pcm_t *pcm)
 | 
				
			||||||
	int ret = 0;
 | 
						int ret = 0;
 | 
				
			||||||
	int err;
 | 
						int err;
 | 
				
			||||||
	assert(pcm);
 | 
						assert(pcm);
 | 
				
			||||||
	if (pcm->mmap_status) {
 | 
						if (pcm->mmap_info) {
 | 
				
			||||||
		if ((err = snd_pcm_munmap_status(pcm)) < 0)
 | 
							if ((err = snd_pcm_munmap(pcm)) < 0)
 | 
				
			||||||
			ret = err;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if (pcm->mmap_control) {
 | 
					 | 
				
			||||||
		if ((err = snd_pcm_munmap_control(pcm)) < 0)
 | 
					 | 
				
			||||||
			ret = err;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if (pcm->mmap_data) {
 | 
					 | 
				
			||||||
		if ((err = snd_pcm_munmap_data(pcm)) < 0)
 | 
					 | 
				
			||||||
			ret = err;
 | 
								ret = err;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if ((err = pcm->ops->close(pcm->op_arg)) < 0)
 | 
						if ((err = pcm->ops->close(pcm->op_arg)) < 0)
 | 
				
			||||||
| 
						 | 
					@ -156,12 +136,21 @@ int snd_pcm_params(snd_pcm_t *pcm, snd_pcm_params_t *params)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int err;
 | 
						int err;
 | 
				
			||||||
	snd_pcm_setup_t setup;
 | 
						snd_pcm_setup_t setup;
 | 
				
			||||||
 | 
						int mmap = 0;
 | 
				
			||||||
	assert(pcm && params);
 | 
						assert(pcm && params);
 | 
				
			||||||
	assert(!pcm->mmap_data);
 | 
						if (pcm->mmap_info) {
 | 
				
			||||||
 | 
							mmap = 1;
 | 
				
			||||||
 | 
							err = snd_pcm_munmap(pcm);
 | 
				
			||||||
 | 
							if (err < 0)
 | 
				
			||||||
 | 
								return err;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	if ((err = pcm->ops->params(pcm->op_arg, params)) < 0)
 | 
						if ((err = pcm->ops->params(pcm->op_arg, params)) < 0)
 | 
				
			||||||
		return err;
 | 
							return err;
 | 
				
			||||||
	pcm->valid_setup = 0;
 | 
						pcm->valid_setup = 0;
 | 
				
			||||||
	return snd_pcm_setup(pcm, &setup);
 | 
						err = snd_pcm_setup(pcm, &setup);
 | 
				
			||||||
 | 
						if (pcm->mmap_auto || mmap)
 | 
				
			||||||
 | 
							snd_pcm_mmap(pcm);
 | 
				
			||||||
 | 
						return err;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int snd_pcm_status(snd_pcm_t *pcm, snd_pcm_status_t *status)
 | 
					int snd_pcm_status(snd_pcm_t *pcm, snd_pcm_status_t *status)
 | 
				
			||||||
| 
						 | 
					@ -233,7 +222,7 @@ ssize_t snd_pcm_writei(snd_pcm_t *pcm, const void *buffer, size_t size)
 | 
				
			||||||
	assert(size == 0 || buffer);
 | 
						assert(size == 0 || buffer);
 | 
				
			||||||
	assert(pcm->valid_setup);
 | 
						assert(pcm->valid_setup);
 | 
				
			||||||
	assert(pcm->setup.xfer_mode == SND_PCM_XFER_INTERLEAVED);
 | 
						assert(pcm->setup.xfer_mode == SND_PCM_XFER_INTERLEAVED);
 | 
				
			||||||
	assert(!pcm->mmap_data);
 | 
						assert(!pcm->mmap_info || pcm->mmap_auto);
 | 
				
			||||||
	return _snd_pcm_writei(pcm, buffer, size);
 | 
						return _snd_pcm_writei(pcm, buffer, size);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -243,7 +232,7 @@ ssize_t snd_pcm_writen(snd_pcm_t *pcm, void **bufs, size_t size)
 | 
				
			||||||
	assert(size == 0 || bufs);
 | 
						assert(size == 0 || bufs);
 | 
				
			||||||
	assert(pcm->valid_setup);
 | 
						assert(pcm->valid_setup);
 | 
				
			||||||
	assert(pcm->setup.xfer_mode == SND_PCM_XFER_NONINTERLEAVED);
 | 
						assert(pcm->setup.xfer_mode == SND_PCM_XFER_NONINTERLEAVED);
 | 
				
			||||||
	assert(!pcm->mmap_data);
 | 
						assert(!pcm->mmap_info || pcm->mmap_auto);
 | 
				
			||||||
	return _snd_pcm_writen(pcm, bufs, size);
 | 
						return _snd_pcm_writen(pcm, bufs, size);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -253,7 +242,7 @@ ssize_t snd_pcm_readi(snd_pcm_t *pcm, void *buffer, size_t size)
 | 
				
			||||||
	assert(size == 0 || buffer);
 | 
						assert(size == 0 || buffer);
 | 
				
			||||||
	assert(pcm->valid_setup);
 | 
						assert(pcm->valid_setup);
 | 
				
			||||||
	assert(pcm->setup.xfer_mode == SND_PCM_XFER_INTERLEAVED);
 | 
						assert(pcm->setup.xfer_mode == SND_PCM_XFER_INTERLEAVED);
 | 
				
			||||||
	assert(!pcm->mmap_data);
 | 
						assert(!pcm->mmap_info || pcm->mmap_auto);
 | 
				
			||||||
	return _snd_pcm_readi(pcm, buffer, size);
 | 
						return _snd_pcm_readi(pcm, buffer, size);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -263,7 +252,7 @@ ssize_t snd_pcm_readn(snd_pcm_t *pcm, void **bufs, size_t size)
 | 
				
			||||||
	assert(size == 0 || bufs);
 | 
						assert(size == 0 || bufs);
 | 
				
			||||||
	assert(pcm->valid_setup);
 | 
						assert(pcm->valid_setup);
 | 
				
			||||||
	assert(pcm->setup.xfer_mode == SND_PCM_XFER_NONINTERLEAVED);
 | 
						assert(pcm->setup.xfer_mode == SND_PCM_XFER_NONINTERLEAVED);
 | 
				
			||||||
	assert(!pcm->mmap_data);
 | 
						assert(!pcm->mmap_info || pcm->mmap_auto);
 | 
				
			||||||
	return _snd_pcm_readn(pcm, bufs, size);
 | 
						return _snd_pcm_readn(pcm, bufs, size);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -331,7 +320,7 @@ int snd_pcm_unlink(snd_pcm_t *pcm)
 | 
				
			||||||
int snd_pcm_poll_descriptor(snd_pcm_t *pcm)
 | 
					int snd_pcm_poll_descriptor(snd_pcm_t *pcm)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	assert(pcm);
 | 
						assert(pcm);
 | 
				
			||||||
	return pcm->fast_ops->poll_descriptor(pcm->fast_op_arg);
 | 
						return pcm->poll_fd;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int snd_pcm_channels_mask(snd_pcm_t *pcm, bitset_t *cmask)
 | 
					int snd_pcm_channels_mask(snd_pcm_t *pcm, bitset_t *cmask)
 | 
				
			||||||
| 
						 | 
					@ -547,62 +536,87 @@ int snd_pcm_open(snd_pcm_t **pcmp, char *name,
 | 
				
			||||||
	if (err < 0)
 | 
						if (err < 0)
 | 
				
			||||||
		return err;
 | 
							return err;
 | 
				
			||||||
	err = snd_config_searchv(snd_config, &pcm_conf, "pcm", name, 0);
 | 
						err = snd_config_searchv(snd_config, &pcm_conf, "pcm", name, 0);
 | 
				
			||||||
	if (err < 0)
 | 
						if (err < 0) {
 | 
				
			||||||
 | 
							ERR("Unknown PCM %s", name);
 | 
				
			||||||
		return err;
 | 
							return err;
 | 
				
			||||||
	if (snd_config_type(pcm_conf) != SND_CONFIG_TYPE_COMPOUND)
 | 
						}
 | 
				
			||||||
 | 
						if (snd_config_type(pcm_conf) != SND_CONFIG_TYPE_COMPOUND) {
 | 
				
			||||||
 | 
							ERR("Invalid type for PCM definition");
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	err = snd_config_search(pcm_conf, "stream", &conf);
 | 
						err = snd_config_search(pcm_conf, "stream", &conf);
 | 
				
			||||||
	if (err >= 0) {
 | 
						if (err >= 0) {
 | 
				
			||||||
		err = snd_config_string_get(conf, &str);
 | 
							err = snd_config_string_get(conf, &str);
 | 
				
			||||||
		if (err < 0)
 | 
							if (err < 0) {
 | 
				
			||||||
 | 
								ERR("Invalid type for stream");
 | 
				
			||||||
			return err;
 | 
								return err;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
		if (strcmp(str, "playback") == 0) {
 | 
							if (strcmp(str, "playback") == 0) {
 | 
				
			||||||
			if (stream != SND_PCM_STREAM_PLAYBACK)
 | 
								if (stream != SND_PCM_STREAM_PLAYBACK)
 | 
				
			||||||
				return -EINVAL;
 | 
									return -EINVAL;
 | 
				
			||||||
		} else if (strcmp(str, "capture") == 0) {
 | 
							} else if (strcmp(str, "capture") == 0) {
 | 
				
			||||||
			if (stream != SND_PCM_STREAM_CAPTURE)
 | 
								if (stream != SND_PCM_STREAM_CAPTURE)
 | 
				
			||||||
				return -EINVAL;
 | 
									return -EINVAL;
 | 
				
			||||||
		} else
 | 
							} else {
 | 
				
			||||||
 | 
								ERR("Invalid value for stream");
 | 
				
			||||||
			return -EINVAL;
 | 
								return -EINVAL;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	err = snd_config_search(pcm_conf, "type", &conf);
 | 
						err = snd_config_search(pcm_conf, "type", &conf);
 | 
				
			||||||
	if (err < 0)
 | 
						if (err < 0) {
 | 
				
			||||||
 | 
							ERR("type is not defined");
 | 
				
			||||||
		return err;
 | 
							return err;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	err = snd_config_string_get(conf, &str);
 | 
						err = snd_config_string_get(conf, &str);
 | 
				
			||||||
	if (err < 0)
 | 
						if (err < 0) {
 | 
				
			||||||
 | 
							ERR("Invalid type for type");
 | 
				
			||||||
		return err;
 | 
							return err;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	err = snd_config_searchv(snd_config, &type_conf, "pcmtype", str, 0);
 | 
						err = snd_config_searchv(snd_config, &type_conf, "pcmtype", str, 0);
 | 
				
			||||||
	if (err < 0)
 | 
						if (err < 0) {
 | 
				
			||||||
 | 
							ERR("Unknown PCM type %s", str);
 | 
				
			||||||
		return err;
 | 
							return err;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	snd_config_foreach(i, type_conf) {
 | 
						snd_config_foreach(i, type_conf) {
 | 
				
			||||||
		snd_config_t *n = snd_config_entry(i);
 | 
							snd_config_t *n = snd_config_entry(i);
 | 
				
			||||||
		if (strcmp(n->id, "comment") == 0)
 | 
							if (strcmp(n->id, "comment") == 0)
 | 
				
			||||||
			continue;
 | 
								continue;
 | 
				
			||||||
		if (strcmp(n->id, "lib") == 0) {
 | 
							if (strcmp(n->id, "lib") == 0) {
 | 
				
			||||||
			err = snd_config_string_get(n, &lib);
 | 
								err = snd_config_string_get(n, &lib);
 | 
				
			||||||
			if (err < 0)
 | 
								if (err < 0) {
 | 
				
			||||||
 | 
									ERR("Invalid type for lib");
 | 
				
			||||||
				return -EINVAL;
 | 
									return -EINVAL;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
			continue;
 | 
								continue;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if (strcmp(n->id, "open") == 0) {
 | 
							if (strcmp(n->id, "open") == 0) {
 | 
				
			||||||
			err = snd_config_string_get(n, &open);
 | 
								err = snd_config_string_get(n, &open);
 | 
				
			||||||
			if (err < 0)
 | 
								if (err < 0) {
 | 
				
			||||||
 | 
									ERR("Invalid type for open");
 | 
				
			||||||
				return -EINVAL;
 | 
									return -EINVAL;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
			continue;
 | 
								continue;
 | 
				
			||||||
 | 
								ERR("Unknown field: %s", n->id);
 | 
				
			||||||
			return -EINVAL;
 | 
								return -EINVAL;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if (!open)
 | 
						if (!open) {
 | 
				
			||||||
 | 
							ERR("open is not defined");
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	if (!lib)
 | 
						if (!lib)
 | 
				
			||||||
		lib = "libasound.so";
 | 
							lib = "libasound.so";
 | 
				
			||||||
	h = dlopen(lib, RTLD_NOW);
 | 
						h = dlopen(lib, RTLD_NOW);
 | 
				
			||||||
	if (!h)
 | 
						if (!h) {
 | 
				
			||||||
 | 
							ERR("Cannot open shared library %s", lib);
 | 
				
			||||||
		return -ENOENT;
 | 
							return -ENOENT;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	open_func = dlsym(h, open);
 | 
						open_func = dlsym(h, open);
 | 
				
			||||||
	dlclose(h);
 | 
						dlclose(h);
 | 
				
			||||||
	if (!open_func)
 | 
						if (!open_func) {
 | 
				
			||||||
 | 
							ERR("symbol %s is not defined inside %s", open, lib);
 | 
				
			||||||
		return -ENXIO;
 | 
							return -ENXIO;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	return open_func(pcmp, name, pcm_conf, stream, mode);
 | 
						return open_func(pcmp, name, pcm_conf, stream, mode);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -634,23 +648,11 @@ int snd_pcm_wait(snd_pcm_t *pcm, int timeout)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct pollfd pfd;
 | 
						struct pollfd pfd;
 | 
				
			||||||
	int err;
 | 
						int err;
 | 
				
			||||||
#if 0
 | 
					 | 
				
			||||||
	size_t bavail, aavail;
 | 
					 | 
				
			||||||
	struct timeval before, after, diff;
 | 
					 | 
				
			||||||
	bavail = snd_pcm_avail_update(pcm);
 | 
					 | 
				
			||||||
	gettimeofday(&before, 0);
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
	pfd.fd = snd_pcm_poll_descriptor(pcm);
 | 
						pfd.fd = snd_pcm_poll_descriptor(pcm);
 | 
				
			||||||
	pfd.events = pcm->stream == SND_PCM_STREAM_PLAYBACK ? POLLOUT : POLLIN;
 | 
						pfd.events = pcm->stream == SND_PCM_STREAM_PLAYBACK ? POLLOUT : POLLIN;
 | 
				
			||||||
	err = poll(&pfd, 1, timeout);
 | 
						err = poll(&pfd, 1, timeout);
 | 
				
			||||||
	if (err < 0)
 | 
						if (err < 0)
 | 
				
			||||||
		return err;
 | 
							return err;
 | 
				
			||||||
#if 0
 | 
					 | 
				
			||||||
	aavail = snd_pcm_avail_update(pcm);
 | 
					 | 
				
			||||||
	gettimeofday(&after, 0);
 | 
					 | 
				
			||||||
	timersub(&after, &before, &diff);
 | 
					 | 
				
			||||||
	fprintf(stderr, "%s %ld.%06ld: get=%d (%d-%d)\n", pcm->stream == SND_PCM_STREAM_PLAYBACK ? "playback" : "capture", diff.tv_sec, diff.tv_usec, aavail - bavail, aavail, bavail);
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1044,7 +1046,7 @@ ssize_t snd_pcm_write_areas(snd_pcm_t *pcm, snd_pcm_channel_area_t *areas,
 | 
				
			||||||
	return err;
 | 
						return err;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void snd_pcm_error_default(const char *file, int line, const char *function, const char *fmt, ...)
 | 
					void snd_pcm_error(const char *file, int line, const char *function, const char *fmt, ...)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	va_list arg;
 | 
						va_list arg;
 | 
				
			||||||
	va_start(arg, fmt);
 | 
						va_start(arg, fmt);
 | 
				
			||||||
| 
						 | 
					@ -1053,5 +1055,3 @@ void snd_pcm_error_default(const char *file, int line, const char *function, con
 | 
				
			||||||
	putc('\n', stderr);
 | 
						putc('\n', stderr);
 | 
				
			||||||
	va_end(arg);
 | 
						va_end(arg);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					 | 
				
			||||||
void (*snd_pcm_error)(const char *file, int line, const char *function, const char *fmt, ...) = snd_pcm_error_default;
 | 
					 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -377,11 +377,6 @@ static int snd_pcm_adpcm_params(snd_pcm_t *pcm, snd_pcm_params_t * params)
 | 
				
			||||||
		params->fail_reason = SND_PCM_PARAMS_FAIL_INVAL;
 | 
							params->fail_reason = SND_PCM_PARAMS_FAIL_INVAL;
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if (slave->mmap_data) {
 | 
					 | 
				
			||||||
		err = snd_pcm_munmap_data(slave);
 | 
					 | 
				
			||||||
		if (err < 0)
 | 
					 | 
				
			||||||
			return err;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	adpcm->cformat = params->format.sfmt;
 | 
						adpcm->cformat = params->format.sfmt;
 | 
				
			||||||
	adpcm->cxfer_mode = params->xfer_mode;
 | 
						adpcm->cxfer_mode = params->xfer_mode;
 | 
				
			||||||
	adpcm->cmmap_shape = params->mmap_shape;
 | 
						adpcm->cmmap_shape = params->mmap_shape;
 | 
				
			||||||
| 
						 | 
					@ -392,10 +387,6 @@ static int snd_pcm_adpcm_params(snd_pcm_t *pcm, snd_pcm_params_t * params)
 | 
				
			||||||
	params->format.sfmt = adpcm->cformat;
 | 
						params->format.sfmt = adpcm->cformat;
 | 
				
			||||||
	params->xfer_mode = adpcm->cxfer_mode;
 | 
						params->xfer_mode = adpcm->cxfer_mode;
 | 
				
			||||||
	params->mmap_shape = adpcm->cmmap_shape;
 | 
						params->mmap_shape = adpcm->cmmap_shape;
 | 
				
			||||||
	if (slave->valid_setup) {
 | 
					 | 
				
			||||||
		int r = snd_pcm_mmap_data(slave, NULL);
 | 
					 | 
				
			||||||
		assert(r >= 0);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return err;
 | 
						return err;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -533,7 +524,7 @@ static void snd_pcm_adpcm_dump(snd_pcm_t *pcm, FILE *fp)
 | 
				
			||||||
	snd_pcm_dump(adpcm->plug.slave, fp);
 | 
						snd_pcm_dump(adpcm->plug.slave, fp);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct snd_pcm_ops snd_pcm_adpcm_ops = {
 | 
					snd_pcm_ops_t snd_pcm_adpcm_ops = {
 | 
				
			||||||
	close: snd_pcm_adpcm_close,
 | 
						close: snd_pcm_adpcm_close,
 | 
				
			||||||
	info: snd_pcm_plugin_info,
 | 
						info: snd_pcm_plugin_info,
 | 
				
			||||||
	params_info: snd_pcm_adpcm_params_info,
 | 
						params_info: snd_pcm_adpcm_params_info,
 | 
				
			||||||
| 
						 | 
					@ -545,20 +536,15 @@ struct snd_pcm_ops snd_pcm_adpcm_ops = {
 | 
				
			||||||
	dump: snd_pcm_adpcm_dump,
 | 
						dump: snd_pcm_adpcm_dump,
 | 
				
			||||||
	nonblock: snd_pcm_plugin_nonblock,
 | 
						nonblock: snd_pcm_plugin_nonblock,
 | 
				
			||||||
	async: snd_pcm_plugin_async,
 | 
						async: snd_pcm_plugin_async,
 | 
				
			||||||
	mmap_status: snd_pcm_plugin_mmap_status,
 | 
						mmap: snd_pcm_plugin_mmap,
 | 
				
			||||||
	mmap_control: snd_pcm_plugin_mmap_control,
 | 
						munmap: snd_pcm_plugin_munmap,
 | 
				
			||||||
	mmap_data: snd_pcm_plugin_mmap_data,
 | 
					 | 
				
			||||||
	munmap_status: snd_pcm_plugin_munmap_status,
 | 
					 | 
				
			||||||
	munmap_control: snd_pcm_plugin_munmap_control,
 | 
					 | 
				
			||||||
	munmap_data: snd_pcm_plugin_munmap_data,
 | 
					 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int snd_pcm_adpcm_open(snd_pcm_t **handlep, char *name, int sformat, snd_pcm_t *slave, int close_slave)
 | 
					int snd_pcm_adpcm_open(snd_pcm_t **pcmp, char *name, int sformat, snd_pcm_t *slave, int close_slave)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	snd_pcm_t *handle;
 | 
						snd_pcm_t *pcm;
 | 
				
			||||||
	snd_pcm_adpcm_t *adpcm;
 | 
						snd_pcm_adpcm_t *adpcm;
 | 
				
			||||||
	int err;
 | 
						assert(pcmp && slave);
 | 
				
			||||||
	assert(handlep && slave);
 | 
					 | 
				
			||||||
	if (snd_pcm_format_linear(sformat) != 1 &&
 | 
						if (snd_pcm_format_linear(sformat) != 1 &&
 | 
				
			||||||
	    sformat != SND_PCM_SFMT_IMA_ADPCM)
 | 
						    sformat != SND_PCM_SFMT_IMA_ADPCM)
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
| 
						 | 
					@ -573,27 +559,25 @@ int snd_pcm_adpcm_open(snd_pcm_t **handlep, char *name, int sformat, snd_pcm_t *
 | 
				
			||||||
	adpcm->plug.slave = slave;
 | 
						adpcm->plug.slave = slave;
 | 
				
			||||||
	adpcm->plug.close_slave = close_slave;
 | 
						adpcm->plug.close_slave = close_slave;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	handle = calloc(1, sizeof(snd_pcm_t));
 | 
						pcm = calloc(1, sizeof(snd_pcm_t));
 | 
				
			||||||
	if (!handle) {
 | 
						if (!pcm) {
 | 
				
			||||||
		free(adpcm);
 | 
							free(adpcm);
 | 
				
			||||||
		return -ENOMEM;
 | 
							return -ENOMEM;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if (name)
 | 
						if (name)
 | 
				
			||||||
		handle->name = strdup(name);
 | 
							pcm->name = strdup(name);
 | 
				
			||||||
	handle->type = SND_PCM_TYPE_ADPCM;
 | 
						pcm->type = SND_PCM_TYPE_ADPCM;
 | 
				
			||||||
	handle->stream = slave->stream;
 | 
						pcm->stream = slave->stream;
 | 
				
			||||||
	handle->ops = &snd_pcm_adpcm_ops;
 | 
						pcm->mode = slave->mode;
 | 
				
			||||||
	handle->op_arg = handle;
 | 
						pcm->ops = &snd_pcm_adpcm_ops;
 | 
				
			||||||
	handle->fast_ops = &snd_pcm_plugin_fast_ops;
 | 
						pcm->op_arg = pcm;
 | 
				
			||||||
	handle->fast_op_arg = handle;
 | 
						pcm->fast_ops = &snd_pcm_plugin_fast_ops;
 | 
				
			||||||
	handle->mode = slave->mode;
 | 
						pcm->fast_op_arg = pcm;
 | 
				
			||||||
	handle->private = adpcm;
 | 
						pcm->private = adpcm;
 | 
				
			||||||
	err = snd_pcm_init(handle);
 | 
						pcm->poll_fd = slave->poll_fd;
 | 
				
			||||||
	if (err < 0) {
 | 
						pcm->hw_ptr = &adpcm->plug.hw_ptr;
 | 
				
			||||||
		snd_pcm_close(handle);
 | 
						pcm->appl_ptr = &adpcm->plug.appl_ptr;
 | 
				
			||||||
		return err;
 | 
						*pcmp = pcm;
 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	*handlep = handle;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -259,11 +259,6 @@ static int snd_pcm_alaw_params(snd_pcm_t *pcm, snd_pcm_params_t * params)
 | 
				
			||||||
		params->fail_reason = SND_PCM_PARAMS_FAIL_INVAL;
 | 
							params->fail_reason = SND_PCM_PARAMS_FAIL_INVAL;
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if (slave->mmap_data) {
 | 
					 | 
				
			||||||
		err = snd_pcm_munmap_data(slave);
 | 
					 | 
				
			||||||
		if (err < 0)
 | 
					 | 
				
			||||||
			return err;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	alaw->cformat = params->format.sfmt;
 | 
						alaw->cformat = params->format.sfmt;
 | 
				
			||||||
	alaw->cxfer_mode = params->xfer_mode;
 | 
						alaw->cxfer_mode = params->xfer_mode;
 | 
				
			||||||
	alaw->cmmap_shape = params->mmap_shape;
 | 
						alaw->cmmap_shape = params->mmap_shape;
 | 
				
			||||||
| 
						 | 
					@ -274,10 +269,6 @@ static int snd_pcm_alaw_params(snd_pcm_t *pcm, snd_pcm_params_t * params)
 | 
				
			||||||
	params->format.sfmt = alaw->cformat;
 | 
						params->format.sfmt = alaw->cformat;
 | 
				
			||||||
	params->xfer_mode = alaw->cxfer_mode;
 | 
						params->xfer_mode = alaw->cxfer_mode;
 | 
				
			||||||
	params->mmap_shape = alaw->cmmap_shape;
 | 
						params->mmap_shape = alaw->cmmap_shape;
 | 
				
			||||||
	if (slave->valid_setup) {
 | 
					 | 
				
			||||||
		int r = snd_pcm_mmap_data(slave, NULL);
 | 
					 | 
				
			||||||
		assert(r >= 0);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return err;
 | 
						return err;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -401,7 +392,7 @@ static void snd_pcm_alaw_dump(snd_pcm_t *pcm, FILE *fp)
 | 
				
			||||||
	snd_pcm_dump(alaw->plug.slave, fp);
 | 
						snd_pcm_dump(alaw->plug.slave, fp);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct snd_pcm_ops snd_pcm_alaw_ops = {
 | 
					snd_pcm_ops_t snd_pcm_alaw_ops = {
 | 
				
			||||||
	close: snd_pcm_plugin_close,
 | 
						close: snd_pcm_plugin_close,
 | 
				
			||||||
	info: snd_pcm_plugin_info,
 | 
						info: snd_pcm_plugin_info,
 | 
				
			||||||
	params_info: snd_pcm_alaw_params_info,
 | 
						params_info: snd_pcm_alaw_params_info,
 | 
				
			||||||
| 
						 | 
					@ -413,20 +404,15 @@ struct snd_pcm_ops snd_pcm_alaw_ops = {
 | 
				
			||||||
	dump: snd_pcm_alaw_dump,
 | 
						dump: snd_pcm_alaw_dump,
 | 
				
			||||||
	nonblock: snd_pcm_plugin_nonblock,
 | 
						nonblock: snd_pcm_plugin_nonblock,
 | 
				
			||||||
	async: snd_pcm_plugin_async,
 | 
						async: snd_pcm_plugin_async,
 | 
				
			||||||
	mmap_status: snd_pcm_plugin_mmap_status,
 | 
						mmap: snd_pcm_plugin_mmap,
 | 
				
			||||||
	mmap_control: snd_pcm_plugin_mmap_control,
 | 
						munmap: snd_pcm_plugin_munmap,
 | 
				
			||||||
	mmap_data: snd_pcm_plugin_mmap_data,
 | 
					 | 
				
			||||||
	munmap_status: snd_pcm_plugin_munmap_status,
 | 
					 | 
				
			||||||
	munmap_control: snd_pcm_plugin_munmap_control,
 | 
					 | 
				
			||||||
	munmap_data: snd_pcm_plugin_munmap_data,
 | 
					 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int snd_pcm_alaw_open(snd_pcm_t **handlep, char *name, int sformat, snd_pcm_t *slave, int close_slave)
 | 
					int snd_pcm_alaw_open(snd_pcm_t **pcmp, char *name, int sformat, snd_pcm_t *slave, int close_slave)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	snd_pcm_t *handle;
 | 
						snd_pcm_t *pcm;
 | 
				
			||||||
	snd_pcm_alaw_t *alaw;
 | 
						snd_pcm_alaw_t *alaw;
 | 
				
			||||||
	int err;
 | 
						assert(pcmp && slave);
 | 
				
			||||||
	assert(handlep && slave);
 | 
					 | 
				
			||||||
	if (snd_pcm_format_linear(sformat) != 1 &&
 | 
						if (snd_pcm_format_linear(sformat) != 1 &&
 | 
				
			||||||
	    sformat != SND_PCM_SFMT_A_LAW)
 | 
						    sformat != SND_PCM_SFMT_A_LAW)
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
| 
						 | 
					@ -440,27 +426,25 @@ int snd_pcm_alaw_open(snd_pcm_t **handlep, char *name, int sformat, snd_pcm_t *s
 | 
				
			||||||
	alaw->plug.slave = slave;
 | 
						alaw->plug.slave = slave;
 | 
				
			||||||
	alaw->plug.close_slave = close_slave;
 | 
						alaw->plug.close_slave = close_slave;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	handle = calloc(1, sizeof(snd_pcm_t));
 | 
						pcm = calloc(1, sizeof(snd_pcm_t));
 | 
				
			||||||
	if (!handle) {
 | 
						if (!pcm) {
 | 
				
			||||||
		free(alaw);
 | 
							free(alaw);
 | 
				
			||||||
		return -ENOMEM;
 | 
							return -ENOMEM;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if (name)
 | 
						if (name)
 | 
				
			||||||
		handle->name = strdup(name);
 | 
							pcm->name = strdup(name);
 | 
				
			||||||
	handle->type = SND_PCM_TYPE_ALAW;
 | 
						pcm->type = SND_PCM_TYPE_ALAW;
 | 
				
			||||||
	handle->stream = slave->stream;
 | 
						pcm->stream = slave->stream;
 | 
				
			||||||
	handle->ops = &snd_pcm_alaw_ops;
 | 
						pcm->mode = slave->mode;
 | 
				
			||||||
	handle->op_arg = handle;
 | 
						pcm->ops = &snd_pcm_alaw_ops;
 | 
				
			||||||
	handle->fast_ops = &snd_pcm_plugin_fast_ops;
 | 
						pcm->op_arg = pcm;
 | 
				
			||||||
	handle->fast_op_arg = handle;
 | 
						pcm->fast_ops = &snd_pcm_plugin_fast_ops;
 | 
				
			||||||
	handle->mode = slave->mode;
 | 
						pcm->fast_op_arg = pcm;
 | 
				
			||||||
	handle->private = alaw;
 | 
						pcm->private = alaw;
 | 
				
			||||||
	err = snd_pcm_init(handle);
 | 
						pcm->poll_fd = slave->poll_fd;
 | 
				
			||||||
	if (err < 0) {
 | 
						pcm->hw_ptr = &alaw->plug.hw_ptr;
 | 
				
			||||||
		snd_pcm_close(handle);
 | 
						pcm->appl_ptr = &alaw->plug.appl_ptr;
 | 
				
			||||||
		return err;
 | 
						*pcmp = pcm;
 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	*handlep = handle;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,857 +0,0 @@
 | 
				
			||||||
/*
 | 
					 | 
				
			||||||
 *  PCM - Client
 | 
					 | 
				
			||||||
 *  Copyright (c) 2000 by Abramo Bagnara <abramo@alsa-project.org>
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 *   This library is free software; you can redistribute it and/or modify
 | 
					 | 
				
			||||||
 *   it under the terms of the GNU Library General Public License as
 | 
					 | 
				
			||||||
 *   published by the Free Software Foundation; either version 2 of
 | 
					 | 
				
			||||||
 *   the License, or (at your option) any later version.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 *   This program is distributed in the hope that it will be useful,
 | 
					 | 
				
			||||||
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
					 | 
				
			||||||
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
					 | 
				
			||||||
 *   GNU Library General Public License for more details.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 *   You should have received a copy of the GNU Library General Public
 | 
					 | 
				
			||||||
 *   License along with this library; if not, write to the Free Software
 | 
					 | 
				
			||||||
 *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
  
 | 
					 | 
				
			||||||
#include <stdio.h>
 | 
					 | 
				
			||||||
#include <stdlib.h>
 | 
					 | 
				
			||||||
#include <stddef.h>
 | 
					 | 
				
			||||||
#include <unistd.h>
 | 
					 | 
				
			||||||
#include <string.h>
 | 
					 | 
				
			||||||
#include <errno.h>
 | 
					 | 
				
			||||||
#include <fcntl.h>
 | 
					 | 
				
			||||||
#include <sys/shm.h>
 | 
					 | 
				
			||||||
#include <sys/socket.h>
 | 
					 | 
				
			||||||
#include <sys/poll.h>
 | 
					 | 
				
			||||||
#include <sys/un.h>
 | 
					 | 
				
			||||||
#include <sys/mman.h>
 | 
					 | 
				
			||||||
#include <netinet/in.h>
 | 
					 | 
				
			||||||
#include <netdb.h>
 | 
					 | 
				
			||||||
#include "pcm_local.h"
 | 
					 | 
				
			||||||
#include "aserver.h"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
typedef struct {
 | 
					 | 
				
			||||||
	int data_fd;
 | 
					 | 
				
			||||||
	int ctrl_fd;
 | 
					 | 
				
			||||||
	union {
 | 
					 | 
				
			||||||
		struct {
 | 
					 | 
				
			||||||
			void *ctrl;
 | 
					 | 
				
			||||||
		} shm;
 | 
					 | 
				
			||||||
	} u;
 | 
					 | 
				
			||||||
} snd_pcm_client_t;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int receive_fd(int socket, void *data, size_t len, int *fd)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    int ret;
 | 
					 | 
				
			||||||
    size_t cmsg_len = CMSG_LEN(sizeof(int));
 | 
					 | 
				
			||||||
    struct cmsghdr *cmsg = alloca(cmsg_len);
 | 
					 | 
				
			||||||
    int *fds = (int *) CMSG_DATA(cmsg);
 | 
					 | 
				
			||||||
    struct msghdr msghdr;
 | 
					 | 
				
			||||||
    struct iovec vec;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    vec.iov_base = (void *)&data;
 | 
					 | 
				
			||||||
    vec.iov_len = len;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    cmsg->cmsg_len = cmsg_len;
 | 
					 | 
				
			||||||
    cmsg->cmsg_level = SOL_SOCKET;
 | 
					 | 
				
			||||||
    cmsg->cmsg_type = SCM_RIGHTS;
 | 
					 | 
				
			||||||
    *fds = -1;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    msghdr.msg_name = NULL;
 | 
					 | 
				
			||||||
    msghdr.msg_namelen = 0;
 | 
					 | 
				
			||||||
    msghdr.msg_iov = &vec;
 | 
					 | 
				
			||||||
    msghdr.msg_iovlen = 1;
 | 
					 | 
				
			||||||
    msghdr.msg_control = cmsg;
 | 
					 | 
				
			||||||
    msghdr.msg_controllen = cmsg_len;
 | 
					 | 
				
			||||||
    msghdr.msg_flags = 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    ret = recvmsg(socket, &msghdr, 0);
 | 
					 | 
				
			||||||
    if (ret < 0)
 | 
					 | 
				
			||||||
	    return -errno;
 | 
					 | 
				
			||||||
    *fd = *fds;
 | 
					 | 
				
			||||||
    return ret;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void clean_poll(snd_pcm_t *pcm)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	snd_pcm_client_t *client = pcm->private;
 | 
					 | 
				
			||||||
	struct pollfd pfd;
 | 
					 | 
				
			||||||
	int err;
 | 
					 | 
				
			||||||
	char buf[1];
 | 
					 | 
				
			||||||
	pfd.fd = client->data_fd;
 | 
					 | 
				
			||||||
	switch (pcm->stream) {
 | 
					 | 
				
			||||||
	case SND_PCM_STREAM_PLAYBACK:
 | 
					 | 
				
			||||||
		pfd.events = POLLOUT;
 | 
					 | 
				
			||||||
		while (1) {
 | 
					 | 
				
			||||||
			err = poll(&pfd, 1, 0);
 | 
					 | 
				
			||||||
			if (err == 0)
 | 
					 | 
				
			||||||
				break;
 | 
					 | 
				
			||||||
			assert(err > 0);
 | 
					 | 
				
			||||||
			err = write(client->data_fd, buf, 1);
 | 
					 | 
				
			||||||
			assert(err == 1);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		break;
 | 
					 | 
				
			||||||
	case SND_PCM_STREAM_CAPTURE:
 | 
					 | 
				
			||||||
		pfd.events = POLLIN;
 | 
					 | 
				
			||||||
		while (1) {
 | 
					 | 
				
			||||||
			err = poll(&pfd, 1, 0);
 | 
					 | 
				
			||||||
			if (err == 0)
 | 
					 | 
				
			||||||
				break;
 | 
					 | 
				
			||||||
			assert(err > 0);
 | 
					 | 
				
			||||||
			err = read(client->data_fd, buf, 1);
 | 
					 | 
				
			||||||
			assert(err == 1);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		break;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int snd_pcm_client_shm_action(snd_pcm_t *pcm)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	snd_pcm_client_t *client = pcm->private;
 | 
					 | 
				
			||||||
	int err;
 | 
					 | 
				
			||||||
	char buf[1];
 | 
					 | 
				
			||||||
	snd_pcm_client_shm_t *ctrl = client->u.shm.ctrl;
 | 
					 | 
				
			||||||
	clean_poll(pcm);
 | 
					 | 
				
			||||||
	err = write(client->ctrl_fd, buf, 1);
 | 
					 | 
				
			||||||
	if (err != 1)
 | 
					 | 
				
			||||||
		return -EBADFD;
 | 
					 | 
				
			||||||
	err = read(client->ctrl_fd, buf, 1);
 | 
					 | 
				
			||||||
	if (err != 1)
 | 
					 | 
				
			||||||
		return -EBADFD;
 | 
					 | 
				
			||||||
	if (ctrl->cmd) {
 | 
					 | 
				
			||||||
		fprintf(stderr, "Server has not done the cmd\n");
 | 
					 | 
				
			||||||
		return -EBADFD;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int snd_pcm_client_shm_action_fd(snd_pcm_t *pcm)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	snd_pcm_client_t *client = pcm->private;
 | 
					 | 
				
			||||||
	int err;
 | 
					 | 
				
			||||||
	char buf[1];
 | 
					 | 
				
			||||||
	snd_pcm_client_shm_t *ctrl = client->u.shm.ctrl;
 | 
					 | 
				
			||||||
	int fd;
 | 
					 | 
				
			||||||
	clean_poll(pcm);
 | 
					 | 
				
			||||||
	err = write(client->ctrl_fd, buf, 1);
 | 
					 | 
				
			||||||
	if (err != 1)
 | 
					 | 
				
			||||||
		return -EBADFD;
 | 
					 | 
				
			||||||
	err = receive_fd(client->ctrl_fd, buf, 1, &fd);
 | 
					 | 
				
			||||||
	if (err != 1)
 | 
					 | 
				
			||||||
		return -EBADFD;
 | 
					 | 
				
			||||||
	if (ctrl->cmd) {
 | 
					 | 
				
			||||||
		fprintf(stderr, "Server has not done the cmd\n");
 | 
					 | 
				
			||||||
		return -EBADFD;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if (ctrl->result < 0)
 | 
					 | 
				
			||||||
		return ctrl->result;
 | 
					 | 
				
			||||||
	return fd;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int snd_pcm_client_shm_close(snd_pcm_t *pcm)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	snd_pcm_client_t *client = pcm->private;
 | 
					 | 
				
			||||||
	snd_pcm_client_shm_t *ctrl = client->u.shm.ctrl;
 | 
					 | 
				
			||||||
	int result;
 | 
					 | 
				
			||||||
	ctrl->cmd = SND_PCM_IOCTL_CLOSE;
 | 
					 | 
				
			||||||
	result = snd_pcm_client_shm_action(pcm);
 | 
					 | 
				
			||||||
	if (result >= 0)
 | 
					 | 
				
			||||||
		result = ctrl->result;
 | 
					 | 
				
			||||||
	shmdt((void *)ctrl);
 | 
					 | 
				
			||||||
	close(client->data_fd);
 | 
					 | 
				
			||||||
	close(client->ctrl_fd);
 | 
					 | 
				
			||||||
	free(client);
 | 
					 | 
				
			||||||
	return result;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int snd_pcm_client_shm_nonblock(snd_pcm_t *pcm ATTRIBUTE_UNUSED, int nonblock ATTRIBUTE_UNUSED)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int snd_pcm_client_async(snd_pcm_t *pcm, int sig, pid_t pid)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	snd_pcm_client_t *client = pcm->private;
 | 
					 | 
				
			||||||
	snd_pcm_client_shm_t *ctrl = client->u.shm.ctrl;
 | 
					 | 
				
			||||||
	int err;
 | 
					 | 
				
			||||||
	ctrl->cmd = SND_PCM_IOCTL_ASYNC;
 | 
					 | 
				
			||||||
	ctrl->u.async.sig = sig;
 | 
					 | 
				
			||||||
	if (pid == 0)
 | 
					 | 
				
			||||||
		pid = getpid();
 | 
					 | 
				
			||||||
	ctrl->u.async.pid = pid;
 | 
					 | 
				
			||||||
	err = snd_pcm_client_shm_action(pcm);
 | 
					 | 
				
			||||||
	if (err < 0)
 | 
					 | 
				
			||||||
		return err;
 | 
					 | 
				
			||||||
	return ctrl->result;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int snd_pcm_client_shm_info(snd_pcm_t *pcm, snd_pcm_info_t * info)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	snd_pcm_client_t *client = pcm->private;
 | 
					 | 
				
			||||||
	snd_pcm_client_shm_t *ctrl = client->u.shm.ctrl;
 | 
					 | 
				
			||||||
	int err;
 | 
					 | 
				
			||||||
//	ctrl->u.info = *info;
 | 
					 | 
				
			||||||
	ctrl->cmd = SND_PCM_IOCTL_INFO;
 | 
					 | 
				
			||||||
	err = snd_pcm_client_shm_action(pcm);
 | 
					 | 
				
			||||||
	if (err < 0)
 | 
					 | 
				
			||||||
		return err;
 | 
					 | 
				
			||||||
	*info = ctrl->u.info;
 | 
					 | 
				
			||||||
	return ctrl->result;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int snd_pcm_client_shm_params_info(snd_pcm_t *pcm, snd_pcm_params_info_t * info)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	snd_pcm_client_t *client = pcm->private;
 | 
					 | 
				
			||||||
	snd_pcm_client_shm_t *ctrl = client->u.shm.ctrl;
 | 
					 | 
				
			||||||
	int err;
 | 
					 | 
				
			||||||
	ctrl->cmd = SND_PCM_IOCTL_PARAMS_INFO;
 | 
					 | 
				
			||||||
	ctrl->u.params_info = *info;
 | 
					 | 
				
			||||||
	err = snd_pcm_client_shm_action(pcm);
 | 
					 | 
				
			||||||
	if (err < 0)
 | 
					 | 
				
			||||||
		return err;
 | 
					 | 
				
			||||||
	*info = ctrl->u.params_info;
 | 
					 | 
				
			||||||
	return ctrl->result;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int snd_pcm_client_shm_params(snd_pcm_t *pcm, snd_pcm_params_t * params)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	snd_pcm_client_t *client = pcm->private;
 | 
					 | 
				
			||||||
	snd_pcm_client_shm_t *ctrl = client->u.shm.ctrl;
 | 
					 | 
				
			||||||
	int err;
 | 
					 | 
				
			||||||
	ctrl->cmd = SND_PCM_IOCTL_PARAMS;
 | 
					 | 
				
			||||||
	ctrl->u.params = *params;
 | 
					 | 
				
			||||||
	err = snd_pcm_client_shm_action(pcm);
 | 
					 | 
				
			||||||
	if (err < 0)
 | 
					 | 
				
			||||||
		return err;
 | 
					 | 
				
			||||||
	*params = ctrl->u.params;
 | 
					 | 
				
			||||||
	return ctrl->result;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int snd_pcm_client_shm_setup(snd_pcm_t *pcm, snd_pcm_setup_t * setup)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	snd_pcm_client_t *client = pcm->private;
 | 
					 | 
				
			||||||
	snd_pcm_client_shm_t *ctrl = client->u.shm.ctrl;
 | 
					 | 
				
			||||||
	int err;
 | 
					 | 
				
			||||||
	ctrl->cmd = SND_PCM_IOCTL_SETUP;
 | 
					 | 
				
			||||||
	// ctrl->u.setup = *setup;
 | 
					 | 
				
			||||||
	err = snd_pcm_client_shm_action(pcm);
 | 
					 | 
				
			||||||
	if (err < 0)
 | 
					 | 
				
			||||||
		return err;
 | 
					 | 
				
			||||||
	*setup = ctrl->u.setup;
 | 
					 | 
				
			||||||
	return ctrl->result;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int snd_pcm_client_shm_channel_info(snd_pcm_t *pcm, snd_pcm_channel_info_t * info)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	snd_pcm_client_t *client = pcm->private;
 | 
					 | 
				
			||||||
	snd_pcm_client_shm_t *ctrl = client->u.shm.ctrl;
 | 
					 | 
				
			||||||
	int err;
 | 
					 | 
				
			||||||
	ctrl->cmd = SND_PCM_IOCTL_CHANNEL_INFO;
 | 
					 | 
				
			||||||
	ctrl->u.channel_info = *info;
 | 
					 | 
				
			||||||
	err = snd_pcm_client_shm_action(pcm);
 | 
					 | 
				
			||||||
	if (err < 0)
 | 
					 | 
				
			||||||
		return err;
 | 
					 | 
				
			||||||
	*info = ctrl->u.channel_info;
 | 
					 | 
				
			||||||
	return ctrl->result;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int snd_pcm_client_shm_channel_params(snd_pcm_t *pcm, snd_pcm_channel_params_t * params)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	snd_pcm_client_t *client = pcm->private;
 | 
					 | 
				
			||||||
	snd_pcm_client_shm_t *ctrl = client->u.shm.ctrl;
 | 
					 | 
				
			||||||
	int err;
 | 
					 | 
				
			||||||
	ctrl->cmd = SND_PCM_IOCTL_CHANNEL_PARAMS;
 | 
					 | 
				
			||||||
	ctrl->u.channel_params = *params;
 | 
					 | 
				
			||||||
	err = snd_pcm_client_shm_action(pcm);
 | 
					 | 
				
			||||||
	if (err < 0)
 | 
					 | 
				
			||||||
		return err;
 | 
					 | 
				
			||||||
	*params = ctrl->u.channel_params;
 | 
					 | 
				
			||||||
	return ctrl->result;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int snd_pcm_client_shm_channel_setup(snd_pcm_t *pcm, snd_pcm_channel_setup_t * setup)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	snd_pcm_client_t *client = pcm->private;
 | 
					 | 
				
			||||||
	snd_pcm_client_shm_t *ctrl = client->u.shm.ctrl;
 | 
					 | 
				
			||||||
	int err;
 | 
					 | 
				
			||||||
	ctrl->cmd = SND_PCM_IOCTL_CHANNEL_SETUP;
 | 
					 | 
				
			||||||
	ctrl->u.channel_setup = *setup;
 | 
					 | 
				
			||||||
	err = snd_pcm_client_shm_action(pcm);
 | 
					 | 
				
			||||||
	if (err < 0)
 | 
					 | 
				
			||||||
		return err;
 | 
					 | 
				
			||||||
	*setup = ctrl->u.channel_setup;
 | 
					 | 
				
			||||||
	return ctrl->result;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int snd_pcm_client_shm_status(snd_pcm_t *pcm, snd_pcm_status_t * status)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	snd_pcm_client_t *client = pcm->private;
 | 
					 | 
				
			||||||
	snd_pcm_client_shm_t *ctrl = client->u.shm.ctrl;
 | 
					 | 
				
			||||||
	int err;
 | 
					 | 
				
			||||||
	ctrl->cmd = SND_PCM_IOCTL_STATUS;
 | 
					 | 
				
			||||||
	// ctrl->u.status = *status;
 | 
					 | 
				
			||||||
	err = snd_pcm_client_shm_action(pcm);
 | 
					 | 
				
			||||||
	if (err < 0)
 | 
					 | 
				
			||||||
		return err;
 | 
					 | 
				
			||||||
	*status = ctrl->u.status;
 | 
					 | 
				
			||||||
	return ctrl->result;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int snd_pcm_client_shm_state(snd_pcm_t *pcm)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	snd_pcm_client_t *client = pcm->private;
 | 
					 | 
				
			||||||
	snd_pcm_client_shm_t *ctrl = client->u.shm.ctrl;
 | 
					 | 
				
			||||||
	int err;
 | 
					 | 
				
			||||||
	ctrl->cmd = SND_PCM_IOCTL_STATE;
 | 
					 | 
				
			||||||
	err = snd_pcm_client_shm_action(pcm);
 | 
					 | 
				
			||||||
	if (err < 0)
 | 
					 | 
				
			||||||
		return err;
 | 
					 | 
				
			||||||
	return ctrl->result;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int snd_pcm_client_shm_delay(snd_pcm_t *pcm, ssize_t *delayp)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	snd_pcm_client_t *client = pcm->private;
 | 
					 | 
				
			||||||
	snd_pcm_client_shm_t *ctrl = client->u.shm.ctrl;
 | 
					 | 
				
			||||||
	int err;
 | 
					 | 
				
			||||||
	ctrl->cmd = SND_PCM_IOCTL_DELAY;
 | 
					 | 
				
			||||||
	err = snd_pcm_client_shm_action(pcm);
 | 
					 | 
				
			||||||
	if (err < 0)
 | 
					 | 
				
			||||||
		return err;
 | 
					 | 
				
			||||||
	*delayp = ctrl->u.delay;
 | 
					 | 
				
			||||||
	return ctrl->result;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static ssize_t snd_pcm_client_avail_update(snd_pcm_t *pcm)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	snd_pcm_client_t *client = pcm->private;
 | 
					 | 
				
			||||||
	snd_pcm_client_shm_t *ctrl = client->u.shm.ctrl;
 | 
					 | 
				
			||||||
	int err;
 | 
					 | 
				
			||||||
	ctrl->cmd = SND_PCM_IOCTL_AVAIL_UPDATE;
 | 
					 | 
				
			||||||
	err = snd_pcm_client_shm_action(pcm);
 | 
					 | 
				
			||||||
	if (err < 0)
 | 
					 | 
				
			||||||
		return err;
 | 
					 | 
				
			||||||
	return ctrl->result;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int snd_pcm_client_shm_prepare(snd_pcm_t *pcm)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	snd_pcm_client_t *client = pcm->private;
 | 
					 | 
				
			||||||
	snd_pcm_client_shm_t *ctrl = client->u.shm.ctrl;
 | 
					 | 
				
			||||||
	int err;
 | 
					 | 
				
			||||||
	ctrl->cmd = SND_PCM_IOCTL_PREPARE;
 | 
					 | 
				
			||||||
	err = snd_pcm_client_shm_action(pcm);
 | 
					 | 
				
			||||||
	if (err < 0)
 | 
					 | 
				
			||||||
		return err;
 | 
					 | 
				
			||||||
	return ctrl->result;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int snd_pcm_client_shm_start(snd_pcm_t *pcm)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	snd_pcm_client_t *client = pcm->private;
 | 
					 | 
				
			||||||
	snd_pcm_client_shm_t *ctrl = client->u.shm.ctrl;
 | 
					 | 
				
			||||||
	int err;
 | 
					 | 
				
			||||||
	ctrl->cmd = SND_PCM_IOCTL_START;
 | 
					 | 
				
			||||||
	err = snd_pcm_client_shm_action(pcm);
 | 
					 | 
				
			||||||
	if (err < 0)
 | 
					 | 
				
			||||||
		return err;
 | 
					 | 
				
			||||||
	return ctrl->result;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int snd_pcm_client_shm_drop(snd_pcm_t *pcm)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	snd_pcm_client_t *client = pcm->private;
 | 
					 | 
				
			||||||
	snd_pcm_client_shm_t *ctrl = client->u.shm.ctrl;
 | 
					 | 
				
			||||||
	int err;
 | 
					 | 
				
			||||||
	ctrl->cmd = SND_PCM_IOCTL_DROP;
 | 
					 | 
				
			||||||
	err = snd_pcm_client_shm_action(pcm);
 | 
					 | 
				
			||||||
	if (err < 0)
 | 
					 | 
				
			||||||
		return err;
 | 
					 | 
				
			||||||
	return ctrl->result;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int snd_pcm_client_shm_drain(snd_pcm_t *pcm)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	snd_pcm_client_t *client = pcm->private;
 | 
					 | 
				
			||||||
	snd_pcm_client_shm_t *ctrl = client->u.shm.ctrl;
 | 
					 | 
				
			||||||
	int err;
 | 
					 | 
				
			||||||
	ctrl->cmd = SND_PCM_IOCTL_DRAIN;
 | 
					 | 
				
			||||||
	err = snd_pcm_client_shm_action(pcm);
 | 
					 | 
				
			||||||
	if (err < 0)
 | 
					 | 
				
			||||||
		return err;
 | 
					 | 
				
			||||||
	return ctrl->result;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int snd_pcm_client_shm_pause(snd_pcm_t *pcm, int enable)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	snd_pcm_client_t *client = pcm->private;
 | 
					 | 
				
			||||||
	snd_pcm_client_shm_t *ctrl = client->u.shm.ctrl;
 | 
					 | 
				
			||||||
	int err;
 | 
					 | 
				
			||||||
	ctrl->cmd = SND_PCM_IOCTL_PAUSE;
 | 
					 | 
				
			||||||
	ctrl->u.pause = enable;
 | 
					 | 
				
			||||||
	err = snd_pcm_client_shm_action(pcm);
 | 
					 | 
				
			||||||
	if (err < 0)
 | 
					 | 
				
			||||||
		return err;
 | 
					 | 
				
			||||||
	return ctrl->result;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static ssize_t snd_pcm_client_shm_rewind(snd_pcm_t *pcm, size_t frames)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	snd_pcm_client_t *client = pcm->private;
 | 
					 | 
				
			||||||
	snd_pcm_client_shm_t *ctrl = client->u.shm.ctrl;
 | 
					 | 
				
			||||||
	int err;
 | 
					 | 
				
			||||||
	ctrl->cmd = SND_PCM_IOCTL_REWIND;
 | 
					 | 
				
			||||||
	ctrl->u.rewind = frames;
 | 
					 | 
				
			||||||
	err = snd_pcm_client_shm_action(pcm);
 | 
					 | 
				
			||||||
	if (err < 0)
 | 
					 | 
				
			||||||
		return err;
 | 
					 | 
				
			||||||
	return ctrl->result;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int snd_pcm_client_shm_mmap_status(snd_pcm_t *pcm)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	snd_pcm_client_t *client = pcm->private;
 | 
					 | 
				
			||||||
	snd_pcm_client_shm_t *ctrl = client->u.shm.ctrl;
 | 
					 | 
				
			||||||
	void *ptr;
 | 
					 | 
				
			||||||
	int fd;
 | 
					 | 
				
			||||||
	ctrl->cmd = SND_PCM_IOCTL_MMAP_STATUS;
 | 
					 | 
				
			||||||
	fd = snd_pcm_client_shm_action_fd(pcm);
 | 
					 | 
				
			||||||
	if (fd < 0)
 | 
					 | 
				
			||||||
		return fd;
 | 
					 | 
				
			||||||
	/* FIXME: not mmap */
 | 
					 | 
				
			||||||
	ptr = mmap(NULL, sizeof(snd_pcm_mmap_status_t), PROT_READ, MAP_FILE|MAP_SHARED, 
 | 
					 | 
				
			||||||
		   fd, SND_PCM_MMAP_OFFSET_STATUS);
 | 
					 | 
				
			||||||
	close(fd);
 | 
					 | 
				
			||||||
	if (ptr == MAP_FAILED || ptr == NULL)
 | 
					 | 
				
			||||||
		return -errno;
 | 
					 | 
				
			||||||
	pcm->mmap_status = ptr;
 | 
					 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int snd_pcm_client_shm_mmap_control(snd_pcm_t *pcm)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	snd_pcm_client_t *client = pcm->private;
 | 
					 | 
				
			||||||
	snd_pcm_client_shm_t *ctrl = client->u.shm.ctrl;
 | 
					 | 
				
			||||||
	void *ptr;
 | 
					 | 
				
			||||||
	int fd;
 | 
					 | 
				
			||||||
	ctrl->cmd = SND_PCM_IOCTL_MMAP_CONTROL;
 | 
					 | 
				
			||||||
	fd = snd_pcm_client_shm_action_fd(pcm);
 | 
					 | 
				
			||||||
	if (fd < 0)
 | 
					 | 
				
			||||||
		return fd;
 | 
					 | 
				
			||||||
	/* FIXME: not mmap */
 | 
					 | 
				
			||||||
	ptr = mmap(NULL, sizeof(snd_pcm_mmap_control_t), PROT_READ|PROT_WRITE, MAP_FILE|MAP_SHARED, 
 | 
					 | 
				
			||||||
		   fd, SND_PCM_MMAP_OFFSET_CONTROL);
 | 
					 | 
				
			||||||
	close(fd);
 | 
					 | 
				
			||||||
	if (ptr == MAP_FAILED || ptr == NULL)
 | 
					 | 
				
			||||||
		return -errno;
 | 
					 | 
				
			||||||
	pcm->mmap_control = ptr;
 | 
					 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int snd_pcm_client_shm_mmap_data(snd_pcm_t *pcm)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	snd_pcm_client_t *client = pcm->private;
 | 
					 | 
				
			||||||
	snd_pcm_client_shm_t *ctrl = client->u.shm.ctrl;
 | 
					 | 
				
			||||||
	void *ptr;
 | 
					 | 
				
			||||||
	int prot;
 | 
					 | 
				
			||||||
	int fd;
 | 
					 | 
				
			||||||
	ctrl->cmd = SND_PCM_IOCTL_MMAP_DATA;
 | 
					 | 
				
			||||||
	fd = snd_pcm_client_shm_action_fd(pcm);
 | 
					 | 
				
			||||||
	if (fd < 0)
 | 
					 | 
				
			||||||
		return fd;
 | 
					 | 
				
			||||||
	/* FIXME: not mmap */
 | 
					 | 
				
			||||||
	prot = pcm->stream == SND_PCM_STREAM_PLAYBACK ? PROT_WRITE : PROT_READ;
 | 
					 | 
				
			||||||
	ptr = mmap(NULL, pcm->setup.mmap_bytes, prot, MAP_FILE|MAP_SHARED, 
 | 
					 | 
				
			||||||
		     fd, SND_PCM_MMAP_OFFSET_DATA);
 | 
					 | 
				
			||||||
	close(fd);
 | 
					 | 
				
			||||||
	if (ptr == MAP_FAILED || ptr == NULL)
 | 
					 | 
				
			||||||
		return -errno;
 | 
					 | 
				
			||||||
	pcm->mmap_data = ptr;
 | 
					 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int snd_pcm_client_shm_munmap_status(snd_pcm_t *pcm)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	snd_pcm_client_t *client = pcm->private;
 | 
					 | 
				
			||||||
	snd_pcm_client_shm_t *ctrl = client->u.shm.ctrl;
 | 
					 | 
				
			||||||
	int err;
 | 
					 | 
				
			||||||
	ctrl->cmd = SND_PCM_IOCTL_MUNMAP_STATUS;
 | 
					 | 
				
			||||||
	err = snd_pcm_client_shm_action(pcm);
 | 
					 | 
				
			||||||
	if (err < 0)
 | 
					 | 
				
			||||||
		return err;
 | 
					 | 
				
			||||||
	/* FIXME: not mmap */
 | 
					 | 
				
			||||||
	if (munmap((void*)pcm->mmap_status, sizeof(*pcm->mmap_status)) < 0)
 | 
					 | 
				
			||||||
		return -errno;
 | 
					 | 
				
			||||||
	return ctrl->result;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int snd_pcm_client_shm_munmap_control(snd_pcm_t *pcm)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	snd_pcm_client_t *client = pcm->private;
 | 
					 | 
				
			||||||
	snd_pcm_client_shm_t *ctrl = client->u.shm.ctrl;
 | 
					 | 
				
			||||||
	int err;
 | 
					 | 
				
			||||||
	ctrl->cmd = SND_PCM_IOCTL_MUNMAP_CONTROL;
 | 
					 | 
				
			||||||
	err = snd_pcm_client_shm_action(pcm);
 | 
					 | 
				
			||||||
	if (err < 0)
 | 
					 | 
				
			||||||
		return err;
 | 
					 | 
				
			||||||
	/* FIXME: not mmap */
 | 
					 | 
				
			||||||
	if (munmap(pcm->mmap_control, sizeof(*pcm->mmap_control)) < 0)
 | 
					 | 
				
			||||||
		return -errno;
 | 
					 | 
				
			||||||
	return ctrl->result;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int snd_pcm_client_shm_munmap_data(snd_pcm_t *pcm)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	snd_pcm_client_t *client = pcm->private;
 | 
					 | 
				
			||||||
	snd_pcm_client_shm_t *ctrl = client->u.shm.ctrl;
 | 
					 | 
				
			||||||
	int err;
 | 
					 | 
				
			||||||
	ctrl->cmd = SND_PCM_IOCTL_MUNMAP_DATA;
 | 
					 | 
				
			||||||
	err = snd_pcm_client_shm_action(pcm);
 | 
					 | 
				
			||||||
	if (err < 0)
 | 
					 | 
				
			||||||
		return err;
 | 
					 | 
				
			||||||
	/* FIXME: not mmap */
 | 
					 | 
				
			||||||
	if (munmap(pcm->mmap_data, pcm->setup.mmap_bytes) < 0)
 | 
					 | 
				
			||||||
		return -errno;
 | 
					 | 
				
			||||||
	return ctrl->result;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static ssize_t snd_pcm_client_mmap_forward(snd_pcm_t *pcm, size_t size)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	snd_pcm_client_t *client = pcm->private;
 | 
					 | 
				
			||||||
	snd_pcm_client_shm_t *ctrl = client->u.shm.ctrl;
 | 
					 | 
				
			||||||
	int err;
 | 
					 | 
				
			||||||
	ctrl->cmd = SND_PCM_IOCTL_MMAP_FORWARD;
 | 
					 | 
				
			||||||
	ctrl->u.mmap_forward = size;
 | 
					 | 
				
			||||||
	err = snd_pcm_client_shm_action(pcm);
 | 
					 | 
				
			||||||
	if (err < 0)
 | 
					 | 
				
			||||||
		return err;
 | 
					 | 
				
			||||||
	return ctrl->result;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int snd_pcm_client_poll_descriptor(snd_pcm_t *pcm)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	snd_pcm_client_t *client = pcm->private;
 | 
					 | 
				
			||||||
	return client->data_fd;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int snd_pcm_client_channels_mask(snd_pcm_t *pcm ATTRIBUTE_UNUSED,
 | 
					 | 
				
			||||||
					bitset_t *cmask ATTRIBUTE_UNUSED)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void snd_pcm_client_dump(snd_pcm_t *pcm, FILE *fp)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	fprintf(fp, "Client PCM\n");
 | 
					 | 
				
			||||||
	if (pcm->valid_setup) {
 | 
					 | 
				
			||||||
		fprintf(fp, "\nIts setup is:\n");
 | 
					 | 
				
			||||||
		snd_pcm_dump_setup(pcm, fp);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
struct snd_pcm_ops snd_pcm_client_ops = {
 | 
					 | 
				
			||||||
	close: snd_pcm_client_shm_close,
 | 
					 | 
				
			||||||
	info: snd_pcm_client_shm_info,
 | 
					 | 
				
			||||||
	params_info: snd_pcm_client_shm_params_info,
 | 
					 | 
				
			||||||
	params: snd_pcm_client_shm_params,
 | 
					 | 
				
			||||||
	setup: snd_pcm_client_shm_setup,
 | 
					 | 
				
			||||||
	channel_info: snd_pcm_client_shm_channel_info,
 | 
					 | 
				
			||||||
	channel_params: snd_pcm_client_shm_channel_params,
 | 
					 | 
				
			||||||
	channel_setup: snd_pcm_client_shm_channel_setup,
 | 
					 | 
				
			||||||
	dump: snd_pcm_client_dump,
 | 
					 | 
				
			||||||
	nonblock: snd_pcm_client_shm_nonblock,
 | 
					 | 
				
			||||||
	async: snd_pcm_client_async,
 | 
					 | 
				
			||||||
	mmap_status: snd_pcm_client_shm_mmap_status,
 | 
					 | 
				
			||||||
	mmap_control: snd_pcm_client_shm_mmap_control,
 | 
					 | 
				
			||||||
	mmap_data: snd_pcm_client_shm_mmap_data,
 | 
					 | 
				
			||||||
	munmap_status: snd_pcm_client_shm_munmap_status,
 | 
					 | 
				
			||||||
	munmap_control: snd_pcm_client_shm_munmap_control,
 | 
					 | 
				
			||||||
	munmap_data: snd_pcm_client_shm_munmap_data,
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
struct snd_pcm_fast_ops snd_pcm_client_fast_ops = {
 | 
					 | 
				
			||||||
	status: snd_pcm_client_shm_status,
 | 
					 | 
				
			||||||
	state: snd_pcm_client_shm_state,
 | 
					 | 
				
			||||||
	delay: snd_pcm_client_shm_delay,
 | 
					 | 
				
			||||||
	prepare: snd_pcm_client_shm_prepare,
 | 
					 | 
				
			||||||
	start: snd_pcm_client_shm_start,
 | 
					 | 
				
			||||||
	drop: snd_pcm_client_shm_drop,
 | 
					 | 
				
			||||||
	drain: snd_pcm_client_shm_drain,
 | 
					 | 
				
			||||||
	pause: snd_pcm_client_shm_pause,
 | 
					 | 
				
			||||||
	rewind: snd_pcm_client_shm_rewind,
 | 
					 | 
				
			||||||
	writei: snd_pcm_mmap_writei,
 | 
					 | 
				
			||||||
	writen: snd_pcm_mmap_writen,
 | 
					 | 
				
			||||||
	readi: snd_pcm_mmap_readi,
 | 
					 | 
				
			||||||
	readn: snd_pcm_mmap_readn,
 | 
					 | 
				
			||||||
	poll_descriptor: snd_pcm_client_poll_descriptor,
 | 
					 | 
				
			||||||
	channels_mask: snd_pcm_client_channels_mask,
 | 
					 | 
				
			||||||
	avail_update: snd_pcm_client_avail_update,
 | 
					 | 
				
			||||||
	mmap_forward: snd_pcm_client_mmap_forward,
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int make_local_socket(const char *filename)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	size_t l = strlen(filename);
 | 
					 | 
				
			||||||
	size_t size = offsetof(struct sockaddr_un, sun_path) + l;
 | 
					 | 
				
			||||||
	struct sockaddr_un *addr = alloca(size);
 | 
					 | 
				
			||||||
	int sock;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	sock = socket(PF_LOCAL, SOCK_STREAM, 0);
 | 
					 | 
				
			||||||
	if (sock < 0)
 | 
					 | 
				
			||||||
		return -errno;
 | 
					 | 
				
			||||||
	
 | 
					 | 
				
			||||||
	addr->sun_family = AF_LOCAL;
 | 
					 | 
				
			||||||
	memcpy(addr->sun_path, filename, l);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (connect(sock, (struct sockaddr *) addr, size) < 0)
 | 
					 | 
				
			||||||
		return -errno;
 | 
					 | 
				
			||||||
	return sock;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int make_inet_socket(const char *host, int port)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct sockaddr_in addr;
 | 
					 | 
				
			||||||
	int sock;
 | 
					 | 
				
			||||||
	struct hostent *h = gethostbyname(host);
 | 
					 | 
				
			||||||
	if (!h)
 | 
					 | 
				
			||||||
		return -ENOENT;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	sock = socket(PF_INET, SOCK_STREAM, 0);
 | 
					 | 
				
			||||||
	if (sock < 0)
 | 
					 | 
				
			||||||
		return -errno;
 | 
					 | 
				
			||||||
	
 | 
					 | 
				
			||||||
	addr.sin_family = AF_INET;
 | 
					 | 
				
			||||||
	addr.sin_port = htons(port);
 | 
					 | 
				
			||||||
	memcpy(&addr.sin_addr, h->h_addr_list[0], sizeof(struct in_addr));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (connect(sock, (struct sockaddr *) &addr, sizeof(addr)) < 0)
 | 
					 | 
				
			||||||
		return -errno;
 | 
					 | 
				
			||||||
	return sock;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* port == -1 -> PF_LOCAL and host is the socket name */
 | 
					 | 
				
			||||||
int snd_pcm_client_create(snd_pcm_t **handlep, char *host, int port, int transport, char *name, int stream, int mode)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	snd_pcm_t *handle;
 | 
					 | 
				
			||||||
	snd_pcm_client_t *client;
 | 
					 | 
				
			||||||
	snd_client_open_request_t *req;
 | 
					 | 
				
			||||||
	snd_client_open_answer_t ans;
 | 
					 | 
				
			||||||
	size_t namelen, reqlen;
 | 
					 | 
				
			||||||
	int err;
 | 
					 | 
				
			||||||
	int result;
 | 
					 | 
				
			||||||
	int fds[2] = {-1, -1};
 | 
					 | 
				
			||||||
	int k;
 | 
					 | 
				
			||||||
	snd_pcm_client_shm_t *ctrl = NULL;
 | 
					 | 
				
			||||||
	uint32_t rcookie, scookie = getpid();
 | 
					 | 
				
			||||||
	namelen = strlen(name);
 | 
					 | 
				
			||||||
	if (namelen > 255)
 | 
					 | 
				
			||||||
		return -EINVAL;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	for (k = 0; k < 2; ++k) {
 | 
					 | 
				
			||||||
		if (port == -1)
 | 
					 | 
				
			||||||
			fds[k] = make_local_socket(host);
 | 
					 | 
				
			||||||
		else
 | 
					 | 
				
			||||||
			fds[k] = make_inet_socket(host, port);
 | 
					 | 
				
			||||||
		if (fds[k] < 0) {
 | 
					 | 
				
			||||||
			result = fds[k];
 | 
					 | 
				
			||||||
			goto _err;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		err = write(fds[k], &scookie, sizeof(scookie));
 | 
					 | 
				
			||||||
		if (err != sizeof(scookie)) {
 | 
					 | 
				
			||||||
			result = -EBADFD;
 | 
					 | 
				
			||||||
			goto _err;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		err = read(fds[k], &rcookie, sizeof(rcookie));
 | 
					 | 
				
			||||||
		if (err != sizeof(rcookie) ||
 | 
					 | 
				
			||||||
		    rcookie != scookie) {
 | 
					 | 
				
			||||||
			result = -EBADFD;
 | 
					 | 
				
			||||||
			goto _err;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	reqlen = sizeof(*req) + namelen;
 | 
					 | 
				
			||||||
	req = alloca(reqlen);
 | 
					 | 
				
			||||||
	memcpy(req->name, name, namelen);
 | 
					 | 
				
			||||||
	req->dev_type = SND_DEV_TYPE_PCM;
 | 
					 | 
				
			||||||
	req->transport_type = transport;
 | 
					 | 
				
			||||||
	req->stream = stream;
 | 
					 | 
				
			||||||
	req->mode = mode;
 | 
					 | 
				
			||||||
	req->namelen = namelen;
 | 
					 | 
				
			||||||
	err = write(fds[1], req, reqlen);
 | 
					 | 
				
			||||||
	if (err < 0) {
 | 
					 | 
				
			||||||
		result = -errno;
 | 
					 | 
				
			||||||
		goto _err;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if ((size_t) err != reqlen) {
 | 
					 | 
				
			||||||
		result = -EINVAL;
 | 
					 | 
				
			||||||
		goto _err;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	err = read(fds[1], &ans, sizeof(ans));
 | 
					 | 
				
			||||||
	if (err < 0) {
 | 
					 | 
				
			||||||
		result = -errno;
 | 
					 | 
				
			||||||
		goto _err;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if (err != sizeof(ans)) {
 | 
					 | 
				
			||||||
		result = -EINVAL;
 | 
					 | 
				
			||||||
		goto _err;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	result = ans.result;
 | 
					 | 
				
			||||||
	if (result < 0)
 | 
					 | 
				
			||||||
		goto _err;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	switch (transport) {
 | 
					 | 
				
			||||||
	case SND_TRANSPORT_TYPE_SHM:
 | 
					 | 
				
			||||||
		ctrl = shmat(ans.cookie, 0, 0);
 | 
					 | 
				
			||||||
		if (!ctrl) {
 | 
					 | 
				
			||||||
			result = -errno;
 | 
					 | 
				
			||||||
			goto _err;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		break;
 | 
					 | 
				
			||||||
	default:
 | 
					 | 
				
			||||||
		result = -ENOSYS;
 | 
					 | 
				
			||||||
		goto _err;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
		
 | 
					 | 
				
			||||||
	if (stream == SND_PCM_STREAM_PLAYBACK) {
 | 
					 | 
				
			||||||
		struct pollfd pfd;
 | 
					 | 
				
			||||||
		char buf[1];
 | 
					 | 
				
			||||||
		int bufsize = 1;
 | 
					 | 
				
			||||||
		pfd.fd = fds[0];
 | 
					 | 
				
			||||||
		pfd.events = POLLOUT;
 | 
					 | 
				
			||||||
		err = setsockopt(fds[0], SOL_SOCKET, SO_SNDBUF, &bufsize, sizeof(bufsize));
 | 
					 | 
				
			||||||
		if (err < 0) {
 | 
					 | 
				
			||||||
			result = -errno;
 | 
					 | 
				
			||||||
			goto _err;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		if (poll(&pfd, 1, 0) != 1) {
 | 
					 | 
				
			||||||
			result = -errno;
 | 
					 | 
				
			||||||
			goto _err;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		while (1) {
 | 
					 | 
				
			||||||
			err = write(fds[0], buf, 1);
 | 
					 | 
				
			||||||
			if (err != 1) {
 | 
					 | 
				
			||||||
				result = -errno;
 | 
					 | 
				
			||||||
				goto _err;
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			err = poll(&pfd, 1, 0);
 | 
					 | 
				
			||||||
			if (err < 0) {
 | 
					 | 
				
			||||||
				result = -errno;
 | 
					 | 
				
			||||||
				goto _err;
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			if (err == 0)
 | 
					 | 
				
			||||||
				break;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	client = calloc(1, sizeof(snd_pcm_client_t));
 | 
					 | 
				
			||||||
	if (!client) {
 | 
					 | 
				
			||||||
		result = -ENOMEM;
 | 
					 | 
				
			||||||
		goto _err;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	client->data_fd = fds[0];
 | 
					 | 
				
			||||||
	client->ctrl_fd = fds[1];
 | 
					 | 
				
			||||||
	switch (transport) {
 | 
					 | 
				
			||||||
	case SND_TRANSPORT_TYPE_SHM:
 | 
					 | 
				
			||||||
		client->u.shm.ctrl = ctrl;
 | 
					 | 
				
			||||||
		break;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	handle = calloc(1, sizeof(snd_pcm_t));
 | 
					 | 
				
			||||||
	if (!handle) {
 | 
					 | 
				
			||||||
		free(client);
 | 
					 | 
				
			||||||
		result = -ENOMEM;
 | 
					 | 
				
			||||||
		goto _err;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	handle->type = SND_PCM_TYPE_CLIENT;
 | 
					 | 
				
			||||||
	handle->stream = stream;
 | 
					 | 
				
			||||||
	handle->ops = &snd_pcm_client_ops;
 | 
					 | 
				
			||||||
	handle->op_arg = handle;
 | 
					 | 
				
			||||||
	handle->fast_ops = &snd_pcm_client_fast_ops;
 | 
					 | 
				
			||||||
	handle->fast_op_arg = handle;
 | 
					 | 
				
			||||||
	handle->mode = mode;
 | 
					 | 
				
			||||||
	handle->private = client;
 | 
					 | 
				
			||||||
	err = snd_pcm_init(handle);
 | 
					 | 
				
			||||||
	if (err < 0) {
 | 
					 | 
				
			||||||
		snd_pcm_close(handle);
 | 
					 | 
				
			||||||
		return err;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	*handlep = handle;
 | 
					 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 _err:
 | 
					 | 
				
			||||||
	if (fds[0] >= 0)
 | 
					 | 
				
			||||||
		close(fds[0]);
 | 
					 | 
				
			||||||
	if (fds[1] >= 0)
 | 
					 | 
				
			||||||
		close(fds[1]);
 | 
					 | 
				
			||||||
	switch (transport) {
 | 
					 | 
				
			||||||
	case SND_TRANSPORT_TYPE_SHM:
 | 
					 | 
				
			||||||
		if (ctrl)
 | 
					 | 
				
			||||||
			shmdt(ctrl);
 | 
					 | 
				
			||||||
		break;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return result;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int _snd_pcm_client_open(snd_pcm_t **pcmp, char *name, snd_config_t *conf,
 | 
					 | 
				
			||||||
			 int stream, int mode)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	snd_config_iterator_t i;
 | 
					 | 
				
			||||||
	char *socket = NULL;
 | 
					 | 
				
			||||||
	char *sname = NULL;
 | 
					 | 
				
			||||||
	char *host = NULL;
 | 
					 | 
				
			||||||
	long port = -1;
 | 
					 | 
				
			||||||
	int err;
 | 
					 | 
				
			||||||
	snd_config_foreach(i, conf) {
 | 
					 | 
				
			||||||
		snd_config_t *n = snd_config_entry(i);
 | 
					 | 
				
			||||||
		if (strcmp(n->id, "comment") == 0)
 | 
					 | 
				
			||||||
			continue;
 | 
					 | 
				
			||||||
		if (strcmp(n->id, "type") == 0)
 | 
					 | 
				
			||||||
			continue;
 | 
					 | 
				
			||||||
		if (strcmp(n->id, "stream") == 0)
 | 
					 | 
				
			||||||
			continue;
 | 
					 | 
				
			||||||
		if (strcmp(n->id, "socket") == 0) {
 | 
					 | 
				
			||||||
			err = snd_config_string_get(n, &socket);
 | 
					 | 
				
			||||||
			if (err < 0)
 | 
					 | 
				
			||||||
				return -EINVAL;
 | 
					 | 
				
			||||||
			continue;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		if (strcmp(n->id, "host") == 0) {
 | 
					 | 
				
			||||||
			err = snd_config_string_get(n, &host);
 | 
					 | 
				
			||||||
			if (err < 0)
 | 
					 | 
				
			||||||
				return -EINVAL;
 | 
					 | 
				
			||||||
			continue;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		if (strcmp(n->id, "port") == 0) {
 | 
					 | 
				
			||||||
			err = snd_config_integer_get(n, &port);
 | 
					 | 
				
			||||||
			if (err < 0)
 | 
					 | 
				
			||||||
				return -EINVAL;
 | 
					 | 
				
			||||||
			continue;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		if (strcmp(n->id, "sname") == 0) {
 | 
					 | 
				
			||||||
			err = snd_config_string_get(n, &sname);
 | 
					 | 
				
			||||||
			if (err < 0)
 | 
					 | 
				
			||||||
				return -EINVAL;
 | 
					 | 
				
			||||||
			continue;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		return -EINVAL;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if (!sname)
 | 
					 | 
				
			||||||
		return -EINVAL;
 | 
					 | 
				
			||||||
	if (socket) {
 | 
					 | 
				
			||||||
		if (port >= 0 || host)
 | 
					 | 
				
			||||||
			return -EINVAL;
 | 
					 | 
				
			||||||
		return snd_pcm_client_create(pcmp, socket, -1, SND_TRANSPORT_TYPE_SHM, sname, stream, mode);
 | 
					 | 
				
			||||||
	} else  {
 | 
					 | 
				
			||||||
		if (port < 0 || !name)
 | 
					 | 
				
			||||||
			return -EINVAL;
 | 
					 | 
				
			||||||
		return snd_pcm_client_create(pcmp, host, port, SND_TRANSPORT_TYPE_TCP, sname, stream, mode);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
				
 | 
					 | 
				
			||||||
| 
						 | 
					@ -219,7 +219,7 @@ static ssize_t snd_pcm_file_readn(snd_pcm_t *pcm, void **bufs, size_t size)
 | 
				
			||||||
static ssize_t snd_pcm_file_mmap_forward(snd_pcm_t *pcm, size_t size)
 | 
					static ssize_t snd_pcm_file_mmap_forward(snd_pcm_t *pcm, size_t size)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	snd_pcm_file_t *file = pcm->private;
 | 
						snd_pcm_file_t *file = pcm->private;
 | 
				
			||||||
	size_t ofs = pcm->mmap_control->appl_ptr % pcm->setup.buffer_size;
 | 
						size_t ofs = snd_pcm_mmap_offset(pcm);
 | 
				
			||||||
	ssize_t n = snd_pcm_mmap_forward(file->slave, size);
 | 
						ssize_t n = snd_pcm_mmap_forward(file->slave, size);
 | 
				
			||||||
	size_t xfer = 0;
 | 
						size_t xfer = 0;
 | 
				
			||||||
	if (n <= 0)
 | 
						if (n <= 0)
 | 
				
			||||||
| 
						 | 
					@ -244,60 +244,28 @@ static ssize_t snd_pcm_file_avail_update(snd_pcm_t *pcm)
 | 
				
			||||||
	return snd_pcm_avail_update(file->slave);
 | 
						return snd_pcm_avail_update(file->slave);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int snd_pcm_file_mmap_status(snd_pcm_t *pcm)
 | 
					static int snd_pcm_file_mmap(snd_pcm_t *pcm)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	snd_pcm_file_t *file = pcm->private;
 | 
						snd_pcm_file_t *file = pcm->private;
 | 
				
			||||||
	int err = snd_pcm_mmap_status(file->slave, &pcm->mmap_status);
 | 
						int err = snd_pcm_mmap(file->slave);
 | 
				
			||||||
	if (err < 0)
 | 
						if (err < 0)
 | 
				
			||||||
		return err;
 | 
							return err;
 | 
				
			||||||
	pcm->mmap_status = file->slave->mmap_status;
 | 
						pcm->mmap_info_count = file->slave->mmap_info_count;
 | 
				
			||||||
 | 
						pcm->mmap_info = file->slave->mmap_info;
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int snd_pcm_file_mmap_control(snd_pcm_t *pcm)
 | 
					static int snd_pcm_file_munmap(snd_pcm_t *pcm)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	snd_pcm_file_t *file = pcm->private;
 | 
						snd_pcm_file_t *file = pcm->private;
 | 
				
			||||||
	int err = snd_pcm_mmap_control(file->slave, &pcm->mmap_control);
 | 
						int err = snd_pcm_munmap(file->slave);
 | 
				
			||||||
	if (err < 0)
 | 
						if (err < 0)
 | 
				
			||||||
		return err;
 | 
							return err;
 | 
				
			||||||
	pcm->mmap_control = file->slave->mmap_control;
 | 
						pcm->mmap_info_count = 0;
 | 
				
			||||||
 | 
						pcm->mmap_info = 0;
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int snd_pcm_file_mmap_data(snd_pcm_t *pcm)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	snd_pcm_file_t *file = pcm->private;
 | 
					 | 
				
			||||||
	int err = snd_pcm_mmap_data(file->slave, &pcm->mmap_data);
 | 
					 | 
				
			||||||
	if (err < 0)
 | 
					 | 
				
			||||||
		return err;
 | 
					 | 
				
			||||||
	pcm->mmap_data = file->slave->mmap_data;
 | 
					 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int snd_pcm_file_munmap_status(snd_pcm_t *pcm)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	snd_pcm_file_t *file = pcm->private;
 | 
					 | 
				
			||||||
	return snd_pcm_munmap_status(file->slave);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int snd_pcm_file_munmap_control(snd_pcm_t *pcm)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	snd_pcm_file_t *file = pcm->private;
 | 
					 | 
				
			||||||
	return snd_pcm_munmap_control(file->slave);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int snd_pcm_file_munmap_data(snd_pcm_t *pcm)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	snd_pcm_file_t *file = pcm->private;
 | 
					 | 
				
			||||||
	return snd_pcm_munmap_data(file->slave);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int snd_pcm_file_poll_descriptor(snd_pcm_t *pcm)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	snd_pcm_file_t *file = pcm->private;
 | 
					 | 
				
			||||||
	return snd_pcm_poll_descriptor(file->slave);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int snd_pcm_file_channels_mask(snd_pcm_t *pcm, bitset_t *cmask)
 | 
					static int snd_pcm_file_channels_mask(snd_pcm_t *pcm, bitset_t *cmask)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	snd_pcm_file_t *file = pcm->private;
 | 
						snd_pcm_file_t *file = pcm->private;
 | 
				
			||||||
| 
						 | 
					@ -337,7 +305,7 @@ static void snd_pcm_file_dump(snd_pcm_t *pcm, FILE *fp)
 | 
				
			||||||
	snd_pcm_dump(file->slave, fp);
 | 
						snd_pcm_dump(file->slave, fp);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct snd_pcm_ops snd_pcm_file_ops = {
 | 
					snd_pcm_ops_t snd_pcm_file_ops = {
 | 
				
			||||||
	close: snd_pcm_file_close,
 | 
						close: snd_pcm_file_close,
 | 
				
			||||||
	info: snd_pcm_file_info,
 | 
						info: snd_pcm_file_info,
 | 
				
			||||||
	params_info: snd_pcm_file_params_info,
 | 
						params_info: snd_pcm_file_params_info,
 | 
				
			||||||
| 
						 | 
					@ -349,15 +317,11 @@ struct snd_pcm_ops snd_pcm_file_ops = {
 | 
				
			||||||
	dump: snd_pcm_file_dump,
 | 
						dump: snd_pcm_file_dump,
 | 
				
			||||||
	nonblock: snd_pcm_file_nonblock,
 | 
						nonblock: snd_pcm_file_nonblock,
 | 
				
			||||||
	async: snd_pcm_file_async,
 | 
						async: snd_pcm_file_async,
 | 
				
			||||||
	mmap_status: snd_pcm_file_mmap_status,
 | 
						mmap: snd_pcm_file_mmap,
 | 
				
			||||||
	mmap_control: snd_pcm_file_mmap_control,
 | 
						munmap: snd_pcm_file_munmap,
 | 
				
			||||||
	mmap_data: snd_pcm_file_mmap_data,
 | 
					 | 
				
			||||||
	munmap_status: snd_pcm_file_munmap_status,
 | 
					 | 
				
			||||||
	munmap_control: snd_pcm_file_munmap_control,
 | 
					 | 
				
			||||||
	munmap_data: snd_pcm_file_munmap_data,
 | 
					 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct snd_pcm_fast_ops snd_pcm_file_fast_ops = {
 | 
					snd_pcm_fast_ops_t snd_pcm_file_fast_ops = {
 | 
				
			||||||
	status: snd_pcm_file_status,
 | 
						status: snd_pcm_file_status,
 | 
				
			||||||
	state: snd_pcm_file_state,
 | 
						state: snd_pcm_file_state,
 | 
				
			||||||
	delay: snd_pcm_file_delay,
 | 
						delay: snd_pcm_file_delay,
 | 
				
			||||||
| 
						 | 
					@ -371,18 +335,16 @@ struct snd_pcm_fast_ops snd_pcm_file_fast_ops = {
 | 
				
			||||||
	writen: snd_pcm_file_writen,
 | 
						writen: snd_pcm_file_writen,
 | 
				
			||||||
	readi: snd_pcm_file_readi,
 | 
						readi: snd_pcm_file_readi,
 | 
				
			||||||
	readn: snd_pcm_file_readn,
 | 
						readn: snd_pcm_file_readn,
 | 
				
			||||||
	poll_descriptor: snd_pcm_file_poll_descriptor,
 | 
					 | 
				
			||||||
	channels_mask: snd_pcm_file_channels_mask,
 | 
						channels_mask: snd_pcm_file_channels_mask,
 | 
				
			||||||
	avail_update: snd_pcm_file_avail_update,
 | 
						avail_update: snd_pcm_file_avail_update,
 | 
				
			||||||
	mmap_forward: snd_pcm_file_mmap_forward,
 | 
						mmap_forward: snd_pcm_file_mmap_forward,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int snd_pcm_file_open(snd_pcm_t **handlep, char *name, char *fname, int fd, snd_pcm_t *slave, int close_slave)
 | 
					int snd_pcm_file_open(snd_pcm_t **pcmp, char *name, char *fname, int fd, snd_pcm_t *slave, int close_slave)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	snd_pcm_t *handle;
 | 
						snd_pcm_t *pcm;
 | 
				
			||||||
	snd_pcm_file_t *file;
 | 
						snd_pcm_file_t *file;
 | 
				
			||||||
	int err;
 | 
						assert(pcmp && slave);
 | 
				
			||||||
	assert(handlep && slave);
 | 
					 | 
				
			||||||
	if (fname) {
 | 
						if (fname) {
 | 
				
			||||||
		fd = open(fname, O_WRONLY|O_CREAT, 0666);
 | 
							fd = open(fname, O_WRONLY|O_CREAT, 0666);
 | 
				
			||||||
		if (fd < 0)
 | 
							if (fd < 0)
 | 
				
			||||||
| 
						 | 
					@ -397,27 +359,25 @@ int snd_pcm_file_open(snd_pcm_t **handlep, char *name, char *fname, int fd, snd_
 | 
				
			||||||
	file->slave = slave;
 | 
						file->slave = slave;
 | 
				
			||||||
	file->close_slave = close_slave;
 | 
						file->close_slave = close_slave;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	handle = calloc(1, sizeof(snd_pcm_t));
 | 
						pcm = calloc(1, sizeof(snd_pcm_t));
 | 
				
			||||||
	if (!handle) {
 | 
						if (!pcm) {
 | 
				
			||||||
		free(file);
 | 
							free(file);
 | 
				
			||||||
		return -ENOMEM;
 | 
							return -ENOMEM;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if (name)
 | 
						if (name)
 | 
				
			||||||
		handle->name = strdup(name);
 | 
							pcm->name = strdup(name);
 | 
				
			||||||
	handle->type = SND_PCM_TYPE_FILE;
 | 
						pcm->type = SND_PCM_TYPE_FILE;
 | 
				
			||||||
	handle->stream = slave->stream;
 | 
						pcm->stream = slave->stream;
 | 
				
			||||||
	handle->ops = &snd_pcm_file_ops;
 | 
						pcm->mode = slave->mode;
 | 
				
			||||||
	handle->op_arg = handle;
 | 
						pcm->ops = &snd_pcm_file_ops;
 | 
				
			||||||
	handle->fast_ops = &snd_pcm_file_fast_ops;
 | 
						pcm->op_arg = pcm;
 | 
				
			||||||
	handle->fast_op_arg = handle;
 | 
						pcm->fast_ops = &snd_pcm_file_fast_ops;
 | 
				
			||||||
	handle->mode = slave->mode;
 | 
						pcm->fast_op_arg = pcm;
 | 
				
			||||||
	handle->private = file;
 | 
						pcm->private = file;
 | 
				
			||||||
	err = snd_pcm_init(handle);
 | 
						pcm->poll_fd = slave->poll_fd;
 | 
				
			||||||
	if (err < 0) {
 | 
						pcm->hw_ptr = slave->hw_ptr;
 | 
				
			||||||
		snd_pcm_close(handle);
 | 
						pcm->appl_ptr = slave->appl_ptr;
 | 
				
			||||||
		return err;
 | 
						*pcmp = pcm;
 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	*handlep = handle;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										226
									
								
								src/pcm/pcm_hw.c
									
										
									
									
									
								
							
							
						
						
									
										226
									
								
								src/pcm/pcm_hw.c
									
										
									
									
									
								
							| 
						 | 
					@ -37,25 +37,14 @@
 | 
				
			||||||
typedef struct {
 | 
					typedef struct {
 | 
				
			||||||
	int fd;
 | 
						int fd;
 | 
				
			||||||
	int card, device, subdevice;
 | 
						int card, device, subdevice;
 | 
				
			||||||
	int mmap_emulation;
 | 
						volatile snd_pcm_mmap_status_t *mmap_status;
 | 
				
			||||||
 | 
						snd_pcm_mmap_control_t *mmap_control;
 | 
				
			||||||
} snd_pcm_hw_t;
 | 
					} snd_pcm_hw_t;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define SND_FILE_PCM_STREAM_PLAYBACK		"/dev/snd/pcmC%iD%ip"
 | 
					#define SND_FILE_PCM_STREAM_PLAYBACK		"/dev/snd/pcmC%iD%ip"
 | 
				
			||||||
#define SND_FILE_PCM_STREAM_CAPTURE		"/dev/snd/pcmC%iD%ic"
 | 
					#define SND_FILE_PCM_STREAM_CAPTURE		"/dev/snd/pcmC%iD%ic"
 | 
				
			||||||
#define SND_PCM_VERSION_MAX	SND_PROTOCOL_VERSION(2, 0, 0)
 | 
					#define SND_PCM_VERSION_MAX	SND_PROTOCOL_VERSION(2, 0, 0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int snd_pcm_hw_close(snd_pcm_t *pcm)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	snd_pcm_hw_t *hw = pcm->private;
 | 
					 | 
				
			||||||
	int fd = hw->fd;
 | 
					 | 
				
			||||||
	free(hw);
 | 
					 | 
				
			||||||
	if (close(fd)) {
 | 
					 | 
				
			||||||
		ERR("close failed\n");
 | 
					 | 
				
			||||||
		return -errno;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int snd_pcm_hw_nonblock(snd_pcm_t *pcm, int nonblock)
 | 
					static int snd_pcm_hw_nonblock(snd_pcm_t *pcm, int nonblock)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	long flags;
 | 
						long flags;
 | 
				
			||||||
| 
						 | 
					@ -158,9 +147,7 @@ static int snd_pcm_hw_setup(snd_pcm_t *pcm, snd_pcm_setup_t * setup)
 | 
				
			||||||
			setup->mmap_shape = SND_PCM_MMAP_INTERLEAVED;
 | 
								setup->mmap_shape = SND_PCM_MMAP_INTERLEAVED;
 | 
				
			||||||
		else
 | 
							else
 | 
				
			||||||
			setup->mmap_shape = SND_PCM_MMAP_NONINTERLEAVED;
 | 
								setup->mmap_shape = SND_PCM_MMAP_NONINTERLEAVED;
 | 
				
			||||||
		hw->mmap_emulation = 1;
 | 
						}
 | 
				
			||||||
	} else
 | 
					 | 
				
			||||||
		hw->mmap_emulation = 0;
 | 
					 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -194,19 +181,21 @@ static int snd_pcm_hw_channel_setup(snd_pcm_t *pcm, snd_pcm_channel_setup_t * se
 | 
				
			||||||
		ERR("SND_PCM_IOCTL_CHANNEL_SETUP failed");
 | 
							ERR("SND_PCM_IOCTL_CHANNEL_SETUP failed");
 | 
				
			||||||
		return -errno;
 | 
							return -errno;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if (hw->mmap_emulation) {
 | 
						if (!pcm->mmap_info)
 | 
				
			||||||
		if (pcm->setup.mmap_shape == SND_PCM_MMAP_INTERLEAVED) {
 | 
							return 0;
 | 
				
			||||||
			setup->running_area.addr = pcm->mmap_data;
 | 
						if (pcm->setup.mmap_shape == SND_PCM_MMAP_UNSPECIFIED) {
 | 
				
			||||||
 | 
							if (pcm->setup.xfer_mode == SND_PCM_XFER_INTERLEAVED) {
 | 
				
			||||||
 | 
								setup->running_area.addr = pcm->mmap_info->addr;
 | 
				
			||||||
			setup->running_area.first = setup->channel * pcm->bits_per_sample;
 | 
								setup->running_area.first = setup->channel * pcm->bits_per_sample;
 | 
				
			||||||
			setup->running_area.step = pcm->bits_per_frame;
 | 
								setup->running_area.step = pcm->bits_per_frame;
 | 
				
			||||||
		} else {
 | 
							} else {
 | 
				
			||||||
			setup->running_area.addr = pcm->mmap_data + setup->channel * pcm->setup.buffer_size * pcm->bits_per_sample / 8;
 | 
								setup->running_area.addr = pcm->mmap_info->addr + setup->channel * pcm->setup.buffer_size * pcm->bits_per_sample / 8;
 | 
				
			||||||
			setup->running_area.first = 0;
 | 
								setup->running_area.first = 0;
 | 
				
			||||||
			setup->running_area.step = pcm->bits_per_sample;
 | 
								setup->running_area.step = pcm->bits_per_sample;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		setup->stopped_area = setup->running_area;
 | 
							setup->stopped_area = setup->running_area;
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		setup->running_area.addr = (char *)pcm->mmap_data + (long)setup->running_area.addr;
 | 
							setup->running_area.addr = pcm->mmap_info->addr + (long)setup->running_area.addr;
 | 
				
			||||||
		setup->stopped_area.addr = setup->running_area.addr;
 | 
							setup->stopped_area.addr = setup->running_area.addr;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
| 
						 | 
					@ -225,7 +214,8 @@ static int snd_pcm_hw_status(snd_pcm_t *pcm, snd_pcm_status_t * status)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int snd_pcm_hw_state(snd_pcm_t *pcm)
 | 
					static int snd_pcm_hw_state(snd_pcm_t *pcm)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	return pcm->mmap_status->state;
 | 
						snd_pcm_hw_t *hw = pcm->private;
 | 
				
			||||||
 | 
						return hw->mmap_status->state;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int snd_pcm_hw_delay(snd_pcm_t *pcm, ssize_t *delayp)
 | 
					static int snd_pcm_hw_delay(snd_pcm_t *pcm, ssize_t *delayp)
 | 
				
			||||||
| 
						 | 
					@ -378,7 +368,8 @@ static int snd_pcm_hw_mmap_status(snd_pcm_t *pcm)
 | 
				
			||||||
		ERR("status mmap failed");
 | 
							ERR("status mmap failed");
 | 
				
			||||||
		return -errno;
 | 
							return -errno;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	pcm->mmap_status = ptr;
 | 
						hw->mmap_status = ptr;
 | 
				
			||||||
 | 
						pcm->hw_ptr = &hw->mmap_status->hw_ptr;
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -392,36 +383,50 @@ static int snd_pcm_hw_mmap_control(snd_pcm_t *pcm)
 | 
				
			||||||
		ERR("control mmap failed");
 | 
							ERR("control mmap failed");
 | 
				
			||||||
		return -errno;
 | 
							return -errno;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	pcm->mmap_control = ptr;
 | 
						hw->mmap_control = ptr;
 | 
				
			||||||
 | 
						pcm->appl_ptr = &hw->mmap_control->appl_ptr;
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int snd_pcm_hw_mmap_data(snd_pcm_t *pcm)
 | 
					static int snd_pcm_hw_mmap(snd_pcm_t *pcm)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	snd_pcm_hw_t *hw = pcm->private;
 | 
						snd_pcm_hw_t *hw = pcm->private;
 | 
				
			||||||
	void *ptr;
 | 
						pcm->mmap_info = calloc(1, sizeof(*pcm->mmap_info));
 | 
				
			||||||
	if (hw->mmap_emulation) {
 | 
						if (!pcm->mmap_info)
 | 
				
			||||||
		ptr = malloc(snd_pcm_frames_to_bytes(pcm, pcm->setup.buffer_size));
 | 
							return -ENOMEM;
 | 
				
			||||||
		if (!ptr)
 | 
						pcm->mmap_info_count = 1;
 | 
				
			||||||
 | 
						if (pcm->setup.mmap_shape == SND_PCM_MMAP_UNSPECIFIED) {
 | 
				
			||||||
 | 
							pcm->mmap_info->type = SND_PCM_MMAP_USER;
 | 
				
			||||||
 | 
							pcm->mmap_info->size = snd_pcm_frames_to_bytes(pcm, pcm->setup.buffer_size);
 | 
				
			||||||
 | 
							pcm->mmap_info->addr = valloc(pcm->mmap_info->size);
 | 
				
			||||||
 | 
							if (!pcm->mmap_info->addr) {
 | 
				
			||||||
 | 
								free(pcm->mmap_info);
 | 
				
			||||||
 | 
								pcm->mmap_info = 0;
 | 
				
			||||||
			return -ENOMEM;
 | 
								return -ENOMEM;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		int prot;
 | 
							pcm->mmap_info->type = SND_PCM_MMAP_KERNEL;
 | 
				
			||||||
		prot = PROT_WRITE | PROT_READ;
 | 
							pcm->mmap_info->size = pcm->setup.mmap_bytes;
 | 
				
			||||||
		ptr = mmap(NULL, pcm->setup.mmap_bytes,
 | 
							pcm->mmap_info->addr = mmap(NULL, pcm->setup.mmap_bytes,
 | 
				
			||||||
			   prot, MAP_FILE|MAP_SHARED, 
 | 
										    PROT_WRITE | PROT_READ,
 | 
				
			||||||
			   hw->fd, SND_PCM_MMAP_OFFSET_DATA);
 | 
										    MAP_FILE|MAP_SHARED, 
 | 
				
			||||||
		if (ptr == MAP_FAILED || ptr == NULL) {
 | 
										    hw->fd, SND_PCM_MMAP_OFFSET_DATA);
 | 
				
			||||||
 | 
							if (pcm->mmap_info->addr == MAP_FAILED ||
 | 
				
			||||||
 | 
							    pcm->mmap_info->addr == NULL) {
 | 
				
			||||||
			ERR("data mmap failed");
 | 
								ERR("data mmap failed");
 | 
				
			||||||
 | 
								free(pcm->mmap_info);
 | 
				
			||||||
 | 
								pcm->mmap_info = 0;
 | 
				
			||||||
			return -errno;
 | 
								return -errno;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
							pcm->mmap_info->u.kernel.fd = hw->fd;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	pcm->mmap_data = ptr;
 | 
					 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int snd_pcm_hw_munmap_status(snd_pcm_t *pcm)
 | 
					static int snd_pcm_hw_munmap_status(snd_pcm_t *pcm)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (munmap((void*)pcm->mmap_status, sizeof(*pcm->mmap_status)) < 0) {
 | 
						snd_pcm_hw_t *hw = pcm->private;
 | 
				
			||||||
 | 
						if (munmap((void*)hw->mmap_status, sizeof(*hw->mmap_status)) < 0) {
 | 
				
			||||||
		ERR("status munmap failed");
 | 
							ERR("status munmap failed");
 | 
				
			||||||
		return -errno;
 | 
							return -errno;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -430,30 +435,46 @@ static int snd_pcm_hw_munmap_status(snd_pcm_t *pcm)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int snd_pcm_hw_munmap_control(snd_pcm_t *pcm)
 | 
					static int snd_pcm_hw_munmap_control(snd_pcm_t *pcm)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (munmap(pcm->mmap_control, sizeof(*pcm->mmap_control)) < 0) {
 | 
						snd_pcm_hw_t *hw = pcm->private;
 | 
				
			||||||
 | 
						if (munmap(hw->mmap_control, sizeof(*hw->mmap_control)) < 0) {
 | 
				
			||||||
		ERR("control munmap failed");
 | 
							ERR("control munmap failed");
 | 
				
			||||||
		return -errno;
 | 
							return -errno;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int snd_pcm_hw_munmap_data(snd_pcm_t *pcm)
 | 
					static int snd_pcm_hw_munmap(snd_pcm_t *pcm)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	snd_pcm_hw_t *hw = pcm->private;
 | 
						if (pcm->setup.mmap_shape == SND_PCM_MMAP_UNSPECIFIED)
 | 
				
			||||||
	if (hw->mmap_emulation)
 | 
							free(pcm->mmap_info->addr);
 | 
				
			||||||
		free(pcm->mmap_data);
 | 
					 | 
				
			||||||
	else
 | 
						else
 | 
				
			||||||
		if (munmap(pcm->mmap_data, pcm->setup.mmap_bytes) < 0) {
 | 
							if (munmap(pcm->mmap_info->addr, pcm->mmap_info->size) < 0) {
 | 
				
			||||||
			ERR("data munmap failed");
 | 
								ERR("data munmap failed");
 | 
				
			||||||
			return -errno;
 | 
								return -errno;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
						pcm->mmap_info_count = 0;
 | 
				
			||||||
 | 
						free(pcm->mmap_info);
 | 
				
			||||||
 | 
						pcm->mmap_info = 0;
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int snd_pcm_hw_close(snd_pcm_t *pcm)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						snd_pcm_hw_t *hw = pcm->private;
 | 
				
			||||||
 | 
						int fd = hw->fd;
 | 
				
			||||||
 | 
						free(hw);
 | 
				
			||||||
 | 
						if (close(fd)) {
 | 
				
			||||||
 | 
							ERR("close failed\n");
 | 
				
			||||||
 | 
							return -errno;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						snd_pcm_hw_munmap_status(pcm);
 | 
				
			||||||
 | 
						snd_pcm_hw_munmap_control(pcm);
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static ssize_t snd_pcm_hw_mmap_forward(snd_pcm_t *pcm, size_t size)
 | 
					static ssize_t snd_pcm_hw_mmap_forward(snd_pcm_t *pcm, size_t size)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	snd_pcm_hw_t *hw = pcm->private;
 | 
						if (pcm->setup.mmap_shape == SND_PCM_MMAP_UNSPECIFIED && pcm->stream == SND_PCM_STREAM_PLAYBACK)
 | 
				
			||||||
	if (hw->mmap_emulation && pcm->stream == SND_PCM_STREAM_PLAYBACK)
 | 
					 | 
				
			||||||
		return snd_pcm_write_mmap(pcm, size);
 | 
							return snd_pcm_write_mmap(pcm, size);
 | 
				
			||||||
	snd_pcm_mmap_appl_forward(pcm, size);
 | 
						snd_pcm_mmap_appl_forward(pcm, size);
 | 
				
			||||||
	return size;
 | 
						return size;
 | 
				
			||||||
| 
						 | 
					@ -461,7 +482,6 @@ static ssize_t snd_pcm_hw_mmap_forward(snd_pcm_t *pcm, size_t size)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static ssize_t snd_pcm_hw_avail_update(snd_pcm_t *pcm)
 | 
					static ssize_t snd_pcm_hw_avail_update(snd_pcm_t *pcm)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	snd_pcm_hw_t *hw = pcm->private;
 | 
					 | 
				
			||||||
	size_t avail;
 | 
						size_t avail;
 | 
				
			||||||
	ssize_t err;
 | 
						ssize_t err;
 | 
				
			||||||
	if (pcm->setup.ready_mode == SND_PCM_READY_ASAP ||
 | 
						if (pcm->setup.ready_mode == SND_PCM_READY_ASAP ||
 | 
				
			||||||
| 
						 | 
					@ -475,7 +495,7 @@ static ssize_t snd_pcm_hw_avail_update(snd_pcm_t *pcm)
 | 
				
			||||||
		avail = snd_pcm_mmap_playback_avail(pcm);
 | 
							avail = snd_pcm_mmap_playback_avail(pcm);
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		avail = snd_pcm_mmap_capture_avail(pcm);
 | 
							avail = snd_pcm_mmap_capture_avail(pcm);
 | 
				
			||||||
		if (avail > 0 && hw->mmap_emulation) {
 | 
							if (avail > 0 && pcm->setup.mmap_shape == SND_PCM_MMAP_UNSPECIFIED) {
 | 
				
			||||||
			err = snd_pcm_read_mmap(pcm, avail);
 | 
								err = snd_pcm_read_mmap(pcm, avail);
 | 
				
			||||||
			if (err < 0)
 | 
								if (err < 0)
 | 
				
			||||||
				return err;
 | 
									return err;
 | 
				
			||||||
| 
						 | 
					@ -488,12 +508,6 @@ static ssize_t snd_pcm_hw_avail_update(snd_pcm_t *pcm)
 | 
				
			||||||
	return avail;
 | 
						return avail;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int snd_pcm_hw_poll_descriptor(snd_pcm_t *pcm)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	snd_pcm_hw_t *hw = pcm->private;
 | 
					 | 
				
			||||||
	return hw->fd;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int snd_pcm_hw_channels_mask(snd_pcm_t *pcm ATTRIBUTE_UNUSED,
 | 
					static int snd_pcm_hw_channels_mask(snd_pcm_t *pcm ATTRIBUTE_UNUSED,
 | 
				
			||||||
				    bitset_t *cmask ATTRIBUTE_UNUSED)
 | 
									    bitset_t *cmask ATTRIBUTE_UNUSED)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
| 
						 | 
					@ -514,7 +528,7 @@ static void snd_pcm_hw_dump(snd_pcm_t *pcm, FILE *fp)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct snd_pcm_ops snd_pcm_hw_ops = {
 | 
					snd_pcm_ops_t snd_pcm_hw_ops = {
 | 
				
			||||||
	close: snd_pcm_hw_close,
 | 
						close: snd_pcm_hw_close,
 | 
				
			||||||
	info: snd_pcm_hw_info,
 | 
						info: snd_pcm_hw_info,
 | 
				
			||||||
	params_info: snd_pcm_hw_params_info,
 | 
						params_info: snd_pcm_hw_params_info,
 | 
				
			||||||
| 
						 | 
					@ -526,15 +540,11 @@ struct snd_pcm_ops snd_pcm_hw_ops = {
 | 
				
			||||||
	dump: snd_pcm_hw_dump,
 | 
						dump: snd_pcm_hw_dump,
 | 
				
			||||||
	nonblock: snd_pcm_hw_nonblock,
 | 
						nonblock: snd_pcm_hw_nonblock,
 | 
				
			||||||
	async: snd_pcm_hw_async,
 | 
						async: snd_pcm_hw_async,
 | 
				
			||||||
	mmap_status: snd_pcm_hw_mmap_status,
 | 
						mmap: snd_pcm_hw_mmap,
 | 
				
			||||||
	mmap_control: snd_pcm_hw_mmap_control,
 | 
						munmap: snd_pcm_hw_munmap,
 | 
				
			||||||
	mmap_data: snd_pcm_hw_mmap_data,
 | 
					 | 
				
			||||||
	munmap_status: snd_pcm_hw_munmap_status,
 | 
					 | 
				
			||||||
	munmap_control: snd_pcm_hw_munmap_control,
 | 
					 | 
				
			||||||
	munmap_data: snd_pcm_hw_munmap_data,
 | 
					 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct snd_pcm_fast_ops snd_pcm_hw_fast_ops = {
 | 
					snd_pcm_fast_ops_t snd_pcm_hw_fast_ops = {
 | 
				
			||||||
	status: snd_pcm_hw_status,
 | 
						status: snd_pcm_hw_status,
 | 
				
			||||||
	state: snd_pcm_hw_state,
 | 
						state: snd_pcm_hw_state,
 | 
				
			||||||
	delay: snd_pcm_hw_delay,
 | 
						delay: snd_pcm_hw_delay,
 | 
				
			||||||
| 
						 | 
					@ -548,13 +558,12 @@ struct snd_pcm_fast_ops snd_pcm_hw_fast_ops = {
 | 
				
			||||||
	writen: snd_pcm_hw_writen,
 | 
						writen: snd_pcm_hw_writen,
 | 
				
			||||||
	readi: snd_pcm_hw_readi,
 | 
						readi: snd_pcm_hw_readi,
 | 
				
			||||||
	readn: snd_pcm_hw_readn,
 | 
						readn: snd_pcm_hw_readn,
 | 
				
			||||||
	poll_descriptor: snd_pcm_hw_poll_descriptor,
 | 
					 | 
				
			||||||
	channels_mask: snd_pcm_hw_channels_mask,
 | 
						channels_mask: snd_pcm_hw_channels_mask,
 | 
				
			||||||
	avail_update: snd_pcm_hw_avail_update,
 | 
						avail_update: snd_pcm_hw_avail_update,
 | 
				
			||||||
	mmap_forward: snd_pcm_hw_mmap_forward,
 | 
						mmap_forward: snd_pcm_hw_mmap_forward,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int snd_pcm_hw_open_subdevice(snd_pcm_t **handlep, int card, int device, int subdevice, int stream, int mode)
 | 
					int snd_pcm_hw_open_subdevice(snd_pcm_t **pcmp, int card, int device, int subdevice, int stream, int mode)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	char filename[32];
 | 
						char filename[32];
 | 
				
			||||||
	char *filefmt;
 | 
						char *filefmt;
 | 
				
			||||||
| 
						 | 
					@ -564,12 +573,12 @@ int snd_pcm_hw_open_subdevice(snd_pcm_t **handlep, int card, int device, int sub
 | 
				
			||||||
	snd_pcm_info_t info;
 | 
						snd_pcm_info_t info;
 | 
				
			||||||
	int fmode;
 | 
						int fmode;
 | 
				
			||||||
	snd_ctl_t *ctl;
 | 
						snd_ctl_t *ctl;
 | 
				
			||||||
	snd_pcm_t *handle;
 | 
						snd_pcm_t *pcm = NULL;
 | 
				
			||||||
	snd_pcm_hw_t *hw;
 | 
						snd_pcm_hw_t *hw = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	assert(handlep);
 | 
						assert(pcmp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if ((ret = snd_ctl_hw_open(&ctl, card)) < 0)
 | 
						if ((ret = snd_ctl_hw_open(&ctl, NULL, card)) < 0)
 | 
				
			||||||
		return ret;
 | 
							return ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	switch (stream) {
 | 
						switch (stream) {
 | 
				
			||||||
| 
						 | 
					@ -582,37 +591,35 @@ int snd_pcm_hw_open_subdevice(snd_pcm_t **handlep, int card, int device, int sub
 | 
				
			||||||
	default:
 | 
						default:
 | 
				
			||||||
		assert(0);
 | 
							assert(0);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if ((ret = snd_ctl_pcm_prefer_subdevice(ctl, subdevice)) < 0)
 | 
						ret = snd_ctl_pcm_prefer_subdevice(ctl, subdevice);
 | 
				
			||||||
		goto __end;
 | 
						snd_ctl_close(ctl);
 | 
				
			||||||
 | 
						if (ret < 0)
 | 
				
			||||||
 | 
							return ret;
 | 
				
			||||||
	sprintf(filename, filefmt, card, device);
 | 
						sprintf(filename, filefmt, card, device);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      __again:
 | 
					      __again:
 | 
				
			||||||
      	if (attempt++ > 3) {
 | 
					      	if (attempt++ > 3)
 | 
				
			||||||
		ret = -EBUSY;
 | 
							return -EBUSY;
 | 
				
			||||||
		goto __end;
 | 
					 | 
				
			||||||
      	}
 | 
					 | 
				
			||||||
	fmode = O_RDWR;
 | 
						fmode = O_RDWR;
 | 
				
			||||||
	if (mode & SND_PCM_NONBLOCK)
 | 
						if (mode & SND_PCM_NONBLOCK)
 | 
				
			||||||
		fmode |= O_NONBLOCK;
 | 
							fmode |= O_NONBLOCK;
 | 
				
			||||||
	if (mode & SND_PCM_ASYNC)
 | 
						if (mode & SND_PCM_ASYNC)
 | 
				
			||||||
		fmode |= O_ASYNC;
 | 
							fmode |= O_ASYNC;
 | 
				
			||||||
	if ((fd = open(filename, fmode)) < 0) {
 | 
						if ((fd = open(filename, fmode)) < 0)
 | 
				
			||||||
		ret = -errno;
 | 
							return -errno;
 | 
				
			||||||
		goto __end;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if (ioctl(fd, SND_PCM_IOCTL_PVERSION, &ver) < 0) {
 | 
						if (ioctl(fd, SND_PCM_IOCTL_PVERSION, &ver) < 0) {
 | 
				
			||||||
		ret = -errno;
 | 
							ret = -errno;
 | 
				
			||||||
		goto __end;
 | 
							goto _err;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if (SND_PROTOCOL_INCOMPATIBLE(ver, SND_PCM_VERSION_MAX)) {
 | 
						if (SND_PROTOCOL_INCOMPATIBLE(ver, SND_PCM_VERSION_MAX)) {
 | 
				
			||||||
		ret = -SND_ERROR_INCOMPATIBLE_VERSION;
 | 
							ret = -SND_ERROR_INCOMPATIBLE_VERSION;
 | 
				
			||||||
		goto __end;
 | 
							goto _err;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if (subdevice >= 0) {
 | 
						if (subdevice >= 0) {
 | 
				
			||||||
		memset(&info, 0, sizeof(info));
 | 
							memset(&info, 0, sizeof(info));
 | 
				
			||||||
		if (ioctl(fd, SND_PCM_IOCTL_INFO, &info) < 0) {
 | 
							if (ioctl(fd, SND_PCM_IOCTL_INFO, &info) < 0) {
 | 
				
			||||||
			ret = -errno;
 | 
								ret = -errno;
 | 
				
			||||||
			goto __end;
 | 
								goto _err;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if (info.subdevice != subdevice) {
 | 
							if (info.subdevice != subdevice) {
 | 
				
			||||||
			close(fd);
 | 
								close(fd);
 | 
				
			||||||
| 
						 | 
					@ -622,54 +629,61 @@ int snd_pcm_hw_open_subdevice(snd_pcm_t **handlep, int card, int device, int sub
 | 
				
			||||||
	hw = calloc(1, sizeof(snd_pcm_hw_t));
 | 
						hw = calloc(1, sizeof(snd_pcm_hw_t));
 | 
				
			||||||
	if (!hw) {
 | 
						if (!hw) {
 | 
				
			||||||
		ret = -ENOMEM;
 | 
							ret = -ENOMEM;
 | 
				
			||||||
		goto __end;
 | 
							goto _err;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	hw->card = card;
 | 
						hw->card = card;
 | 
				
			||||||
	hw->device = device;
 | 
						hw->device = device;
 | 
				
			||||||
	hw->subdevice = subdevice;
 | 
						hw->subdevice = subdevice;
 | 
				
			||||||
	hw->fd = fd;
 | 
						hw->fd = fd;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	handle = calloc(1, sizeof(snd_pcm_t));
 | 
						pcm = calloc(1, sizeof(snd_pcm_t));
 | 
				
			||||||
	if (!handle) {
 | 
						if (!pcm) {
 | 
				
			||||||
		free(hw);
 | 
					 | 
				
			||||||
		ret = -ENOMEM;
 | 
							ret = -ENOMEM;
 | 
				
			||||||
		goto __end;
 | 
							goto _err;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	handle->type = SND_PCM_TYPE_HW;
 | 
						pcm->type = SND_PCM_TYPE_HW;
 | 
				
			||||||
	handle->stream = stream;
 | 
						pcm->stream = stream;
 | 
				
			||||||
	handle->ops = &snd_pcm_hw_ops;
 | 
						pcm->mode = mode;
 | 
				
			||||||
	handle->op_arg = handle;
 | 
						pcm->ops = &snd_pcm_hw_ops;
 | 
				
			||||||
	handle->fast_ops = &snd_pcm_hw_fast_ops;
 | 
						pcm->op_arg = pcm;
 | 
				
			||||||
	handle->fast_op_arg = handle;
 | 
						pcm->fast_ops = &snd_pcm_hw_fast_ops;
 | 
				
			||||||
	handle->mode = mode;
 | 
						pcm->fast_op_arg = pcm;
 | 
				
			||||||
	handle->private = hw;
 | 
						pcm->private = hw;
 | 
				
			||||||
	ret = snd_pcm_init(handle);
 | 
						pcm->poll_fd = fd;
 | 
				
			||||||
 | 
						*pcmp = pcm;
 | 
				
			||||||
 | 
						ret = snd_pcm_hw_mmap_status(pcm);
 | 
				
			||||||
	if (ret < 0) {
 | 
						if (ret < 0) {
 | 
				
			||||||
		snd_pcm_close(handle);
 | 
							snd_pcm_close(pcm);
 | 
				
			||||||
		snd_ctl_close(ctl);
 | 
					 | 
				
			||||||
		return ret;
 | 
							return ret;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	*handlep = handle;
 | 
						ret = snd_pcm_hw_mmap_control(pcm);
 | 
				
			||||||
 | 
						if (ret < 0) {
 | 
				
			||||||
 | 
							snd_pcm_close(pcm);
 | 
				
			||||||
 | 
							return ret;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
 __end:
 | 
					 _err:
 | 
				
			||||||
	if (ret < 0 && fd >= 0)
 | 
						if (hw)
 | 
				
			||||||
		close(fd);
 | 
							free(hw);
 | 
				
			||||||
	snd_ctl_close(ctl);
 | 
						if (pcm)
 | 
				
			||||||
 | 
							free(pcm);
 | 
				
			||||||
 | 
						close(fd);
 | 
				
			||||||
	return ret;
 | 
						return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int snd_pcm_hw_open_device(snd_pcm_t **handlep, int card, int device, int stream, int mode)
 | 
					int snd_pcm_hw_open_device(snd_pcm_t **pcmp, int card, int device, int stream, int mode)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	return snd_pcm_hw_open_subdevice(handlep, card, device, -1, stream, mode);
 | 
						return snd_pcm_hw_open_subdevice(pcmp, card, device, -1, stream, mode);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int snd_pcm_hw_open(snd_pcm_t **handlep, char *name, int card, int device, int subdevice, int stream, int mode)
 | 
					int snd_pcm_hw_open(snd_pcm_t **pcmp, char *name, int card, int device, int subdevice, int stream, int mode)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int err = snd_pcm_hw_open_subdevice(handlep, card, device, subdevice, stream, mode);
 | 
						int err = snd_pcm_hw_open_subdevice(pcmp, card, device, subdevice, stream, mode);
 | 
				
			||||||
	if (err < 0)
 | 
						if (err < 0)
 | 
				
			||||||
		return err;
 | 
							return err;
 | 
				
			||||||
	if (name)
 | 
						if (name)
 | 
				
			||||||
		(*handlep)->name = strdup(name);
 | 
							(*pcmp)->name = strdup(name);
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -114,11 +114,6 @@ static int snd_pcm_linear_params(snd_pcm_t *pcm, snd_pcm_params_t * params)
 | 
				
			||||||
		params->fail_reason = SND_PCM_PARAMS_FAIL_INVAL;
 | 
							params->fail_reason = SND_PCM_PARAMS_FAIL_INVAL;
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if (slave->mmap_data) {
 | 
					 | 
				
			||||||
		err = snd_pcm_munmap_data(slave);
 | 
					 | 
				
			||||||
		if (err < 0)
 | 
					 | 
				
			||||||
			return err;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	linear->cformat = params->format.sfmt;
 | 
						linear->cformat = params->format.sfmt;
 | 
				
			||||||
	linear->cxfer_mode = params->xfer_mode;
 | 
						linear->cxfer_mode = params->xfer_mode;
 | 
				
			||||||
	linear->cmmap_shape = params->mmap_shape;
 | 
						linear->cmmap_shape = params->mmap_shape;
 | 
				
			||||||
| 
						 | 
					@ -129,10 +124,6 @@ static int snd_pcm_linear_params(snd_pcm_t *pcm, snd_pcm_params_t * params)
 | 
				
			||||||
	params->format.sfmt = linear->cformat;
 | 
						params->format.sfmt = linear->cformat;
 | 
				
			||||||
	params->xfer_mode = linear->cxfer_mode;
 | 
						params->xfer_mode = linear->cxfer_mode;
 | 
				
			||||||
	params->mmap_shape = linear->cmmap_shape;
 | 
						params->mmap_shape = linear->cmmap_shape;
 | 
				
			||||||
	if (slave->valid_setup) {
 | 
					 | 
				
			||||||
		int r = snd_pcm_mmap_data(slave, NULL);
 | 
					 | 
				
			||||||
		assert(r >= 0);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return err;
 | 
						return err;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -244,7 +235,7 @@ static void snd_pcm_linear_dump(snd_pcm_t *pcm, FILE *fp)
 | 
				
			||||||
	snd_pcm_dump(linear->plug.slave, fp);
 | 
						snd_pcm_dump(linear->plug.slave, fp);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct snd_pcm_ops snd_pcm_linear_ops = {
 | 
					snd_pcm_ops_t snd_pcm_linear_ops = {
 | 
				
			||||||
	close: snd_pcm_plugin_close,
 | 
						close: snd_pcm_plugin_close,
 | 
				
			||||||
	info: snd_pcm_plugin_info,
 | 
						info: snd_pcm_plugin_info,
 | 
				
			||||||
	params_info: snd_pcm_linear_params_info,
 | 
						params_info: snd_pcm_linear_params_info,
 | 
				
			||||||
| 
						 | 
					@ -256,20 +247,15 @@ struct snd_pcm_ops snd_pcm_linear_ops = {
 | 
				
			||||||
	dump: snd_pcm_linear_dump,
 | 
						dump: snd_pcm_linear_dump,
 | 
				
			||||||
	nonblock: snd_pcm_plugin_nonblock,
 | 
						nonblock: snd_pcm_plugin_nonblock,
 | 
				
			||||||
	async: snd_pcm_plugin_async,
 | 
						async: snd_pcm_plugin_async,
 | 
				
			||||||
	mmap_status: snd_pcm_plugin_mmap_status,
 | 
						mmap: snd_pcm_plugin_mmap,
 | 
				
			||||||
	mmap_control: snd_pcm_plugin_mmap_control,
 | 
						munmap: snd_pcm_plugin_munmap,
 | 
				
			||||||
	mmap_data: snd_pcm_plugin_mmap_data,
 | 
					 | 
				
			||||||
	munmap_status: snd_pcm_plugin_munmap_status,
 | 
					 | 
				
			||||||
	munmap_control: snd_pcm_plugin_munmap_control,
 | 
					 | 
				
			||||||
	munmap_data: snd_pcm_plugin_munmap_data,
 | 
					 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int snd_pcm_linear_open(snd_pcm_t **handlep, char *name, int sformat, snd_pcm_t *slave, int close_slave)
 | 
					int snd_pcm_linear_open(snd_pcm_t **pcmp, char *name, int sformat, snd_pcm_t *slave, int close_slave)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	snd_pcm_t *handle;
 | 
						snd_pcm_t *pcm;
 | 
				
			||||||
	snd_pcm_linear_t *linear;
 | 
						snd_pcm_linear_t *linear;
 | 
				
			||||||
	int err;
 | 
						assert(pcmp && slave);
 | 
				
			||||||
	assert(handlep && slave);
 | 
					 | 
				
			||||||
	if (snd_pcm_format_linear(sformat) != 1)
 | 
						if (snd_pcm_format_linear(sformat) != 1)
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
	linear = calloc(1, sizeof(snd_pcm_linear_t));
 | 
						linear = calloc(1, sizeof(snd_pcm_linear_t));
 | 
				
			||||||
| 
						 | 
					@ -282,27 +268,25 @@ int snd_pcm_linear_open(snd_pcm_t **handlep, char *name, int sformat, snd_pcm_t
 | 
				
			||||||
	linear->plug.slave = slave;
 | 
						linear->plug.slave = slave;
 | 
				
			||||||
	linear->plug.close_slave = close_slave;
 | 
						linear->plug.close_slave = close_slave;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	handle = calloc(1, sizeof(snd_pcm_t));
 | 
						pcm = calloc(1, sizeof(snd_pcm_t));
 | 
				
			||||||
	if (!handle) {
 | 
						if (!pcm) {
 | 
				
			||||||
		free(linear);
 | 
							free(linear);
 | 
				
			||||||
		return -ENOMEM;
 | 
							return -ENOMEM;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if (name)
 | 
						if (name)
 | 
				
			||||||
		handle->name = strdup(name);
 | 
							pcm->name = strdup(name);
 | 
				
			||||||
	handle->type = SND_PCM_TYPE_LINEAR;
 | 
						pcm->type = SND_PCM_TYPE_LINEAR;
 | 
				
			||||||
	handle->stream = slave->stream;
 | 
						pcm->stream = slave->stream;
 | 
				
			||||||
	handle->ops = &snd_pcm_linear_ops;
 | 
						pcm->mode = slave->mode;
 | 
				
			||||||
	handle->op_arg = handle;
 | 
						pcm->ops = &snd_pcm_linear_ops;
 | 
				
			||||||
	handle->fast_ops = &snd_pcm_plugin_fast_ops;
 | 
						pcm->op_arg = pcm;
 | 
				
			||||||
	handle->fast_op_arg = handle;
 | 
						pcm->fast_ops = &snd_pcm_plugin_fast_ops;
 | 
				
			||||||
	handle->mode = slave->mode;
 | 
						pcm->fast_op_arg = pcm;
 | 
				
			||||||
	handle->private = linear;
 | 
						pcm->private = linear;
 | 
				
			||||||
	err = snd_pcm_init(handle);
 | 
						pcm->poll_fd = slave->poll_fd;
 | 
				
			||||||
	if (err < 0) {
 | 
						pcm->hw_ptr = &linear->plug.hw_ptr;
 | 
				
			||||||
		snd_pcm_close(handle);
 | 
						pcm->appl_ptr = &linear->plug.appl_ptr;
 | 
				
			||||||
		return err;
 | 
						*pcmp = pcm;
 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	*handlep = handle;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -32,7 +32,7 @@
 | 
				
			||||||
#define ERR(args...) snd_pcm_error(__FILE__, __LINE__, __FUNCTION__, ##args)
 | 
					#define ERR(args...) snd_pcm_error(__FILE__, __LINE__, __FUNCTION__, ##args)
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct snd_pcm_ops {
 | 
					typedef struct {
 | 
				
			||||||
	int (*close)(snd_pcm_t *pcm);
 | 
						int (*close)(snd_pcm_t *pcm);
 | 
				
			||||||
	int (*nonblock)(snd_pcm_t *pcm, int nonblock);
 | 
						int (*nonblock)(snd_pcm_t *pcm, int nonblock);
 | 
				
			||||||
	int (*async)(snd_pcm_t *pcm, int sig, pid_t pid);
 | 
						int (*async)(snd_pcm_t *pcm, int sig, pid_t pid);
 | 
				
			||||||
| 
						 | 
					@ -44,15 +44,11 @@ struct snd_pcm_ops {
 | 
				
			||||||
	int (*channel_params)(snd_pcm_t *pcm, snd_pcm_channel_params_t *params);
 | 
						int (*channel_params)(snd_pcm_t *pcm, snd_pcm_channel_params_t *params);
 | 
				
			||||||
	int (*channel_setup)(snd_pcm_t *pcm, snd_pcm_channel_setup_t *setup);
 | 
						int (*channel_setup)(snd_pcm_t *pcm, snd_pcm_channel_setup_t *setup);
 | 
				
			||||||
	void (*dump)(snd_pcm_t *pcm, FILE *fp);
 | 
						void (*dump)(snd_pcm_t *pcm, FILE *fp);
 | 
				
			||||||
	int (*mmap_status)(snd_pcm_t *pcm);
 | 
						int (*mmap)(snd_pcm_t *pcm);
 | 
				
			||||||
	int (*mmap_control)(snd_pcm_t *pcm);
 | 
						int (*munmap)(snd_pcm_t *pcm);
 | 
				
			||||||
	int (*mmap_data)(snd_pcm_t *pcm);
 | 
					} snd_pcm_ops_t;
 | 
				
			||||||
	int (*munmap_status)(snd_pcm_t *pcm);
 | 
					 | 
				
			||||||
	int (*munmap_control)(snd_pcm_t *pcm);
 | 
					 | 
				
			||||||
	int (*munmap_data)(snd_pcm_t *pcm);
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct snd_pcm_fast_ops {
 | 
					typedef struct {
 | 
				
			||||||
	int (*status)(snd_pcm_t *pcm, snd_pcm_status_t *status);
 | 
						int (*status)(snd_pcm_t *pcm, snd_pcm_status_t *status);
 | 
				
			||||||
	int (*prepare)(snd_pcm_t *pcm);
 | 
						int (*prepare)(snd_pcm_t *pcm);
 | 
				
			||||||
	int (*start)(snd_pcm_t *pcm);
 | 
						int (*start)(snd_pcm_t *pcm);
 | 
				
			||||||
| 
						 | 
					@ -66,43 +62,55 @@ struct snd_pcm_fast_ops {
 | 
				
			||||||
	ssize_t (*writen)(snd_pcm_t *pcm, void **bufs, size_t size);
 | 
						ssize_t (*writen)(snd_pcm_t *pcm, void **bufs, size_t size);
 | 
				
			||||||
	ssize_t (*readi)(snd_pcm_t *pcm, void *buffer, size_t size);
 | 
						ssize_t (*readi)(snd_pcm_t *pcm, void *buffer, size_t size);
 | 
				
			||||||
	ssize_t (*readn)(snd_pcm_t *pcm, void **bufs, size_t size);
 | 
						ssize_t (*readn)(snd_pcm_t *pcm, void **bufs, size_t size);
 | 
				
			||||||
	int (*poll_descriptor)(snd_pcm_t *pcm);
 | 
					 | 
				
			||||||
	int (*channels_mask)(snd_pcm_t *pcm, bitset_t *cmask);
 | 
						int (*channels_mask)(snd_pcm_t *pcm, bitset_t *cmask);
 | 
				
			||||||
	ssize_t (*avail_update)(snd_pcm_t *pcm);
 | 
						ssize_t (*avail_update)(snd_pcm_t *pcm);
 | 
				
			||||||
	ssize_t (*mmap_forward)(snd_pcm_t *pcm, size_t size);
 | 
						ssize_t (*mmap_forward)(snd_pcm_t *pcm, size_t size);
 | 
				
			||||||
};
 | 
					} snd_pcm_fast_ops_t;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef struct {
 | 
				
			||||||
 | 
						unsigned int index;
 | 
				
			||||||
 | 
						enum { SND_PCM_MMAP_KERNEL, SND_PCM_MMAP_USER } type;
 | 
				
			||||||
 | 
						void *addr;
 | 
				
			||||||
 | 
						size_t size;
 | 
				
			||||||
 | 
						union {
 | 
				
			||||||
 | 
							struct {
 | 
				
			||||||
 | 
								int shmid;
 | 
				
			||||||
 | 
							} user;
 | 
				
			||||||
 | 
							struct {
 | 
				
			||||||
 | 
								int fd;
 | 
				
			||||||
 | 
							} kernel;
 | 
				
			||||||
 | 
						} u;
 | 
				
			||||||
 | 
					} snd_pcm_mmap_info_t;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct snd_pcm {
 | 
					struct snd_pcm {
 | 
				
			||||||
	char *name;
 | 
						char *name;
 | 
				
			||||||
	snd_pcm_type_t type;
 | 
						snd_pcm_type_t type;
 | 
				
			||||||
	int stream;
 | 
						int stream;
 | 
				
			||||||
	int mode;
 | 
						int mode;
 | 
				
			||||||
 | 
						int poll_fd;
 | 
				
			||||||
	int valid_setup;
 | 
						int valid_setup;
 | 
				
			||||||
	snd_pcm_setup_t setup;
 | 
						snd_pcm_setup_t setup;
 | 
				
			||||||
	size_t bits_per_sample;
 | 
						size_t bits_per_sample;
 | 
				
			||||||
	size_t bits_per_frame;
 | 
						size_t bits_per_frame;
 | 
				
			||||||
	volatile snd_pcm_mmap_status_t *mmap_status;
 | 
						size_t *appl_ptr;
 | 
				
			||||||
	snd_pcm_mmap_control_t *mmap_control;
 | 
						volatile size_t *hw_ptr;
 | 
				
			||||||
	void *mmap_data;
 | 
						int mmap_auto;
 | 
				
			||||||
 | 
						size_t mmap_info_count;
 | 
				
			||||||
 | 
						snd_pcm_mmap_info_t *mmap_info;
 | 
				
			||||||
	snd_pcm_channel_area_t *running_areas;
 | 
						snd_pcm_channel_area_t *running_areas;
 | 
				
			||||||
	snd_pcm_channel_area_t *stopped_areas;
 | 
						snd_pcm_channel_area_t *stopped_areas;
 | 
				
			||||||
	struct snd_pcm_ops *ops;
 | 
						snd_pcm_ops_t *ops;
 | 
				
			||||||
	struct snd_pcm_fast_ops *fast_ops;
 | 
						snd_pcm_fast_ops_t *fast_ops;
 | 
				
			||||||
	snd_pcm_t *op_arg;
 | 
						snd_pcm_t *op_arg;
 | 
				
			||||||
	snd_pcm_t *fast_op_arg;
 | 
						snd_pcm_t *fast_op_arg;
 | 
				
			||||||
	void *private;
 | 
						void *private;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int snd_pcm_init(snd_pcm_t *pcm);
 | 
					 | 
				
			||||||
void snd_pcm_areas_from_buf(snd_pcm_t *pcm, snd_pcm_channel_area_t *areas, void *buf);
 | 
					void snd_pcm_areas_from_buf(snd_pcm_t *pcm, snd_pcm_channel_area_t *areas, void *buf);
 | 
				
			||||||
void snd_pcm_areas_from_bufs(snd_pcm_t *pcm, snd_pcm_channel_area_t *areas, void **bufs);
 | 
					void snd_pcm_areas_from_bufs(snd_pcm_t *pcm, snd_pcm_channel_area_t *areas, void **bufs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int snd_pcm_mmap_status(snd_pcm_t *pcm, volatile snd_pcm_mmap_status_t **status);
 | 
					int snd_pcm_mmap(snd_pcm_t *pcm);
 | 
				
			||||||
int snd_pcm_mmap_control(snd_pcm_t *pcm, snd_pcm_mmap_control_t **control);
 | 
					int snd_pcm_munmap(snd_pcm_t *pcm);
 | 
				
			||||||
int snd_pcm_mmap_data(snd_pcm_t *pcm, void **buffer);
 | 
					 | 
				
			||||||
int snd_pcm_munmap_status(snd_pcm_t *pcm);
 | 
					 | 
				
			||||||
int snd_pcm_munmap_control(snd_pcm_t *pcm);
 | 
					 | 
				
			||||||
int snd_pcm_munmap_data(snd_pcm_t *pcm);
 | 
					 | 
				
			||||||
int snd_pcm_mmap_ready(snd_pcm_t *pcm);
 | 
					int snd_pcm_mmap_ready(snd_pcm_t *pcm);
 | 
				
			||||||
ssize_t snd_pcm_mmap_appl_ptr(snd_pcm_t *pcm, off_t offset);
 | 
					ssize_t snd_pcm_mmap_appl_ptr(snd_pcm_t *pcm, off_t offset);
 | 
				
			||||||
void snd_pcm_mmap_appl_backward(snd_pcm_t *pcm, size_t frames);
 | 
					void snd_pcm_mmap_appl_backward(snd_pcm_t *pcm, size_t frames);
 | 
				
			||||||
| 
						 | 
					@ -130,7 +138,7 @@ ssize_t snd_pcm_write_mmap(snd_pcm_t *pcm, size_t size);
 | 
				
			||||||
static inline size_t snd_pcm_mmap_playback_avail(snd_pcm_t *pcm)
 | 
					static inline size_t snd_pcm_mmap_playback_avail(snd_pcm_t *pcm)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	ssize_t avail;
 | 
						ssize_t avail;
 | 
				
			||||||
	avail = pcm->mmap_status->hw_ptr + pcm->setup.buffer_size - pcm->mmap_control->appl_ptr;
 | 
						avail = *pcm->hw_ptr + pcm->setup.buffer_size - *pcm->appl_ptr;
 | 
				
			||||||
	if (avail < 0)
 | 
						if (avail < 0)
 | 
				
			||||||
		avail += pcm->setup.boundary;
 | 
							avail += pcm->setup.boundary;
 | 
				
			||||||
	return avail;
 | 
						return avail;
 | 
				
			||||||
| 
						 | 
					@ -139,7 +147,7 @@ static inline size_t snd_pcm_mmap_playback_avail(snd_pcm_t *pcm)
 | 
				
			||||||
static inline size_t snd_pcm_mmap_capture_avail(snd_pcm_t *pcm)
 | 
					static inline size_t snd_pcm_mmap_capture_avail(snd_pcm_t *pcm)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	ssize_t avail;
 | 
						ssize_t avail;
 | 
				
			||||||
	avail = pcm->mmap_status->hw_ptr - pcm->mmap_control->appl_ptr;
 | 
						avail = *pcm->hw_ptr - *pcm->appl_ptr;
 | 
				
			||||||
	if (avail < 0)
 | 
						if (avail < 0)
 | 
				
			||||||
		avail += pcm->setup.boundary;
 | 
							avail += pcm->setup.boundary;
 | 
				
			||||||
	return avail;
 | 
						return avail;
 | 
				
			||||||
| 
						 | 
					@ -156,7 +164,7 @@ static inline size_t snd_pcm_mmap_avail(snd_pcm_t *pcm)
 | 
				
			||||||
static inline ssize_t snd_pcm_mmap_playback_hw_avail(snd_pcm_t *pcm)
 | 
					static inline ssize_t snd_pcm_mmap_playback_hw_avail(snd_pcm_t *pcm)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	ssize_t avail;
 | 
						ssize_t avail;
 | 
				
			||||||
	avail = pcm->mmap_status->hw_ptr + pcm->setup.buffer_size - pcm->mmap_control->appl_ptr;
 | 
						avail = *pcm->hw_ptr + pcm->setup.buffer_size - *pcm->appl_ptr;
 | 
				
			||||||
	if (avail < 0)
 | 
						if (avail < 0)
 | 
				
			||||||
		avail += pcm->setup.boundary;
 | 
							avail += pcm->setup.boundary;
 | 
				
			||||||
	return pcm->setup.buffer_size - avail;
 | 
						return pcm->setup.buffer_size - avail;
 | 
				
			||||||
| 
						 | 
					@ -165,7 +173,7 @@ static inline ssize_t snd_pcm_mmap_playback_hw_avail(snd_pcm_t *pcm)
 | 
				
			||||||
static inline ssize_t snd_pcm_mmap_capture_hw_avail(snd_pcm_t *pcm)
 | 
					static inline ssize_t snd_pcm_mmap_capture_hw_avail(snd_pcm_t *pcm)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	ssize_t avail;
 | 
						ssize_t avail;
 | 
				
			||||||
	avail = pcm->mmap_status->hw_ptr - pcm->mmap_control->appl_ptr;
 | 
						avail = *pcm->hw_ptr - *pcm->appl_ptr;
 | 
				
			||||||
	if (avail < 0)
 | 
						if (avail < 0)
 | 
				
			||||||
		avail += pcm->setup.boundary;
 | 
							avail += pcm->setup.boundary;
 | 
				
			||||||
	return pcm->setup.buffer_size - avail;
 | 
						return pcm->setup.buffer_size - avail;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -36,12 +36,11 @@ snd_pcm_channel_area_t *snd_pcm_mmap_areas(snd_pcm_t *pcm)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
size_t snd_pcm_mmap_playback_xfer(snd_pcm_t *pcm, size_t frames)
 | 
					size_t snd_pcm_mmap_playback_xfer(snd_pcm_t *pcm, size_t frames)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	snd_pcm_mmap_control_t *control = pcm->mmap_control;
 | 
					 | 
				
			||||||
	size_t cont;
 | 
						size_t cont;
 | 
				
			||||||
	size_t avail = snd_pcm_mmap_playback_avail(pcm);
 | 
						size_t avail = snd_pcm_mmap_playback_avail(pcm);
 | 
				
			||||||
	if (avail < frames)
 | 
						if (avail < frames)
 | 
				
			||||||
		frames = avail;
 | 
							frames = avail;
 | 
				
			||||||
	cont = pcm->setup.buffer_size - control->appl_ptr % pcm->setup.buffer_size;
 | 
						cont = pcm->setup.buffer_size - *pcm->appl_ptr % pcm->setup.buffer_size;
 | 
				
			||||||
	if (cont < frames)
 | 
						if (cont < frames)
 | 
				
			||||||
		frames = cont;
 | 
							frames = cont;
 | 
				
			||||||
	return frames;
 | 
						return frames;
 | 
				
			||||||
| 
						 | 
					@ -49,12 +48,11 @@ size_t snd_pcm_mmap_playback_xfer(snd_pcm_t *pcm, size_t frames)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
size_t snd_pcm_mmap_capture_xfer(snd_pcm_t *pcm, size_t frames)
 | 
					size_t snd_pcm_mmap_capture_xfer(snd_pcm_t *pcm, size_t frames)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	snd_pcm_mmap_control_t *control = pcm->mmap_control;
 | 
					 | 
				
			||||||
	size_t cont;
 | 
						size_t cont;
 | 
				
			||||||
	size_t avail = snd_pcm_mmap_capture_avail(pcm);
 | 
						size_t avail = snd_pcm_mmap_capture_avail(pcm);
 | 
				
			||||||
	if (avail < frames)
 | 
						if (avail < frames)
 | 
				
			||||||
		frames = avail;
 | 
							frames = avail;
 | 
				
			||||||
	cont = pcm->setup.buffer_size - control->appl_ptr % pcm->setup.buffer_size;
 | 
						cont = pcm->setup.buffer_size - *pcm->appl_ptr % pcm->setup.buffer_size;
 | 
				
			||||||
	if (cont < frames)
 | 
						if (cont < frames)
 | 
				
			||||||
		frames = cont;
 | 
							frames = cont;
 | 
				
			||||||
	return frames;
 | 
						return frames;
 | 
				
			||||||
| 
						 | 
					@ -63,7 +61,6 @@ size_t snd_pcm_mmap_capture_xfer(snd_pcm_t *pcm, size_t frames)
 | 
				
			||||||
size_t snd_pcm_mmap_xfer(snd_pcm_t *pcm, size_t frames)
 | 
					size_t snd_pcm_mmap_xfer(snd_pcm_t *pcm, size_t frames)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
        assert(pcm);
 | 
					        assert(pcm);
 | 
				
			||||||
	assert(pcm->mmap_status && pcm->mmap_control);
 | 
					 | 
				
			||||||
	if (pcm->stream == SND_PCM_STREAM_PLAYBACK)
 | 
						if (pcm->stream == SND_PCM_STREAM_PLAYBACK)
 | 
				
			||||||
		return snd_pcm_mmap_playback_xfer(pcm, frames);
 | 
							return snd_pcm_mmap_playback_xfer(pcm, frames);
 | 
				
			||||||
	else
 | 
						else
 | 
				
			||||||
| 
						 | 
					@ -73,51 +70,49 @@ size_t snd_pcm_mmap_xfer(snd_pcm_t *pcm, size_t frames)
 | 
				
			||||||
size_t snd_pcm_mmap_offset(snd_pcm_t *pcm)
 | 
					size_t snd_pcm_mmap_offset(snd_pcm_t *pcm)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
        assert(pcm);
 | 
					        assert(pcm);
 | 
				
			||||||
	assert(pcm->mmap_control);
 | 
						return *pcm->appl_ptr % pcm->setup.buffer_size;
 | 
				
			||||||
	return pcm->mmap_control->appl_ptr % pcm->setup.buffer_size;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
size_t snd_pcm_mmap_hw_offset(snd_pcm_t *pcm)
 | 
					size_t snd_pcm_mmap_hw_offset(snd_pcm_t *pcm)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
        assert(pcm);
 | 
					        assert(pcm);
 | 
				
			||||||
	assert(pcm->mmap_status);
 | 
						return *pcm->hw_ptr % pcm->setup.buffer_size;
 | 
				
			||||||
	return pcm->mmap_status->hw_ptr % pcm->setup.buffer_size;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void snd_pcm_mmap_appl_backward(snd_pcm_t *pcm, size_t frames)
 | 
					void snd_pcm_mmap_appl_backward(snd_pcm_t *pcm, size_t frames)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	ssize_t appl_ptr = pcm->mmap_control->appl_ptr;
 | 
						ssize_t appl_ptr = *pcm->appl_ptr;
 | 
				
			||||||
	appl_ptr -= frames;
 | 
						appl_ptr -= frames;
 | 
				
			||||||
	if (appl_ptr < 0)
 | 
						if (appl_ptr < 0)
 | 
				
			||||||
		appl_ptr += pcm->setup.boundary;
 | 
							appl_ptr += pcm->setup.boundary;
 | 
				
			||||||
	pcm->mmap_control->appl_ptr = appl_ptr;
 | 
						*pcm->appl_ptr = appl_ptr;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void snd_pcm_mmap_appl_forward(snd_pcm_t *pcm, size_t frames)
 | 
					void snd_pcm_mmap_appl_forward(snd_pcm_t *pcm, size_t frames)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	size_t appl_ptr = pcm->mmap_control->appl_ptr;
 | 
						size_t appl_ptr = *pcm->appl_ptr;
 | 
				
			||||||
	appl_ptr += frames;
 | 
						appl_ptr += frames;
 | 
				
			||||||
	if (appl_ptr >= pcm->setup.boundary)
 | 
						if (appl_ptr >= pcm->setup.boundary)
 | 
				
			||||||
		appl_ptr -= pcm->setup.boundary;
 | 
							appl_ptr -= pcm->setup.boundary;
 | 
				
			||||||
	pcm->mmap_control->appl_ptr = appl_ptr;
 | 
						*pcm->appl_ptr = appl_ptr;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void snd_pcm_mmap_hw_backward(snd_pcm_t *pcm, size_t frames)
 | 
					void snd_pcm_mmap_hw_backward(snd_pcm_t *pcm, size_t frames)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	ssize_t hw_ptr = pcm->mmap_status->hw_ptr;
 | 
						ssize_t hw_ptr = *pcm->hw_ptr;
 | 
				
			||||||
	hw_ptr -= frames;
 | 
						hw_ptr -= frames;
 | 
				
			||||||
	if (hw_ptr < 0)
 | 
						if (hw_ptr < 0)
 | 
				
			||||||
		hw_ptr += pcm->setup.boundary;
 | 
							hw_ptr += pcm->setup.boundary;
 | 
				
			||||||
	pcm->mmap_status->hw_ptr = hw_ptr;
 | 
						*pcm->hw_ptr = hw_ptr;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void snd_pcm_mmap_hw_forward(snd_pcm_t *pcm, size_t frames)
 | 
					void snd_pcm_mmap_hw_forward(snd_pcm_t *pcm, size_t frames)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	size_t hw_ptr = pcm->mmap_status->hw_ptr;
 | 
						size_t hw_ptr = *pcm->hw_ptr;
 | 
				
			||||||
	hw_ptr += frames;
 | 
						hw_ptr += frames;
 | 
				
			||||||
	if (hw_ptr >= pcm->setup.boundary)
 | 
						if (hw_ptr >= pcm->setup.boundary)
 | 
				
			||||||
		hw_ptr -= pcm->setup.boundary;
 | 
							hw_ptr -= pcm->setup.boundary;
 | 
				
			||||||
	pcm->mmap_status->hw_ptr = hw_ptr;
 | 
						*pcm->hw_ptr = hw_ptr;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ssize_t snd_pcm_mmap_write_areas(snd_pcm_t *pcm,
 | 
					ssize_t snd_pcm_mmap_write_areas(snd_pcm_t *pcm,
 | 
				
			||||||
| 
						 | 
					@ -216,32 +211,6 @@ ssize_t snd_pcm_mmap_readn(snd_pcm_t *pcm, void **bufs, size_t size)
 | 
				
			||||||
				  snd_pcm_mmap_read_areas);
 | 
									  snd_pcm_mmap_read_areas);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int snd_pcm_mmap_status(snd_pcm_t *pcm, volatile snd_pcm_mmap_status_t **status)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	int err;
 | 
					 | 
				
			||||||
	assert(pcm);
 | 
					 | 
				
			||||||
	if (!pcm->mmap_status) {
 | 
					 | 
				
			||||||
		if ((err = pcm->ops->mmap_status(pcm->op_arg)) < 0)
 | 
					 | 
				
			||||||
			return err;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if (status)
 | 
					 | 
				
			||||||
		*status = pcm->mmap_status;
 | 
					 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int snd_pcm_mmap_control(snd_pcm_t *pcm, snd_pcm_mmap_control_t **control)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	int err;
 | 
					 | 
				
			||||||
	assert(pcm);
 | 
					 | 
				
			||||||
	if (!pcm->mmap_control) {
 | 
					 | 
				
			||||||
		if ((err = pcm->ops->mmap_control(pcm->op_arg)) < 0)
 | 
					 | 
				
			||||||
			return err;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if (control)
 | 
					 | 
				
			||||||
		*control = pcm->mmap_control;
 | 
					 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int snd_pcm_mmap_get_areas(snd_pcm_t *pcm, snd_pcm_channel_area_t *stopped_areas, snd_pcm_channel_area_t *running_areas)
 | 
					int snd_pcm_mmap_get_areas(snd_pcm_t *pcm, snd_pcm_channel_area_t *stopped_areas, snd_pcm_channel_area_t *running_areas)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	snd_pcm_channel_setup_t setup;
 | 
						snd_pcm_channel_setup_t setup;
 | 
				
			||||||
| 
						 | 
					@ -249,7 +218,7 @@ int snd_pcm_mmap_get_areas(snd_pcm_t *pcm, snd_pcm_channel_area_t *stopped_areas
 | 
				
			||||||
	unsigned int channel;
 | 
						unsigned int channel;
 | 
				
			||||||
	int err;
 | 
						int err;
 | 
				
			||||||
	assert(pcm);
 | 
						assert(pcm);
 | 
				
			||||||
	assert(pcm->mmap_data);
 | 
						assert(pcm->mmap_info);
 | 
				
			||||||
	if (!pcm->running_areas) {
 | 
						if (!pcm->running_areas) {
 | 
				
			||||||
		r = calloc(pcm->setup.format.channels, sizeof(*r));
 | 
							r = calloc(pcm->setup.format.channels, sizeof(*r));
 | 
				
			||||||
		s = calloc(pcm->setup.format.channels, sizeof(*s));
 | 
							s = calloc(pcm->setup.format.channels, sizeof(*s));
 | 
				
			||||||
| 
						 | 
					@ -274,75 +243,36 @@ int snd_pcm_mmap_get_areas(snd_pcm_t *pcm, snd_pcm_channel_area_t *stopped_areas
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int snd_pcm_mmap_data(snd_pcm_t *pcm, void **data)
 | 
					int snd_pcm_mmap(snd_pcm_t *pcm)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int err;
 | 
						int err;
 | 
				
			||||||
	assert(pcm);
 | 
						assert(pcm);
 | 
				
			||||||
	assert(pcm->valid_setup);
 | 
						assert(pcm->valid_setup);
 | 
				
			||||||
	if (pcm->mmap_data) {
 | 
						if (pcm->mmap_info)
 | 
				
			||||||
		if (data)
 | 
					 | 
				
			||||||
			*data = pcm->mmap_data;
 | 
					 | 
				
			||||||
		return 0;
 | 
							return 0;
 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if ((err = pcm->ops->mmap_data(pcm->op_arg)) < 0)
 | 
						if ((err = pcm->ops->mmap(pcm->op_arg)) < 0)
 | 
				
			||||||
		return err;
 | 
							return err;
 | 
				
			||||||
	if (data) 
 | 
					 | 
				
			||||||
		*data = pcm->mmap_data;
 | 
					 | 
				
			||||||
	err = snd_pcm_mmap_get_areas(pcm, NULL, NULL);
 | 
						err = snd_pcm_mmap_get_areas(pcm, NULL, NULL);
 | 
				
			||||||
	if (err < 0)
 | 
						if (err < 0)
 | 
				
			||||||
		return err;
 | 
							return err;
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int snd_pcm_munmap_status(snd_pcm_t *pcm)
 | 
					int snd_pcm_munmap(snd_pcm_t *pcm)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int err;
 | 
						int err;
 | 
				
			||||||
	assert(pcm);
 | 
						assert(pcm);
 | 
				
			||||||
	assert(pcm->mmap_status);
 | 
						assert(pcm->mmap_info);
 | 
				
			||||||
	if ((err = pcm->ops->munmap_status(pcm->op_arg)) < 0)
 | 
						if ((err = pcm->ops->munmap(pcm->op_arg)) < 0)
 | 
				
			||||||
		return err;
 | 
					 | 
				
			||||||
	pcm->mmap_status = 0;
 | 
					 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int snd_pcm_munmap_control(snd_pcm_t *pcm)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	int err;
 | 
					 | 
				
			||||||
	assert(pcm);
 | 
					 | 
				
			||||||
	assert(pcm->mmap_control);
 | 
					 | 
				
			||||||
	if ((err = pcm->ops->munmap_control(pcm->op_arg)) < 0)
 | 
					 | 
				
			||||||
		return err;
 | 
					 | 
				
			||||||
	pcm->mmap_control = 0;
 | 
					 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int snd_pcm_munmap_data(snd_pcm_t *pcm)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	int err;
 | 
					 | 
				
			||||||
	assert(pcm);
 | 
					 | 
				
			||||||
	assert(pcm->mmap_data);
 | 
					 | 
				
			||||||
	if ((err = pcm->ops->munmap_data(pcm->op_arg)) < 0)
 | 
					 | 
				
			||||||
		return err;
 | 
							return err;
 | 
				
			||||||
	free(pcm->stopped_areas);
 | 
						free(pcm->stopped_areas);
 | 
				
			||||||
	free(pcm->running_areas);
 | 
						free(pcm->running_areas);
 | 
				
			||||||
	pcm->stopped_areas = 0;
 | 
						pcm->stopped_areas = 0;
 | 
				
			||||||
	pcm->running_areas = 0;
 | 
						pcm->running_areas = 0;
 | 
				
			||||||
	pcm->mmap_data = 0;
 | 
					 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int snd_pcm_mmap(snd_pcm_t *pcm, void **data)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	return snd_pcm_mmap_data(pcm, data);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int snd_pcm_munmap(snd_pcm_t *pcm)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	return snd_pcm_munmap_data(pcm);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
ssize_t snd_pcm_write_mmap(snd_pcm_t *pcm, size_t size)
 | 
					ssize_t snd_pcm_write_mmap(snd_pcm_t *pcm, size_t size)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	size_t xfer = 0;
 | 
						size_t xfer = 0;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -276,11 +276,6 @@ static int snd_pcm_mulaw_params(snd_pcm_t *pcm, snd_pcm_params_t * params)
 | 
				
			||||||
		params->fail_reason = SND_PCM_PARAMS_FAIL_INVAL;
 | 
							params->fail_reason = SND_PCM_PARAMS_FAIL_INVAL;
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if (slave->mmap_data) {
 | 
					 | 
				
			||||||
		err = snd_pcm_munmap_data(slave);
 | 
					 | 
				
			||||||
		if (err < 0)
 | 
					 | 
				
			||||||
			return err;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	mulaw->cformat = params->format.sfmt;
 | 
						mulaw->cformat = params->format.sfmt;
 | 
				
			||||||
	mulaw->cxfer_mode = params->xfer_mode;
 | 
						mulaw->cxfer_mode = params->xfer_mode;
 | 
				
			||||||
	mulaw->cmmap_shape = params->mmap_shape;
 | 
						mulaw->cmmap_shape = params->mmap_shape;
 | 
				
			||||||
| 
						 | 
					@ -291,10 +286,6 @@ static int snd_pcm_mulaw_params(snd_pcm_t *pcm, snd_pcm_params_t * params)
 | 
				
			||||||
	params->format.sfmt = mulaw->cformat;
 | 
						params->format.sfmt = mulaw->cformat;
 | 
				
			||||||
	params->xfer_mode = mulaw->cxfer_mode;
 | 
						params->xfer_mode = mulaw->cxfer_mode;
 | 
				
			||||||
	params->mmap_shape = mulaw->cmmap_shape;
 | 
						params->mmap_shape = mulaw->cmmap_shape;
 | 
				
			||||||
 	if (slave->valid_setup) {
 | 
					 | 
				
			||||||
		int r = snd_pcm_mmap_data(slave, NULL);
 | 
					 | 
				
			||||||
		assert(r >= 0);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return err;
 | 
						return err;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -418,7 +409,7 @@ static void snd_pcm_mulaw_dump(snd_pcm_t *pcm, FILE *fp)
 | 
				
			||||||
	snd_pcm_dump(mulaw->plug.slave, fp);
 | 
						snd_pcm_dump(mulaw->plug.slave, fp);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct snd_pcm_ops snd_pcm_mulaw_ops = {
 | 
					snd_pcm_ops_t snd_pcm_mulaw_ops = {
 | 
				
			||||||
	close: snd_pcm_plugin_close,
 | 
						close: snd_pcm_plugin_close,
 | 
				
			||||||
	info: snd_pcm_plugin_info,
 | 
						info: snd_pcm_plugin_info,
 | 
				
			||||||
	params_info: snd_pcm_mulaw_params_info,
 | 
						params_info: snd_pcm_mulaw_params_info,
 | 
				
			||||||
| 
						 | 
					@ -430,20 +421,15 @@ struct snd_pcm_ops snd_pcm_mulaw_ops = {
 | 
				
			||||||
	dump: snd_pcm_mulaw_dump,
 | 
						dump: snd_pcm_mulaw_dump,
 | 
				
			||||||
	nonblock: snd_pcm_plugin_nonblock,
 | 
						nonblock: snd_pcm_plugin_nonblock,
 | 
				
			||||||
	async: snd_pcm_plugin_async,
 | 
						async: snd_pcm_plugin_async,
 | 
				
			||||||
	mmap_status: snd_pcm_plugin_mmap_status,
 | 
						mmap: snd_pcm_plugin_mmap,
 | 
				
			||||||
	mmap_control: snd_pcm_plugin_mmap_control,
 | 
						munmap: snd_pcm_plugin_munmap,
 | 
				
			||||||
	mmap_data: snd_pcm_plugin_mmap_data,
 | 
					 | 
				
			||||||
	munmap_status: snd_pcm_plugin_munmap_status,
 | 
					 | 
				
			||||||
	munmap_control: snd_pcm_plugin_munmap_control,
 | 
					 | 
				
			||||||
	munmap_data: snd_pcm_plugin_munmap_data,
 | 
					 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int snd_pcm_mulaw_open(snd_pcm_t **handlep, char *name, int sformat, snd_pcm_t *slave, int close_slave)
 | 
					int snd_pcm_mulaw_open(snd_pcm_t **pcmp, char *name, int sformat, snd_pcm_t *slave, int close_slave)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	snd_pcm_t *handle;
 | 
						snd_pcm_t *pcm;
 | 
				
			||||||
	snd_pcm_mulaw_t *mulaw;
 | 
						snd_pcm_mulaw_t *mulaw;
 | 
				
			||||||
	int err;
 | 
						assert(pcmp && slave);
 | 
				
			||||||
	assert(handlep && slave);
 | 
					 | 
				
			||||||
	if (snd_pcm_format_linear(sformat) != 1 &&
 | 
						if (snd_pcm_format_linear(sformat) != 1 &&
 | 
				
			||||||
	    sformat != SND_PCM_SFMT_MU_LAW)
 | 
						    sformat != SND_PCM_SFMT_MU_LAW)
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
| 
						 | 
					@ -457,27 +443,25 @@ int snd_pcm_mulaw_open(snd_pcm_t **handlep, char *name, int sformat, snd_pcm_t *
 | 
				
			||||||
	mulaw->plug.slave = slave;
 | 
						mulaw->plug.slave = slave;
 | 
				
			||||||
	mulaw->plug.close_slave = close_slave;
 | 
						mulaw->plug.close_slave = close_slave;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	handle = calloc(1, sizeof(snd_pcm_t));
 | 
						pcm = calloc(1, sizeof(snd_pcm_t));
 | 
				
			||||||
	if (!handle) {
 | 
						if (!pcm) {
 | 
				
			||||||
		free(mulaw);
 | 
							free(mulaw);
 | 
				
			||||||
		return -ENOMEM;
 | 
							return -ENOMEM;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if (name)
 | 
						if (name)
 | 
				
			||||||
		handle->name = strdup(name);
 | 
							pcm->name = strdup(name);
 | 
				
			||||||
	handle->type = SND_PCM_TYPE_MULAW;
 | 
						pcm->type = SND_PCM_TYPE_MULAW;
 | 
				
			||||||
	handle->stream = slave->stream;
 | 
						pcm->stream = slave->stream;
 | 
				
			||||||
	handle->ops = &snd_pcm_mulaw_ops;
 | 
						pcm->mode = slave->mode;
 | 
				
			||||||
	handle->op_arg = handle;
 | 
						pcm->ops = &snd_pcm_mulaw_ops;
 | 
				
			||||||
	handle->fast_ops = &snd_pcm_plugin_fast_ops;
 | 
						pcm->op_arg = pcm;
 | 
				
			||||||
	handle->fast_op_arg = handle;
 | 
						pcm->fast_ops = &snd_pcm_plugin_fast_ops;
 | 
				
			||||||
	handle->mode = slave->mode;
 | 
						pcm->fast_op_arg = pcm;
 | 
				
			||||||
	handle->private = mulaw;
 | 
						pcm->private = mulaw;
 | 
				
			||||||
	err = snd_pcm_init(handle);
 | 
						pcm->poll_fd = slave->poll_fd;
 | 
				
			||||||
	if (err < 0) {
 | 
						pcm->hw_ptr = &mulaw->plug.hw_ptr;
 | 
				
			||||||
		snd_pcm_close(handle);
 | 
						pcm->appl_ptr = &mulaw->plug.appl_ptr;
 | 
				
			||||||
		return err;
 | 
						*pcmp = pcm;
 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	*handlep = handle;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -152,6 +152,60 @@ static int snd_pcm_multi_params_info(snd_pcm_t *pcm, snd_pcm_params_info_t *info
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int snd_pcm_multi_mmap(snd_pcm_t *pcm)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						snd_pcm_multi_t *multi = pcm->private;
 | 
				
			||||||
 | 
						unsigned int i;
 | 
				
			||||||
 | 
						size_t count = 0;
 | 
				
			||||||
 | 
						for (i = 0; i < multi->slaves_count; ++i) {
 | 
				
			||||||
 | 
							snd_pcm_t *slave = multi->slaves[i].pcm;
 | 
				
			||||||
 | 
							snd_pcm_setup_t *setup;
 | 
				
			||||||
 | 
							int err = snd_pcm_mmap(slave);
 | 
				
			||||||
 | 
							if (err < 0)
 | 
				
			||||||
 | 
								return err;
 | 
				
			||||||
 | 
							count += slave->mmap_info_count;
 | 
				
			||||||
 | 
							setup = &slave->setup;
 | 
				
			||||||
 | 
							if (pcm->stream == SND_PCM_STREAM_PLAYBACK) {
 | 
				
			||||||
 | 
								snd_pcm_channel_area_t r[setup->format.channels];
 | 
				
			||||||
 | 
								snd_pcm_channel_area_t s[setup->format.channels];
 | 
				
			||||||
 | 
								err = snd_pcm_mmap_get_areas(slave, s, r);
 | 
				
			||||||
 | 
								if (err < 0)
 | 
				
			||||||
 | 
									return err;
 | 
				
			||||||
 | 
								err = snd_pcm_areas_silence(s, 0, setup->format.channels, setup->buffer_size, setup->format.sfmt);
 | 
				
			||||||
 | 
								if (err < 0)
 | 
				
			||||||
 | 
									return err;
 | 
				
			||||||
 | 
								err = snd_pcm_areas_silence(r, 0, setup->format.channels, setup->buffer_size, setup->format.sfmt);
 | 
				
			||||||
 | 
								if (err < 0)
 | 
				
			||||||
 | 
									return err;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						pcm->mmap_info_count = count;
 | 
				
			||||||
 | 
						pcm->mmap_info = malloc(count * sizeof(*pcm->mmap_info));
 | 
				
			||||||
 | 
						count = 0;
 | 
				
			||||||
 | 
						for (i = 0; i < multi->slaves_count; ++i) {
 | 
				
			||||||
 | 
							snd_pcm_t *slave = multi->slaves[i].pcm;
 | 
				
			||||||
 | 
							memcpy(&pcm->mmap_info[count], slave->mmap_info, slave->mmap_info_count * sizeof(*pcm->mmap_info));
 | 
				
			||||||
 | 
							count += slave->mmap_info_count;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int snd_pcm_multi_munmap(snd_pcm_t *pcm)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						snd_pcm_multi_t *multi = pcm->private;
 | 
				
			||||||
 | 
						unsigned int i;
 | 
				
			||||||
 | 
						for (i = 0; i < multi->slaves_count; ++i) {
 | 
				
			||||||
 | 
							snd_pcm_t *slave = multi->slaves[i].pcm;
 | 
				
			||||||
 | 
							int err = snd_pcm_munmap(slave);
 | 
				
			||||||
 | 
							if (err < 0)
 | 
				
			||||||
 | 
								return err;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						pcm->mmap_info_count = 0;
 | 
				
			||||||
 | 
						free(pcm->mmap_info);
 | 
				
			||||||
 | 
						pcm->mmap_info = 0;
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
							
 | 
				
			||||||
static int snd_pcm_multi_params(snd_pcm_t *pcm, snd_pcm_params_t *params)
 | 
					static int snd_pcm_multi_params(snd_pcm_t *pcm, snd_pcm_params_t *params)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	snd_pcm_multi_t *multi = pcm->private;
 | 
						snd_pcm_multi_t *multi = pcm->private;
 | 
				
			||||||
| 
						 | 
					@ -166,11 +220,6 @@ static int snd_pcm_multi_params(snd_pcm_t *pcm, snd_pcm_params_t *params)
 | 
				
			||||||
	p = *params;
 | 
						p = *params;
 | 
				
			||||||
	for (i = 0; i < multi->slaves_count; ++i) {
 | 
						for (i = 0; i < multi->slaves_count; ++i) {
 | 
				
			||||||
		snd_pcm_t *slave = multi->slaves[i].pcm;
 | 
							snd_pcm_t *slave = multi->slaves[i].pcm;
 | 
				
			||||||
		if (slave->mmap_data) {
 | 
					 | 
				
			||||||
			err = snd_pcm_munmap_data(slave);
 | 
					 | 
				
			||||||
			if (err < 0)
 | 
					 | 
				
			||||||
				return err;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		p.format.channels = multi->slaves[i].channels_count;
 | 
							p.format.channels = multi->slaves[i].channels_count;
 | 
				
			||||||
		err = snd_pcm_params(slave, &p);
 | 
							err = snd_pcm_params(slave, &p);
 | 
				
			||||||
		if (err < 0) {
 | 
							if (err < 0) {
 | 
				
			||||||
| 
						 | 
					@ -179,14 +228,6 @@ static int snd_pcm_multi_params(snd_pcm_t *pcm, snd_pcm_params_t *params)
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	for (i = 0; i < multi->slaves_count; ++i) {
 | 
					 | 
				
			||||||
		snd_pcm_t *slave = multi->slaves[i].pcm;
 | 
					 | 
				
			||||||
		snd_pcm_mmap_data(slave, NULL);
 | 
					 | 
				
			||||||
		if (pcm->stream == SND_PCM_STREAM_PLAYBACK &&
 | 
					 | 
				
			||||||
		    err == 0)
 | 
					 | 
				
			||||||
			snd_pcm_areas_silence(snd_pcm_mmap_areas(slave), 0, slave->setup.format.channels, 
 | 
					 | 
				
			||||||
					      slave->setup.buffer_size, slave->setup.format.sfmt);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if (err == 0)
 | 
						if (err == 0)
 | 
				
			||||||
		multi->xfer_mode = params->xfer_mode;
 | 
							multi->xfer_mode = params->xfer_mode;
 | 
				
			||||||
	return err;
 | 
						return err;
 | 
				
			||||||
| 
						 | 
					@ -346,73 +387,6 @@ static ssize_t snd_pcm_multi_rewind(snd_pcm_t *pcm, size_t frames)
 | 
				
			||||||
	return frames;
 | 
						return frames;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int snd_pcm_multi_mmap_status(snd_pcm_t *pcm)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	snd_pcm_multi_t *multi = pcm->private;
 | 
					 | 
				
			||||||
	pcm->mmap_status = multi->slaves[0].pcm->mmap_status;
 | 
					 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int snd_pcm_multi_mmap_control(snd_pcm_t *pcm)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	snd_pcm_multi_t *multi = pcm->private;
 | 
					 | 
				
			||||||
	pcm->mmap_control = multi->slaves[0].pcm->mmap_control;
 | 
					 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int snd_pcm_multi_mmap_data(snd_pcm_t *pcm)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	snd_pcm_multi_t *multi = pcm->private;
 | 
					 | 
				
			||||||
	unsigned int i;
 | 
					 | 
				
			||||||
	for (i = 0; i < multi->slaves_count; ++i) {
 | 
					 | 
				
			||||||
		snd_pcm_t *slave = multi->slaves[i].pcm;
 | 
					 | 
				
			||||||
		int err = snd_pcm_mmap_data(slave, 0);
 | 
					 | 
				
			||||||
		snd_pcm_setup_t *setup;
 | 
					 | 
				
			||||||
		if (err < 0)
 | 
					 | 
				
			||||||
			return err;
 | 
					 | 
				
			||||||
		setup = &slave->setup;
 | 
					 | 
				
			||||||
		if (pcm->stream == SND_PCM_STREAM_PLAYBACK) {
 | 
					 | 
				
			||||||
			snd_pcm_channel_area_t r[setup->format.channels];
 | 
					 | 
				
			||||||
			snd_pcm_channel_area_t s[setup->format.channels];
 | 
					 | 
				
			||||||
			err = snd_pcm_mmap_get_areas(slave, s, r);
 | 
					 | 
				
			||||||
			if (err < 0)
 | 
					 | 
				
			||||||
				return err;
 | 
					 | 
				
			||||||
			err = snd_pcm_areas_silence(s, 0, setup->format.channels, setup->buffer_size, setup->format.sfmt);
 | 
					 | 
				
			||||||
			if (err < 0)
 | 
					 | 
				
			||||||
				return err;
 | 
					 | 
				
			||||||
			err = snd_pcm_areas_silence(r, 0, setup->format.channels, setup->buffer_size, setup->format.sfmt);
 | 
					 | 
				
			||||||
			if (err < 0)
 | 
					 | 
				
			||||||
				return err;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	pcm->mmap_data = multi->slaves[0].pcm->mmap_data;
 | 
					 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int snd_pcm_multi_munmap_status(snd_pcm_t *pcm ATTRIBUTE_UNUSED)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
		
 | 
					 | 
				
			||||||
static int snd_pcm_multi_munmap_control(snd_pcm_t *pcm ATTRIBUTE_UNUSED)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
		
 | 
					 | 
				
			||||||
static int snd_pcm_multi_munmap_data(snd_pcm_t *pcm)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	snd_pcm_multi_t *multi = pcm->private;
 | 
					 | 
				
			||||||
	unsigned int i;
 | 
					 | 
				
			||||||
	int ret = 0;
 | 
					 | 
				
			||||||
	for (i = 0; i < multi->slaves_count; ++i) {
 | 
					 | 
				
			||||||
		snd_pcm_t *slave = multi->slaves[i].pcm;
 | 
					 | 
				
			||||||
		int err = snd_pcm_munmap_data(slave);
 | 
					 | 
				
			||||||
		if (err < 0)
 | 
					 | 
				
			||||||
			ret = err;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return ret;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
		
 | 
					 | 
				
			||||||
static ssize_t snd_pcm_multi_mmap_forward(snd_pcm_t *pcm, size_t size)
 | 
					static ssize_t snd_pcm_multi_mmap_forward(snd_pcm_t *pcm, size_t size)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	snd_pcm_multi_t *multi = pcm->private;
 | 
						snd_pcm_multi_t *multi = pcm->private;
 | 
				
			||||||
| 
						 | 
					@ -500,7 +474,7 @@ static void snd_pcm_multi_dump(snd_pcm_t *pcm, FILE *fp)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct snd_pcm_ops snd_pcm_multi_ops = {
 | 
					snd_pcm_ops_t snd_pcm_multi_ops = {
 | 
				
			||||||
	close: snd_pcm_multi_close,
 | 
						close: snd_pcm_multi_close,
 | 
				
			||||||
	info: snd_pcm_multi_info,
 | 
						info: snd_pcm_multi_info,
 | 
				
			||||||
	params_info: snd_pcm_multi_params_info,
 | 
						params_info: snd_pcm_multi_params_info,
 | 
				
			||||||
| 
						 | 
					@ -512,15 +486,11 @@ struct snd_pcm_ops snd_pcm_multi_ops = {
 | 
				
			||||||
	dump: snd_pcm_multi_dump,
 | 
						dump: snd_pcm_multi_dump,
 | 
				
			||||||
	nonblock: snd_pcm_multi_nonblock,
 | 
						nonblock: snd_pcm_multi_nonblock,
 | 
				
			||||||
	async: snd_pcm_multi_async,
 | 
						async: snd_pcm_multi_async,
 | 
				
			||||||
	mmap_status: snd_pcm_multi_mmap_status,
 | 
						mmap: snd_pcm_multi_mmap,
 | 
				
			||||||
	mmap_control: snd_pcm_multi_mmap_control,
 | 
						munmap: snd_pcm_multi_munmap,
 | 
				
			||||||
	mmap_data: snd_pcm_multi_mmap_data,
 | 
					 | 
				
			||||||
	munmap_status: snd_pcm_multi_munmap_status,
 | 
					 | 
				
			||||||
	munmap_control: snd_pcm_multi_munmap_control,
 | 
					 | 
				
			||||||
	munmap_data: snd_pcm_multi_munmap_data,
 | 
					 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct snd_pcm_fast_ops snd_pcm_multi_fast_ops = {
 | 
					snd_pcm_fast_ops_t snd_pcm_multi_fast_ops = {
 | 
				
			||||||
	status: snd_pcm_multi_status,
 | 
						status: snd_pcm_multi_status,
 | 
				
			||||||
	state: snd_pcm_multi_state,
 | 
						state: snd_pcm_multi_state,
 | 
				
			||||||
	delay: snd_pcm_multi_delay,
 | 
						delay: snd_pcm_multi_delay,
 | 
				
			||||||
| 
						 | 
					@ -534,28 +504,26 @@ struct snd_pcm_fast_ops snd_pcm_multi_fast_ops = {
 | 
				
			||||||
	readi: snd_pcm_mmap_readi,
 | 
						readi: snd_pcm_mmap_readi,
 | 
				
			||||||
	readn: snd_pcm_mmap_readn,
 | 
						readn: snd_pcm_mmap_readn,
 | 
				
			||||||
	rewind: snd_pcm_multi_rewind,
 | 
						rewind: snd_pcm_multi_rewind,
 | 
				
			||||||
	poll_descriptor: snd_pcm_multi_poll_descriptor,
 | 
					 | 
				
			||||||
	channels_mask: snd_pcm_multi_channels_mask,
 | 
						channels_mask: snd_pcm_multi_channels_mask,
 | 
				
			||||||
	avail_update: snd_pcm_multi_avail_update,
 | 
						avail_update: snd_pcm_multi_avail_update,
 | 
				
			||||||
	mmap_forward: snd_pcm_multi_mmap_forward,
 | 
						mmap_forward: snd_pcm_multi_mmap_forward,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int snd_pcm_multi_open(snd_pcm_t **handlep, char *name,
 | 
					int snd_pcm_multi_open(snd_pcm_t **pcmp, char *name,
 | 
				
			||||||
		       size_t slaves_count,
 | 
							       size_t slaves_count,
 | 
				
			||||||
		       snd_pcm_t **slaves_handle, size_t *schannels_count,
 | 
							       snd_pcm_t **slaves_pcm, size_t *schannels_count,
 | 
				
			||||||
		       size_t channels_count,
 | 
							       size_t channels_count,
 | 
				
			||||||
		       int *sidxs, unsigned int *schannels,
 | 
							       int *sidxs, unsigned int *schannels,
 | 
				
			||||||
		       int close_slaves)
 | 
							       int close_slaves)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	snd_pcm_t *handle;
 | 
						snd_pcm_t *pcm;
 | 
				
			||||||
	snd_pcm_multi_t *multi;
 | 
						snd_pcm_multi_t *multi;
 | 
				
			||||||
	unsigned int i;
 | 
						unsigned int i;
 | 
				
			||||||
	int err;
 | 
					 | 
				
			||||||
	int stream;
 | 
						int stream;
 | 
				
			||||||
	char slave_map[32][32] = { { 0 } };
 | 
						char slave_map[32][32] = { { 0 } };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	assert(handlep);
 | 
						assert(pcmp);
 | 
				
			||||||
	assert(slaves_count > 0 && slaves_handle && schannels_count);
 | 
						assert(slaves_count > 0 && slaves_pcm && schannels_count);
 | 
				
			||||||
	assert(channels_count > 0 && sidxs && schannels);
 | 
						assert(channels_count > 0 && sidxs && schannels);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	multi = calloc(1, sizeof(snd_pcm_multi_t));
 | 
						multi = calloc(1, sizeof(snd_pcm_multi_t));
 | 
				
			||||||
| 
						 | 
					@ -563,7 +531,7 @@ int snd_pcm_multi_open(snd_pcm_t **handlep, char *name,
 | 
				
			||||||
		return -ENOMEM;
 | 
							return -ENOMEM;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	stream = slaves_handle[0]->stream;
 | 
						stream = slaves_pcm[0]->stream;
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
	multi->slaves_count = slaves_count;
 | 
						multi->slaves_count = slaves_count;
 | 
				
			||||||
	multi->slaves = calloc(slaves_count, sizeof(*multi->slaves));
 | 
						multi->slaves = calloc(slaves_count, sizeof(*multi->slaves));
 | 
				
			||||||
| 
						 | 
					@ -571,12 +539,12 @@ int snd_pcm_multi_open(snd_pcm_t **handlep, char *name,
 | 
				
			||||||
	multi->channels = calloc(channels_count, sizeof(*multi->channels));
 | 
						multi->channels = calloc(channels_count, sizeof(*multi->channels));
 | 
				
			||||||
	for (i = 0; i < slaves_count; ++i) {
 | 
						for (i = 0; i < slaves_count; ++i) {
 | 
				
			||||||
		snd_pcm_multi_slave_t *slave = &multi->slaves[i];
 | 
							snd_pcm_multi_slave_t *slave = &multi->slaves[i];
 | 
				
			||||||
		assert(slaves_handle[i]->stream == stream);
 | 
							assert(slaves_pcm[i]->stream == stream);
 | 
				
			||||||
		slave->pcm = slaves_handle[i];
 | 
							slave->pcm = slaves_pcm[i];
 | 
				
			||||||
		slave->channels_count = schannels_count[i];
 | 
							slave->channels_count = schannels_count[i];
 | 
				
			||||||
		slave->close_slave = close_slaves;
 | 
							slave->close_slave = close_slaves;
 | 
				
			||||||
		if (i != 0)
 | 
							if (i != 0)
 | 
				
			||||||
			snd_pcm_link(slaves_handle[i-1], slaves_handle[i]);
 | 
								snd_pcm_link(slaves_pcm[i-1], slaves_pcm[i]);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	for (i = 0; i < channels_count; ++i) {
 | 
						for (i = 0; i < channels_count; ++i) {
 | 
				
			||||||
		snd_pcm_multi_channel_t *bind = &multi->channels[i];
 | 
							snd_pcm_multi_channel_t *bind = &multi->channels[i];
 | 
				
			||||||
| 
						 | 
					@ -591,27 +559,26 @@ int snd_pcm_multi_open(snd_pcm_t **handlep, char *name,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	multi->channels_count = channels_count;
 | 
						multi->channels_count = channels_count;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	handle = calloc(1, sizeof(snd_pcm_t));
 | 
						pcm = calloc(1, sizeof(snd_pcm_t));
 | 
				
			||||||
	if (!handle) {
 | 
						if (!pcm) {
 | 
				
			||||||
		free(multi);
 | 
							free(multi);
 | 
				
			||||||
		return -ENOMEM;
 | 
							return -ENOMEM;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if (name)
 | 
						if (name)
 | 
				
			||||||
		handle->name = strdup(name);
 | 
							pcm->name = strdup(name);
 | 
				
			||||||
	handle->type = SND_PCM_TYPE_MULTI;
 | 
						pcm->type = SND_PCM_TYPE_MULTI;
 | 
				
			||||||
	handle->stream = stream;
 | 
						pcm->stream = stream;
 | 
				
			||||||
	handle->mode = multi->slaves[0].pcm->mode;
 | 
						pcm->mode = multi->slaves[0].pcm->mode;
 | 
				
			||||||
	handle->ops = &snd_pcm_multi_ops;
 | 
						pcm->mmap_auto = 1;
 | 
				
			||||||
	handle->op_arg = handle;
 | 
						pcm->ops = &snd_pcm_multi_ops;
 | 
				
			||||||
	handle->fast_ops = &snd_pcm_multi_fast_ops;
 | 
						pcm->op_arg = pcm;
 | 
				
			||||||
	handle->fast_op_arg = handle;
 | 
						pcm->fast_ops = &snd_pcm_multi_fast_ops;
 | 
				
			||||||
	handle->private = multi;
 | 
						pcm->fast_op_arg = pcm;
 | 
				
			||||||
	err = snd_pcm_init(handle);
 | 
						pcm->private = multi;
 | 
				
			||||||
	if (err < 0) {
 | 
						pcm->poll_fd = multi->slaves[0].pcm->poll_fd;
 | 
				
			||||||
		snd_pcm_close(handle);
 | 
						pcm->hw_ptr = multi->slaves[0].pcm->hw_ptr;
 | 
				
			||||||
		return err;
 | 
						pcm->appl_ptr = multi->slaves[0].pcm->appl_ptr;
 | 
				
			||||||
	}
 | 
						*pcmp = pcm;
 | 
				
			||||||
	*handlep = handle;
 | 
					 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -323,6 +323,7 @@ static int snd_pcm_plug_change_rate(snd_pcm_t *pcm, snd_pcm_t **new, snd_pcm_for
 | 
				
			||||||
	err = snd_pcm_rate_open(new, NULL, slv->sfmt, slv->rate, plug->slave, plug->slave != plug->req_slave);
 | 
						err = snd_pcm_rate_open(new, NULL, slv->sfmt, slv->rate, plug->slave, plug->slave != plug->req_slave);
 | 
				
			||||||
	if (err < 0)
 | 
						if (err < 0)
 | 
				
			||||||
		return err;
 | 
							return err;
 | 
				
			||||||
 | 
						(*new)->mmap_auto = 1;
 | 
				
			||||||
	slv->rate = clt->rate;
 | 
						slv->rate = clt->rate;
 | 
				
			||||||
	if (snd_pcm_format_linear(clt->sfmt))
 | 
						if (snd_pcm_format_linear(clt->sfmt))
 | 
				
			||||||
		slv->sfmt = clt->sfmt;
 | 
							slv->sfmt = clt->sfmt;
 | 
				
			||||||
| 
						 | 
					@ -387,6 +388,7 @@ static int snd_pcm_plug_change_channels(snd_pcm_t *pcm, snd_pcm_t **new, snd_pcm
 | 
				
			||||||
	err = snd_pcm_route_open(new, NULL, slv->sfmt, slv->channels, ttable, tt_ssize, tt_cused, tt_sused, plug->slave, plug->slave != plug->req_slave);
 | 
						err = snd_pcm_route_open(new, NULL, slv->sfmt, slv->channels, ttable, tt_ssize, tt_cused, tt_sused, plug->slave, plug->slave != plug->req_slave);
 | 
				
			||||||
	if (err < 0)
 | 
						if (err < 0)
 | 
				
			||||||
		return err;
 | 
							return err;
 | 
				
			||||||
 | 
						(*new)->mmap_auto = 1;
 | 
				
			||||||
	slv->channels = clt->channels;
 | 
						slv->channels = clt->channels;
 | 
				
			||||||
	if (snd_pcm_format_linear(clt->sfmt))
 | 
						if (snd_pcm_format_linear(clt->sfmt))
 | 
				
			||||||
		slv->sfmt = clt->sfmt;
 | 
							slv->sfmt = clt->sfmt;
 | 
				
			||||||
| 
						 | 
					@ -397,7 +399,7 @@ static int snd_pcm_plug_change_format(snd_pcm_t *pcm, snd_pcm_t **new, snd_pcm_f
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	snd_pcm_plug_t *plug = pcm->private;
 | 
						snd_pcm_plug_t *plug = pcm->private;
 | 
				
			||||||
	int err, cfmt;
 | 
						int err, cfmt;
 | 
				
			||||||
	int (*f)(snd_pcm_t **handle, char *name, int sformat, snd_pcm_t *slave, int close_slave);
 | 
						int (*f)(snd_pcm_t **pcm, char *name, int sformat, snd_pcm_t *slave, int close_slave);
 | 
				
			||||||
	if (snd_pcm_format_linear(slv->sfmt)) {
 | 
						if (snd_pcm_format_linear(slv->sfmt)) {
 | 
				
			||||||
		/* Conversion is done in another plugin */
 | 
							/* Conversion is done in another plugin */
 | 
				
			||||||
		if (clt->sfmt == slv->sfmt ||
 | 
							if (clt->sfmt == slv->sfmt ||
 | 
				
			||||||
| 
						 | 
					@ -451,6 +453,7 @@ static int snd_pcm_plug_change_format(snd_pcm_t *pcm, snd_pcm_t **new, snd_pcm_f
 | 
				
			||||||
	err = f(new, NULL, slv->sfmt, plug->slave, plug->slave != plug->req_slave);
 | 
						err = f(new, NULL, slv->sfmt, plug->slave, plug->slave != plug->req_slave);
 | 
				
			||||||
	if (err < 0)
 | 
						if (err < 0)
 | 
				
			||||||
		return err;
 | 
							return err;
 | 
				
			||||||
 | 
						(*new)->mmap_auto = 1;
 | 
				
			||||||
	slv->sfmt = cfmt;
 | 
						slv->sfmt = cfmt;
 | 
				
			||||||
	return 1;
 | 
						return 1;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -489,6 +492,7 @@ static int snd_pcm_plug_insert_plugins(snd_pcm_t *pcm,
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		k++;
 | 
							k++;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						plug->slave->mmap_auto = 0;
 | 
				
			||||||
	assert(0);
 | 
						assert(0);
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -563,15 +567,16 @@ static int snd_pcm_plug_params(snd_pcm_t *pcm, snd_pcm_params_t *params)
 | 
				
			||||||
		return err;
 | 
							return err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	err = snd_pcm_params(plug->slave, params);
 | 
						err = snd_pcm_params(plug->slave, params);
 | 
				
			||||||
	if (err < 0)
 | 
						if (err < 0) {
 | 
				
			||||||
		snd_pcm_plug_clear(pcm);
 | 
							snd_pcm_plug_clear(pcm);
 | 
				
			||||||
	else {
 | 
							return err;
 | 
				
			||||||
		assert(slave->setup.format.sfmt == slave_format->sfmt);
 | 
					 | 
				
			||||||
		assert(slave->setup.format.channels == slave_format->channels);
 | 
					 | 
				
			||||||
		assert(slave->setup.format.rate == slave_format->rate);
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						assert(slave->setup.format.sfmt == slave_format->sfmt);
 | 
				
			||||||
	return err;
 | 
						assert(slave->setup.format.channels == slave_format->channels);
 | 
				
			||||||
 | 
						assert(slave->setup.format.rate == slave_format->rate);
 | 
				
			||||||
 | 
						pcm->hw_ptr = slave->hw_ptr;
 | 
				
			||||||
 | 
						pcm->appl_ptr = slave->appl_ptr;
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int snd_pcm_plug_setup(snd_pcm_t *pcm, snd_pcm_setup_t *setup)
 | 
					static int snd_pcm_plug_setup(snd_pcm_t *pcm, snd_pcm_setup_t *setup)
 | 
				
			||||||
| 
						 | 
					@ -598,54 +603,28 @@ static int snd_pcm_plug_channel_setup(snd_pcm_t *pcm, snd_pcm_channel_setup_t *s
 | 
				
			||||||
	return snd_pcm_channel_setup(plug->slave, setup);
 | 
						return snd_pcm_channel_setup(plug->slave, setup);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int snd_pcm_plug_mmap_status(snd_pcm_t *pcm)
 | 
					static int snd_pcm_plug_mmap(snd_pcm_t *pcm)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	snd_pcm_plug_t *plug = pcm->private;
 | 
						snd_pcm_plug_t *plug = pcm->private;
 | 
				
			||||||
	int err = snd_pcm_mmap_status(plug->slave, NULL);
 | 
						int err = snd_pcm_mmap(plug->slave);
 | 
				
			||||||
	if (err < 0)
 | 
						if (err < 0)
 | 
				
			||||||
		return err;
 | 
							return err;
 | 
				
			||||||
	pcm->mmap_status = plug->slave->mmap_status;
 | 
						pcm->mmap_info_count = plug->slave->mmap_info_count;
 | 
				
			||||||
 | 
						pcm->mmap_info = plug->slave->mmap_info;
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int snd_pcm_plug_mmap_control(snd_pcm_t *pcm)
 | 
					static int snd_pcm_plug_munmap(snd_pcm_t *pcm)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	snd_pcm_plug_t *plug = pcm->private;
 | 
						snd_pcm_plug_t *plug = pcm->private;
 | 
				
			||||||
	int err = snd_pcm_mmap_control(plug->slave, NULL);
 | 
						int err = snd_pcm_munmap(plug->slave);
 | 
				
			||||||
	if (err < 0)
 | 
						if (err < 0)
 | 
				
			||||||
		return err;
 | 
							return err;
 | 
				
			||||||
	pcm->mmap_control = plug->slave->mmap_control;
 | 
						pcm->mmap_info_count = 0;
 | 
				
			||||||
 | 
						pcm->mmap_info = 0;
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
		
 | 
							
 | 
				
			||||||
static int snd_pcm_plug_mmap_data(snd_pcm_t *pcm)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	snd_pcm_plug_t *plug = pcm->private;
 | 
					 | 
				
			||||||
	int err = snd_pcm_mmap_data(plug->slave, NULL);
 | 
					 | 
				
			||||||
	if (err < 0)
 | 
					 | 
				
			||||||
		return err;
 | 
					 | 
				
			||||||
	pcm->mmap_data = plug->slave->mmap_data;
 | 
					 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int snd_pcm_plug_munmap_status(snd_pcm_t *pcm)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	snd_pcm_plug_t *plug = pcm->private;
 | 
					 | 
				
			||||||
	return snd_pcm_munmap_status(plug->slave);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
		
 | 
					 | 
				
			||||||
static int snd_pcm_plug_munmap_control(snd_pcm_t *pcm)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	snd_pcm_plug_t *plug = pcm->private;
 | 
					 | 
				
			||||||
	return snd_pcm_munmap_control(plug->slave);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
		
 | 
					 | 
				
			||||||
static int snd_pcm_plug_munmap_data(snd_pcm_t *pcm)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	snd_pcm_plug_t *plug = pcm->private;
 | 
					 | 
				
			||||||
	return snd_pcm_munmap_data(plug->slave);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
		
 | 
					 | 
				
			||||||
static void snd_pcm_plug_dump(snd_pcm_t *pcm, FILE *fp)
 | 
					static void snd_pcm_plug_dump(snd_pcm_t *pcm, FILE *fp)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	snd_pcm_plug_t *plug = pcm->private;
 | 
						snd_pcm_plug_t *plug = pcm->private;
 | 
				
			||||||
| 
						 | 
					@ -653,7 +632,7 @@ static void snd_pcm_plug_dump(snd_pcm_t *pcm, FILE *fp)
 | 
				
			||||||
	snd_pcm_dump(plug->slave, fp);
 | 
						snd_pcm_dump(plug->slave, fp);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct snd_pcm_ops snd_pcm_plug_ops = {
 | 
					snd_pcm_ops_t snd_pcm_plug_ops = {
 | 
				
			||||||
	close: snd_pcm_plug_close,
 | 
						close: snd_pcm_plug_close,
 | 
				
			||||||
	info: snd_pcm_plug_info,
 | 
						info: snd_pcm_plug_info,
 | 
				
			||||||
	params_info: snd_pcm_plug_params_info,
 | 
						params_info: snd_pcm_plug_params_info,
 | 
				
			||||||
| 
						 | 
					@ -665,25 +644,20 @@ struct snd_pcm_ops snd_pcm_plug_ops = {
 | 
				
			||||||
	dump: snd_pcm_plug_dump,
 | 
						dump: snd_pcm_plug_dump,
 | 
				
			||||||
	nonblock: snd_pcm_plug_nonblock,
 | 
						nonblock: snd_pcm_plug_nonblock,
 | 
				
			||||||
	async: snd_pcm_plug_async,
 | 
						async: snd_pcm_plug_async,
 | 
				
			||||||
	mmap_status: snd_pcm_plug_mmap_status,
 | 
						mmap: snd_pcm_plug_mmap,
 | 
				
			||||||
	mmap_control: snd_pcm_plug_mmap_control,
 | 
						munmap: snd_pcm_plug_munmap,
 | 
				
			||||||
	mmap_data: snd_pcm_plug_mmap_data,
 | 
					 | 
				
			||||||
	munmap_status: snd_pcm_plug_munmap_status,
 | 
					 | 
				
			||||||
	munmap_control: snd_pcm_plug_munmap_control,
 | 
					 | 
				
			||||||
	munmap_data: snd_pcm_plug_munmap_data,
 | 
					 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int snd_pcm_plug_open(snd_pcm_t **handlep,
 | 
					int snd_pcm_plug_open(snd_pcm_t **pcmp,
 | 
				
			||||||
		      char *name,
 | 
							      char *name,
 | 
				
			||||||
		      ttable_entry_t *ttable,
 | 
							      ttable_entry_t *ttable,
 | 
				
			||||||
		      unsigned int tt_ssize,
 | 
							      unsigned int tt_ssize,
 | 
				
			||||||
		      unsigned int tt_cused, unsigned int tt_sused,
 | 
							      unsigned int tt_cused, unsigned int tt_sused,
 | 
				
			||||||
		      snd_pcm_t *slave, int close_slave)
 | 
							      snd_pcm_t *slave, int close_slave)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	snd_pcm_t *handle;
 | 
						snd_pcm_t *pcm;
 | 
				
			||||||
	snd_pcm_plug_t *plug;
 | 
						snd_pcm_plug_t *plug;
 | 
				
			||||||
	int err;
 | 
						assert(pcmp && slave);
 | 
				
			||||||
	assert(handlep && slave);
 | 
					 | 
				
			||||||
	plug = calloc(1, sizeof(snd_pcm_plug_t));
 | 
						plug = calloc(1, sizeof(snd_pcm_plug_t));
 | 
				
			||||||
	if (!plug)
 | 
						if (!plug)
 | 
				
			||||||
		return -ENOMEM;
 | 
							return -ENOMEM;
 | 
				
			||||||
| 
						 | 
					@ -694,44 +668,42 @@ int snd_pcm_plug_open(snd_pcm_t **handlep,
 | 
				
			||||||
	plug->tt_cused = tt_cused;
 | 
						plug->tt_cused = tt_cused;
 | 
				
			||||||
	plug->tt_sused = tt_sused;
 | 
						plug->tt_sused = tt_sused;
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
	handle = calloc(1, sizeof(snd_pcm_t));
 | 
						pcm = calloc(1, sizeof(snd_pcm_t));
 | 
				
			||||||
	if (!handle) {
 | 
						if (!pcm) {
 | 
				
			||||||
		free(plug);
 | 
							free(plug);
 | 
				
			||||||
		return -ENOMEM;
 | 
							return -ENOMEM;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if (name)
 | 
						if (name)
 | 
				
			||||||
		handle->name = strdup(name);
 | 
							pcm->name = strdup(name);
 | 
				
			||||||
	handle->type = SND_PCM_TYPE_PLUG;
 | 
						pcm->type = SND_PCM_TYPE_PLUG;
 | 
				
			||||||
	handle->stream = slave->stream;
 | 
						pcm->stream = slave->stream;
 | 
				
			||||||
	handle->ops = &snd_pcm_plug_ops;
 | 
						pcm->mode = slave->mode;
 | 
				
			||||||
	handle->op_arg = handle;
 | 
						pcm->ops = &snd_pcm_plug_ops;
 | 
				
			||||||
	handle->fast_ops = slave->fast_ops;
 | 
						pcm->op_arg = pcm;
 | 
				
			||||||
	handle->fast_op_arg = slave->fast_op_arg;
 | 
						pcm->fast_ops = slave->fast_ops;
 | 
				
			||||||
	handle->mode = slave->mode;
 | 
						pcm->fast_op_arg = slave->fast_op_arg;
 | 
				
			||||||
	handle->private = plug;
 | 
						pcm->private = plug;
 | 
				
			||||||
	err = snd_pcm_init(handle);
 | 
						pcm->poll_fd = slave->poll_fd;
 | 
				
			||||||
	if (err < 0) {
 | 
						pcm->hw_ptr = slave->hw_ptr;
 | 
				
			||||||
		snd_pcm_close(handle);
 | 
						pcm->appl_ptr = slave->appl_ptr;
 | 
				
			||||||
		return err;
 | 
						*pcmp = pcm;
 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	*handlep = handle;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int snd_pcm_plug_open_subdevice(snd_pcm_t **handlep, int card, int device, int subdevice, int stream, int mode)
 | 
					int snd_pcm_plug_open_subdevice(snd_pcm_t **pcmp, int card, int device, int subdevice, int stream, int mode)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	snd_pcm_t *slave;
 | 
						snd_pcm_t *slave;
 | 
				
			||||||
	int err;
 | 
						int err;
 | 
				
			||||||
	err = snd_pcm_hw_open_subdevice(&slave, card, device, subdevice, stream, mode);
 | 
						err = snd_pcm_hw_open_subdevice(&slave, card, device, subdevice, stream, mode);
 | 
				
			||||||
	if (err < 0)
 | 
						if (err < 0)
 | 
				
			||||||
		return err;
 | 
							return err;
 | 
				
			||||||
	return snd_pcm_plug_open(handlep, NULL, 0, 0, 0, 0, slave, 1);
 | 
						return snd_pcm_plug_open(pcmp, NULL, 0, 0, 0, 0, slave, 1);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int snd_pcm_plug_open_device(snd_pcm_t **handlep, int card, int device, int stream, int mode)
 | 
					int snd_pcm_plug_open_device(snd_pcm_t **pcmp, int card, int device, int stream, int mode)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	return snd_pcm_plug_open_subdevice(handlep, card, device, -1, stream, mode);
 | 
						return snd_pcm_plug_open_subdevice(pcmp, card, device, -1, stream, mode);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define MAX_CHANNELS 32
 | 
					#define MAX_CHANNELS 32
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -70,12 +70,14 @@ int snd_pcm_plugin_channel_setup(snd_pcm_t *pcm, snd_pcm_channel_setup_t * setup
 | 
				
			||||||
	err = snd_pcm_channel_setup(plugin->slave, setup);
 | 
						err = snd_pcm_channel_setup(plugin->slave, setup);
 | 
				
			||||||
	if (err < 0)
 | 
						if (err < 0)
 | 
				
			||||||
		return err;
 | 
							return err;
 | 
				
			||||||
 | 
						if (!pcm->mmap_info)
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
	if (pcm->setup.mmap_shape == SND_PCM_MMAP_INTERLEAVED) {
 | 
						if (pcm->setup.mmap_shape == SND_PCM_MMAP_INTERLEAVED) {
 | 
				
			||||||
		setup->running_area.addr = pcm->mmap_data;
 | 
							setup->running_area.addr = pcm->mmap_info->addr;
 | 
				
			||||||
		setup->running_area.first = setup->channel * pcm->bits_per_sample;
 | 
							setup->running_area.first = setup->channel * pcm->bits_per_sample;
 | 
				
			||||||
		setup->running_area.step = pcm->bits_per_frame;
 | 
							setup->running_area.step = pcm->bits_per_frame;
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		setup->running_area.addr = pcm->mmap_data + setup->channel * pcm->setup.buffer_size * pcm->bits_per_sample / 8;
 | 
							setup->running_area.addr = pcm->mmap_info->addr + setup->channel * pcm->setup.buffer_size * pcm->bits_per_sample / 8;
 | 
				
			||||||
		setup->running_area.first = 0;
 | 
							setup->running_area.first = 0;
 | 
				
			||||||
		setup->running_area.step = pcm->bits_per_sample;
 | 
							setup->running_area.step = pcm->bits_per_sample;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -118,8 +120,8 @@ int snd_pcm_plugin_prepare(snd_pcm_t *pcm)
 | 
				
			||||||
	int err = snd_pcm_prepare(plugin->slave);
 | 
						int err = snd_pcm_prepare(plugin->slave);
 | 
				
			||||||
	if (err < 0)
 | 
						if (err < 0)
 | 
				
			||||||
		return err;
 | 
							return err;
 | 
				
			||||||
	plugin->mmap_status.hw_ptr = 0;
 | 
						plugin->hw_ptr = 0;
 | 
				
			||||||
	plugin->mmap_control.appl_ptr = 0;
 | 
						plugin->appl_ptr = 0;
 | 
				
			||||||
	if (plugin->init) {
 | 
						if (plugin->init) {
 | 
				
			||||||
		err = plugin->init(pcm);
 | 
							err = plugin->init(pcm);
 | 
				
			||||||
		if (err < 0)
 | 
							if (err < 0)
 | 
				
			||||||
| 
						 | 
					@ -276,7 +278,7 @@ ssize_t snd_pcm_plugin_avail_update(snd_pcm_t *pcm)
 | 
				
			||||||
	if (slave_size <= 0)
 | 
						if (slave_size <= 0)
 | 
				
			||||||
		return slave_size;
 | 
							return slave_size;
 | 
				
			||||||
	if (pcm->stream == SND_PCM_STREAM_PLAYBACK ||
 | 
						if (pcm->stream == SND_PCM_STREAM_PLAYBACK ||
 | 
				
			||||||
	    !pcm->mmap_data)
 | 
						    !pcm->mmap_info)
 | 
				
			||||||
		return plugin->client_frames ?
 | 
							return plugin->client_frames ?
 | 
				
			||||||
			plugin->client_frames(pcm, slave_size) : slave_size;
 | 
								plugin->client_frames(pcm, slave_size) : slave_size;
 | 
				
			||||||
	client_xfer = snd_pcm_mmap_capture_avail(pcm);
 | 
						client_xfer = snd_pcm_mmap_capture_avail(pcm);
 | 
				
			||||||
| 
						 | 
					@ -301,42 +303,39 @@ ssize_t snd_pcm_plugin_avail_update(snd_pcm_t *pcm)
 | 
				
			||||||
	return err;
 | 
						return err;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int snd_pcm_plugin_mmap_status(snd_pcm_t *pcm)
 | 
					int snd_pcm_plugin_mmap(snd_pcm_t *pcm)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	snd_pcm_plugin_t *plugin = pcm->private;
 | 
						snd_pcm_plugin_t *plugin = pcm->private;
 | 
				
			||||||
	pcm->mmap_status = &plugin->mmap_status;
 | 
						snd_pcm_t *slave = plugin->slave;
 | 
				
			||||||
	return 0;
 | 
						int err = snd_pcm_mmap(slave);
 | 
				
			||||||
}
 | 
						if (err < 0)
 | 
				
			||||||
 | 
							return err;
 | 
				
			||||||
int snd_pcm_plugin_mmap_control(snd_pcm_t *pcm)
 | 
						pcm->mmap_info = calloc(1, sizeof(*pcm->mmap_info));
 | 
				
			||||||
{
 | 
						if (!pcm->mmap_info)
 | 
				
			||||||
	snd_pcm_plugin_t *plugin = pcm->private;
 | 
					 | 
				
			||||||
	pcm->mmap_control = &plugin->mmap_control;
 | 
					 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int snd_pcm_plugin_mmap_data(snd_pcm_t *pcm)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	void *ptr = malloc(snd_pcm_frames_to_bytes(pcm, pcm->setup.buffer_size));
 | 
					 | 
				
			||||||
	if (!ptr)
 | 
					 | 
				
			||||||
		return -ENOMEM;
 | 
							return -ENOMEM;
 | 
				
			||||||
	pcm->mmap_data = ptr;
 | 
						pcm->mmap_info_count = 1;
 | 
				
			||||||
 | 
						pcm->mmap_info->type = SND_PCM_MMAP_USER;
 | 
				
			||||||
 | 
						pcm->mmap_info->size = pcm->setup.buffer_size;
 | 
				
			||||||
 | 
						pcm->mmap_info->addr = valloc(snd_pcm_frames_to_bytes(pcm, pcm->setup.buffer_size));
 | 
				
			||||||
 | 
						if (!pcm->mmap_info->addr) {
 | 
				
			||||||
 | 
							free(pcm->mmap_info);
 | 
				
			||||||
 | 
							pcm->mmap_info = 0;
 | 
				
			||||||
 | 
							return -ENOMEM;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int snd_pcm_plugin_munmap_status(snd_pcm_t *pcm ATTRIBUTE_UNUSED)
 | 
					int snd_pcm_plugin_munmap(snd_pcm_t *pcm)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	return 0;
 | 
						snd_pcm_plugin_t *plugin = pcm->private;
 | 
				
			||||||
}
 | 
						snd_pcm_t *slave = plugin->slave;
 | 
				
			||||||
 | 
						int err = snd_pcm_munmap(slave);
 | 
				
			||||||
int snd_pcm_plugin_munmap_control(snd_pcm_t *pcm ATTRIBUTE_UNUSED)
 | 
						if (err < 0)
 | 
				
			||||||
{
 | 
							return err;
 | 
				
			||||||
	return 0;
 | 
						free(pcm->mmap_info->addr);
 | 
				
			||||||
}
 | 
						free(pcm->mmap_info);
 | 
				
			||||||
 | 
						pcm->mmap_info_count = 0;
 | 
				
			||||||
int snd_pcm_plugin_munmap_data(snd_pcm_t *pcm ATTRIBUTE_UNUSED)
 | 
						pcm->mmap_info = 0;
 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	free(pcm->mmap_data);
 | 
					 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -392,7 +391,7 @@ int getput_index(int format)
 | 
				
			||||||
	return width * 4 + endian * 2 + sign;
 | 
						return width * 4 + endian * 2 + sign;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct snd_pcm_fast_ops snd_pcm_plugin_fast_ops = {
 | 
					snd_pcm_fast_ops_t snd_pcm_plugin_fast_ops = {
 | 
				
			||||||
	status: snd_pcm_plugin_status,
 | 
						status: snd_pcm_plugin_status,
 | 
				
			||||||
	state: snd_pcm_plugin_state,
 | 
						state: snd_pcm_plugin_state,
 | 
				
			||||||
	delay: snd_pcm_plugin_delay,
 | 
						delay: snd_pcm_plugin_delay,
 | 
				
			||||||
| 
						 | 
					@ -406,7 +405,6 @@ struct snd_pcm_fast_ops snd_pcm_plugin_fast_ops = {
 | 
				
			||||||
	writen: snd_pcm_plugin_writen,
 | 
						writen: snd_pcm_plugin_writen,
 | 
				
			||||||
	readi: snd_pcm_plugin_readi,
 | 
						readi: snd_pcm_plugin_readi,
 | 
				
			||||||
	readn: snd_pcm_plugin_readn,
 | 
						readn: snd_pcm_plugin_readn,
 | 
				
			||||||
	poll_descriptor: snd_pcm_plugin_poll_descriptor,
 | 
					 | 
				
			||||||
	channels_mask: snd_pcm_plugin_channels_mask,
 | 
						channels_mask: snd_pcm_plugin_channels_mask,
 | 
				
			||||||
	avail_update: snd_pcm_plugin_avail_update,
 | 
						avail_update: snd_pcm_plugin_avail_update,
 | 
				
			||||||
	mmap_forward: snd_pcm_plugin_mmap_forward,
 | 
						mmap_forward: snd_pcm_plugin_mmap_forward,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -26,8 +26,7 @@ typedef struct {
 | 
				
			||||||
	snd_pcm_xfer_areas_func_t write;
 | 
						snd_pcm_xfer_areas_func_t write;
 | 
				
			||||||
	size_t (*client_frames)(snd_pcm_t *pcm, size_t frames);
 | 
						size_t (*client_frames)(snd_pcm_t *pcm, size_t frames);
 | 
				
			||||||
	int (*init)(snd_pcm_t *pcm);
 | 
						int (*init)(snd_pcm_t *pcm);
 | 
				
			||||||
	snd_pcm_mmap_control_t mmap_control;
 | 
						size_t appl_ptr, hw_ptr;
 | 
				
			||||||
	snd_pcm_mmap_status_t mmap_status;
 | 
					 | 
				
			||||||
} snd_pcm_plugin_t;	
 | 
					} snd_pcm_plugin_t;	
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int snd_pcm_plugin_close(snd_pcm_t *pcm);
 | 
					int snd_pcm_plugin_close(snd_pcm_t *pcm);
 | 
				
			||||||
| 
						 | 
					@ -54,10 +53,10 @@ ssize_t snd_pcm_plugin_mmap_forward(snd_pcm_t *pcm, size_t size);
 | 
				
			||||||
ssize_t snd_pcm_plugin_avail_update(snd_pcm_t *pcm);
 | 
					ssize_t snd_pcm_plugin_avail_update(snd_pcm_t *pcm);
 | 
				
			||||||
int snd_pcm_plugin_mmap_status(snd_pcm_t *pcm);
 | 
					int snd_pcm_plugin_mmap_status(snd_pcm_t *pcm);
 | 
				
			||||||
int snd_pcm_plugin_mmap_control(snd_pcm_t *pcm);
 | 
					int snd_pcm_plugin_mmap_control(snd_pcm_t *pcm);
 | 
				
			||||||
int snd_pcm_plugin_mmap_data(snd_pcm_t *pcm);
 | 
					int snd_pcm_plugin_mmap(snd_pcm_t *pcm);
 | 
				
			||||||
int snd_pcm_plugin_munmap_status(snd_pcm_t *pcm);
 | 
					int snd_pcm_plugin_munmap_status(snd_pcm_t *pcm);
 | 
				
			||||||
int snd_pcm_plugin_munmap_control(snd_pcm_t *pcm);
 | 
					int snd_pcm_plugin_munmap_control(snd_pcm_t *pcm);
 | 
				
			||||||
int snd_pcm_plugin_munmap_data(snd_pcm_t *pcm);
 | 
					int snd_pcm_plugin_munmap(snd_pcm_t *pcm);
 | 
				
			||||||
int snd_pcm_plugin_poll_descriptor(snd_pcm_t *pcm);
 | 
					int snd_pcm_plugin_poll_descriptor(snd_pcm_t *pcm);
 | 
				
			||||||
int snd_pcm_plugin_channels_mask(snd_pcm_t *pcm, bitset_t *cmask);
 | 
					int snd_pcm_plugin_channels_mask(snd_pcm_t *pcm, bitset_t *cmask);
 | 
				
			||||||
int getput_index(int format);
 | 
					int getput_index(int format);
 | 
				
			||||||
| 
						 | 
					@ -71,7 +70,7 @@ int conv_index(int src_format, int dst_format);
 | 
				
			||||||
				SND_PCM_FMT_S32_LE | SND_PCM_FMT_S32_BE | \
 | 
									SND_PCM_FMT_S32_LE | SND_PCM_FMT_S32_BE | \
 | 
				
			||||||
				SND_PCM_FMT_U32_LE | SND_PCM_FMT_U32_BE)
 | 
									SND_PCM_FMT_U32_LE | SND_PCM_FMT_U32_BE)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
extern struct snd_pcm_fast_ops snd_pcm_plugin_fast_ops;
 | 
					extern snd_pcm_fast_ops_t snd_pcm_plugin_fast_ops;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define muldiv64(a,b,d) (((int64_t)(a) * (b) + (b) / 2) / (d))
 | 
					#define muldiv64(a,b,d) (((int64_t)(a) * (b) + (b) / 2) / (d))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -88,19 +87,19 @@ typedef int ttable_entry_t;
 | 
				
			||||||
#define FULL ROUTE_PLUGIN_RESOLUTION
 | 
					#define FULL ROUTE_PLUGIN_RESOLUTION
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int snd_pcm_linear_open(snd_pcm_t **handlep, char *name, int sformat, snd_pcm_t *slave, int close_slave);
 | 
					int snd_pcm_linear_open(snd_pcm_t **pcmp, char *name, int sformat, snd_pcm_t *slave, int close_slave);
 | 
				
			||||||
int snd_pcm_mulaw_open(snd_pcm_t **handlep, char *name, int sformat, snd_pcm_t *slave, int close_slave);
 | 
					int snd_pcm_mulaw_open(snd_pcm_t **pcmp, char *name, int sformat, snd_pcm_t *slave, int close_slave);
 | 
				
			||||||
int snd_pcm_alaw_open(snd_pcm_t **handlep, char *name, int sformat, snd_pcm_t *slave, int close_slave);
 | 
					int snd_pcm_alaw_open(snd_pcm_t **pcmp, char *name, int sformat, snd_pcm_t *slave, int close_slave);
 | 
				
			||||||
int snd_pcm_adpcm_open(snd_pcm_t **handlep, char *name, int sformat, snd_pcm_t *slave, int close_slave);
 | 
					int snd_pcm_adpcm_open(snd_pcm_t **pcmp, char *name, int sformat, snd_pcm_t *slave, int close_slave);
 | 
				
			||||||
int snd_pcm_route_load_ttable(snd_config_t *tt, ttable_entry_t *ttable,
 | 
					int snd_pcm_route_load_ttable(snd_config_t *tt, ttable_entry_t *ttable,
 | 
				
			||||||
			      unsigned int tt_csize, unsigned int tt_ssize,
 | 
								      unsigned int tt_csize, unsigned int tt_ssize,
 | 
				
			||||||
			      unsigned int *tt_cused, unsigned int *tt_sused,
 | 
								      unsigned int *tt_cused, unsigned int *tt_sused,
 | 
				
			||||||
			      int schannels);
 | 
								      int schannels);
 | 
				
			||||||
int snd_pcm_route_open(snd_pcm_t **handlep, char *name,
 | 
					int snd_pcm_route_open(snd_pcm_t **pcmp, char *name,
 | 
				
			||||||
		       int sformat, unsigned int schannels,
 | 
							       int sformat, unsigned int schannels,
 | 
				
			||||||
		       ttable_entry_t *ttable,
 | 
							       ttable_entry_t *ttable,
 | 
				
			||||||
		       unsigned int tt_ssize,
 | 
							       unsigned int tt_ssize,
 | 
				
			||||||
		       unsigned int tt_cused, unsigned int tt_sused,
 | 
							       unsigned int tt_cused, unsigned int tt_sused,
 | 
				
			||||||
		       snd_pcm_t *slave, int close_slave);
 | 
							       snd_pcm_t *slave, int close_slave);
 | 
				
			||||||
int snd_pcm_rate_open(snd_pcm_t **handlep, char *name, int sformat, int srate, snd_pcm_t *slave, int close_slave);
 | 
					int snd_pcm_rate_open(snd_pcm_t **pcmp, char *name, int sformat, int srate, snd_pcm_t *slave, int close_slave);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -326,12 +326,6 @@ static int snd_pcm_rate_params(snd_pcm_t *pcm, snd_pcm_params_t * params)
 | 
				
			||||||
		return err;
 | 
							return err;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (slave->mmap_data) {
 | 
					 | 
				
			||||||
		err = snd_pcm_munmap_data(slave);
 | 
					 | 
				
			||||||
		if (err < 0)
 | 
					 | 
				
			||||||
			return err;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (rate->req_srate - slave_info.min_rate < slave_info.max_rate - rate->req_srate)
 | 
						if (rate->req_srate - slave_info.min_rate < slave_info.max_rate - rate->req_srate)
 | 
				
			||||||
		srate = slave_info.min_rate;
 | 
							srate = slave_info.min_rate;
 | 
				
			||||||
	else
 | 
						else
 | 
				
			||||||
| 
						 | 
					@ -349,10 +343,6 @@ static int snd_pcm_rate_params(snd_pcm_t *pcm, snd_pcm_params_t * params)
 | 
				
			||||||
	err = snd_pcm_params(slave, &slave_params);
 | 
						err = snd_pcm_params(slave, &slave_params);
 | 
				
			||||||
	params->fail_mask = slave_params.fail_mask;
 | 
						params->fail_mask = slave_params.fail_mask;
 | 
				
			||||||
	params->fail_reason = slave_params.fail_reason;
 | 
						params->fail_reason = slave_params.fail_reason;
 | 
				
			||||||
	if (slave->valid_setup) {
 | 
					 | 
				
			||||||
		int r = snd_pcm_mmap_data(slave, NULL);
 | 
					 | 
				
			||||||
		assert(r >= 0);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return err;
 | 
						return err;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -565,7 +555,7 @@ static void snd_pcm_rate_dump(snd_pcm_t *pcm, FILE *fp)
 | 
				
			||||||
	snd_pcm_dump(rate->plug.slave, fp);
 | 
						snd_pcm_dump(rate->plug.slave, fp);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct snd_pcm_ops snd_pcm_rate_ops = {
 | 
					snd_pcm_ops_t snd_pcm_rate_ops = {
 | 
				
			||||||
	close: snd_pcm_rate_close,
 | 
						close: snd_pcm_rate_close,
 | 
				
			||||||
	info: snd_pcm_plugin_info,
 | 
						info: snd_pcm_plugin_info,
 | 
				
			||||||
	params_info: snd_pcm_rate_params_info,
 | 
						params_info: snd_pcm_rate_params_info,
 | 
				
			||||||
| 
						 | 
					@ -577,20 +567,15 @@ struct snd_pcm_ops snd_pcm_rate_ops = {
 | 
				
			||||||
	dump: snd_pcm_rate_dump,
 | 
						dump: snd_pcm_rate_dump,
 | 
				
			||||||
	nonblock: snd_pcm_plugin_nonblock,
 | 
						nonblock: snd_pcm_plugin_nonblock,
 | 
				
			||||||
	async: snd_pcm_plugin_async,
 | 
						async: snd_pcm_plugin_async,
 | 
				
			||||||
	mmap_status: snd_pcm_plugin_mmap_status,
 | 
						mmap: snd_pcm_plugin_mmap,
 | 
				
			||||||
	mmap_control: snd_pcm_plugin_mmap_control,
 | 
						munmap: snd_pcm_plugin_munmap,
 | 
				
			||||||
	mmap_data: snd_pcm_plugin_mmap_data,
 | 
					 | 
				
			||||||
	munmap_status: snd_pcm_plugin_munmap_status,
 | 
					 | 
				
			||||||
	munmap_control: snd_pcm_plugin_munmap_control,
 | 
					 | 
				
			||||||
	munmap_data: snd_pcm_plugin_munmap_data,
 | 
					 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int snd_pcm_rate_open(snd_pcm_t **handlep, char *name, int sformat, int srate, snd_pcm_t *slave, int close_slave)
 | 
					int snd_pcm_rate_open(snd_pcm_t **pcmp, char *name, int sformat, int srate, snd_pcm_t *slave, int close_slave)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	snd_pcm_t *handle;
 | 
						snd_pcm_t *pcm;
 | 
				
			||||||
	snd_pcm_rate_t *rate;
 | 
						snd_pcm_rate_t *rate;
 | 
				
			||||||
	int err;
 | 
						assert(pcmp && slave);
 | 
				
			||||||
	assert(handlep && slave);
 | 
					 | 
				
			||||||
	if (sformat >= 0 && snd_pcm_format_linear(sformat) != 1)
 | 
						if (sformat >= 0 && snd_pcm_format_linear(sformat) != 1)
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
	rate = calloc(1, sizeof(snd_pcm_rate_t));
 | 
						rate = calloc(1, sizeof(snd_pcm_rate_t));
 | 
				
			||||||
| 
						 | 
					@ -606,27 +591,25 @@ int snd_pcm_rate_open(snd_pcm_t **handlep, char *name, int sformat, int srate, s
 | 
				
			||||||
	rate->plug.slave = slave;
 | 
						rate->plug.slave = slave;
 | 
				
			||||||
	rate->plug.close_slave = close_slave;
 | 
						rate->plug.close_slave = close_slave;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	handle = calloc(1, sizeof(snd_pcm_t));
 | 
						pcm = calloc(1, sizeof(snd_pcm_t));
 | 
				
			||||||
	if (!handle) {
 | 
						if (!pcm) {
 | 
				
			||||||
		free(rate);
 | 
							free(rate);
 | 
				
			||||||
		return -ENOMEM;
 | 
							return -ENOMEM;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if (name)
 | 
						if (name)
 | 
				
			||||||
		handle->name = strdup(name);
 | 
							pcm->name = strdup(name);
 | 
				
			||||||
	handle->type = SND_PCM_TYPE_RATE;
 | 
						pcm->type = SND_PCM_TYPE_RATE;
 | 
				
			||||||
	handle->stream = slave->stream;
 | 
						pcm->stream = slave->stream;
 | 
				
			||||||
	handle->ops = &snd_pcm_rate_ops;
 | 
						pcm->mode = slave->mode;
 | 
				
			||||||
	handle->op_arg = handle;
 | 
						pcm->ops = &snd_pcm_rate_ops;
 | 
				
			||||||
	handle->fast_ops = &snd_pcm_plugin_fast_ops;
 | 
						pcm->op_arg = pcm;
 | 
				
			||||||
	handle->fast_op_arg = handle;
 | 
						pcm->fast_ops = &snd_pcm_plugin_fast_ops;
 | 
				
			||||||
	handle->mode = slave->mode;
 | 
						pcm->fast_op_arg = pcm;
 | 
				
			||||||
	handle->private = rate;
 | 
						pcm->private = rate;
 | 
				
			||||||
	err = snd_pcm_init(handle);
 | 
						pcm->poll_fd = slave->poll_fd;
 | 
				
			||||||
	if (err < 0) {
 | 
						pcm->hw_ptr = &rate->plug.hw_ptr;
 | 
				
			||||||
		snd_pcm_close(handle);
 | 
						pcm->appl_ptr = &rate->plug.appl_ptr;
 | 
				
			||||||
		return err;
 | 
						*pcmp = pcm;
 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	*handlep = handle;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -484,11 +484,6 @@ static int snd_pcm_route_params(snd_pcm_t *pcm, snd_pcm_params_t * params)
 | 
				
			||||||
		params->fail_reason = SND_PCM_PARAMS_FAIL_INVAL;
 | 
							params->fail_reason = SND_PCM_PARAMS_FAIL_INVAL;
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if (slave->mmap_data) {
 | 
					 | 
				
			||||||
		err = snd_pcm_munmap_data(slave);
 | 
					 | 
				
			||||||
		if (err < 0)
 | 
					 | 
				
			||||||
			return err;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	route->cformat = params->format.sfmt;
 | 
						route->cformat = params->format.sfmt;
 | 
				
			||||||
	route->cchannels = params->format.channels;
 | 
						route->cchannels = params->format.channels;
 | 
				
			||||||
	route->cxfer_mode = params->xfer_mode;
 | 
						route->cxfer_mode = params->xfer_mode;
 | 
				
			||||||
| 
						 | 
					@ -504,10 +499,6 @@ static int snd_pcm_route_params(snd_pcm_t *pcm, snd_pcm_params_t * params)
 | 
				
			||||||
	params->format.channels = route->cchannels;
 | 
						params->format.channels = route->cchannels;
 | 
				
			||||||
	params->xfer_mode = route->cxfer_mode;
 | 
						params->xfer_mode = route->cxfer_mode;
 | 
				
			||||||
	params->mmap_shape = route->cmmap_shape;
 | 
						params->mmap_shape = route->cmmap_shape;
 | 
				
			||||||
	if (slave->valid_setup) {
 | 
					 | 
				
			||||||
		int r = snd_pcm_mmap_data(slave, NULL);
 | 
					 | 
				
			||||||
		assert(r >= 0);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return err;
 | 
						return err;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -599,12 +590,14 @@ static int snd_pcm_route_channel_setup(snd_pcm_t *pcm, snd_pcm_channel_setup_t *
 | 
				
			||||||
	if (err < 0)
 | 
						if (err < 0)
 | 
				
			||||||
		return err;
 | 
							return err;
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
						if (!pcm->mmap_info)
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
	if (pcm->setup.mmap_shape == SND_PCM_MMAP_INTERLEAVED) {
 | 
						if (pcm->setup.mmap_shape == SND_PCM_MMAP_INTERLEAVED) {
 | 
				
			||||||
		setup->running_area.addr = pcm->mmap_data;
 | 
							setup->running_area.addr = pcm->mmap_info->addr;
 | 
				
			||||||
		setup->running_area.first = setup->channel * pcm->bits_per_sample;
 | 
							setup->running_area.first = setup->channel * pcm->bits_per_sample;
 | 
				
			||||||
		setup->running_area.step = pcm->bits_per_frame;
 | 
							setup->running_area.step = pcm->bits_per_frame;
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		setup->running_area.addr = pcm->mmap_data + setup->channel * pcm->setup.buffer_size * pcm->bits_per_sample / 8;
 | 
							setup->running_area.addr = pcm->mmap_info->addr + setup->channel * pcm->setup.buffer_size * pcm->bits_per_sample / 8;
 | 
				
			||||||
		setup->running_area.first = 0;
 | 
							setup->running_area.first = 0;
 | 
				
			||||||
		setup->running_area.step = pcm->bits_per_sample;
 | 
							setup->running_area.step = pcm->bits_per_sample;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -684,7 +677,7 @@ static void snd_pcm_route_dump(snd_pcm_t *pcm, FILE *fp)
 | 
				
			||||||
	snd_pcm_dump(route->plug.slave, fp);
 | 
						snd_pcm_dump(route->plug.slave, fp);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct snd_pcm_ops snd_pcm_route_ops = {
 | 
					snd_pcm_ops_t snd_pcm_route_ops = {
 | 
				
			||||||
	close: snd_pcm_route_close,
 | 
						close: snd_pcm_route_close,
 | 
				
			||||||
	info: snd_pcm_plugin_info,
 | 
						info: snd_pcm_plugin_info,
 | 
				
			||||||
	params_info: snd_pcm_route_params_info,
 | 
						params_info: snd_pcm_route_params_info,
 | 
				
			||||||
| 
						 | 
					@ -696,12 +689,8 @@ struct snd_pcm_ops snd_pcm_route_ops = {
 | 
				
			||||||
	dump: snd_pcm_route_dump,
 | 
						dump: snd_pcm_route_dump,
 | 
				
			||||||
	nonblock: snd_pcm_plugin_nonblock,
 | 
						nonblock: snd_pcm_plugin_nonblock,
 | 
				
			||||||
	async: snd_pcm_plugin_async,
 | 
						async: snd_pcm_plugin_async,
 | 
				
			||||||
	mmap_status: snd_pcm_plugin_mmap_status,
 | 
						mmap: snd_pcm_plugin_mmap,
 | 
				
			||||||
	mmap_control: snd_pcm_plugin_mmap_control,
 | 
						munmap: snd_pcm_plugin_munmap,
 | 
				
			||||||
	mmap_data: snd_pcm_plugin_mmap_data,
 | 
					 | 
				
			||||||
	munmap_status: snd_pcm_plugin_munmap_status,
 | 
					 | 
				
			||||||
	munmap_control: snd_pcm_plugin_munmap_control,
 | 
					 | 
				
			||||||
	munmap_data: snd_pcm_plugin_munmap_data,
 | 
					 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int route_load_ttable(route_params_t *params, int stream,
 | 
					int route_load_ttable(route_params_t *params, int stream,
 | 
				
			||||||
| 
						 | 
					@ -776,17 +765,17 @@ int route_load_ttable(route_params_t *params, int stream,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int snd_pcm_route_open(snd_pcm_t **handlep, char *name,
 | 
					int snd_pcm_route_open(snd_pcm_t **pcmp, char *name,
 | 
				
			||||||
		       int sformat, unsigned int schannels,
 | 
							       int sformat, unsigned int schannels,
 | 
				
			||||||
		       ttable_entry_t *ttable,
 | 
							       ttable_entry_t *ttable,
 | 
				
			||||||
		       unsigned int tt_ssize,
 | 
							       unsigned int tt_ssize,
 | 
				
			||||||
		       unsigned int tt_cused, unsigned int tt_sused,
 | 
							       unsigned int tt_cused, unsigned int tt_sused,
 | 
				
			||||||
		       snd_pcm_t *slave, int close_slave)
 | 
							       snd_pcm_t *slave, int close_slave)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	snd_pcm_t *handle;
 | 
						snd_pcm_t *pcm;
 | 
				
			||||||
	snd_pcm_route_t *route;
 | 
						snd_pcm_route_t *route;
 | 
				
			||||||
	int err;
 | 
						int err;
 | 
				
			||||||
	assert(handlep && slave && ttable);
 | 
						assert(pcmp && slave && ttable);
 | 
				
			||||||
	if (sformat >= 0 && snd_pcm_format_linear(sformat) != 1)
 | 
						if (sformat >= 0 && snd_pcm_format_linear(sformat) != 1)
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
	route = calloc(1, sizeof(snd_pcm_route_t));
 | 
						route = calloc(1, sizeof(snd_pcm_route_t));
 | 
				
			||||||
| 
						 | 
					@ -800,32 +789,30 @@ int snd_pcm_route_open(snd_pcm_t **handlep, char *name,
 | 
				
			||||||
	route->plug.slave = slave;
 | 
						route->plug.slave = slave;
 | 
				
			||||||
	route->plug.close_slave = close_slave;
 | 
						route->plug.close_slave = close_slave;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	handle = calloc(1, sizeof(snd_pcm_t));
 | 
						pcm = calloc(1, sizeof(snd_pcm_t));
 | 
				
			||||||
	if (!handle) {
 | 
						if (!pcm) {
 | 
				
			||||||
		free(route);
 | 
							free(route);
 | 
				
			||||||
		return -ENOMEM;
 | 
							return -ENOMEM;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if (name)
 | 
						if (name)
 | 
				
			||||||
		handle->name = strdup(name);
 | 
							pcm->name = strdup(name);
 | 
				
			||||||
	handle->type = SND_PCM_TYPE_ROUTE;
 | 
						pcm->type = SND_PCM_TYPE_ROUTE;
 | 
				
			||||||
	handle->stream = slave->stream;
 | 
						pcm->stream = slave->stream;
 | 
				
			||||||
	handle->ops = &snd_pcm_route_ops;
 | 
						pcm->mode = slave->mode;
 | 
				
			||||||
	handle->op_arg = handle;
 | 
						pcm->ops = &snd_pcm_route_ops;
 | 
				
			||||||
	handle->fast_ops = &snd_pcm_plugin_fast_ops;
 | 
						pcm->op_arg = pcm;
 | 
				
			||||||
	handle->fast_op_arg = handle;
 | 
						pcm->fast_ops = &snd_pcm_plugin_fast_ops;
 | 
				
			||||||
	handle->mode = slave->mode;
 | 
						pcm->fast_op_arg = pcm;
 | 
				
			||||||
	handle->private = route;
 | 
						pcm->private = route;
 | 
				
			||||||
	err = snd_pcm_init(handle);
 | 
						pcm->poll_fd = slave->poll_fd;
 | 
				
			||||||
 | 
						pcm->hw_ptr = &route->plug.hw_ptr;
 | 
				
			||||||
 | 
						pcm->appl_ptr = &route->plug.appl_ptr;
 | 
				
			||||||
 | 
						err = route_load_ttable(&route->params, pcm->stream, tt_ssize, ttable, tt_cused, tt_sused);
 | 
				
			||||||
	if (err < 0) {
 | 
						if (err < 0) {
 | 
				
			||||||
		snd_pcm_close(handle);
 | 
							snd_pcm_close(pcm);
 | 
				
			||||||
		return err;
 | 
							return err;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	err = route_load_ttable(&route->params, handle->stream, tt_ssize, ttable, tt_cused, tt_sused);
 | 
						*pcmp = pcm;
 | 
				
			||||||
	if (err < 0) {
 | 
					 | 
				
			||||||
		snd_pcm_close(handle);
 | 
					 | 
				
			||||||
		return err;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	*handlep = handle;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -42,6 +42,7 @@ typedef struct {
 | 
				
			||||||
	size_t channels_count;
 | 
						size_t channels_count;
 | 
				
			||||||
	size_t open_count;
 | 
						size_t open_count;
 | 
				
			||||||
	size_t setup_count;
 | 
						size_t setup_count;
 | 
				
			||||||
 | 
						size_t mmap_count;
 | 
				
			||||||
	size_t prepared_count;
 | 
						size_t prepared_count;
 | 
				
			||||||
	size_t running_count;
 | 
						size_t running_count;
 | 
				
			||||||
	size_t safety_threshold;
 | 
						size_t safety_threshold;
 | 
				
			||||||
| 
						 | 
					@ -61,8 +62,9 @@ typedef struct {
 | 
				
			||||||
	pid_t async_pid;
 | 
						pid_t async_pid;
 | 
				
			||||||
	struct timeval trigger_time;
 | 
						struct timeval trigger_time;
 | 
				
			||||||
	size_t draining_silence;
 | 
						size_t draining_silence;
 | 
				
			||||||
	snd_pcm_mmap_control_t mmap_control;
 | 
						int state;
 | 
				
			||||||
	snd_pcm_mmap_status_t mmap_status;
 | 
						size_t hw_ptr;
 | 
				
			||||||
 | 
						size_t appl_ptr;
 | 
				
			||||||
	int ready;
 | 
						int ready;
 | 
				
			||||||
	int client_socket;
 | 
						int client_socket;
 | 
				
			||||||
	int slave_socket;
 | 
						int slave_socket;
 | 
				
			||||||
| 
						 | 
					@ -79,7 +81,7 @@ static void snd_pcm_share_interrupt(snd_pcm_share_slave_t *slave)
 | 
				
			||||||
		snd_pcm_share_t *share = list_entry(i, snd_pcm_share_t, list);
 | 
							snd_pcm_share_t *share = list_entry(i, snd_pcm_share_t, list);
 | 
				
			||||||
		snd_pcm_t *pcm = share->pcm;
 | 
							snd_pcm_t *pcm = share->pcm;
 | 
				
			||||||
		int ready;
 | 
							int ready;
 | 
				
			||||||
		switch (share->mmap_status.state) {
 | 
							switch (share->state) {
 | 
				
			||||||
		case SND_PCM_STATE_DRAINING:
 | 
							case SND_PCM_STATE_DRAINING:
 | 
				
			||||||
			if (pcm->stream == SND_PCM_STREAM_CAPTURE)
 | 
								if (pcm->stream == SND_PCM_STREAM_CAPTURE)
 | 
				
			||||||
				ready = 1;
 | 
									ready = 1;
 | 
				
			||||||
| 
						 | 
					@ -146,7 +148,7 @@ static void snd_pcm_share_stop(snd_pcm_t *pcm, int state)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	snd_pcm_share_t *share = pcm->private;
 | 
						snd_pcm_share_t *share = pcm->private;
 | 
				
			||||||
	snd_pcm_share_slave_t *slave = share->slave;
 | 
						snd_pcm_share_slave_t *slave = share->slave;
 | 
				
			||||||
	share->mmap_status.state = state;
 | 
						share->state = state;
 | 
				
			||||||
	gettimeofday(&share->trigger_time, 0);
 | 
						gettimeofday(&share->trigger_time, 0);
 | 
				
			||||||
	slave->prepared_count--;
 | 
						slave->prepared_count--;
 | 
				
			||||||
	slave->running_count--;
 | 
						slave->running_count--;
 | 
				
			||||||
| 
						 | 
					@ -160,8 +162,8 @@ static void snd_pcm_share_stop(snd_pcm_t *pcm, int state)
 | 
				
			||||||
				   pcm->setup.format.channels, pcm->setup.buffer_size,
 | 
									   pcm->setup.format.channels, pcm->setup.buffer_size,
 | 
				
			||||||
				   pcm->setup.format.sfmt);
 | 
									   pcm->setup.format.sfmt);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	share->mmap_status.hw_ptr = slave->pcm->mmap_status->hw_ptr;
 | 
						share->hw_ptr = *slave->pcm->hw_ptr;
 | 
				
			||||||
	pcm->mmap_status = &share->mmap_status;
 | 
						pcm->hw_ptr = &share->hw_ptr;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Warning: take the mutex before to call this */
 | 
					/* Warning: take the mutex before to call this */
 | 
				
			||||||
| 
						 | 
					@ -182,11 +184,11 @@ static void snd_pcm_share_slave_forward(snd_pcm_share_slave_t *slave)
 | 
				
			||||||
	buffer_size = slave->pcm->setup.buffer_size;
 | 
						buffer_size = slave->pcm->setup.buffer_size;
 | 
				
			||||||
	min_frames = buffer_size;
 | 
						min_frames = buffer_size;
 | 
				
			||||||
	max_frames = 0;
 | 
						max_frames = 0;
 | 
				
			||||||
	slave_appl_ptr = slave->pcm->mmap_control->appl_ptr;
 | 
						slave_appl_ptr = *slave->pcm->appl_ptr;
 | 
				
			||||||
	for (i = slave->clients.next; i != &slave->clients; i = i->next) {
 | 
						for (i = slave->clients.next; i != &slave->clients; i = i->next) {
 | 
				
			||||||
		snd_pcm_share_t *share = list_entry(i, snd_pcm_share_t, list);
 | 
							snd_pcm_share_t *share = list_entry(i, snd_pcm_share_t, list);
 | 
				
			||||||
		snd_pcm_t *pcm = share->pcm;
 | 
							snd_pcm_t *pcm = share->pcm;
 | 
				
			||||||
		switch (share->mmap_status.state) {
 | 
							switch (share->state) {
 | 
				
			||||||
		case SND_PCM_STATE_RUNNING:
 | 
							case SND_PCM_STATE_RUNNING:
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		case SND_PCM_STATE_DRAINING:
 | 
							case SND_PCM_STATE_DRAINING:
 | 
				
			||||||
| 
						 | 
					@ -220,7 +222,7 @@ static void snd_pcm_share_slave_forward(snd_pcm_share_slave_t *slave)
 | 
				
			||||||
		default:
 | 
							default:
 | 
				
			||||||
			continue;
 | 
								continue;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		frames = share->mmap_control.appl_ptr - slave_appl_ptr;
 | 
							frames = share->appl_ptr - slave_appl_ptr;
 | 
				
			||||||
		if (frames > (ssize_t)buffer_size)
 | 
							if (frames > (ssize_t)buffer_size)
 | 
				
			||||||
			frames -= pcm->setup.boundary;
 | 
								frames -= pcm->setup.boundary;
 | 
				
			||||||
		else if (frames < -(ssize_t)pcm->setup.buffer_size)
 | 
							else if (frames < -(ssize_t)pcm->setup.buffer_size)
 | 
				
			||||||
| 
						 | 
					@ -262,7 +264,7 @@ static int snd_pcm_share_close(snd_pcm_t *pcm)
 | 
				
			||||||
	snd_pcm_share_t *share = pcm->private;
 | 
						snd_pcm_share_t *share = pcm->private;
 | 
				
			||||||
	snd_pcm_share_slave_t *slave = share->slave;
 | 
						snd_pcm_share_slave_t *slave = share->slave;
 | 
				
			||||||
	int err = 0;
 | 
						int err = 0;
 | 
				
			||||||
	if (share->mmap_status.state == SND_PCM_STATE_RUNNING) {
 | 
						if (share->state == SND_PCM_STATE_RUNNING) {
 | 
				
			||||||
		if (pcm->mode & SND_PCM_NONBLOCK)
 | 
							if (pcm->mode & SND_PCM_NONBLOCK)
 | 
				
			||||||
			snd_pcm_drop(pcm);
 | 
								snd_pcm_drop(pcm);
 | 
				
			||||||
		else
 | 
							else
 | 
				
			||||||
| 
						 | 
					@ -276,11 +278,14 @@ static int snd_pcm_share_close(snd_pcm_t *pcm)
 | 
				
			||||||
		pthread_kill(slave->thread, SIGTERM);
 | 
							pthread_kill(slave->thread, SIGTERM);
 | 
				
			||||||
		err = snd_pcm_close(slave->pcm);
 | 
							err = snd_pcm_close(slave->pcm);
 | 
				
			||||||
		list_del(&slave->list);
 | 
							list_del(&slave->list);
 | 
				
			||||||
 | 
							pthread_mutex_unlock(&slave->mutex);
 | 
				
			||||||
		pthread_mutex_destroy(&slave->mutex);
 | 
							pthread_mutex_destroy(&slave->mutex);
 | 
				
			||||||
		free(slave);
 | 
							free(slave);
 | 
				
			||||||
 | 
							list_del(&share->list);
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							list_del(&share->list);
 | 
				
			||||||
 | 
							pthread_mutex_unlock(&slave->mutex);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	list_del(&share->list);
 | 
					 | 
				
			||||||
	pthread_mutex_unlock(&slave->mutex);
 | 
					 | 
				
			||||||
	close(share->client_socket);
 | 
						close(share->client_socket);
 | 
				
			||||||
	close(share->slave_socket);
 | 
						close(share->slave_socket);
 | 
				
			||||||
	free(share->slave_channels);
 | 
						free(share->slave_channels);
 | 
				
			||||||
| 
						 | 
					@ -358,6 +363,64 @@ static int snd_pcm_share_params_info(snd_pcm_t *pcm, snd_pcm_params_info_t *info
 | 
				
			||||||
	return err;
 | 
						return err;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int snd_pcm_share_mmap(snd_pcm_t *pcm)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						snd_pcm_share_t *share = pcm->private;
 | 
				
			||||||
 | 
						snd_pcm_share_slave_t *slave = share->slave;
 | 
				
			||||||
 | 
						snd_pcm_mmap_info_t *i;
 | 
				
			||||||
 | 
						int err;
 | 
				
			||||||
 | 
						pthread_mutex_lock(&slave->mutex);
 | 
				
			||||||
 | 
						if (slave->mmap_count == 0) {
 | 
				
			||||||
 | 
							err = snd_pcm_mmap(slave->pcm);
 | 
				
			||||||
 | 
							if (err < 0) {
 | 
				
			||||||
 | 
								pthread_mutex_unlock(&slave->mutex);
 | 
				
			||||||
 | 
								return err;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if (slave->pcm->stream == SND_PCM_STREAM_PLAYBACK)
 | 
				
			||||||
 | 
								snd_pcm_areas_silence(slave->pcm->running_areas, 0, slave->pcm->setup.format.channels, slave->pcm->setup.buffer_size, slave->pcm->setup.format.sfmt);
 | 
				
			||||||
 | 
							slave->mmap_count++;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						pthread_mutex_unlock(&slave->mutex);
 | 
				
			||||||
 | 
						pcm->mmap_info_count = slave->pcm->mmap_info_count + 1;
 | 
				
			||||||
 | 
						pcm->mmap_info = malloc(pcm->mmap_info_count * sizeof(*pcm->mmap_info));
 | 
				
			||||||
 | 
						if (!pcm->mmap_info)
 | 
				
			||||||
 | 
							return -ENOMEM;
 | 
				
			||||||
 | 
						memcpy(pcm->mmap_info, slave->pcm->mmap_info, slave->pcm->mmap_info_count * sizeof(*pcm->mmap_info));
 | 
				
			||||||
 | 
						i = &pcm->mmap_info[slave->pcm->mmap_info_count];
 | 
				
			||||||
 | 
						i->type = SND_PCM_MMAP_USER;
 | 
				
			||||||
 | 
						i->size = snd_pcm_frames_to_bytes(pcm, pcm->setup.buffer_size);
 | 
				
			||||||
 | 
						share->stopped_data = malloc(i->size);
 | 
				
			||||||
 | 
						if (share->stopped_data == 0) {
 | 
				
			||||||
 | 
							free(pcm->mmap_info);
 | 
				
			||||||
 | 
							pcm->mmap_info = 0;
 | 
				
			||||||
 | 
							return -ENOMEM;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						i->addr = share->stopped_data;
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int snd_pcm_share_munmap(snd_pcm_t *pcm ATTRIBUTE_UNUSED)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						snd_pcm_share_t *share = pcm->private;
 | 
				
			||||||
 | 
						snd_pcm_share_slave_t *slave = share->slave;
 | 
				
			||||||
 | 
						int err;
 | 
				
			||||||
 | 
						pthread_mutex_lock(&slave->mutex);
 | 
				
			||||||
 | 
						slave->mmap_count--;
 | 
				
			||||||
 | 
						if (slave->mmap_count == 0) {
 | 
				
			||||||
 | 
							err = snd_pcm_munmap(slave->pcm);
 | 
				
			||||||
 | 
							if (err < 0) {
 | 
				
			||||||
 | 
								pthread_mutex_unlock(&slave->mutex);
 | 
				
			||||||
 | 
								return err;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						pthread_mutex_unlock(&slave->mutex);
 | 
				
			||||||
 | 
						free(pcm->mmap_info);
 | 
				
			||||||
 | 
						pcm->mmap_info_count = 0;
 | 
				
			||||||
 | 
						pcm->mmap_info = 0;
 | 
				
			||||||
 | 
						free(share->stopped_data);
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
							
 | 
				
			||||||
static int snd_pcm_share_params(snd_pcm_t *pcm, snd_pcm_params_t *params)
 | 
					static int snd_pcm_share_params(snd_pcm_t *pcm, snd_pcm_params_t *params)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	snd_pcm_share_t *share = pcm->private;
 | 
						snd_pcm_share_t *share = pcm->private;
 | 
				
			||||||
| 
						 | 
					@ -367,7 +430,7 @@ static int snd_pcm_share_params(snd_pcm_t *pcm, snd_pcm_params_t *params)
 | 
				
			||||||
	if (channels != share->channels_count) {
 | 
						if (channels != share->channels_count) {
 | 
				
			||||||
		params->fail_mask = SND_PCM_PARAMS_CHANNELS;
 | 
							params->fail_mask = SND_PCM_PARAMS_CHANNELS;
 | 
				
			||||||
		params->fail_reason = SND_PCM_PARAMS_FAIL_INVAL;
 | 
							params->fail_reason = SND_PCM_PARAMS_FAIL_INVAL;
 | 
				
			||||||
		ERR("channels requested (%d) differs from configuration (%d)", channels, share->channels_count);
 | 
							ERR("channels requested (%d) differs from configuration (%ld)", channels, (long)share->channels_count);
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	share->xfer_mode = params->xfer_mode;
 | 
						share->xfer_mode = params->xfer_mode;
 | 
				
			||||||
| 
						 | 
					@ -387,22 +450,14 @@ static int snd_pcm_share_params(snd_pcm_t *pcm, snd_pcm_params_t *params)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		snd_pcm_params_t sp = *params;
 | 
							snd_pcm_params_t sp = *params;
 | 
				
			||||||
		if (slave->pcm->mmap_data) {
 | 
					 | 
				
			||||||
			err = snd_pcm_munmap_data(slave->pcm);
 | 
					 | 
				
			||||||
			if (err < 0)
 | 
					 | 
				
			||||||
				goto _end;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		sp.xfer_mode = SND_PCM_XFER_UNSPECIFIED;
 | 
							sp.xfer_mode = SND_PCM_XFER_UNSPECIFIED;
 | 
				
			||||||
		sp.xrun_mode = SND_PCM_XRUN_NONE;
 | 
							sp.xrun_mode = SND_PCM_XRUN_NONE;
 | 
				
			||||||
		sp.format.channels = slave->channels_count;
 | 
							sp.format.channels = slave->channels_count;
 | 
				
			||||||
		err = snd_pcm_params(slave->pcm, &sp);
 | 
							err = snd_pcm_params(slave->pcm, &sp);
 | 
				
			||||||
		snd_pcm_mmap_data(slave->pcm, NULL);
 | 
					 | 
				
			||||||
		if (err < 0)
 | 
							if (err < 0)
 | 
				
			||||||
			goto _end;
 | 
								goto _end;
 | 
				
			||||||
		if (slave->pcm->stream == SND_PCM_STREAM_PLAYBACK)
 | 
					 | 
				
			||||||
			snd_pcm_areas_silence(slave->pcm->running_areas, 0, slave->pcm->setup.format.channels, slave->pcm->setup.buffer_size, slave->pcm->setup.format.sfmt);
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	share->mmap_status.state = SND_PCM_STATE_SETUP;
 | 
						share->state = SND_PCM_STATE_SETUP;
 | 
				
			||||||
	slave->setup_count++;
 | 
						slave->setup_count++;
 | 
				
			||||||
 _end:
 | 
					 _end:
 | 
				
			||||||
	pthread_mutex_unlock(&slave->mutex);
 | 
						pthread_mutex_unlock(&slave->mutex);
 | 
				
			||||||
| 
						 | 
					@ -437,13 +492,13 @@ static int snd_pcm_share_status(snd_pcm_t *pcm, snd_pcm_status_t *status)
 | 
				
			||||||
	pthread_mutex_lock(&slave->mutex);
 | 
						pthread_mutex_lock(&slave->mutex);
 | 
				
			||||||
	if (pcm->stream == SND_PCM_STREAM_PLAYBACK) {
 | 
						if (pcm->stream == SND_PCM_STREAM_PLAYBACK) {
 | 
				
			||||||
		status->avail = snd_pcm_mmap_playback_avail(pcm);
 | 
							status->avail = snd_pcm_mmap_playback_avail(pcm);
 | 
				
			||||||
		if (share->mmap_status.state != SND_PCM_STATE_RUNNING &&
 | 
							if (share->state != SND_PCM_STATE_RUNNING &&
 | 
				
			||||||
		    share->mmap_status.state != SND_PCM_STATE_DRAINING)
 | 
							    share->state != SND_PCM_STATE_DRAINING)
 | 
				
			||||||
			goto _notrunning;
 | 
								goto _notrunning;
 | 
				
			||||||
		d = pcm->setup.buffer_size - status->avail;
 | 
							d = pcm->setup.buffer_size - status->avail;
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		status->avail = snd_pcm_mmap_capture_avail(pcm);
 | 
							status->avail = snd_pcm_mmap_capture_avail(pcm);
 | 
				
			||||||
		if (share->mmap_status.state != SND_PCM_STATE_RUNNING)
 | 
							if (share->state != SND_PCM_STATE_RUNNING)
 | 
				
			||||||
			goto _notrunning;
 | 
								goto _notrunning;
 | 
				
			||||||
		d = status->avail;
 | 
							d = status->avail;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -452,7 +507,7 @@ static int snd_pcm_share_status(snd_pcm_t *pcm, snd_pcm_status_t *status)
 | 
				
			||||||
		goto _end;
 | 
							goto _end;
 | 
				
			||||||
 _notrunning:
 | 
					 _notrunning:
 | 
				
			||||||
	status->delay = sd + d;
 | 
						status->delay = sd + d;
 | 
				
			||||||
	status->state = share->mmap_status.state;
 | 
						status->state = share->state;
 | 
				
			||||||
	status->trigger_time = share->trigger_time;
 | 
						status->trigger_time = share->trigger_time;
 | 
				
			||||||
 _end:
 | 
					 _end:
 | 
				
			||||||
	pthread_mutex_unlock(&slave->mutex);
 | 
						pthread_mutex_unlock(&slave->mutex);
 | 
				
			||||||
| 
						 | 
					@ -462,7 +517,7 @@ static int snd_pcm_share_status(snd_pcm_t *pcm, snd_pcm_status_t *status)
 | 
				
			||||||
static int snd_pcm_share_state(snd_pcm_t *pcm)
 | 
					static int snd_pcm_share_state(snd_pcm_t *pcm)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	snd_pcm_share_t *share = pcm->private;
 | 
						snd_pcm_share_t *share = pcm->private;
 | 
				
			||||||
	return share->mmap_status.state;
 | 
						return share->state;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int snd_pcm_share_delay(snd_pcm_t *pcm, ssize_t *delayp)
 | 
					static int snd_pcm_share_delay(snd_pcm_t *pcm, ssize_t *delayp)
 | 
				
			||||||
| 
						 | 
					@ -472,7 +527,7 @@ static int snd_pcm_share_delay(snd_pcm_t *pcm, ssize_t *delayp)
 | 
				
			||||||
	int err = 0;
 | 
						int err = 0;
 | 
				
			||||||
	ssize_t sd;
 | 
						ssize_t sd;
 | 
				
			||||||
	pthread_mutex_lock(&slave->mutex);
 | 
						pthread_mutex_lock(&slave->mutex);
 | 
				
			||||||
	switch (share->mmap_status.state) {
 | 
						switch (share->state) {
 | 
				
			||||||
	case SND_PCM_STATE_XRUN:
 | 
						case SND_PCM_STATE_XRUN:
 | 
				
			||||||
		err = -EPIPE;
 | 
							err = -EPIPE;
 | 
				
			||||||
		goto _end;
 | 
							goto _end;
 | 
				
			||||||
| 
						 | 
					@ -507,7 +562,7 @@ static ssize_t snd_pcm_share_avail_update(snd_pcm_t *pcm)
 | 
				
			||||||
		for (i = slave->clients.next; i != &slave->clients; i = i->next) {
 | 
							for (i = slave->clients.next; i != &slave->clients; i = i->next) {
 | 
				
			||||||
			snd_pcm_share_t *share = list_entry(i, snd_pcm_share_t, list);
 | 
								snd_pcm_share_t *share = list_entry(i, snd_pcm_share_t, list);
 | 
				
			||||||
			snd_pcm_t *pcm = share->pcm;
 | 
								snd_pcm_t *pcm = share->pcm;
 | 
				
			||||||
			if (share->mmap_status.state == SND_PCM_STATE_RUNNING &&
 | 
								if (share->state == SND_PCM_STATE_RUNNING &&
 | 
				
			||||||
			    pcm->setup.xrun_mode != SND_PCM_XRUN_NONE)
 | 
								    pcm->setup.xrun_mode != SND_PCM_XRUN_NONE)
 | 
				
			||||||
				snd_pcm_share_stop(pcm, SND_PCM_STATE_XRUN);
 | 
									snd_pcm_share_stop(pcm, SND_PCM_STATE_XRUN);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
| 
						 | 
					@ -521,16 +576,16 @@ static ssize_t snd_pcm_share_avail_update(snd_pcm_t *pcm)
 | 
				
			||||||
	return ret;
 | 
						return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static ssize_t snd_pcm_share_mmap_forward(snd_pcm_t *pcm, size_t size)
 | 
					/* Call it with mutex held */
 | 
				
			||||||
 | 
					static ssize_t _snd_pcm_share_mmap_forward(snd_pcm_t *pcm, size_t size)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	snd_pcm_share_t *share = pcm->private;
 | 
						snd_pcm_share_t *share = pcm->private;
 | 
				
			||||||
	snd_pcm_share_slave_t *slave = share->slave;
 | 
						snd_pcm_share_slave_t *slave = share->slave;
 | 
				
			||||||
	ssize_t ret = 0;
 | 
						ssize_t ret = 0;
 | 
				
			||||||
	ssize_t frames;
 | 
						ssize_t frames;
 | 
				
			||||||
	pthread_mutex_lock(&slave->mutex);
 | 
					 | 
				
			||||||
	if (pcm->stream == SND_PCM_STREAM_PLAYBACK &&
 | 
						if (pcm->stream == SND_PCM_STREAM_PLAYBACK &&
 | 
				
			||||||
	    share->mmap_status.state == SND_PCM_STATE_RUNNING) {
 | 
						    share->state == SND_PCM_STATE_RUNNING) {
 | 
				
			||||||
		frames = slave->pcm->mmap_control->appl_ptr - share->mmap_control.appl_ptr;
 | 
							frames = *slave->pcm->appl_ptr - share->appl_ptr;
 | 
				
			||||||
		if (frames > (ssize_t)pcm->setup.buffer_size)
 | 
							if (frames > (ssize_t)pcm->setup.buffer_size)
 | 
				
			||||||
			frames -= pcm->setup.boundary;
 | 
								frames -= pcm->setup.boundary;
 | 
				
			||||||
		else if (frames < -(ssize_t)pcm->setup.buffer_size)
 | 
							else if (frames < -(ssize_t)pcm->setup.buffer_size)
 | 
				
			||||||
| 
						 | 
					@ -538,19 +593,27 @@ static ssize_t snd_pcm_share_mmap_forward(snd_pcm_t *pcm, size_t size)
 | 
				
			||||||
		if (frames > 0) {
 | 
							if (frames > 0) {
 | 
				
			||||||
			/* Latecomer PCM */
 | 
								/* Latecomer PCM */
 | 
				
			||||||
			ret = snd_pcm_rewind(slave->pcm, frames);
 | 
								ret = snd_pcm_rewind(slave->pcm, frames);
 | 
				
			||||||
			if (ret < 0) {
 | 
								if (ret < 0)
 | 
				
			||||||
				pthread_mutex_unlock(&slave->mutex);
 | 
					 | 
				
			||||||
				return ret;
 | 
									return ret;
 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			size += ret;
 | 
								size += ret;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	snd_pcm_mmap_appl_forward(pcm, size);
 | 
						snd_pcm_mmap_appl_forward(pcm, size);
 | 
				
			||||||
	snd_pcm_share_slave_forward(share->slave);
 | 
						snd_pcm_share_slave_forward(share->slave);
 | 
				
			||||||
	pthread_mutex_unlock(&slave->mutex);
 | 
					 | 
				
			||||||
	return size;
 | 
						return size;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static ssize_t snd_pcm_share_mmap_forward(snd_pcm_t *pcm, size_t size)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						snd_pcm_share_t *share = pcm->private;
 | 
				
			||||||
 | 
						snd_pcm_share_slave_t *slave = share->slave;
 | 
				
			||||||
 | 
						ssize_t ret;
 | 
				
			||||||
 | 
						pthread_mutex_lock(&slave->mutex);
 | 
				
			||||||
 | 
						ret = _snd_pcm_share_mmap_forward(pcm, size);
 | 
				
			||||||
 | 
						pthread_mutex_unlock(&slave->mutex);
 | 
				
			||||||
 | 
						return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int snd_pcm_share_prepare(snd_pcm_t *pcm)
 | 
					static int snd_pcm_share_prepare(snd_pcm_t *pcm)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	snd_pcm_share_t *share = pcm->private;
 | 
						snd_pcm_share_t *share = pcm->private;
 | 
				
			||||||
| 
						 | 
					@ -563,9 +626,9 @@ static int snd_pcm_share_prepare(snd_pcm_t *pcm)
 | 
				
			||||||
			goto _end;
 | 
								goto _end;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	slave->prepared_count++;
 | 
						slave->prepared_count++;
 | 
				
			||||||
	share->mmap_status.hw_ptr = 0;
 | 
						share->hw_ptr = 0;
 | 
				
			||||||
	share->mmap_control.appl_ptr = 0;
 | 
						share->appl_ptr = 0;
 | 
				
			||||||
	share->mmap_status.state = SND_PCM_STATE_PREPARED;
 | 
						share->state = SND_PCM_STATE_PREPARED;
 | 
				
			||||||
 _end:
 | 
					 _end:
 | 
				
			||||||
	pthread_mutex_unlock(&slave->mutex);
 | 
						pthread_mutex_unlock(&slave->mutex);
 | 
				
			||||||
	return err;
 | 
						return err;
 | 
				
			||||||
| 
						 | 
					@ -576,10 +639,10 @@ static int snd_pcm_share_start(snd_pcm_t *pcm)
 | 
				
			||||||
	snd_pcm_share_t *share = pcm->private;
 | 
						snd_pcm_share_t *share = pcm->private;
 | 
				
			||||||
	snd_pcm_share_slave_t *slave = share->slave;
 | 
						snd_pcm_share_slave_t *slave = share->slave;
 | 
				
			||||||
	int err = 0;
 | 
						int err = 0;
 | 
				
			||||||
	if (share->mmap_status.state != SND_PCM_STATE_PREPARED)
 | 
						if (share->state != SND_PCM_STATE_PREPARED)
 | 
				
			||||||
		return -EBADFD;
 | 
							return -EBADFD;
 | 
				
			||||||
	pthread_mutex_lock(&slave->mutex);
 | 
						pthread_mutex_lock(&slave->mutex);
 | 
				
			||||||
	share->mmap_status.state = SND_PCM_STATE_RUNNING;
 | 
						share->state = SND_PCM_STATE_RUNNING;
 | 
				
			||||||
	if (pcm->stream == SND_PCM_STREAM_PLAYBACK) {
 | 
						if (pcm->stream == SND_PCM_STREAM_PLAYBACK) {
 | 
				
			||||||
		size_t hw_avail = snd_pcm_mmap_playback_hw_avail(pcm);
 | 
							size_t hw_avail = snd_pcm_mmap_playback_hw_avail(pcm);
 | 
				
			||||||
		if (hw_avail == 0) {
 | 
							if (hw_avail == 0) {
 | 
				
			||||||
| 
						 | 
					@ -595,15 +658,15 @@ static int snd_pcm_share_start(snd_pcm_t *pcm)
 | 
				
			||||||
			if (err < 0)
 | 
								if (err < 0)
 | 
				
			||||||
				goto _end;
 | 
									goto _end;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		assert(share->mmap_status.hw_ptr == 0);
 | 
							assert(share->hw_ptr == 0);
 | 
				
			||||||
		/* Use the same mmap_status of slave */
 | 
							/* Share the same hw_ptr of slave */
 | 
				
			||||||
		pcm->mmap_status = slave->pcm->mmap_status;
 | 
							pcm->hw_ptr = slave->pcm->hw_ptr;
 | 
				
			||||||
		share->mmap_control.appl_ptr = slave->pcm->mmap_control->appl_ptr;
 | 
							share->appl_ptr = *slave->pcm->appl_ptr;
 | 
				
			||||||
		snd_pcm_areas_copy(pcm->stopped_areas, 0,
 | 
							snd_pcm_areas_copy(pcm->stopped_areas, 0,
 | 
				
			||||||
				   pcm->running_areas, snd_pcm_mmap_offset(pcm),
 | 
									   pcm->running_areas, snd_pcm_mmap_offset(pcm),
 | 
				
			||||||
				   pcm->setup.format.channels, hw_avail,
 | 
									   pcm->setup.format.channels, hw_avail,
 | 
				
			||||||
				   pcm->setup.format.sfmt);
 | 
									   pcm->setup.format.sfmt);
 | 
				
			||||||
		snd_pcm_mmap_forward(pcm, pcm->setup.buffer_size);
 | 
							_snd_pcm_share_mmap_forward(pcm, pcm->setup.buffer_size);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if (slave->running_count == 0) {
 | 
						if (slave->running_count == 0) {
 | 
				
			||||||
		err = snd_pcm_start(slave->pcm);
 | 
							err = snd_pcm_start(slave->pcm);
 | 
				
			||||||
| 
						 | 
					@ -623,7 +686,7 @@ static int snd_pcm_share_drop(snd_pcm_t *pcm)
 | 
				
			||||||
	snd_pcm_share_slave_t *slave = share->slave;
 | 
						snd_pcm_share_slave_t *slave = share->slave;
 | 
				
			||||||
	int err = 0;
 | 
						int err = 0;
 | 
				
			||||||
	pthread_mutex_lock(&slave->mutex);
 | 
						pthread_mutex_lock(&slave->mutex);
 | 
				
			||||||
	switch (share->mmap_status.state) {
 | 
						switch (share->state) {
 | 
				
			||||||
	case SND_PCM_STATE_OPEN:
 | 
						case SND_PCM_STATE_OPEN:
 | 
				
			||||||
		err = -EBADFD;
 | 
							err = -EBADFD;
 | 
				
			||||||
		goto _end;
 | 
							goto _end;
 | 
				
			||||||
| 
						 | 
					@ -631,7 +694,7 @@ static int snd_pcm_share_drop(snd_pcm_t *pcm)
 | 
				
			||||||
		goto _end;
 | 
							goto _end;
 | 
				
			||||||
	case SND_PCM_STATE_DRAINING:
 | 
						case SND_PCM_STATE_DRAINING:
 | 
				
			||||||
		if (pcm->stream == SND_PCM_STREAM_CAPTURE) {
 | 
							if (pcm->stream == SND_PCM_STREAM_CAPTURE) {
 | 
				
			||||||
			share->mmap_status.state = SND_PCM_STATE_SETUP;
 | 
								share->state = SND_PCM_STATE_SETUP;
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		/* Fall through */
 | 
							/* Fall through */
 | 
				
			||||||
| 
						 | 
					@ -640,7 +703,7 @@ static int snd_pcm_share_drop(snd_pcm_t *pcm)
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	case SND_PCM_STATE_PREPARED:
 | 
						case SND_PCM_STATE_PREPARED:
 | 
				
			||||||
	case SND_PCM_STATE_XRUN:
 | 
						case SND_PCM_STATE_XRUN:
 | 
				
			||||||
		share->mmap_status.state = SND_PCM_STATE_SETUP;
 | 
							share->state = SND_PCM_STATE_SETUP;
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
| 
						 | 
					@ -659,7 +722,7 @@ static int snd_pcm_share_drop(snd_pcm_t *pcm)
 | 
				
			||||||
				      pcm->setup.buffer_size, pcm->setup.format.sfmt);
 | 
									      pcm->setup.buffer_size, pcm->setup.format.sfmt);
 | 
				
			||||||
		snd_pcm_mmap_forward(pcm, pcm->setup.buffer_size);
 | 
							snd_pcm_mmap_forward(pcm, pcm->setup.buffer_size);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	share->mmap_control.appl_ptr = share->mmap_status.hw_ptr = 0;
 | 
						share->appl_ptr = share->hw_ptr = 0;
 | 
				
			||||||
 _end:
 | 
					 _end:
 | 
				
			||||||
	pthread_mutex_unlock(&slave->mutex);
 | 
						pthread_mutex_unlock(&slave->mutex);
 | 
				
			||||||
	return err;
 | 
						return err;
 | 
				
			||||||
| 
						 | 
					@ -671,29 +734,29 @@ static int snd_pcm_share_drain(snd_pcm_t *pcm)
 | 
				
			||||||
	snd_pcm_share_slave_t *slave = share->slave;
 | 
						snd_pcm_share_slave_t *slave = share->slave;
 | 
				
			||||||
	int err = 0;
 | 
						int err = 0;
 | 
				
			||||||
	pthread_mutex_lock(&slave->mutex);
 | 
						pthread_mutex_lock(&slave->mutex);
 | 
				
			||||||
	switch (share->mmap_status.state) {
 | 
						switch (share->state) {
 | 
				
			||||||
	case SND_PCM_STATE_OPEN:
 | 
						case SND_PCM_STATE_OPEN:
 | 
				
			||||||
		err = -EBADFD;
 | 
							err = -EBADFD;
 | 
				
			||||||
		goto _end;
 | 
							goto _end;
 | 
				
			||||||
	case SND_PCM_STATE_PREPARED:
 | 
						case SND_PCM_STATE_PREPARED:
 | 
				
			||||||
		share->mmap_status.state = SND_PCM_STATE_SETUP;
 | 
							share->state = SND_PCM_STATE_SETUP;
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	case SND_PCM_STATE_SETUP:
 | 
						case SND_PCM_STATE_SETUP:
 | 
				
			||||||
	case SND_PCM_STATE_DRAINING:
 | 
						case SND_PCM_STATE_DRAINING:
 | 
				
			||||||
		goto _end;
 | 
							goto _end;
 | 
				
			||||||
	case SND_PCM_STATE_XRUN:
 | 
						case SND_PCM_STATE_XRUN:
 | 
				
			||||||
		if (pcm->stream == SND_PCM_STREAM_PLAYBACK) {
 | 
							if (pcm->stream == SND_PCM_STREAM_PLAYBACK) {
 | 
				
			||||||
			share->mmap_status.state = SND_PCM_STATE_SETUP;
 | 
								share->state = SND_PCM_STATE_SETUP;
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		/* Fall through */
 | 
							/* Fall through */
 | 
				
			||||||
	case SND_PCM_STATE_RUNNING:
 | 
						case SND_PCM_STATE_RUNNING:
 | 
				
			||||||
		if (snd_pcm_mmap_avail(pcm) <= 0) {
 | 
							if (snd_pcm_mmap_avail(pcm) <= 0) {
 | 
				
			||||||
			share->mmap_status.state = SND_PCM_STATE_SETUP;
 | 
								share->state = SND_PCM_STATE_SETUP;
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		share->draining_silence = 0;
 | 
							share->draining_silence = 0;
 | 
				
			||||||
		share->mmap_status.state = SND_PCM_STATE_DRAINING;
 | 
							share->state = SND_PCM_STATE_DRAINING;
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 _end:
 | 
					 _end:
 | 
				
			||||||
| 
						 | 
					@ -742,7 +805,26 @@ static int snd_pcm_share_channel_setup(snd_pcm_t *pcm, snd_pcm_channel_setup_t *
 | 
				
			||||||
	setup->channel = c;
 | 
						setup->channel = c;
 | 
				
			||||||
	err = snd_pcm_channel_setup(slave->pcm, setup);
 | 
						err = snd_pcm_channel_setup(slave->pcm, setup);
 | 
				
			||||||
	setup->channel = channel;
 | 
						setup->channel = channel;
 | 
				
			||||||
	return err;
 | 
						if (err < 0)
 | 
				
			||||||
 | 
							return err;
 | 
				
			||||||
 | 
						if (!pcm->mmap_info)
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
						switch (pcm->setup.mmap_shape) {
 | 
				
			||||||
 | 
						case SND_PCM_MMAP_INTERLEAVED:
 | 
				
			||||||
 | 
						case SND_PCM_MMAP_COMPLEX:
 | 
				
			||||||
 | 
							setup->stopped_area.addr = share->stopped_data;
 | 
				
			||||||
 | 
							setup->stopped_area.first = channel * pcm->bits_per_sample;
 | 
				
			||||||
 | 
							setup->stopped_area.step = pcm->bits_per_frame;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case SND_PCM_MMAP_NONINTERLEAVED:
 | 
				
			||||||
 | 
							setup->stopped_area.addr = share->stopped_data + c * pcm->setup.buffer_size * pcm->bits_per_sample / 8;
 | 
				
			||||||
 | 
							setup->stopped_area.first = 0;
 | 
				
			||||||
 | 
							setup->stopped_area.step = pcm->bits_per_sample;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							assert(0);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static ssize_t snd_pcm_share_rewind(snd_pcm_t *pcm, size_t frames)
 | 
					static ssize_t snd_pcm_share_rewind(snd_pcm_t *pcm, size_t frames)
 | 
				
			||||||
| 
						 | 
					@ -751,7 +833,7 @@ static ssize_t snd_pcm_share_rewind(snd_pcm_t *pcm, size_t frames)
 | 
				
			||||||
	snd_pcm_share_slave_t *slave = share->slave;
 | 
						snd_pcm_share_slave_t *slave = share->slave;
 | 
				
			||||||
	int ret = -EBADFD;
 | 
						int ret = -EBADFD;
 | 
				
			||||||
	ssize_t n;
 | 
						ssize_t n;
 | 
				
			||||||
	switch (share->mmap_status.state) {
 | 
						switch (share->state) {
 | 
				
			||||||
	case SND_PCM_STATE_RUNNING:
 | 
						case SND_PCM_STATE_RUNNING:
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	case SND_PCM_STATE_PREPARED:
 | 
						case SND_PCM_STATE_PREPARED:
 | 
				
			||||||
| 
						 | 
					@ -774,7 +856,7 @@ static ssize_t snd_pcm_share_rewind(snd_pcm_t *pcm, size_t frames)
 | 
				
			||||||
			n = frames;
 | 
								n = frames;
 | 
				
			||||||
		frames -= n;
 | 
							frames -= n;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if (share->mmap_status.state == SND_PCM_STATE_RUNNING &&
 | 
						if (share->state == SND_PCM_STATE_RUNNING &&
 | 
				
			||||||
	    frames > 0) {
 | 
						    frames > 0) {
 | 
				
			||||||
		pthread_mutex_lock(&slave->mutex);
 | 
							pthread_mutex_lock(&slave->mutex);
 | 
				
			||||||
		ret = snd_pcm_rewind(slave->pcm, frames);
 | 
							ret = snd_pcm_rewind(slave->pcm, frames);
 | 
				
			||||||
| 
						 | 
					@ -793,43 +875,6 @@ static ssize_t snd_pcm_share_rewind(snd_pcm_t *pcm, size_t frames)
 | 
				
			||||||
	return ret;
 | 
						return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int snd_pcm_share_mmap_status(snd_pcm_t *pcm)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	snd_pcm_share_t *share = pcm->private;
 | 
					 | 
				
			||||||
	pcm->mmap_status = &share->mmap_status;
 | 
					 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int snd_pcm_share_mmap_control(snd_pcm_t *pcm)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	snd_pcm_share_t *share = pcm->private;
 | 
					 | 
				
			||||||
	pcm->mmap_control = &share->mmap_control;
 | 
					 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int snd_pcm_share_mmap_data(snd_pcm_t *pcm)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	snd_pcm_share_t *share = pcm->private;
 | 
					 | 
				
			||||||
	snd_pcm_share_slave_t *slave = share->slave;
 | 
					 | 
				
			||||||
	pcm->mmap_data = slave->pcm->mmap_data;
 | 
					 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int snd_pcm_share_munmap_status(snd_pcm_t *pcm ATTRIBUTE_UNUSED)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
		
 | 
					 | 
				
			||||||
static int snd_pcm_share_munmap_control(snd_pcm_t *pcm ATTRIBUTE_UNUSED)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
		
 | 
					 | 
				
			||||||
static int snd_pcm_share_munmap_data(snd_pcm_t *pcm ATTRIBUTE_UNUSED)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
		
 | 
					 | 
				
			||||||
static int snd_pcm_share_channels_mask(snd_pcm_t *pcm, bitset_t *cmask)
 | 
					static int snd_pcm_share_channels_mask(snd_pcm_t *pcm, bitset_t *cmask)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	snd_pcm_share_t *share = pcm->private;
 | 
						snd_pcm_share_t *share = pcm->private;
 | 
				
			||||||
| 
						 | 
					@ -869,7 +914,7 @@ static void snd_pcm_share_dump(snd_pcm_t *pcm, FILE *fp)
 | 
				
			||||||
	snd_pcm_dump(slave->pcm, fp);
 | 
						snd_pcm_dump(slave->pcm, fp);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct snd_pcm_ops snd_pcm_share_ops = {
 | 
					snd_pcm_ops_t snd_pcm_share_ops = {
 | 
				
			||||||
	close: snd_pcm_share_close,
 | 
						close: snd_pcm_share_close,
 | 
				
			||||||
	info: snd_pcm_share_info,
 | 
						info: snd_pcm_share_info,
 | 
				
			||||||
	params_info: snd_pcm_share_params_info,
 | 
						params_info: snd_pcm_share_params_info,
 | 
				
			||||||
| 
						 | 
					@ -881,15 +926,11 @@ struct snd_pcm_ops snd_pcm_share_ops = {
 | 
				
			||||||
	dump: snd_pcm_share_dump,
 | 
						dump: snd_pcm_share_dump,
 | 
				
			||||||
	nonblock: snd_pcm_share_nonblock,
 | 
						nonblock: snd_pcm_share_nonblock,
 | 
				
			||||||
	async: snd_pcm_share_async,
 | 
						async: snd_pcm_share_async,
 | 
				
			||||||
	mmap_status: snd_pcm_share_mmap_status,
 | 
						mmap: snd_pcm_share_mmap,
 | 
				
			||||||
	mmap_control: snd_pcm_share_mmap_control,
 | 
						munmap: snd_pcm_share_munmap,
 | 
				
			||||||
	mmap_data: snd_pcm_share_mmap_data,
 | 
					 | 
				
			||||||
	munmap_status: snd_pcm_share_munmap_status,
 | 
					 | 
				
			||||||
	munmap_control: snd_pcm_share_munmap_control,
 | 
					 | 
				
			||||||
	munmap_data: snd_pcm_share_munmap_data,
 | 
					 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct snd_pcm_fast_ops snd_pcm_share_fast_ops = {
 | 
					snd_pcm_fast_ops_t snd_pcm_share_fast_ops = {
 | 
				
			||||||
	status: snd_pcm_share_status,
 | 
						status: snd_pcm_share_status,
 | 
				
			||||||
	state: snd_pcm_share_state,
 | 
						state: snd_pcm_share_state,
 | 
				
			||||||
	delay: snd_pcm_share_delay,
 | 
						delay: snd_pcm_share_delay,
 | 
				
			||||||
| 
						 | 
					@ -903,18 +944,17 @@ struct snd_pcm_fast_ops snd_pcm_share_fast_ops = {
 | 
				
			||||||
	readi: snd_pcm_mmap_readi,
 | 
						readi: snd_pcm_mmap_readi,
 | 
				
			||||||
	readn: snd_pcm_mmap_readn,
 | 
						readn: snd_pcm_mmap_readn,
 | 
				
			||||||
	rewind: snd_pcm_share_rewind,
 | 
						rewind: snd_pcm_share_rewind,
 | 
				
			||||||
	poll_descriptor: snd_pcm_share_poll_descriptor,
 | 
					 | 
				
			||||||
	channels_mask: snd_pcm_share_channels_mask,
 | 
						channels_mask: snd_pcm_share_channels_mask,
 | 
				
			||||||
	avail_update: snd_pcm_share_avail_update,
 | 
						avail_update: snd_pcm_share_avail_update,
 | 
				
			||||||
	mmap_forward: snd_pcm_share_mmap_forward,
 | 
						mmap_forward: snd_pcm_share_mmap_forward,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int snd_pcm_share_open(snd_pcm_t **handlep, char *name, char *sname,
 | 
					int snd_pcm_share_open(snd_pcm_t **pcmp, char *name, char *sname,
 | 
				
			||||||
		       size_t schannels_count,
 | 
							       size_t schannels_count,
 | 
				
			||||||
		       size_t channels_count, int *channels_map,
 | 
							       size_t channels_count, int *channels_map,
 | 
				
			||||||
		       int stream, int mode)
 | 
							       int stream, int mode)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	snd_pcm_t *handle;
 | 
						snd_pcm_t *pcm;
 | 
				
			||||||
	snd_pcm_share_t *share;
 | 
						snd_pcm_share_t *share;
 | 
				
			||||||
	int err;
 | 
						int err;
 | 
				
			||||||
	struct list_head *i;
 | 
						struct list_head *i;
 | 
				
			||||||
| 
						 | 
					@ -923,7 +963,7 @@ int snd_pcm_share_open(snd_pcm_t **handlep, char *name, char *sname,
 | 
				
			||||||
	snd_pcm_share_slave_t *slave = NULL;
 | 
						snd_pcm_share_slave_t *slave = NULL;
 | 
				
			||||||
	int sd[2];
 | 
						int sd[2];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	assert(handlep);
 | 
						assert(pcmp);
 | 
				
			||||||
	assert(channels_count > 0 && sname && channels_map);
 | 
						assert(channels_count > 0 && sname && channels_map);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for (k = 0; k < channels_count; ++k) {
 | 
						for (k = 0; k < channels_count; ++k) {
 | 
				
			||||||
| 
						 | 
					@ -951,8 +991,8 @@ int snd_pcm_share_open(snd_pcm_t **handlep, char *name, char *sname,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	memcpy(share->slave_channels, channels_map, channels_count * sizeof(*share->slave_channels));
 | 
						memcpy(share->slave_channels, channels_map, channels_count * sizeof(*share->slave_channels));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	handle = calloc(1, sizeof(snd_pcm_t));
 | 
						pcm = calloc(1, sizeof(snd_pcm_t));
 | 
				
			||||||
	if (!handle) {
 | 
						if (!pcm) {
 | 
				
			||||||
		free(share->slave_channels);
 | 
							free(share->slave_channels);
 | 
				
			||||||
		free(share);
 | 
							free(share);
 | 
				
			||||||
		return -ENOMEM;
 | 
							return -ENOMEM;
 | 
				
			||||||
| 
						 | 
					@ -976,7 +1016,7 @@ int snd_pcm_share_open(snd_pcm_t **handlep, char *name, char *sname,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if (err < 0) {
 | 
						if (err < 0) {
 | 
				
			||||||
		err = -errno;
 | 
							err = -errno;
 | 
				
			||||||
		free(handle);
 | 
							free(pcm);
 | 
				
			||||||
		free(share->slave_channels);
 | 
							free(share->slave_channels);
 | 
				
			||||||
		free(share);
 | 
							free(share);
 | 
				
			||||||
		return err;
 | 
							return err;
 | 
				
			||||||
| 
						 | 
					@ -997,7 +1037,7 @@ int snd_pcm_share_open(snd_pcm_t **handlep, char *name, char *sname,
 | 
				
			||||||
			pthread_mutex_unlock(&slaves_mutex);
 | 
								pthread_mutex_unlock(&slaves_mutex);
 | 
				
			||||||
			close(sd[0]);
 | 
								close(sd[0]);
 | 
				
			||||||
			close(sd[1]);
 | 
								close(sd[1]);
 | 
				
			||||||
			free(handle);
 | 
								free(pcm);
 | 
				
			||||||
			free(share->slave_channels);
 | 
								free(share->slave_channels);
 | 
				
			||||||
			free(share);
 | 
								free(share);
 | 
				
			||||||
			return err;
 | 
								return err;
 | 
				
			||||||
| 
						 | 
					@ -1008,7 +1048,7 @@ int snd_pcm_share_open(snd_pcm_t **handlep, char *name, char *sname,
 | 
				
			||||||
			snd_pcm_close(spcm);
 | 
								snd_pcm_close(spcm);
 | 
				
			||||||
			close(sd[0]);
 | 
								close(sd[0]);
 | 
				
			||||||
			close(sd[1]);
 | 
								close(sd[1]);
 | 
				
			||||||
			free(handle);
 | 
								free(pcm);
 | 
				
			||||||
			free(share->slave_channels);
 | 
								free(share->slave_channels);
 | 
				
			||||||
			free(share);
 | 
								free(share);
 | 
				
			||||||
			return err;
 | 
								return err;
 | 
				
			||||||
| 
						 | 
					@ -1031,28 +1071,27 @@ int snd_pcm_share_open(snd_pcm_t **handlep, char *name, char *sname,
 | 
				
			||||||
	pthread_mutex_unlock(&slave->mutex);
 | 
						pthread_mutex_unlock(&slave->mutex);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	share->slave = slave;
 | 
						share->slave = slave;
 | 
				
			||||||
	share->pcm = handle;
 | 
						share->pcm = pcm;
 | 
				
			||||||
	share->client_socket = sd[0];
 | 
						share->client_socket = sd[0];
 | 
				
			||||||
	share->slave_socket = sd[1];
 | 
						share->slave_socket = sd[1];
 | 
				
			||||||
	share->async_sig = SIGIO;
 | 
						share->async_sig = SIGIO;
 | 
				
			||||||
	share->async_pid = getpid();
 | 
						share->async_pid = getpid();
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
	if (name)
 | 
						if (name)
 | 
				
			||||||
		handle->name = strdup(name);
 | 
							pcm->name = strdup(name);
 | 
				
			||||||
	handle->type = SND_PCM_TYPE_SHARE;
 | 
						pcm->type = SND_PCM_TYPE_SHARE;
 | 
				
			||||||
	handle->stream = stream;
 | 
						pcm->stream = stream;
 | 
				
			||||||
	handle->mode = mode;
 | 
						pcm->mode = mode;
 | 
				
			||||||
	handle->ops = &snd_pcm_share_ops;
 | 
						pcm->mmap_auto = 1;
 | 
				
			||||||
	handle->op_arg = handle;
 | 
						pcm->ops = &snd_pcm_share_ops;
 | 
				
			||||||
	handle->fast_ops = &snd_pcm_share_fast_ops;
 | 
						pcm->op_arg = pcm;
 | 
				
			||||||
	handle->fast_op_arg = handle;
 | 
						pcm->fast_ops = &snd_pcm_share_fast_ops;
 | 
				
			||||||
	handle->private = share;
 | 
						pcm->fast_op_arg = pcm;
 | 
				
			||||||
	err = snd_pcm_init(handle);
 | 
						pcm->private = share;
 | 
				
			||||||
	if (err < 0) {
 | 
						pcm->poll_fd = share->client_socket;
 | 
				
			||||||
		snd_pcm_close(handle);
 | 
						pcm->hw_ptr = &share->hw_ptr;
 | 
				
			||||||
		return err;
 | 
						pcm->appl_ptr = &share->appl_ptr;
 | 
				
			||||||
	}
 | 
						*pcmp = pcm;
 | 
				
			||||||
	*handlep = handle;
 | 
					 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1104,11 +1143,11 @@ int _snd_pcm_share_open(snd_pcm_t **pcmp, char *name, snd_config_t *conf,
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if (!sname) {
 | 
						if (!sname) {
 | 
				
			||||||
		ERR("Missing sname");
 | 
							ERR("sname is not defined");
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if (!binding) {
 | 
						if (!binding) {
 | 
				
			||||||
		ERR("Missing binding");
 | 
							ERR("binding is not defined");
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	snd_config_foreach(i, binding) {
 | 
						snd_config_foreach(i, binding) {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue