00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017 #include <string.h>
00018 #include <stdio.h>
00019 #include <stdlib.h>
00020
00021 #include "xmms/xmms_object.h"
00022 #include "xmmspriv/xmms_ipc.h"
00023 #include "xmmspriv/xmms_sample.h"
00024
00025 #include "common.h"
00026
00027
00028
00029
00030
00031
00032
00033 static xmms_visualization_t *vis = NULL;
00034
00035 static int32_t xmms_visualization_client_query_version (xmms_visualization_t *vis, xmms_error_t *err);
00036 static int32_t xmms_visualization_client_register (xmms_visualization_t *vis, xmms_error_t *err);
00037 static int32_t xmms_visualization_client_init_shm (xmms_visualization_t *vis, int32_t id, const char *shmid, xmms_error_t *err);
00038 static int32_t xmms_visualization_client_init_udp (xmms_visualization_t *vis, int32_t id, xmms_error_t *err);
00039 static int32_t xmms_visualization_client_set_property (xmms_visualization_t *vis, int32_t id, const gchar *key, const gchar *value, xmms_error_t *err);
00040 static int32_t xmms_visualization_client_set_properties (xmms_visualization_t *vis, int32_t id, xmmsv_t *prop, xmms_error_t *err);
00041 static void xmms_visualization_client_shutdown (xmms_visualization_t *vis, int32_t id, xmms_error_t *err);
00042 static void xmms_visualization_destroy (xmms_object_t *object);
00043
00044 #include "visualization/object_ipc.c"
00045
00046
00047 static int32_t
00048 create_client (void)
00049 {
00050 int32_t id;
00051
00052 for (id = 0; id < vis->clientc; ++id) {
00053 if (!vis->clientv[id]) {
00054 break;
00055 }
00056 }
00057
00058 if (id == vis->clientc) {
00059 vis->clientc++;
00060 }
00061
00062 vis->clientv = g_renew (xmms_vis_client_t*, vis->clientv, vis->clientc);
00063 if (!vis->clientv || (!(vis->clientv[id] = g_new (xmms_vis_client_t, 1)))) {
00064 vis->clientc = 0;
00065 id = -1;
00066 }
00067
00068 xmms_log_info ("Attached visualization client %d", id);
00069 return id;
00070 }
00071
00072 xmms_vis_client_t *
00073 get_client (int32_t id)
00074 {
00075 if (id < 0 || id >= vis->clientc) {
00076 return NULL;
00077 }
00078
00079 return vis->clientv[id];
00080 }
00081
00082
00083 void
00084 delete_client (int32_t id)
00085 {
00086 xmms_vis_client_t *c;
00087
00088 if (id < 0 || id >= vis->clientc) {
00089 return;
00090 }
00091
00092 c = vis->clientv[id];
00093 if (c == NULL) {
00094 return;
00095 }
00096
00097 if (c->type == VIS_UNIXSHM) {
00098 cleanup_shm (&c->transport.shm);
00099 } else if (c->type == VIS_UDP) {
00100 cleanup_udp (&c->transport.udp, vis->socket);
00101 }
00102
00103 g_free (c);
00104 vis->clientv[id] = NULL;
00105
00106 xmms_log_info ("Removed visualization client %d", id);
00107 }
00108
00109
00110
00111
00112 xmms_visualization_t *
00113 xmms_visualization_new (xmms_output_t *output)
00114 {
00115 vis = xmms_object_new (xmms_visualization_t, xmms_visualization_destroy);
00116 vis->clientlock = g_mutex_new ();
00117 vis->clientc = 0;
00118 vis->output = output;
00119
00120 xmms_object_ref (output);
00121
00122 xmms_visualization_register_ipc_commands (XMMS_OBJECT (vis));
00123
00124 xmms_socket_invalidate (&vis->socket);
00125
00126 return vis;
00127 }
00128
00129
00130
00131
00132
00133
00134 static void
00135 xmms_visualization_destroy (xmms_object_t *object)
00136 {
00137 xmms_object_unref (vis->output);
00138
00139
00140 g_mutex_free (vis->clientlock);
00141 xmms_log_debug ("starting cleanup of %d vis clients", vis->clientc);
00142 for (; vis->clientc > 0; --vis->clientc) {
00143 delete_client (vis->clientc - 1);
00144 }
00145
00146 if (xmms_socket_valid (vis->socket)) {
00147
00148 g_io_channel_shutdown (vis->socketio, FALSE, NULL);
00149 xmms_socket_close (vis->socket);
00150 }
00151
00152 xmms_visualization_unregister_ipc_commands ();
00153 }
00154
00155 static int32_t
00156 xmms_visualization_client_query_version (xmms_visualization_t *vis, xmms_error_t *err)
00157 {
00158
00159
00160
00161 return XMMS_VISPACKET_VERSION;
00162 }
00163
00164 static void
00165 properties_init (xmmsc_vis_properties_t *p)
00166 {
00167 p->type = VIS_PCM;
00168 p->stereo = 1;
00169 p->pcm_hardwire = 0;
00170 }
00171
00172 static gboolean
00173 property_set (xmmsc_vis_properties_t *p, const gchar* key, const gchar* data)
00174 {
00175
00176 if (!g_strcasecmp (key, "type")) {
00177 if (!g_strcasecmp (data, "pcm")) {
00178 p->type = VIS_PCM;
00179 } else if (!g_strcasecmp (data, "spectrum")) {
00180 p->type = VIS_SPECTRUM;
00181 } else if (!g_strcasecmp (data, "peak")) {
00182 p->type = VIS_PEAK;
00183 } else {
00184 return FALSE;
00185 }
00186 } else if (!g_strcasecmp (key, "stereo")) {
00187 p->stereo = (atoi (data) > 0);
00188 } else if (!g_strcasecmp (key, "pcm.hardwire")) {
00189 p->pcm_hardwire = (atoi (data) > 0);
00190
00191 } else if (!g_strcasecmp (key, "timeframe")) {
00192 p->timeframe = g_strtod (data, NULL);
00193 if (p->timeframe == 0.0) {
00194 return FALSE;
00195 }
00196 } else {
00197 return FALSE;
00198 }
00199 return TRUE;
00200 }
00201
00202 static int32_t
00203 xmms_visualization_client_register (xmms_visualization_t *vis, xmms_error_t *err)
00204 {
00205 int32_t id;
00206 xmms_vis_client_t *c;
00207
00208 g_mutex_lock (vis->clientlock);
00209 id = create_client ();
00210 if (id < 0) {
00211 xmms_error_set (err, XMMS_ERROR_OOM, "could not allocate dataset");
00212 } else {
00213
00214 c = get_client (id);
00215 c->type = VIS_NONE;
00216 c->format = 0;
00217 properties_init (&c->prop);
00218 }
00219 g_mutex_unlock (vis->clientlock);
00220 return id;
00221 }
00222
00223
00224 static int32_t
00225 xmms_visualization_client_set_property (xmms_visualization_t *vis, int32_t id, const gchar* key, const gchar* value, xmms_error_t *err)
00226 {
00227 xmms_vis_client_t *c;
00228
00229 x_fetch_client (id);
00230
00231 if (!property_set (&c->prop, key, value)) {
00232 xmms_error_set (err, XMMS_ERROR_INVAL, "property could not be set!");
00233 }
00234
00235 x_release_client ();
00236
00237
00238
00239 return (++c->format);
00240 }
00241
00242 static int32_t
00243 xmms_visualization_client_set_properties (xmms_visualization_t *vis, int32_t id, xmmsv_t* prop, xmms_error_t *err)
00244 {
00245 xmms_vis_client_t *c;
00246 xmmsv_dict_iter_t *it;
00247 const gchar *key, *valstr;
00248 xmmsv_t *value;
00249
00250 x_fetch_client (id);
00251
00252 if (!xmmsv_get_type (prop) == XMMSV_TYPE_DICT) {
00253 xmms_error_set (err, XMMS_ERROR_INVAL, "properties must be sent as a dict!");
00254 } else {
00255
00256 xmmsv_get_dict_iter (prop, &it);
00257 while (xmmsv_dict_iter_valid (it)) {
00258 if (!xmmsv_dict_iter_pair (it, &key, &value)) {
00259 xmms_error_set (err, XMMS_ERROR_INVAL, "key-value property pair could not be read!");
00260 } else if (!xmmsv_get_string (value, &valstr)) {
00261 xmms_error_set (err, XMMS_ERROR_INVAL, "property value could not be read!");
00262 } else if (!property_set (&c->prop, key, valstr)) {
00263 xmms_error_set (err, XMMS_ERROR_INVAL, "property could not be set!");
00264 }
00265 xmmsv_dict_iter_next (it);
00266 }
00267
00268 }
00269
00270 x_release_client ();
00271
00272 return (++c->format);
00273 }
00274
00275 static int32_t
00276 xmms_visualization_client_init_shm (xmms_visualization_t *vis, int32_t id, const char *shmidstr, xmms_error_t *err)
00277 {
00278 int shmid;
00279
00280 XMMS_DBG ("Trying to init shm!");
00281
00282 if (sscanf (shmidstr, "%d", &shmid) != 1) {
00283 xmms_error_set (err, XMMS_ERROR_INVAL, "couldn't parse shmid");
00284 return -1;
00285 }
00286 return init_shm (vis, id, shmid, err);
00287 }
00288
00289 static int32_t
00290 xmms_visualization_client_init_udp (xmms_visualization_t *vis, int32_t id, xmms_error_t *err)
00291 {
00292 XMMS_DBG ("Trying to init udp!");
00293 return init_udp (vis, id, err);
00294 }
00295
00296 static void
00297 xmms_visualization_client_shutdown (xmms_visualization_t *vis, int32_t id, xmms_error_t *err)
00298 {
00299 g_mutex_lock (vis->clientlock);
00300 delete_client (id);
00301 g_mutex_unlock (vis->clientlock);
00302 }
00303
00304 static gboolean
00305 package_write (xmms_vis_client_t *c, int32_t id, struct timeval *time, int channels, int size, short *buf)
00306 {
00307 if (c->type == VIS_UNIXSHM) {
00308 return write_shm (&c->transport.shm, c, id, time, channels, size, buf);
00309 } else if (c->type == VIS_UDP) {
00310 return write_udp (&c->transport.udp, c, id, time, channels, size, buf, vis->socket);
00311 }
00312 return FALSE;
00313 }
00314
00315 void
00316 send_data (int channels, int size, short *buf)
00317 {
00318 int i;
00319 struct timeval time;
00320 guint32 latency;
00321
00322 if (!vis) {
00323 return;
00324 }
00325
00326 latency = xmms_output_latency (vis->output);
00327
00328 fft_init ();
00329
00330 gettimeofday (&time, NULL);
00331 time.tv_sec += (latency / 1000);
00332 time.tv_usec += (latency % 1000) * 1000;
00333 if (time.tv_usec > 1000000) {
00334 time.tv_sec++;
00335 time.tv_usec -= 1000000;
00336 }
00337
00338 g_mutex_lock (vis->clientlock);
00339 for (i = 0; i < vis->clientc; ++i) {
00340 if (vis->clientv[i]) {
00341 package_write (vis->clientv[i], i, &time, channels, size, buf);
00342 }
00343 }
00344 g_mutex_unlock (vis->clientlock);
00345 }
00346
00347