aboutsummaryrefslogtreecommitdiffstats
path: root/src/output/raop_output_plugin.c
diff options
context:
space:
mode:
authorMax Kellermann <max@duempel.org>2011-08-24 00:14:12 +0200
committerMax Kellermann <max@duempel.org>2011-08-24 01:47:26 +0200
commit350aa330220685721eaeb3f8e5ee669a5ef4d015 (patch)
tree2f710fcefb53f44ca1ec3be8774b270690cfb478 /src/output/raop_output_plugin.c
parentd6290a2f1a27696f72e3ae599bdf8135e59be559 (diff)
downloadmpd-350aa330220685721eaeb3f8e5ee669a5ef4d015.tar.gz
mpd-350aa330220685721eaeb3f8e5ee669a5ef4d015.tar.xz
mpd-350aa330220685721eaeb3f8e5ee669a5ef4d015.zip
output/raop: consistently use GError
Diffstat (limited to '')
-rw-r--r--src/output/raop_output_plugin.c229
1 files changed, 152 insertions, 77 deletions
diff --git a/src/output/raop_output_plugin.c b/src/output/raop_output_plugin.c
index 542cd7b06..69818a4b0 100644
--- a/src/output/raop_output_plugin.c
+++ b/src/output/raop_output_plugin.c
@@ -52,7 +52,7 @@ raop_output_quark(void)
}
static struct raop_data *
-new_raop_data(void)
+new_raop_data(GError **error_r)
{
struct raop_data *ret = g_new(struct raop_data, 1);
int i;
@@ -79,7 +79,8 @@ new_raop_data(void)
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))) {
- 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;
}
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)
* if hostname=NULL, use INADDR_ANY.
* 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;
socklen_t nlen = sizeof(struct sockaddr);
@@ -222,7 +224,9 @@ static int bind_host(int sd, char *hostname, unsigned long ulAddr, unsigned shor
my_addr.sin_addr.s_addr=-1;
} else {
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;
}
}
@@ -245,7 +249,9 @@ static int bind_host(int sd, char *hostname, unsigned long ulAddr, unsigned shor
my_addr.sin_port = htons(*port);
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;
}
@@ -260,17 +266,21 @@ static int bind_host(int sd, char *hostname, unsigned long ulAddr, unsigned shor
/*
* 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;
/* socket creation */
sd = socket(AF_INET, SOCK_STREAM, 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;
}
- if (bind_host(sd, hostname,0, port)) {
+ if (bind_host(sd, hostname, 0, port, error_r)) {
close(sd);
return -1;
}
@@ -281,7 +291,9 @@ static int open_tcp_socket(char *hostname, unsigned short *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 size = 30000;
@@ -289,14 +301,18 @@ static int open_udp_socket(char *hostname, unsigned short *port)
/* socket creation */
sd = socket(PF_INET, SOCK_DGRAM, 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;
}
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;
}
- if (bind_host(sd, hostname,0, port)) {
+ if (bind_host(sd, hostname, 0, port, error_r)) {
close(sd);
return -1;
}
@@ -310,14 +326,17 @@ static int open_udp_socket(char *hostname, unsigned short *port)
* nsport is network byte order
*/
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))){
SLEEP_MSEC(100L);
// try one more time
if (connect(sd, (struct sockaddr *)&dest_addr, sizeof(struct sockaddr))) {
- g_warning("error:get_tcp_nconnect addr=%s, port=%d\n",
- inet_ntoa(dest_addr.sin_addr), ntohs(dest_addr.sin_port));
+ g_set_error(error_r, raop_output_quark(), errno,
+ "failed to connect to %s:%d: %s",
+ inet_ntoa(dest_addr.sin_addr),
+ ntohs(dest_addr.sin_port),
+ g_strerror(errno));
return false;
}
}
@@ -325,7 +344,9 @@ get_tcp_connect(int sd, struct sockaddr_in dest_addr)
}
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;
@@ -336,7 +357,8 @@ get_sockaddr_by_host(const char *host, short destport, struct sockaddr_in *addr)
} else {
addr->sin_family = AF_INET;
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;
}
}
@@ -345,13 +367,13 @@ get_sockaddr_by_host(const char *host, short destport, struct sockaddr_in *addr)
}
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;
- get_sockaddr_by_host(host, destport, &addr);
-
- return get_tcp_connect(sd, addr);
+ return get_sockaddr_by_host(host, destport, &addr, error_r) &&
+ get_tcp_connect(sd, addr, error_r);
}
/*
@@ -515,7 +537,8 @@ static bool
exec_request(struct rtspcl_data *rtspcld, const char *cmd,
const char *content_type, const char *content,
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 req[1024];
@@ -531,7 +554,11 @@ exec_request(struct rtspcl_data *rtspcld, const char *cmd,
int fdmax = 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 );
@@ -568,6 +595,13 @@ exec_request(struct rtspcl_data *rtspcld, const char *cmd,
strncat(req, content, sizeof(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);
if (!get_response) return true;
@@ -587,15 +621,23 @@ exec_request(struct rtspcl_data *rtspcld, const char *cmd,
}
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;
}
g_debug("received %s", line);
token = strtok(line, delimiters);
token = strtok(NULL, delimiters);
- if (token == NULL || strcmp(token,"200")) {
- g_warning("%s: request failed, error %s\n", __func__, token);
+ if (token == NULL) {
+ 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;
}
@@ -613,9 +655,11 @@ exec_request(struct rtspcl_data *rtspcld, const char *cmd,
}
dp = strstr(line, ":");
if (!dp) {
- g_warning("%s: Request failed, bad header\n", __func__);
free_kd(*kd);
*kd = NULL;
+
+ g_set_error_literal(error_r, raop_output_quark(), 0,
+ "request failed, bad header");
return false;
}
*dp = 0;
@@ -636,10 +680,11 @@ exec_request(struct rtspcl_data *rtspcld, const char *cmd,
}
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",
- parameter, 1, NULL, &rtspcld->kd);
+ parameter, 1, NULL, &rtspcld->kd, error_r);
}
static struct rtspcl_data *
@@ -692,16 +737,16 @@ rtspcl_add_exthds(struct rtspcl_data *rtspcld, const char *key, char *data)
static bool
rtspcl_connect(struct rtspcl_data *rtspcld, const char *host, short destport,
- const char *sid)
+ const char *sid, GError **error_r)
{
unsigned short myport = 0;
struct sockaddr_in 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;
- if (!get_tcp_connect_by_host(rtspcld->fd, host, destport))
+ if (!get_tcp_connect_by_host(rtspcld->fd, host, destport, error_r))
return false;
getsockname(rtspcld->fd, (struct sockaddr*)&name, &namelen);
@@ -713,13 +758,16 @@ rtspcl_connect(struct rtspcl_data *rtspcld, const char *host, short destport,
}
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
-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;
const char delimiters[] = ";";
@@ -737,14 +785,18 @@ rtspcl_setup(struct rtspcl_data *rtspcld, struct key_data **kd)
hds.key = transport_key;
hds.data = transport_value;
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")))) {
- 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;
}
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;
}
buf = g_strdup(rtspcld->transport);
@@ -764,11 +816,13 @@ rtspcl_setup(struct rtspcl_data *rtspcld, struct key_data **kd)
token = strtok(NULL, delimiters);
}
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;
}
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;
}
rval = true;
@@ -783,10 +837,11 @@ rtspcl_setup(struct rtspcl_data *rtspcld, struct key_data **kd)
}
static bool
-rtspcl_record(struct rtspcl_data *rtspcld)
+rtspcl_record(struct rtspcl_data *rtspcld, GError **error_r)
{
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;
}
@@ -807,7 +862,7 @@ rtspcl_record(struct rtspcl_data *rtspcld)
range.next = &rtp;
return exec_request(rtspcld, "RECORD", NULL, NULL, 1, &range,
- &rtspcld->kd);
+ &rtspcld->kd, error_r);
}
static void
@@ -958,7 +1013,7 @@ raopcl_stream_connect(G_GNUC_UNUSED struct raop_data *rd)
static bool
-raopcl_connect(struct raop_data *rd)
+raopcl_connect(struct raop_data *rd, GError **error_r)
{
unsigned char buf[4 + 8 + 16];
char sid[16];
@@ -989,7 +1044,8 @@ raopcl_connect(struct raop_data *rd)
rtspcl_add_exthds(rd->rtspcl, "Client-Instance", sci);
rtspcl_add_exthds(rd->rtspcl, "DACP-ID", sci);
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);
key = g_base64_encode(rsakey, i);
@@ -1010,11 +1066,14 @@ raopcl_connect(struct raop_data *rd)
sid, rtspcl_local_ip(rd->rtspcl), rd->addr, NUMSAMPLES, key, iv);
remove_char_from_string(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_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"))) {
- 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;
}
@@ -1033,10 +1092,16 @@ raopcl_connect(struct raop_data *rd)
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->server_port, &rd->data_addr)) goto erexit;
+ if (!get_sockaddr_by_host(rd->addr, rd->rtspcl->control_port,
+ &rd->ctrl_addr, error_r))
+ 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)) goto erexit;
+ if (!rtspcl_record(rd->rtspcl, error_r))
+ goto erexit;
raopcl_stream_connect(rd);
@@ -1076,7 +1141,7 @@ difference (struct timeval *t1, struct timeval *t2)
* requests.
*/
static bool
-send_audio_data(int fd)
+send_audio_data(int fd, GError **error_r)
{
int i = 0;
struct timeval current_time, tout, rtp_time;
@@ -1105,11 +1170,14 @@ send_audio_data(int fd)
raop_session->wblk_remsize, 0, (struct sockaddr *) &rd->data_addr,
sizeof(rd->data_addr));
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;
}
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;
}
rd = rd->next;
@@ -1124,11 +1192,14 @@ send_audio_data(int fd)
static void *
raop_output_init(G_GNUC_UNUSED const struct audio_format *audio_format,
G_GNUC_UNUSED const struct config_param *param,
- G_GNUC_UNUSED GError **error)
+ GError **error_r)
{
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->rtsp_port = config_get_block_unsigned(param, "port", 5000);
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,
}
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];
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)
}
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;
bool rval;
@@ -1175,7 +1246,7 @@ raop_set_volume(struct raop_data *rd, unsigned volume)
(RAOP_VOLUME_MAX - RAOP_VOLUME_MIN) * volume / 100;
}
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;
g_mutex_unlock(rd->control_mutex);
@@ -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);
kd.data = buf;
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);
}
@@ -1256,7 +1328,8 @@ raop_output_close(void *data)
g_mutex_unlock(raop_session->list_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);
rd->started = 0;
@@ -1276,11 +1349,21 @@ raop_output_open(void *data, struct audio_format *audio_format, GError **error_r
raop_session->raop_list = rd;
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;
+
+ raop_session->ntp.fd =
+ open_udp_socket(NULL, &raop_session->ntp.port,
+ error_r);
+ if (raop_session->ntp.fd < 0)
return false;
- if ((raop_session->ntp.fd = open_udp_socket(NULL, &raop_session->ntp.port)) == -1) return false;
- if ((raop_session->ctrl.fd = open_udp_socket(NULL, &raop_session->ctrl.port)) == -1) {
+ 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);
raop_session->ctrl.fd = -1;
g_mutex_unlock(raop_session->list_mutex);
@@ -1291,16 +1374,11 @@ raop_output_open(void *data, struct audio_format *audio_format, GError **error_r
audio_format->format = SAMPLE_FORMAT_S16;
g_debug("raop_openDevice %s %d\n", rd->addr, rd->rtsp_port);
- if (!raopcl_connect(rd)) {
- g_set_error(error_r, raop_output_quark(), -1,
- "Unable to connect to device");
+ if (!raopcl_connect(rd, error_r))
return false;
- }
- if (!raop_set_volume(rd, rd->volume)) {
- g_set_error(error_r, raop_output_quark(), -1,
- "Unable to set volume after connecting to device");
+
+ if (!raop_set_volume(rd, rd->volume, error_r))
return false;
- }
g_mutex_lock(raop_session->list_mutex);
if (!rd->is_master) {
@@ -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_wsize = 0;
- if (!send_audio_data(raop_session->data_fd)) {
- g_set_error(error_r, raop_output_quark(), -1,
- "Unable to write to device");
+ if (!send_audio_data(raop_session->data_fd, error_r))
goto erexit;
- }
raop_session->bufferSize = 0;
}