Begin a DACP monitor. Very incomplete -- work in progress only

This commit is contained in:
Mike Brady
2017-11-27 09:39:40 +00:00
parent 455d93485d
commit fe3b70b4b2
3 changed files with 96 additions and 25 deletions
+84 -25
View File
@@ -1,6 +1,6 @@
/*
* DACP protocol handler. This file is part of Shairport Sync.
* Copyright (c) Mike Brady
* Copyright (c) Mike Brady 2017
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person
@@ -34,9 +34,52 @@
#include <memory.h>
#include <netdb.h>
#include <netinet/in.h>
#include <pthread.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
uint16_t dacp_port;
pthread_t dacp_monitor_thread;
static pthread_mutex_t dacp_conversation_lock = PTHREAD_MUTEX_INITIALIZER;
static pthread_mutex_t dacp_server_information_lock = PTHREAD_MUTEX_INITIALIZER;
static pthread_cond_t dacp_server_information_cv = PTHREAD_COND_INITIALIZER;
// this will be running on the thread of its caller, not of the conversation thread...
void set_dacp_port(
uint16_t port) { // tell the DACP conversation thread that the port has been set or changed
pthread_mutex_lock(&dacp_server_information_lock);
dacp_port = port;
pthread_cond_signal(&dacp_server_information_cv);
pthread_mutex_unlock(&dacp_server_information_lock);
}
// this will be running on the thread of its caller, not of the conversation thread...
void unset_dacp_port() { // tell the DACP conversation thread that that port has gone offline.
pthread_mutex_lock(&dacp_server_information_lock);
dacp_port = 0;
pthread_cond_signal(&dacp_server_information_cv);
pthread_mutex_unlock(&dacp_server_information_lock);
}
void *dacp_monitor_thread_code(void *na) {
// wait until we get a valid port number to begin monitoring it
while (1) {
pthread_mutex_lock(&dacp_server_information_lock);
while (dacp_port == 0)
pthread_cond_wait(&dacp_server_information_cv, &dacp_server_information_lock);
pthread_mutex_unlock(&dacp_server_information_lock);
debug(1, "DACP Monitor Thread active now.");
sleep(3);
}
pthread_exit(NULL);
}
void dacp_monitor_start() {
pthread_create(&dacp_monitor_thread, NULL, dacp_monitor_thread_code, NULL);
}
uint32_t dacp_tlv_crawl(char **p, int32_t *length) {
char typecode[5];
memcpy(typecode, *p, 4);
@@ -52,6 +95,12 @@ uint32_t dacp_tlv_crawl(char **p, int32_t *length) {
ssize_t dacp_send_client_command(rtsp_conn_info *conn, const char *command, char *response,
size_t max_response_length) {
ssize_t reply_size = -1;
// try to do this transaction on the DACP server, but don't wait for more than 20 ms to be allowed
// to do it.
struct timespec mutex_wait_time;
mutex_wait_time.tv_sec = 0;
mutex_wait_time.tv_nsec = 20000000; // 20 ms
if (conn->rtp_running) {
if (conn->dacp_port == 0) {
debug(1, "Can't send a remote request: no valid active remote.");
@@ -84,40 +133,50 @@ ssize_t dacp_send_client_command(rtsp_conn_info *conn, const char *command, char
getaddrinfo(server, portstring, &hints, &res);
// make a socket:
// only do this one at a time -- not sure it is necessary, but better safe than sorry
sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
int mutex_reply = pthread_mutex_timedlock(&dacp_conversation_lock, &mutex_wait_time);
if (mutex_reply == 0) {
if (sockfd == -1) {
debug(1, "Could not create socket");
} else {
// make a socket:
// connect!
sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
if (connect(sockfd, res->ai_addr, res->ai_addrlen) < 0) {
debug(1, "connect failed. Error");
if (sockfd == -1) {
debug(1, "Could not create socket");
} else {
sprintf(message,
"GET /ctrl-int/1/%s HTTP/1.1\r\nHost: %s:%u\r\nActive-Remote: %u\r\n\r\n",
command, conn->client_ip_string, conn->dacp_port, conn->dacp_active_remote);
// connect!
// Send command
if (connect(sockfd, res->ai_addr, res->ai_addrlen) < 0) {
debug(1, "connect failed. Error");
} else {
if (send(sockfd, message, strlen(message), 0) < 0) {
debug(1, "Send failed");
sprintf(message,
"GET /ctrl-int/1/%s HTTP/1.1\r\nHost: %s:%u\r\nActive-Remote: %u\r\n\r\n",
command, conn->client_ip_string, conn->dacp_port, conn->dacp_active_remote);
// Send command
if (send(sockfd, message, strlen(message), 0) < 0) {
debug(1, "Send failed");
}
// Receive a reply from the server
if ((response) && (max_response_length))
reply_size = recv(sockfd, response, max_response_length, 0);
else
reply_size = recv(sockfd, server_reply, sizeof(server_reply), 0);
if (reply_size < 0) {
debug(1, "recv failed");
}
close(sockfd);
}
// Receive a reply from the server
if ((response) && (max_response_length))
reply_size = recv(sockfd, response, max_response_length, 0);
else
reply_size = recv(sockfd, server_reply, sizeof(server_reply), 0);
if (reply_size < 0) {
debug(1, "recv failed");
}
close(sockfd);
}
pthread_mutex_unlock(&dacp_conversation_lock);
} else {
debug(1,
"Could not acquire a lock on the dacp transmit/receive section. Possible timeout?");
}
}
} else {
+7
View File
@@ -2,9 +2,14 @@
#include "common.h"
#include "config.h"
#include <sys/socket.h>
#include <pthread.h>
#include "player.h"
static pthread_mutex_t dacp_server_information_lock;
static pthread_cond_t dacp_server_information_cv;
typedef struct dacp_speaker_stuff {
int64_t speaker_number;
int active;
@@ -22,3 +27,5 @@ int dacp_set_include_speaker_volume(rtsp_conn_info *conn, int64_t machine_number
int dacp_set_speaker_volume(rtsp_conn_info *conn, int64_t machine_number, int32_t vo);
int dacp_get_speaker_list(rtsp_conn_info *conn, dacp_spkr_stuff *speaker_array,
int max_size_of_array);
void set_dacp_port(uint16_t port); // tell the DACP conversation thread that the port has been set or changed
void unset_dacp_port(); // tell the DACP conversation thread that that port has gone offline.
+5
View File
@@ -28,9 +28,12 @@
#include <pthread.h>
#include <stdlib.h>
#include "config.h"
#include "common.h"
#include "mdns.h"
#include "rtsp.h"
#include "dacp.h"
#include <string.h>
#include <avahi-client/client.h>
@@ -86,6 +89,7 @@ static void resolve_callback(AvahiServiceResolver *r, AVAHI_GCC_UNUSED AvahiIfIn
if (*p != port) {
debug(1, "Client's DACP port: %u.", port);
*p = port;
set_dacp_port(port);
#ifdef CONFIG_METADATA
char portstring[20];
memset(portstring, 0, sizeof(portstring));
@@ -135,6 +139,7 @@ static void browse_callback(AvahiServiceBrowser *b, AvahiIfIndex interface, Avah
if (*p != 0) {
debug(1, "Client's DACP status withdrawn.");
*p = 0;
unset_dacp_port();
}
}
} else {