|
Packit Service |
cd2a00 |
/*
|
|
Packit Service |
cd2a00 |
* ALSA -> Arcam AV control plugin
|
|
Packit Service |
cd2a00 |
*
|
|
Packit Service |
cd2a00 |
* Copyright (c) 2009 by Peter Stokes <linux@dadeos.co.uk>
|
|
Packit Service |
cd2a00 |
*
|
|
Packit Service |
cd2a00 |
* This library is free software; you can redistribute it and/or modify
|
|
Packit Service |
cd2a00 |
* it under the terms of the GNU Lesser General Public License as
|
|
Packit Service |
cd2a00 |
* published by the Free Software Foundation; either version 2.1 of
|
|
Packit Service |
cd2a00 |
* the License, or (at your option) any later version.
|
|
Packit Service |
cd2a00 |
*
|
|
Packit Service |
cd2a00 |
* This program is distributed in the hope that it will be useful,
|
|
Packit Service |
cd2a00 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit Service |
cd2a00 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
Packit Service |
cd2a00 |
* GNU Lesser General Public License for more details.
|
|
Packit Service |
cd2a00 |
*
|
|
Packit Service |
cd2a00 |
* You should have received a copy of the GNU Lesser General Public
|
|
Packit Service |
cd2a00 |
* License along with this library; if not, write to the Free Software
|
|
Packit Service |
cd2a00 |
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
Packit Service |
cd2a00 |
*/
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
#include "arcam_av.h"
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
#include <errno.h>
|
|
Packit Service |
cd2a00 |
#include <fcntl.h>
|
|
Packit Service |
cd2a00 |
#include <semaphore.h>
|
|
Packit Service |
cd2a00 |
#include <signal.h>
|
|
Packit Service |
cd2a00 |
#include <stddef.h>
|
|
Packit Service |
cd2a00 |
#include <stdio.h>
|
|
Packit Service |
cd2a00 |
#include <termios.h>
|
|
Packit Service |
cd2a00 |
#include <unistd.h>
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
#include <sys/ipc.h>
|
|
Packit Service |
cd2a00 |
#include <sys/select.h>
|
|
Packit Service |
cd2a00 |
#include <sys/shm.h>
|
|
Packit Service |
cd2a00 |
#include <sys/stat.h>
|
|
Packit Service |
cd2a00 |
#include <sys/stat.h>
|
|
Packit Service |
cd2a00 |
#include <sys/socket.h>
|
|
Packit Service |
cd2a00 |
#include <sys/un.h>
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
#define MIN(a, b) ((a) < (b) ? (a) : (b))
|
|
Packit Service |
cd2a00 |
#define MAX(a, b) ((a) > (b) ? (a) : (b))
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
int arcam_av_connect(const char* port)
|
|
Packit Service |
cd2a00 |
{
|
|
Packit Service |
cd2a00 |
struct termios portsettings;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
int fd = open(port, O_RDWR | O_NOCTTY);
|
|
Packit Service |
cd2a00 |
if (fd < 0)
|
|
Packit Service |
cd2a00 |
return -errno;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
bzero(&portsettings, sizeof(portsettings));
|
|
Packit Service |
cd2a00 |
portsettings.c_cflag = B38400 | CS8 | CLOCAL | CREAD;
|
|
Packit Service |
cd2a00 |
portsettings.c_iflag = IGNPAR;
|
|
Packit Service |
cd2a00 |
portsettings.c_oflag = 0;
|
|
Packit Service |
cd2a00 |
portsettings.c_lflag = 0;
|
|
Packit Service |
cd2a00 |
portsettings.c_cc[VTIME] = 0;
|
|
Packit Service |
cd2a00 |
portsettings.c_cc[VMIN] = 5;
|
|
Packit Service |
cd2a00 |
tcflush(fd, TCIFLUSH);
|
|
Packit Service |
cd2a00 |
tcsetattr(fd, TCSANOW, &portsettings);
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
return fd;
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
int arcam_av_send(int fd, arcam_av_cc_t command, unsigned char param1, unsigned char param2)
|
|
Packit Service |
cd2a00 |
{
|
|
Packit Service |
cd2a00 |
const char buffer[7] = {'P', 'C', '_', command, param1, param2, 0x0D};
|
|
Packit Service |
cd2a00 |
const char* cursor = buffer;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
tcdrain(fd);
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
do {
|
|
Packit Service |
cd2a00 |
ssize_t bytes = write(fd, cursor, sizeof buffer - (cursor - buffer));
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
if (bytes <= 0)
|
|
Packit Service |
cd2a00 |
return -errno;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
cursor += bytes;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
} while (cursor < buffer + sizeof buffer);
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
return 0;
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
static int arcam_av_receive(int fd, arcam_av_cc_t* command, unsigned char* param1, unsigned char* param2)
|
|
Packit Service |
cd2a00 |
{
|
|
Packit Service |
cd2a00 |
static int index = 0;
|
|
Packit Service |
cd2a00 |
static arcam_av_cc_t received_command;
|
|
Packit Service |
cd2a00 |
static unsigned char received_param1;
|
|
Packit Service |
cd2a00 |
static unsigned char received_param2;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
do {
|
|
Packit Service |
cd2a00 |
static char buffer[8];
|
|
Packit Service |
cd2a00 |
char* cursor = buffer;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
ssize_t bytes = read(fd, buffer, sizeof buffer - index);
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
if (bytes <= 0)
|
|
Packit Service |
cd2a00 |
return -errno;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
while(bytes > 0) {
|
|
Packit Service |
cd2a00 |
switch(index++) {
|
|
Packit Service |
cd2a00 |
case 0:
|
|
Packit Service |
cd2a00 |
if (*cursor != 'A')
|
|
Packit Service |
cd2a00 |
index = 0;
|
|
Packit Service |
cd2a00 |
break;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
case 1:
|
|
Packit Service |
cd2a00 |
if (*cursor != 'V') {
|
|
Packit Service |
cd2a00 |
index = 0;
|
|
Packit Service |
cd2a00 |
continue;
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
break;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
case 2:
|
|
Packit Service |
cd2a00 |
if (*cursor != '_') {
|
|
Packit Service |
cd2a00 |
index = 0;
|
|
Packit Service |
cd2a00 |
continue;
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
break;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
case 3:
|
|
Packit Service |
cd2a00 |
received_command = *cursor;
|
|
Packit Service |
cd2a00 |
break;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
case 4:
|
|
Packit Service |
cd2a00 |
if (*cursor != ARCAM_AV_OK) {
|
|
Packit Service |
cd2a00 |
index = 0;
|
|
Packit Service |
cd2a00 |
continue;
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
break;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
case 5:
|
|
Packit Service |
cd2a00 |
received_param1 = *cursor;
|
|
Packit Service |
cd2a00 |
break;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
case 6:
|
|
Packit Service |
cd2a00 |
received_param2 = *cursor;
|
|
Packit Service |
cd2a00 |
break;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
case 7:
|
|
Packit Service |
cd2a00 |
if (*cursor != 0x0D) {
|
|
Packit Service |
cd2a00 |
index = 0;
|
|
Packit Service |
cd2a00 |
continue;
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
break;
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
++cursor;
|
|
Packit Service |
cd2a00 |
--bytes;
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
} while (index < 8);
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
index = 0;
|
|
Packit Service |
cd2a00 |
*command = received_command;
|
|
Packit Service |
cd2a00 |
*param1 = received_param1;
|
|
Packit Service |
cd2a00 |
*param2 = received_param2;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
return 0;
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
static int arcam_av_update(arcam_av_state_t* state, int fd)
|
|
Packit Service |
cd2a00 |
{
|
|
Packit Service |
cd2a00 |
int result = -1;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
arcam_av_cc_t command = 0;
|
|
Packit Service |
cd2a00 |
unsigned char param1 = 0;
|
|
Packit Service |
cd2a00 |
unsigned char param2 = 0;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
while (!arcam_av_receive(fd, &command, ¶m1, ¶m2)) {
|
|
Packit Service |
cd2a00 |
switch(command) {
|
|
Packit Service |
cd2a00 |
case ARCAM_AV_POWER:
|
|
Packit Service |
cd2a00 |
switch(param1) {
|
|
Packit Service |
cd2a00 |
case ARCAM_AV_ZONE1:
|
|
Packit Service |
cd2a00 |
state->zone1.power = param2;
|
|
Packit Service |
cd2a00 |
result = 0;
|
|
Packit Service |
cd2a00 |
break;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
case ARCAM_AV_ZONE2:
|
|
Packit Service |
cd2a00 |
state->zone2.power = param2;
|
|
Packit Service |
cd2a00 |
result = 0;
|
|
Packit Service |
cd2a00 |
break;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
default:
|
|
Packit Service |
cd2a00 |
break;
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
break;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
case ARCAM_AV_VOLUME_CHANGE:
|
|
Packit Service |
cd2a00 |
case ARCAM_AV_VOLUME_SET:
|
|
Packit Service |
cd2a00 |
switch(param1) {
|
|
Packit Service |
cd2a00 |
case ARCAM_AV_ZONE1:
|
|
Packit Service |
cd2a00 |
state->zone1.volume = param2;
|
|
Packit Service |
cd2a00 |
result = 0;
|
|
Packit Service |
cd2a00 |
break;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
case ARCAM_AV_ZONE2:
|
|
Packit Service |
cd2a00 |
state->zone2.volume = param2;
|
|
Packit Service |
cd2a00 |
result = 0;
|
|
Packit Service |
cd2a00 |
break;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
default:
|
|
Packit Service |
cd2a00 |
break;
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
break;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
case ARCAM_AV_MUTE:
|
|
Packit Service |
cd2a00 |
switch(param1) {
|
|
Packit Service |
cd2a00 |
case ARCAM_AV_ZONE1:
|
|
Packit Service |
cd2a00 |
state->zone1.mute = param2;
|
|
Packit Service |
cd2a00 |
result = 0;
|
|
Packit Service |
cd2a00 |
break;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
case ARCAM_AV_ZONE2:
|
|
Packit Service |
cd2a00 |
state->zone2.mute = param2;
|
|
Packit Service |
cd2a00 |
result = 0;
|
|
Packit Service |
cd2a00 |
break;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
default:
|
|
Packit Service |
cd2a00 |
break;
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
break;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
case ARCAM_AV_DIRECT:
|
|
Packit Service |
cd2a00 |
switch(param1) {
|
|
Packit Service |
cd2a00 |
case ARCAM_AV_ZONE1:
|
|
Packit Service |
cd2a00 |
state->zone1.direct = param2;
|
|
Packit Service |
cd2a00 |
result = 0;
|
|
Packit Service |
cd2a00 |
break;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
default:
|
|
Packit Service |
cd2a00 |
break;
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
break;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
case ARCAM_AV_SOURCE:
|
|
Packit Service |
cd2a00 |
switch(param1) {
|
|
Packit Service |
cd2a00 |
case ARCAM_AV_ZONE1:
|
|
Packit Service |
cd2a00 |
state->zone1.source = param2;
|
|
Packit Service |
cd2a00 |
result = 0;
|
|
Packit Service |
cd2a00 |
break;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
case ARCAM_AV_ZONE2:
|
|
Packit Service |
cd2a00 |
state->zone2.source = param2;
|
|
Packit Service |
cd2a00 |
result = 0;
|
|
Packit Service |
cd2a00 |
break;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
default:
|
|
Packit Service |
cd2a00 |
break;
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
break;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
case ARCAM_AV_SOURCE_TYPE:
|
|
Packit Service |
cd2a00 |
switch(param1) {
|
|
Packit Service |
cd2a00 |
case ARCAM_AV_ZONE1:
|
|
Packit Service |
cd2a00 |
state->zone1.source_type = param2;
|
|
Packit Service |
cd2a00 |
result = 0;
|
|
Packit Service |
cd2a00 |
break;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
default:
|
|
Packit Service |
cd2a00 |
break;
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
break;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
case ARCAM_AV_STEREO_DECODE:
|
|
Packit Service |
cd2a00 |
switch(param1) {
|
|
Packit Service |
cd2a00 |
case ARCAM_AV_ZONE1:
|
|
Packit Service |
cd2a00 |
state->zone1.stereo_decode = param2;
|
|
Packit Service |
cd2a00 |
result = 0;
|
|
Packit Service |
cd2a00 |
break;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
default:
|
|
Packit Service |
cd2a00 |
break;
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
break;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
case ARCAM_AV_STEREO_EFFECT:
|
|
Packit Service |
cd2a00 |
switch(param1) {
|
|
Packit Service |
cd2a00 |
case ARCAM_AV_ZONE1:
|
|
Packit Service |
cd2a00 |
state->zone1.stereo_effect = param2;
|
|
Packit Service |
cd2a00 |
result = 0;
|
|
Packit Service |
cd2a00 |
break;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
default:
|
|
Packit Service |
cd2a00 |
break;
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
break;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
case ARCAM_AV_MULTI_DECODE:
|
|
Packit Service |
cd2a00 |
switch(param1) {
|
|
Packit Service |
cd2a00 |
case ARCAM_AV_ZONE1:
|
|
Packit Service |
cd2a00 |
state->zone1.multi_decode = param2;
|
|
Packit Service |
cd2a00 |
result = 0;
|
|
Packit Service |
cd2a00 |
break;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
default:
|
|
Packit Service |
cd2a00 |
break;
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
break;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
default:
|
|
Packit Service |
cd2a00 |
break;
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
return result;
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
static void arcam_av_state_query(int fd)
|
|
Packit Service |
cd2a00 |
{
|
|
Packit Service |
cd2a00 |
arcam_av_send(fd, ARCAM_AV_POWER, ARCAM_AV_ZONE1, ARCAM_AV_POWER_REQUEST);
|
|
Packit Service |
cd2a00 |
arcam_av_send(fd, ARCAM_AV_VOLUME_CHANGE, ARCAM_AV_ZONE1, ARCAM_AV_VOLUME_REQUEST);
|
|
Packit Service |
cd2a00 |
arcam_av_send(fd, ARCAM_AV_MUTE, ARCAM_AV_ZONE1, ARCAM_AV_MUTE_REQUEST);
|
|
Packit Service |
cd2a00 |
arcam_av_send(fd, ARCAM_AV_DIRECT, ARCAM_AV_ZONE1, ARCAM_AV_DIRECT_REQUEST);
|
|
Packit Service |
cd2a00 |
arcam_av_send(fd, ARCAM_AV_SOURCE, ARCAM_AV_ZONE1, ARCAM_AV_SOURCE_REQUEST);
|
|
Packit Service |
cd2a00 |
arcam_av_send(fd, ARCAM_AV_SOURCE_TYPE, ARCAM_AV_ZONE1, ARCAM_AV_SOURCE_TYPE_REQUEST);
|
|
Packit Service |
cd2a00 |
arcam_av_send(fd, ARCAM_AV_STEREO_DECODE, ARCAM_AV_ZONE1, ARCAM_AV_STEREO_DECODE_REQUEST);
|
|
Packit Service |
cd2a00 |
arcam_av_send(fd, ARCAM_AV_MULTI_DECODE, ARCAM_AV_ZONE1, ARCAM_AV_MULTI_DECODE_REQUEST);
|
|
Packit Service |
cd2a00 |
arcam_av_send(fd, ARCAM_AV_STEREO_EFFECT, ARCAM_AV_ZONE1, ARCAM_AV_STEREO_EFFECT_REQUEST);
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
arcam_av_send(fd, ARCAM_AV_POWER, ARCAM_AV_ZONE2, ARCAM_AV_POWER_REQUEST);
|
|
Packit Service |
cd2a00 |
arcam_av_send(fd, ARCAM_AV_VOLUME_CHANGE, ARCAM_AV_ZONE2, ARCAM_AV_VOLUME_REQUEST);
|
|
Packit Service |
cd2a00 |
arcam_av_send(fd, ARCAM_AV_MUTE, ARCAM_AV_ZONE2, ARCAM_AV_MUTE_REQUEST);
|
|
Packit Service |
cd2a00 |
arcam_av_send(fd, ARCAM_AV_SOURCE, ARCAM_AV_ZONE2, ARCAM_AV_SOURCE_REQUEST);
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
arcam_av_state_t* arcam_av_state_attach(const char* port)
|
|
Packit Service |
cd2a00 |
{
|
|
Packit Service |
cd2a00 |
arcam_av_state_t* state;
|
|
Packit Service |
cd2a00 |
struct stat port_stat;
|
|
Packit Service |
cd2a00 |
key_t ipc_key;
|
|
Packit Service |
cd2a00 |
int shmid, shmflg;
|
|
Packit Service |
cd2a00 |
struct shmid_ds shm_stat;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
if (stat(port, &port_stat))
|
|
Packit Service |
cd2a00 |
return NULL;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
ipc_key = ftok(port, 'A');
|
|
Packit Service |
cd2a00 |
if (ipc_key < 0)
|
|
Packit Service |
cd2a00 |
return NULL;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
shmflg = IPC_CREAT | (port_stat.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO));
|
|
Packit Service |
cd2a00 |
shmid = shmget(ipc_key, sizeof(arcam_av_state_t), shmflg);
|
|
Packit Service |
cd2a00 |
if (shmid < 0)
|
|
Packit Service |
cd2a00 |
return NULL;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
if (shmctl(shmid, IPC_STAT, &shm_stat))
|
|
Packit Service |
cd2a00 |
return NULL;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
shm_stat.shm_perm.uid = port_stat.st_uid;
|
|
Packit Service |
cd2a00 |
shm_stat.shm_perm.gid = port_stat.st_gid;
|
|
Packit Service |
cd2a00 |
shmctl(shmid, IPC_SET, &shm_stat);
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
state = shmat(shmid, NULL, 0);
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
return (state == (void*)-1) ? NULL : state;
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
int arcam_av_state_detach(arcam_av_state_t* state)
|
|
Packit Service |
cd2a00 |
{
|
|
Packit Service |
cd2a00 |
return shmdt(state);
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
static void arcam_av_server_broadcast(fd_set* fds, int fd_max, void* buffer, int bytes)
|
|
Packit Service |
cd2a00 |
{
|
|
Packit Service |
cd2a00 |
int fd;
|
|
Packit Service |
cd2a00 |
for (fd = 0; fd <= fd_max; ++fd) {
|
|
Packit Service |
cd2a00 |
if (FD_ISSET(fd, fds)) {
|
|
Packit Service |
cd2a00 |
send(fd, buffer, bytes, 0);
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
static int arcam_av_server_master(int server_fd)
|
|
Packit Service |
cd2a00 |
{
|
|
Packit Service |
cd2a00 |
struct sockaddr_un server_address;
|
|
Packit Service |
cd2a00 |
socklen_t server_address_length;
|
|
Packit Service |
cd2a00 |
const char* port;
|
|
Packit Service |
cd2a00 |
int arcam_fd;
|
|
Packit Service |
cd2a00 |
arcam_av_state_t* state;
|
|
Packit Service |
cd2a00 |
fd_set all_fds, client_fds, read_fds;
|
|
Packit Service |
cd2a00 |
int fd, fd_max;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
int result = 0;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
server_address_length = sizeof(server_address) - 1;
|
|
Packit Service |
cd2a00 |
if (getsockname(server_fd, (struct sockaddr*) &server_address, &server_address_length))
|
|
Packit Service |
cd2a00 |
return -errno;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
server_address.sun_path[server_address_length - offsetof(struct sockaddr_un, sun_path)] = '\0';
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
port = server_address.sun_path + 1;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
arcam_fd = arcam_av_connect(port);
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
state = arcam_av_state_attach(port);
|
|
Packit Service |
cd2a00 |
if (!state) {
|
|
Packit Service |
cd2a00 |
close(arcam_fd);
|
|
Packit Service |
cd2a00 |
return -errno;
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
arcam_av_state_query(arcam_fd);
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
fcntl(arcam_fd, F_SETFL, O_NONBLOCK);
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
FD_ZERO(&all_fds);
|
|
Packit Service |
cd2a00 |
FD_ZERO(&client_fds);
|
|
Packit Service |
cd2a00 |
FD_SET(arcam_fd, &all_fds);
|
|
Packit Service |
cd2a00 |
FD_SET(server_fd, &all_fds);
|
|
Packit Service |
cd2a00 |
fd_max = MAX(arcam_fd, server_fd);
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
for(;;) {
|
|
Packit Service |
cd2a00 |
read_fds = all_fds;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
if (select(fd_max + 1, &read_fds, NULL, NULL, NULL) < 0) {
|
|
Packit Service |
cd2a00 |
perror("arcam_av_server_master(): select");
|
|
Packit Service |
cd2a00 |
result = -errno;
|
|
Packit Service |
cd2a00 |
break;
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
for(fd = fd_max; fd; --fd) {
|
|
Packit Service |
cd2a00 |
if (FD_ISSET(fd, &read_fds)) {
|
|
Packit Service |
cd2a00 |
if (fd == arcam_fd) {
|
|
Packit Service |
cd2a00 |
if (arcam_av_update(state, arcam_fd))
|
|
Packit Service |
cd2a00 |
continue;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
arcam_av_server_broadcast(&client_fds, fd_max, "", 1);
|
|
Packit Service |
cd2a00 |
} else if (fd == server_fd) {
|
|
Packit Service |
cd2a00 |
struct sockaddr_un client_address;
|
|
Packit Service |
cd2a00 |
socklen_t client_address_length = sizeof(client_address);
|
|
Packit Service |
cd2a00 |
int client_fd = accept(server_fd, (struct sockaddr*) &client_address, &client_address_length);
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
if (client_fd >= 0) {
|
|
Packit Service |
cd2a00 |
FD_SET(client_fd, &all_fds);
|
|
Packit Service |
cd2a00 |
FD_SET(client_fd, &client_fds);
|
|
Packit Service |
cd2a00 |
fd_max = MAX(fd_max, client_fd);
|
|
Packit Service |
cd2a00 |
} else {
|
|
Packit Service |
cd2a00 |
perror("arcam_av_server_master(): accept");
|
|
Packit Service |
cd2a00 |
result = -errno;
|
|
Packit Service |
cd2a00 |
goto exit;
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
} else {
|
|
Packit Service |
cd2a00 |
pthread_t thread;
|
|
Packit Service |
cd2a00 |
int bytes = recv(fd, &thread, sizeof(pthread_t), 0);
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
if (bytes > 0) {
|
|
Packit Service |
cd2a00 |
if (bytes == sizeof(pthread_t)) {
|
|
Packit Service |
cd2a00 |
if (thread == pthread_self())
|
|
Packit Service |
cd2a00 |
goto exit;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
arcam_av_server_broadcast(&client_fds, fd_max, &thread, sizeof(pthread_t));
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
} else {
|
|
Packit Service |
cd2a00 |
close(fd);
|
|
Packit Service |
cd2a00 |
FD_CLR(fd, &all_fds);
|
|
Packit Service |
cd2a00 |
FD_CLR(fd, &client_fds);
|
|
Packit Service |
cd2a00 |
fd_max -= (fd_max == fd);
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
exit:
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
for (fd = 0; fd <= fd_max; ++fd) {
|
|
Packit Service |
cd2a00 |
if (fd != server_fd && FD_ISSET(fd, &all_fds)) {
|
|
Packit Service |
cd2a00 |
close(fd);
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
if (state)
|
|
Packit Service |
cd2a00 |
arcam_av_state_detach(state);
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
return result;
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
static int arcam_av_server_slave(int server_fd)
|
|
Packit Service |
cd2a00 |
{
|
|
Packit Service |
cd2a00 |
for (;;) {
|
|
Packit Service |
cd2a00 |
pthread_t thread;
|
|
Packit Service |
cd2a00 |
int bytes = recv(server_fd, &thread, sizeof(pthread_t), 0);
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
if (bytes > 0) {
|
|
Packit Service |
cd2a00 |
if (bytes == sizeof(pthread_t))
|
|
Packit Service |
cd2a00 |
if (thread == pthread_self())
|
|
Packit Service |
cd2a00 |
return 0;
|
|
Packit Service |
cd2a00 |
} else {
|
|
Packit Service |
cd2a00 |
break;
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
return -1;
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
static void* arcam_av_server_thread(void* context)
|
|
Packit Service |
cd2a00 |
{
|
|
Packit Service |
cd2a00 |
struct sockaddr_un address;
|
|
Packit Service |
cd2a00 |
int size;
|
|
Packit Service |
cd2a00 |
int quit = 0;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
sem_t* semaphore = context;
|
|
Packit Service |
cd2a00 |
const char* port = *(const char**)(semaphore + 1);
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
address.sun_family = AF_FILE;
|
|
Packit Service |
cd2a00 |
address.sun_path[0] = '\0';
|
|
Packit Service |
cd2a00 |
strncpy(&address.sun_path[1], port, sizeof(address.sun_path) - 1);
|
|
Packit Service |
cd2a00 |
size = offsetof(struct sockaddr_un, sun_path) +
|
|
Packit Service |
cd2a00 |
MIN(strlen(port) + 1, sizeof(address.sun_path));
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
signal(SIGPIPE, SIG_IGN);
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
while (!quit) {
|
|
Packit Service |
cd2a00 |
int server_fd = socket(PF_UNIX, SOCK_STREAM, 0);
|
|
Packit Service |
cd2a00 |
if (server_fd < 0) {
|
|
Packit Service |
cd2a00 |
perror("arcam_av_server_thread(): socket");
|
|
Packit Service |
cd2a00 |
break;
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
if (!bind(server_fd, (struct sockaddr*) &address, size)) {
|
|
Packit Service |
cd2a00 |
if (!listen(server_fd, 10)) {
|
|
Packit Service |
cd2a00 |
if (semaphore) {
|
|
Packit Service |
cd2a00 |
sem_post(semaphore);
|
|
Packit Service |
cd2a00 |
semaphore = NULL;
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
arcam_av_server_master(server_fd);
|
|
Packit Service |
cd2a00 |
} else {
|
|
Packit Service |
cd2a00 |
perror("arcam_av_server_master(): listen");
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
quit = 1;
|
|
Packit Service |
cd2a00 |
} else if (errno != EADDRINUSE) {
|
|
Packit Service |
cd2a00 |
perror("arcam_av_server_thread(): bind");
|
|
Packit Service |
cd2a00 |
quit = 1;
|
|
Packit Service |
cd2a00 |
} else if (!connect(server_fd, (struct sockaddr*) &address, size)) {
|
|
Packit Service |
cd2a00 |
if (semaphore) {
|
|
Packit Service |
cd2a00 |
sem_post(semaphore);
|
|
Packit Service |
cd2a00 |
semaphore = NULL;
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
quit = !arcam_av_server_slave(server_fd);
|
|
Packit Service |
cd2a00 |
} else {
|
|
Packit Service |
cd2a00 |
perror("arcam_av_server_thread(): connect");
|
|
Packit Service |
cd2a00 |
quit = 1;
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
close(server_fd);
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
if (semaphore)
|
|
Packit Service |
cd2a00 |
sem_post(semaphore);
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
return NULL;
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
int arcam_av_server_start(pthread_t* thread, const char* port)
|
|
Packit Service |
cd2a00 |
{
|
|
Packit Service |
cd2a00 |
struct {
|
|
Packit Service |
cd2a00 |
sem_t semaphore;
|
|
Packit Service |
cd2a00 |
const char* port;
|
|
Packit Service |
cd2a00 |
} context;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
int result = 0;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
if (sem_init(&context.semaphore, 0, 0))
|
|
Packit Service |
cd2a00 |
return -1;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
context.port = port;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
if (pthread_create(thread, NULL, arcam_av_server_thread, &context))
|
|
Packit Service |
cd2a00 |
result = -1;
|
|
Packit Service |
cd2a00 |
else
|
|
Packit Service |
cd2a00 |
sem_wait(&context.semaphore);
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
sem_destroy(&context.semaphore);
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
return result;
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
int arcam_av_server_stop(pthread_t thread, const char* port)
|
|
Packit Service |
cd2a00 |
{
|
|
Packit Service |
cd2a00 |
int client_fd = arcam_av_client(port);
|
|
Packit Service |
cd2a00 |
if (client_fd < 0)
|
|
Packit Service |
cd2a00 |
return -1;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
if (send(client_fd, &thread, sizeof(pthread_t), 0) > 0)
|
|
Packit Service |
cd2a00 |
pthread_join(thread, NULL);
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
close(client_fd);
|
|
Packit Service |
cd2a00 |
return 0;
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
int arcam_av_client(const char* port)
|
|
Packit Service |
cd2a00 |
{
|
|
Packit Service |
cd2a00 |
struct sockaddr_un address;
|
|
Packit Service |
cd2a00 |
int size;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
const int max_retries = 5;
|
|
Packit Service |
cd2a00 |
int retries = max_retries;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
int client_fd = socket(PF_UNIX, SOCK_STREAM, 0);
|
|
Packit Service |
cd2a00 |
if (client_fd < 0)
|
|
Packit Service |
cd2a00 |
return -1;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
address.sun_family = AF_FILE;
|
|
Packit Service |
cd2a00 |
address.sun_path[0] = '\0';
|
|
Packit Service |
cd2a00 |
strncpy(&address.sun_path[1], port, sizeof(address.sun_path) - 1);
|
|
Packit Service |
cd2a00 |
size = offsetof(struct sockaddr_un, sun_path) +
|
|
Packit Service |
cd2a00 |
MIN(strlen(port) + 1, sizeof(address.sun_path));
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
do {
|
|
Packit Service |
cd2a00 |
if (!connect(client_fd, (struct sockaddr*) &address, size))
|
|
Packit Service |
cd2a00 |
return client_fd;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
if (!retries--)
|
|
Packit Service |
cd2a00 |
break;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
struct timeval sleep = {0, 10 * (max_retries - retries)};
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
select(0, NULL, NULL, NULL, &sleep);
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
} while (errno == ECONNREFUSED);
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
perror("arcam_av_client(): connect");
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
close(client_fd);
|
|
Packit Service |
cd2a00 |
return -1;
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
|