00001 #include "common.h"
00002
00003 static double
00004 udp_timediff (int32_t id, int socket) {
00005 int i;
00006 double lag;
00007 struct timeval time;
00008 double diff = 0.0;
00009 int diffc = 0;
00010 xmmsc_vis_udp_timing_t packet_d;
00011 char* packet = packet_init_timing (&packet_d);
00012
00013 gettimeofday (&time, NULL);
00014 XMMSC_VIS_UNALIGNED_WRITE (packet_d.__unaligned_id, (int32_t)htonl (id), int32_t);
00015 XMMSC_VIS_UNALIGNED_WRITE (&packet_d.__unaligned_clientstamp[0],
00016 (int32_t)htonl (time.tv_sec), int32_t);
00017 XMMSC_VIS_UNALIGNED_WRITE (&packet_d.__unaligned_clientstamp[1],
00018 (int32_t)htonl (time.tv_usec), int32_t);
00019
00020
00021 for (i = 0; i < 10; ++i) {
00022 send (socket, packet, packet_d.size, 0);
00023 }
00024 printf ("Syncing ");
00025 do {
00026 if ((recv (socket, packet, packet_d.size, 0) == packet_d.size) && (*packet_d.__unaligned_type == 'T')) {
00027 struct timeval rtv;
00028 gettimeofday (&time, NULL);
00029 XMMSC_VIS_UNALIGNED_READ (rtv.tv_sec, &packet_d.__unaligned_clientstamp[0], int32_t);
00030 XMMSC_VIS_UNALIGNED_READ (rtv.tv_usec, &packet_d.__unaligned_clientstamp[1], int32_t);
00031 rtv.tv_sec = ntohl (rtv.tv_sec);
00032 rtv.tv_usec = ntohl (rtv.tv_usec);
00033
00034 lag = (tv2ts (&time) - tv2ts (&rtv)) / 2.0;
00035 diffc++;
00036
00037 XMMSC_VIS_UNALIGNED_READ (rtv.tv_sec, &packet_d.__unaligned_serverstamp[0], int32_t);
00038 XMMSC_VIS_UNALIGNED_READ (rtv.tv_usec, &packet_d.__unaligned_serverstamp[1], int32_t);
00039 rtv.tv_sec = ntohl (rtv.tv_sec);
00040 rtv.tv_usec = ntohl (rtv.tv_usec);
00041
00042 diff += tv2ts (&rtv) - lag;
00043
00044
00045
00046
00047 putchar('.');
00048 }
00049 } while (diffc < 10);
00050 free (packet);
00051
00052 puts (" done.");
00053 return diff / (double)diffc;
00054 }
00055
00056 static bool
00057 setup_socket (xmmsc_connection_t *c, xmmsc_vis_udp_t *t, int32_t id, int32_t port) {
00058 struct addrinfo hints;
00059 struct addrinfo *result, *rp;
00060 char *host;
00061 char portstr[10];
00062 char packet[1 + sizeof(int32_t)];
00063 int32_t* packet_id = (int32_t*)&packet[1];
00064 sprintf (portstr, "%d", port);
00065
00066 memset (&hints, 0, sizeof (hints));
00067 hints.ai_family = AF_UNSPEC;
00068 hints.ai_socktype = SOCK_DGRAM;
00069 hints.ai_flags = 0;
00070 hints.ai_protocol = 0;
00071
00072 host = xmms_ipc_hostname (c->path);
00073 if (!host) {
00074 host = strdup ("localhost");
00075 }
00076
00077 if (xmms_getaddrinfo (host, portstr, &hints, &result) != 0)
00078 {
00079 c->error = strdup("Couldn't setup socket!");
00080 return false;
00081 }
00082 free (host);
00083
00084 for (rp = result; rp != NULL; rp = rp->ai_next) {
00085 if (!xmms_socket_valid (t->socket[0] = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol))) {
00086 continue;
00087 }
00088 if (connect (t->socket[0], rp->ai_addr, rp->ai_addrlen) != -1) {
00089
00090
00091 xmms_socket_set_nonblock (t->socket[0]);
00092
00093 t->socket[1] = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
00094 connect (t->socket[1], rp->ai_addr, rp->ai_addrlen);
00095 break;
00096 } else {
00097 xmms_socket_close (t->socket[0]);
00098 }
00099 }
00100 if (rp == NULL) {
00101 c->error = strdup("Could not connect!");
00102 return false;
00103 }
00104 xmms_freeaddrinfo (result);
00105
00106 packet[0] = 'H';
00107 *packet_id = htonl (id);
00108 send (t->socket[0], &packet, sizeof (packet), 0);
00109
00110 t->timediff = udp_timediff (id, t->socket[1]);
00111
00112 return true;
00113 }
00114
00115 xmmsc_result_t *
00116 setup_udp_prepare (xmmsc_connection_t *c, int32_t vv)
00117 {
00118 xmmsc_result_t *res;
00119 xmmsc_visualization_t *v;
00120
00121 x_check_conn (c, 0);
00122 v = get_dataset (c, vv);
00123
00124 res = xmmsc_send_cmd (c, XMMS_IPC_OBJECT_VISUALIZATION,
00125 XMMS_IPC_CMD_VISUALIZATION_INIT_UDP,
00126 XMMSV_LIST_ENTRY_INT (v->id),
00127 XMMSV_LIST_END);
00128
00129 if (res) {
00130 xmmsc_result_visc_set (res, v);
00131 }
00132 return res;
00133 }
00134
00135 bool
00136 setup_udp_handle (xmmsc_result_t *res)
00137 {
00138 bool ret;
00139 xmmsc_vis_udp_t *t;
00140 xmmsc_visualization_t *visc;
00141
00142 visc = xmmsc_result_visc_get (res);
00143 if (!visc) {
00144 x_api_error_if (1, "non vis result?", -1);
00145 }
00146
00147 t = &visc->transport.udp;
00148
00149 if (!xmmsc_result_iserror (res)) {
00150 xmmsv_t *val;
00151 int port;
00152 val = xmmsc_result_get_value (res);
00153 xmmsv_get_int (val, &port);
00154 ret = setup_socket (xmmsc_result_get_connection (res), t, visc->id, port);
00155 } else {
00156 ret = false;
00157 }
00158
00159 return ret;
00160 }
00161
00162 void
00163 cleanup_udp (xmmsc_vis_udp_t *t)
00164 {
00165 xmms_socket_close (t->socket[0]);
00166 xmms_socket_close (t->socket[1]);
00167 }
00168
00169
00170 static int
00171 wait_for_socket (xmmsc_vis_udp_t *t, unsigned int blocking)
00172 {
00173 int ret;
00174 fd_set rfds;
00175 struct timeval time;
00176 FD_ZERO (&rfds);
00177 FD_SET (t->socket[0], &rfds);
00178 time.tv_sec = blocking / 1000;
00179 time.tv_usec = (blocking % 1000) * 1000;
00180 ret = select (t->socket[0] + 1, &rfds, NULL, NULL, &time);
00181 return ret;
00182 }
00183
00184 int
00185 read_do_udp (xmmsc_vis_udp_t *t, xmmsc_visualization_t *v, short *buffer, int drawtime, unsigned int blocking)
00186 {
00187 int old;
00188 int ret;
00189 int i, size;
00190 xmmsc_vis_udp_data_t packet_d;
00191 char* packet = packet_init_data (&packet_d);
00192 xmmsc_vischunk_t data;
00193
00194 if (blocking) {
00195 wait_for_socket (t, blocking);
00196 }
00197
00198 ret = recv (t->socket[0], packet, packet_d.size, 0);
00199 if ((ret > 0) && (*packet_d.__unaligned_type == 'V')) {
00200 uint16_t grace;
00201 struct timeval rtv;
00202
00203 XMMSC_VIS_UNALIGNED_READ (data, packet_d.__unaligned_data, xmmsc_vischunk_t);
00204
00205
00206 XMMSC_VIS_UNALIGNED_READ (grace, packet_d.__unaligned_grace, uint16_t);
00207 grace = ntohs (grace);
00208 if (grace < 1000) {
00209 if (t->grace != 0) {
00210 t->grace = 0;
00211
00212 t->timediff = udp_timediff (v->id, t->socket[1]);
00213 }
00214 } else {
00215 t->grace = grace;
00216 }
00217
00218
00219 rtv.tv_sec = ntohl (data.timestamp[0]);
00220 rtv.tv_usec = ntohl (data.timestamp[1]);
00221
00222 double interim = tv2ts (&rtv);
00223 interim -= t->timediff;
00224 ts2net (data.timestamp, interim);
00225 ret = 1;
00226 } else {
00227 if (ret == 1 && *packet_d.__unaligned_type == 'K') {
00228 ret = -1;
00229 } else if (ret > -1 || xmms_socket_error_recoverable ()) {
00230 ret = 0;
00231 } else {
00232 ret = -1;
00233 }
00234 free (packet);
00235 return ret;
00236 }
00237
00238 old = check_drawtime (net2ts (data.timestamp), drawtime);
00239
00240 if (!old) {
00241 size = ntohs (data.size);
00242 for (i = 0; i < size; ++i) {
00243 buffer[i] = (int16_t)ntohs (data.data[i]);
00244 }
00245 }
00246
00247 free (packet);
00248
00249 if (!old) {
00250 return size;
00251 }
00252 return 0;
00253 }