Commit 350aa330 authored by Max Kellermann's avatar Max Kellermann

output/raop: consistently use GError

parent d6290a2f
...@@ -63,11 +63,11 @@ raop_mixer_get_volume(struct mixer *mixer, G_GNUC_UNUSED GError **error_r) ...@@ -63,11 +63,11 @@ raop_mixer_get_volume(struct mixer *mixer, G_GNUC_UNUSED GError **error_r)
} }
static bool static bool
raop_mixer_set_volume(struct mixer *mixer, unsigned volume, G_GNUC_UNUSED GError **error_r) raop_mixer_set_volume(struct mixer *mixer, unsigned volume, GError **error_r)
{ {
struct raop_mixer_plugin *rm = (struct raop_mixer_plugin *)mixer; struct raop_mixer_plugin *rm = (struct raop_mixer_plugin *)mixer;
g_debug("raop_mixer_set_volume\n"); g_debug("raop_mixer_set_volume\n");
return raop_set_volume(rm->rd, volume); return raop_set_volume(rm->rd, volume, error_r);
} }
const struct mixer_plugin raop_mixer_plugin = { const struct mixer_plugin raop_mixer_plugin = {
......
...@@ -52,7 +52,7 @@ raop_output_quark(void) ...@@ -52,7 +52,7 @@ raop_output_quark(void)
} }
static struct raop_data * static struct raop_data *
new_raop_data(void) new_raop_data(GError **error_r)
{ {
struct raop_data *ret = g_new(struct raop_data, 1); struct raop_data *ret = g_new(struct raop_data, 1);
int i; int i;
...@@ -79,7 +79,8 @@ new_raop_data(void) ...@@ -79,7 +79,8 @@ new_raop_data(void)
raop_session->play_state.last_send.tv_usec = 0; raop_session->play_state.last_send.tv_usec = 0;
if (!RAND_bytes(raop_session->encrypt.iv, sizeof(raop_session->encrypt.iv)) || !RAND_bytes(raop_session->encrypt.key, sizeof(raop_session->encrypt.key))) { if (!RAND_bytes(raop_session->encrypt.iv, sizeof(raop_session->encrypt.iv)) || !RAND_bytes(raop_session->encrypt.key, sizeof(raop_session->encrypt.key))) {
g_warning("%s:RAND_bytes error code=%ld\n",__func__,ERR_get_error()); g_set_error(error_r, raop_output_quark(), 0,
"RAND_bytes error code=%ld", ERR_get_error());
return NULL; return NULL;
} }
memcpy(raop_session->encrypt.nv, raop_session->encrypt.iv, sizeof(raop_session->encrypt.nv)); memcpy(raop_session->encrypt.nv, raop_session->encrypt.iv, sizeof(raop_session->encrypt.nv));
...@@ -206,7 +207,8 @@ remove_char_from_string(char *str, char c) ...@@ -206,7 +207,8 @@ remove_char_from_string(char *str, char c)
* if hostname=NULL, use INADDR_ANY. * if hostname=NULL, use INADDR_ANY.
* if *port=0, use dynamically assigned port * if *port=0, use dynamically assigned port
*/ */
static int bind_host(int sd, char *hostname, unsigned long ulAddr, unsigned short *port) static int bind_host(int sd, char *hostname, unsigned long ulAddr,
unsigned short *port, GError **error_r)
{ {
struct sockaddr_in my_addr; struct sockaddr_in my_addr;
socklen_t nlen = sizeof(struct sockaddr); socklen_t nlen = sizeof(struct sockaddr);
...@@ -222,7 +224,9 @@ static int bind_host(int sd, char *hostname, unsigned long ulAddr, unsigned shor ...@@ -222,7 +224,9 @@ static int bind_host(int sd, char *hostname, unsigned long ulAddr, unsigned shor
my_addr.sin_addr.s_addr=-1; my_addr.sin_addr.s_addr=-1;
} else { } else {
if ((my_addr.sin_addr.s_addr = inet_addr(hostname)) == 0xFFFFFFFF) { if ((my_addr.sin_addr.s_addr = inet_addr(hostname)) == 0xFFFFFFFF) {
g_warning("gethostbyname: '%s' \n", hostname); g_set_error(error_r, raop_output_quark(), 0,
"failed to resolve host '%s'",
hostname);
return -1; return -1;
} }
} }
...@@ -245,7 +249,9 @@ static int bind_host(int sd, char *hostname, unsigned long ulAddr, unsigned shor ...@@ -245,7 +249,9 @@ static int bind_host(int sd, char *hostname, unsigned long ulAddr, unsigned shor
my_addr.sin_port = htons(*port); my_addr.sin_port = htons(*port);
if (bind(sd, (struct sockaddr *) &my_addr, sizeof(my_addr)) < 0) { if (bind(sd, (struct sockaddr *) &my_addr, sizeof(my_addr)) < 0) {
g_warning("bind error: %s\n", strerror(errno)); g_set_error(error_r, raop_output_quark(), errno,
"failed to bind socket: %s",
g_strerror(errno));
return -1; return -1;
} }
...@@ -260,17 +266,21 @@ static int bind_host(int sd, char *hostname, unsigned long ulAddr, unsigned shor ...@@ -260,17 +266,21 @@ static int bind_host(int sd, char *hostname, unsigned long ulAddr, unsigned shor
/* /*
* open tcp port * open tcp port
*/ */
static int open_tcp_socket(char *hostname, unsigned short *port) static int
open_tcp_socket(char *hostname, unsigned short *port,
GError **error_r)
{ {
int sd; int sd;
/* socket creation */ /* socket creation */
sd = socket(AF_INET, SOCK_STREAM, 0); sd = socket(AF_INET, SOCK_STREAM, 0);
if (sd < 0) { if (sd < 0) {
g_warning("cannot create tcp socket\n"); g_set_error(error_r, raop_output_quark(), errno,
"failed to create TCP socket: %s",
g_strerror(errno));
return -1; return -1;
} }
if (bind_host(sd, hostname,0, port)) { if (bind_host(sd, hostname, 0, port, error_r)) {
close(sd); close(sd);
return -1; return -1;
} }
...@@ -281,7 +291,9 @@ static int open_tcp_socket(char *hostname, unsigned short *port) ...@@ -281,7 +291,9 @@ static int open_tcp_socket(char *hostname, unsigned short *port)
/* /*
* open udp port * open udp port
*/ */
static int open_udp_socket(char *hostname, unsigned short *port) static int
open_udp_socket(char *hostname, unsigned short *port,
GError **error_r)
{ {
int sd; int sd;
int size = 30000; int size = 30000;
...@@ -289,14 +301,18 @@ static int open_udp_socket(char *hostname, unsigned short *port) ...@@ -289,14 +301,18 @@ static int open_udp_socket(char *hostname, unsigned short *port)
/* socket creation */ /* socket creation */
sd = socket(PF_INET, SOCK_DGRAM, 0); sd = socket(PF_INET, SOCK_DGRAM, 0);
if (sd < 0) { if (sd < 0) {
g_warning("cannot create udp socket\n"); g_set_error(error_r, raop_output_quark(), errno,
"failed to create UDP socket: %s",
g_strerror(errno));
return -1; return -1;
} }
if (setsockopt(sd, SOL_SOCKET, SO_SNDBUF, (void *) &size, sizeof(size)) < 0) { if (setsockopt(sd, SOL_SOCKET, SO_SNDBUF, (void *) &size, sizeof(size)) < 0) {
g_warning("Could not set udp send buffer to %d\n", size); g_set_error(error_r, raop_output_quark(), errno,
"failed to set UDP buffer size: %s",
g_strerror(errno));
return -1; return -1;
} }
if (bind_host(sd, hostname,0, port)) { if (bind_host(sd, hostname, 0, port, error_r)) {
close(sd); close(sd);
return -1; return -1;
} }
...@@ -310,14 +326,17 @@ static int open_udp_socket(char *hostname, unsigned short *port) ...@@ -310,14 +326,17 @@ static int open_udp_socket(char *hostname, unsigned short *port)
* nsport is network byte order * nsport is network byte order
*/ */
static bool static bool
get_tcp_connect(int sd, struct sockaddr_in dest_addr) get_tcp_connect(int sd, struct sockaddr_in dest_addr, GError **error_r)
{ {
if (connect(sd, (struct sockaddr *)&dest_addr, sizeof(struct sockaddr))){ if (connect(sd, (struct sockaddr *)&dest_addr, sizeof(struct sockaddr))){
SLEEP_MSEC(100L); SLEEP_MSEC(100L);
// try one more time // try one more time
if (connect(sd, (struct sockaddr *)&dest_addr, sizeof(struct sockaddr))) { if (connect(sd, (struct sockaddr *)&dest_addr, sizeof(struct sockaddr))) {
g_warning("error:get_tcp_nconnect addr=%s, port=%d\n", g_set_error(error_r, raop_output_quark(), errno,
inet_ntoa(dest_addr.sin_addr), ntohs(dest_addr.sin_port)); "failed to connect to %s:%d: %s",
inet_ntoa(dest_addr.sin_addr),
ntohs(dest_addr.sin_port),
g_strerror(errno));
return false; return false;
} }
} }
...@@ -325,7 +344,9 @@ get_tcp_connect(int sd, struct sockaddr_in dest_addr) ...@@ -325,7 +344,9 @@ get_tcp_connect(int sd, struct sockaddr_in dest_addr)
} }
static bool static bool
get_sockaddr_by_host(const char *host, short destport, struct sockaddr_in *addr) get_sockaddr_by_host(const char *host, short destport,
struct sockaddr_in *addr,
GError **error_r)
{ {
struct hostent *h; struct hostent *h;
...@@ -336,7 +357,8 @@ get_sockaddr_by_host(const char *host, short destport, struct sockaddr_in *addr) ...@@ -336,7 +357,8 @@ get_sockaddr_by_host(const char *host, short destport, struct sockaddr_in *addr)
} else { } else {
addr->sin_family = AF_INET; addr->sin_family = AF_INET;
if ((addr->sin_addr.s_addr=inet_addr(host))==0xFFFFFFFF) { if ((addr->sin_addr.s_addr=inet_addr(host))==0xFFFFFFFF) {
g_warning("gethostbyname: '%s' \n", host); g_set_error(error_r, raop_output_quark(), 0,
"failed to resolve host '%s'", host);
return false; return false;
} }
} }
...@@ -345,13 +367,13 @@ get_sockaddr_by_host(const char *host, short destport, struct sockaddr_in *addr) ...@@ -345,13 +367,13 @@ get_sockaddr_by_host(const char *host, short destport, struct sockaddr_in *addr)
} }
static bool static bool
get_tcp_connect_by_host(int sd, const char *host, short destport) get_tcp_connect_by_host(int sd, const char *host, short destport,
GError **error_r)
{ {
struct sockaddr_in addr; struct sockaddr_in addr;
get_sockaddr_by_host(host, destport, &addr); return get_sockaddr_by_host(host, destport, &addr, error_r) &&
get_tcp_connect(sd, addr, error_r);
return get_tcp_connect(sd, addr);
} }
/* /*
...@@ -515,7 +537,8 @@ static bool ...@@ -515,7 +537,8 @@ static bool
exec_request(struct rtspcl_data *rtspcld, const char *cmd, exec_request(struct rtspcl_data *rtspcld, const char *cmd,
const char *content_type, const char *content, const char *content_type, const char *content,
int get_response, int get_response,
const struct key_data *hds, struct key_data **kd) const struct key_data *hds, struct key_data **kd,
GError **error_r)
{ {
char line[1024]; char line[1024];
char req[1024]; char req[1024];
...@@ -531,7 +554,11 @@ exec_request(struct rtspcl_data *rtspcld, const char *cmd, ...@@ -531,7 +554,11 @@ exec_request(struct rtspcl_data *rtspcld, const char *cmd,
int fdmax = 0; int fdmax = 0;
struct timeval tout = {.tv_sec=10, .tv_usec=0}; struct timeval tout = {.tv_sec=10, .tv_usec=0};
if (!rtspcld) return false; if (!rtspcld) {
g_set_error_literal(error_r, raop_output_quark(), 0,
"not connected");
return false;
}
sprintf(req, "%s %s RTSP/1.0\r\nCSeq: %d\r\n", cmd, rtspcld->url, ++rtspcld->cseq ); sprintf(req, "%s %s RTSP/1.0\r\nCSeq: %d\r\n", cmd, rtspcld->url, ++rtspcld->cseq );
...@@ -568,6 +595,13 @@ exec_request(struct rtspcl_data *rtspcld, const char *cmd, ...@@ -568,6 +595,13 @@ exec_request(struct rtspcl_data *rtspcld, const char *cmd,
strncat(req, content, sizeof(req)); strncat(req, content, sizeof(req));
rval = write(rtspcld->fd, req, strlen(req)); rval = write(rtspcld->fd, req, strlen(req));
if (rval < 0) {
g_set_error(error_r, raop_output_quark(), errno,
"write error: %s",
g_strerror(errno));
return false;
}
g_debug("sent %s", req); g_debug("sent %s", req);
if (!get_response) return true; if (!get_response) return true;
...@@ -587,15 +621,23 @@ exec_request(struct rtspcl_data *rtspcld, const char *cmd, ...@@ -587,15 +621,23 @@ exec_request(struct rtspcl_data *rtspcld, const char *cmd,
} }
if (read_line(rtspcld->fd, line, sizeof(line), timeout, 0) <= 0) { if (read_line(rtspcld->fd, line, sizeof(line), timeout, 0) <= 0) {
g_warning("%s: request failed\n",__func__); g_set_error_literal(error_r, raop_output_quark(), 0,
"request failed");
return false; return false;
} }
g_debug("received %s", line); g_debug("received %s", line);
token = strtok(line, delimiters); token = strtok(line, delimiters);
token = strtok(NULL, delimiters); token = strtok(NULL, delimiters);
if (token == NULL || strcmp(token,"200")) { if (token == NULL) {
g_warning("%s: request failed, error %s\n", __func__, token); g_set_error_literal(error_r, raop_output_quark(), 0,
"request failed");
return false;
}
if (strcmp(token, "200") != 0) {
g_set_error(error_r, raop_output_quark(), 0,
"request failed: %s", token);
return false; return false;
} }
...@@ -613,9 +655,11 @@ exec_request(struct rtspcl_data *rtspcld, const char *cmd, ...@@ -613,9 +655,11 @@ exec_request(struct rtspcl_data *rtspcld, const char *cmd,
} }
dp = strstr(line, ":"); dp = strstr(line, ":");
if (!dp) { if (!dp) {
g_warning("%s: Request failed, bad header\n", __func__);
free_kd(*kd); free_kd(*kd);
*kd = NULL; *kd = NULL;
g_set_error_literal(error_r, raop_output_quark(), 0,
"request failed, bad header");
return false; return false;
} }
*dp = 0; *dp = 0;
...@@ -636,10 +680,11 @@ exec_request(struct rtspcl_data *rtspcld, const char *cmd, ...@@ -636,10 +680,11 @@ exec_request(struct rtspcl_data *rtspcld, const char *cmd,
} }
static bool static bool
rtspcl_set_parameter(struct rtspcl_data *rtspcld, const char *parameter) rtspcl_set_parameter(struct rtspcl_data *rtspcld, const char *parameter,
GError **error_r)
{ {
return exec_request(rtspcld, "SET_PARAMETER", "text/parameters", return exec_request(rtspcld, "SET_PARAMETER", "text/parameters",
parameter, 1, NULL, &rtspcld->kd); parameter, 1, NULL, &rtspcld->kd, error_r);
} }
static struct rtspcl_data * static struct rtspcl_data *
...@@ -692,16 +737,16 @@ rtspcl_add_exthds(struct rtspcl_data *rtspcld, const char *key, char *data) ...@@ -692,16 +737,16 @@ rtspcl_add_exthds(struct rtspcl_data *rtspcld, const char *key, char *data)
static bool static bool
rtspcl_connect(struct rtspcl_data *rtspcld, const char *host, short destport, rtspcl_connect(struct rtspcl_data *rtspcld, const char *host, short destport,
const char *sid) const char *sid, GError **error_r)
{ {
unsigned short myport = 0; unsigned short myport = 0;
struct sockaddr_in name; struct sockaddr_in name;
socklen_t namelen = sizeof(name); socklen_t namelen = sizeof(name);
if ((rtspcld->fd = open_tcp_socket(NULL, &myport)) == -1) if ((rtspcld->fd = open_tcp_socket(NULL, &myport, error_r)) == -1)
return false; return false;
if (!get_tcp_connect_by_host(rtspcld->fd, host, destport)) if (!get_tcp_connect_by_host(rtspcld->fd, host, destport, error_r))
return false; return false;
getsockname(rtspcld->fd, (struct sockaddr*)&name, &namelen); getsockname(rtspcld->fd, (struct sockaddr*)&name, &namelen);
...@@ -713,13 +758,16 @@ rtspcl_connect(struct rtspcl_data *rtspcld, const char *host, short destport, ...@@ -713,13 +758,16 @@ rtspcl_connect(struct rtspcl_data *rtspcld, const char *host, short destport,
} }
static bool static bool
rtspcl_announce_sdp(struct rtspcl_data *rtspcld, const char *sdp) rtspcl_announce_sdp(struct rtspcl_data *rtspcld, const char *sdp,
GError **error_r)
{ {
return exec_request(rtspcld, "ANNOUNCE", "application/sdp", sdp, 1, NULL, &rtspcld->kd); return exec_request(rtspcld, "ANNOUNCE", "application/sdp", sdp, 1,
NULL, &rtspcld->kd, error_r);
} }
static bool static bool
rtspcl_setup(struct rtspcl_data *rtspcld, struct key_data **kd) rtspcl_setup(struct rtspcl_data *rtspcld, struct key_data **kd,
GError **error_r)
{ {
struct key_data *rkd = NULL, hds; struct key_data *rkd = NULL, hds;
const char delimiters[] = ";"; const char delimiters[] = ";";
...@@ -737,14 +785,18 @@ rtspcl_setup(struct rtspcl_data *rtspcld, struct key_data **kd) ...@@ -737,14 +785,18 @@ rtspcl_setup(struct rtspcl_data *rtspcld, struct key_data **kd)
hds.key = transport_key; hds.key = transport_key;
hds.data = transport_value; hds.data = transport_value;
hds.next = NULL; hds.next = NULL;
if (!exec_request(rtspcld, "SETUP", NULL, NULL, 1, &hds, &rkd)) return false; if (!exec_request(rtspcld, "SETUP", NULL, NULL, 1,
&hds, &rkd, error_r))
return false;
if (!(rtspcld->session = g_strdup(kd_lookup(rkd, "Session")))) { if (!(rtspcld->session = g_strdup(kd_lookup(rkd, "Session")))) {
g_warning("%s: no session in response\n",__func__); g_set_error_literal(error_r, raop_output_quark(), 0,
"no session in response");
goto erexit; goto erexit;
} }
if (!(rtspcld->transport = kd_lookup(rkd, "Transport"))) { if (!(rtspcld->transport = kd_lookup(rkd, "Transport"))) {
g_warning("%s: no transport in response\n",__func__); g_set_error_literal(error_r, raop_output_quark(), 0,
"no transport in response");
goto erexit; goto erexit;
} }
buf = g_strdup(rtspcld->transport); buf = g_strdup(rtspcld->transport);
...@@ -764,11 +816,13 @@ rtspcl_setup(struct rtspcl_data *rtspcld, struct key_data **kd) ...@@ -764,11 +816,13 @@ rtspcl_setup(struct rtspcl_data *rtspcld, struct key_data **kd)
token = strtok(NULL, delimiters); token = strtok(NULL, delimiters);
} }
if (rtspcld->server_port == 0) { if (rtspcld->server_port == 0) {
g_warning("%s: no server_port in response\n",__func__); g_set_error_literal(error_r, raop_output_quark(), 0,
"no server_port in response");
goto erexit; goto erexit;
} }
if (rtspcld->control_port == 0) { if (rtspcld->control_port == 0) {
g_warning("%s: no control_port in response\n",__func__); g_set_error_literal(error_r, raop_output_quark(), 0,
"no control_port in response");
goto erexit; goto erexit;
} }
rval = true; rval = true;
...@@ -783,10 +837,11 @@ rtspcl_setup(struct rtspcl_data *rtspcld, struct key_data **kd) ...@@ -783,10 +837,11 @@ rtspcl_setup(struct rtspcl_data *rtspcld, struct key_data **kd)
} }
static bool static bool
rtspcl_record(struct rtspcl_data *rtspcld) rtspcl_record(struct rtspcl_data *rtspcld, GError **error_r)
{ {
if (!rtspcld->session) { if (!rtspcld->session) {
g_warning("%s: no session in progress\n", __func__); g_set_error_literal(error_r, raop_output_quark(), 0,
"no session in progress");
return false; return false;
} }
...@@ -807,7 +862,7 @@ rtspcl_record(struct rtspcl_data *rtspcld) ...@@ -807,7 +862,7 @@ rtspcl_record(struct rtspcl_data *rtspcld)
range.next = &rtp; range.next = &rtp;
return exec_request(rtspcld, "RECORD", NULL, NULL, 1, &range, return exec_request(rtspcld, "RECORD", NULL, NULL, 1, &range,
&rtspcld->kd); &rtspcld->kd, error_r);
} }
static void static void
...@@ -958,7 +1013,7 @@ raopcl_stream_connect(G_GNUC_UNUSED struct raop_data *rd) ...@@ -958,7 +1013,7 @@ raopcl_stream_connect(G_GNUC_UNUSED struct raop_data *rd)
static bool static bool
raopcl_connect(struct raop_data *rd) raopcl_connect(struct raop_data *rd, GError **error_r)
{ {
unsigned char buf[4 + 8 + 16]; unsigned char buf[4 + 8 + 16];
char sid[16]; char sid[16];
...@@ -989,7 +1044,8 @@ raopcl_connect(struct raop_data *rd) ...@@ -989,7 +1044,8 @@ raopcl_connect(struct raop_data *rd)
rtspcl_add_exthds(rd->rtspcl, "Client-Instance", sci); rtspcl_add_exthds(rd->rtspcl, "Client-Instance", sci);
rtspcl_add_exthds(rd->rtspcl, "DACP-ID", sci); rtspcl_add_exthds(rd->rtspcl, "DACP-ID", sci);
rtspcl_add_exthds(rd->rtspcl, "Active-Remote", act_r); rtspcl_add_exthds(rd->rtspcl, "Active-Remote", act_r);
if (!rtspcl_connect(rd->rtspcl, rd->addr, rd->rtsp_port, sid)) goto erexit; if (!rtspcl_connect(rd->rtspcl, rd->addr, rd->rtsp_port, sid, error_r))
goto erexit;
i = rsa_encrypt(raop_session->encrypt.key, 16, rsakey); i = rsa_encrypt(raop_session->encrypt.key, 16, rsakey);
key = g_base64_encode(rsakey, i); key = g_base64_encode(rsakey, i);
...@@ -1010,11 +1066,14 @@ raopcl_connect(struct raop_data *rd) ...@@ -1010,11 +1066,14 @@ raopcl_connect(struct raop_data *rd)
sid, rtspcl_local_ip(rd->rtspcl), rd->addr, NUMSAMPLES, key, iv); sid, rtspcl_local_ip(rd->rtspcl), rd->addr, NUMSAMPLES, key, iv);
remove_char_from_string(sac, '='); remove_char_from_string(sac, '=');
// rtspcl_add_exthds(rd->rtspcl, "Apple-Challenge", sac); // rtspcl_add_exthds(rd->rtspcl, "Apple-Challenge", sac);
if (!rtspcl_announce_sdp(rd->rtspcl, sdp)) goto erexit; if (!rtspcl_announce_sdp(rd->rtspcl, sdp, error_r))
goto erexit;
// if (!rtspcl_mark_del_exthds(rd->rtspcl, "Apple-Challenge")) goto erexit; // if (!rtspcl_mark_del_exthds(rd->rtspcl, "Apple-Challenge")) goto erexit;
if (!rtspcl_setup(rd->rtspcl, &setup_kd)) goto erexit; if (!rtspcl_setup(rd->rtspcl, &setup_kd, error_r))
goto erexit;
if (!(aj = kd_lookup(setup_kd,"Audio-Jack-Status"))) { if (!(aj = kd_lookup(setup_kd,"Audio-Jack-Status"))) {
g_warning("%s: Audio-Jack-Status is missing\n",__func__); g_set_error_literal(error_r, raop_output_quark(), 0,
"Audio-Jack-Status is missing");
goto erexit; goto erexit;
} }
...@@ -1033,10 +1092,16 @@ raopcl_connect(struct raop_data *rd) ...@@ -1033,10 +1092,16 @@ raopcl_connect(struct raop_data *rd)
token = strtok(NULL, delimiters); token = strtok(NULL, delimiters);
} }
if (!get_sockaddr_by_host(rd->addr, rd->rtspcl->control_port, &rd->ctrl_addr)) goto erexit; if (!get_sockaddr_by_host(rd->addr, rd->rtspcl->control_port,
if (!get_sockaddr_by_host(rd->addr, rd->rtspcl->server_port, &rd->data_addr)) goto erexit; &rd->ctrl_addr, error_r))
goto erexit;
if (!rtspcl_record(rd->rtspcl)) goto erexit; if (!get_sockaddr_by_host(rd->addr, rd->rtspcl->server_port,
&rd->data_addr, error_r))
goto erexit;
if (!rtspcl_record(rd->rtspcl, error_r))
goto erexit;
raopcl_stream_connect(rd); raopcl_stream_connect(rd);
...@@ -1076,7 +1141,7 @@ difference (struct timeval *t1, struct timeval *t2) ...@@ -1076,7 +1141,7 @@ difference (struct timeval *t1, struct timeval *t2)
* requests. * requests.
*/ */
static bool static bool
send_audio_data(int fd) send_audio_data(int fd, GError **error_r)
{ {
int i = 0; int i = 0;
struct timeval current_time, tout, rtp_time; struct timeval current_time, tout, rtp_time;
...@@ -1105,11 +1170,14 @@ send_audio_data(int fd) ...@@ -1105,11 +1170,14 @@ send_audio_data(int fd)
raop_session->wblk_remsize, 0, (struct sockaddr *) &rd->data_addr, raop_session->wblk_remsize, 0, (struct sockaddr *) &rd->data_addr,
sizeof(rd->data_addr)); sizeof(rd->data_addr));
if (i < 0) { if (i < 0) {
g_warning("%s: write error: %s\n", __func__, strerror(errno)); g_set_error(error_r, raop_output_quark(), errno,
"write error: %s",
g_strerror(errno));
return false; return false;
} }
if (i == 0) { if (i == 0) {
g_warning("%s: write, disconnected on the other end\n", __func__); g_set_error_literal(error_r, raop_output_quark(), 0,
"disconnected on the other end");
return false; return false;
} }
rd = rd->next; rd = rd->next;
...@@ -1124,11 +1192,14 @@ send_audio_data(int fd) ...@@ -1124,11 +1192,14 @@ send_audio_data(int fd)
static void * static void *
raop_output_init(G_GNUC_UNUSED const struct audio_format *audio_format, raop_output_init(G_GNUC_UNUSED const struct audio_format *audio_format,
G_GNUC_UNUSED const struct config_param *param, G_GNUC_UNUSED const struct config_param *param,
G_GNUC_UNUSED GError **error) GError **error_r)
{ {
struct raop_data *rd; struct raop_data *rd;
rd = new_raop_data(); rd = new_raop_data(error_r);
if (rd == NULL)
return NULL;
rd->addr = config_get_block_string(param, "host", NULL); rd->addr = config_get_block_string(param, "host", NULL);
rd->rtsp_port = config_get_block_unsigned(param, "port", 5000); rd->rtsp_port = config_get_block_unsigned(param, "port", 5000);
rd->volume = config_get_block_unsigned(param, "volume", 75); rd->volume = config_get_block_unsigned(param, "volume", 75);
...@@ -1136,11 +1207,11 @@ raop_output_init(G_GNUC_UNUSED const struct audio_format *audio_format, ...@@ -1136,11 +1207,11 @@ raop_output_init(G_GNUC_UNUSED const struct audio_format *audio_format,
} }
static bool static bool
raop_set_volume_local(struct raop_data *rd, int volume) raop_set_volume_local(struct raop_data *rd, int volume, GError **error_r)
{ {
char vol_str[128]; char vol_str[128];
sprintf(vol_str, "volume: %d.000000\r\n", volume); sprintf(vol_str, "volume: %d.000000\r\n", volume);
return rtspcl_set_parameter(rd->rtspcl, vol_str); return rtspcl_set_parameter(rd->rtspcl, vol_str, error_r);
} }
...@@ -1162,7 +1233,7 @@ raop_get_volume(struct raop_data *rd) ...@@ -1162,7 +1233,7 @@ raop_get_volume(struct raop_data *rd)
} }
bool bool
raop_set_volume(struct raop_data *rd, unsigned volume) raop_set_volume(struct raop_data *rd, unsigned volume, GError **error_r)
{ {
int raop_volume; int raop_volume;
bool rval; bool rval;
...@@ -1175,7 +1246,7 @@ raop_set_volume(struct raop_data *rd, unsigned volume) ...@@ -1175,7 +1246,7 @@ raop_set_volume(struct raop_data *rd, unsigned volume)
(RAOP_VOLUME_MAX - RAOP_VOLUME_MIN) * volume / 100; (RAOP_VOLUME_MAX - RAOP_VOLUME_MIN) * volume / 100;
} }
g_mutex_lock(rd->control_mutex); g_mutex_lock(rd->control_mutex);
rval = raop_set_volume_local(rd, raop_volume); rval = raop_set_volume_local(rd, raop_volume, error_r);
if (rval) rd->volume = volume; if (rval) rd->volume = volume;
g_mutex_unlock(rd->control_mutex); g_mutex_unlock(rd->control_mutex);
...@@ -1205,7 +1276,8 @@ raop_output_cancel(void *data) ...@@ -1205,7 +1276,8 @@ raop_output_cancel(void *data)
sprintf(buf, "seq=%d; rtptime=%d", raop_session->play_state.seq_num + flush_diff, raop_session->play_state.rtptime + NUMSAMPLES * flush_diff); sprintf(buf, "seq=%d; rtptime=%d", raop_session->play_state.seq_num + flush_diff, raop_session->play_state.rtptime + NUMSAMPLES * flush_diff);
kd.data = buf; kd.data = buf;
kd.next = NULL; kd.next = NULL;
exec_request(rd->rtspcl, "FLUSH", NULL, NULL, 1, &kd, &(rd->rtspcl->kd)); exec_request(rd->rtspcl, "FLUSH", NULL, NULL, 1,
&kd, &(rd->rtspcl->kd), NULL);
g_mutex_unlock(rd->control_mutex); g_mutex_unlock(rd->control_mutex);
} }
...@@ -1256,7 +1328,8 @@ raop_output_close(void *data) ...@@ -1256,7 +1328,8 @@ raop_output_close(void *data)
g_mutex_unlock(raop_session->list_mutex); g_mutex_unlock(raop_session->list_mutex);
g_mutex_lock(rd->control_mutex); g_mutex_lock(rd->control_mutex);
exec_request(rd->rtspcl, "TEARDOWN", NULL, NULL, 0, NULL, &(rd->rtspcl->kd)); exec_request(rd->rtspcl, "TEARDOWN", NULL, NULL, 0,
NULL, &rd->rtspcl->kd, NULL);
g_mutex_unlock(rd->control_mutex); g_mutex_unlock(rd->control_mutex);
rd->started = 0; rd->started = 0;
...@@ -1276,11 +1349,21 @@ raop_output_open(void *data, struct audio_format *audio_format, GError **error_r ...@@ -1276,11 +1349,21 @@ raop_output_open(void *data, struct audio_format *audio_format, GError **error_r
raop_session->raop_list = rd; raop_session->raop_list = rd;
rd->is_master = true; rd->is_master = true;
if ((raop_session->data_fd = open_udp_socket(NULL, &myport)) == -1) raop_session->data_fd = open_udp_socket(NULL, &myport,
error_r);
if (raop_session->data_fd < 0)
return false; return false;
if ((raop_session->ntp.fd = open_udp_socket(NULL, &raop_session->ntp.port)) == -1) return false; raop_session->ntp.fd =
if ((raop_session->ctrl.fd = open_udp_socket(NULL, &raop_session->ctrl.port)) == -1) { open_udp_socket(NULL, &raop_session->ntp.port,
error_r);
if (raop_session->ntp.fd < 0)
return false;
raop_session->ctrl.fd =
open_udp_socket(NULL, &raop_session->ctrl.port,
error_r);
if (raop_session->ctrl.fd < 0) {
close(raop_session->ntp.fd); close(raop_session->ntp.fd);
raop_session->ctrl.fd = -1; raop_session->ctrl.fd = -1;
g_mutex_unlock(raop_session->list_mutex); g_mutex_unlock(raop_session->list_mutex);
...@@ -1291,16 +1374,11 @@ raop_output_open(void *data, struct audio_format *audio_format, GError **error_r ...@@ -1291,16 +1374,11 @@ raop_output_open(void *data, struct audio_format *audio_format, GError **error_r
audio_format->format = SAMPLE_FORMAT_S16; audio_format->format = SAMPLE_FORMAT_S16;
g_debug("raop_openDevice %s %d\n", rd->addr, rd->rtsp_port); g_debug("raop_openDevice %s %d\n", rd->addr, rd->rtsp_port);
if (!raopcl_connect(rd)) { if (!raopcl_connect(rd, error_r))
g_set_error(error_r, raop_output_quark(), -1,
"Unable to connect to device");
return false; return false;
}
if (!raop_set_volume(rd, rd->volume)) { if (!raop_set_volume(rd, rd->volume, error_r))
g_set_error(error_r, raop_output_quark(), -1,
"Unable to set volume after connecting to device");
return false; return false;
}
g_mutex_lock(raop_session->list_mutex); g_mutex_lock(raop_session->list_mutex);
if (!rd->is_master) { if (!rd->is_master) {
...@@ -1391,11 +1469,8 @@ raop_output_play(void *data, const void *chunk, size_t size, ...@@ -1391,11 +1469,8 @@ raop_output_play(void *data, const void *chunk, size_t size,
raop_session->wblk_remsize = count + RAOP_HEADER_SIZE; raop_session->wblk_remsize = count + RAOP_HEADER_SIZE;
raop_session->wblk_wsize = 0; raop_session->wblk_wsize = 0;
if (!send_audio_data(raop_session->data_fd)) { if (!send_audio_data(raop_session->data_fd, error_r))
g_set_error(error_r, raop_output_quark(), -1,
"Unable to write to device");
goto erexit; goto erexit;
}
raop_session->bufferSize = 0; raop_session->bufferSize = 0;
} }
......
...@@ -155,7 +155,7 @@ struct raop_session_data { ...@@ -155,7 +155,7 @@ struct raop_session_data {
/*********************************************************************/ /*********************************************************************/
bool bool
raop_set_volume(struct raop_data *rd, unsigned volume); raop_set_volume(struct raop_data *rd, unsigned volume, GError **error_r);
int int
raop_get_volume(struct raop_data *rd); raop_get_volume(struct raop_data *rd);
......
...@@ -60,7 +60,8 @@ pulse_output_set_volume(G_GNUC_UNUSED struct pulse_output *po, ...@@ -60,7 +60,8 @@ pulse_output_set_volume(G_GNUC_UNUSED struct pulse_output *po,
bool bool
raop_set_volume(G_GNUC_UNUSED struct raop_data *rd, raop_set_volume(G_GNUC_UNUSED struct raop_data *rd,
G_GNUC_UNUSED unsigned volume) G_GNUC_UNUSED unsigned volume,
G_GNUC_UNUSED GError **error_r)
{ {
return false; return false;
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment