diff options
-rw-r--r-- | src/mixer/raop_mixer_plugin.c | 4 | ||||
-rw-r--r-- | src/output/raop_output_plugin.c | 229 | ||||
-rw-r--r-- | src/output/raop_output_plugin.h | 2 | ||||
-rw-r--r-- | test/read_mixer.c | 3 |
4 files changed, 157 insertions, 81 deletions
diff --git a/src/mixer/raop_mixer_plugin.c b/src/mixer/raop_mixer_plugin.c index 7ea156683..8173305bd 100644 --- a/src/mixer/raop_mixer_plugin.c +++ b/src/mixer/raop_mixer_plugin.c @@ -63,11 +63,11 @@ raop_mixer_get_volume(struct mixer *mixer, G_GNUC_UNUSED GError **error_r) } 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; 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 = { 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; } diff --git a/src/output/raop_output_plugin.h b/src/output/raop_output_plugin.h index 562cb054b..ed655330c 100644 --- a/src/output/raop_output_plugin.h +++ b/src/output/raop_output_plugin.h @@ -155,7 +155,7 @@ struct raop_session_data { /*********************************************************************/ bool -raop_set_volume(struct raop_data *rd, unsigned volume); +raop_set_volume(struct raop_data *rd, unsigned volume, GError **error_r); int raop_get_volume(struct raop_data *rd); diff --git a/test/read_mixer.c b/test/read_mixer.c index 713fc9f38..b45a14400 100644 --- a/test/read_mixer.c +++ b/test/read_mixer.c @@ -60,7 +60,8 @@ pulse_output_set_volume(G_GNUC_UNUSED struct pulse_output *po, bool 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; } |