hythmbox-2.98/lib/libmediaplayerid/mpid-device.c

No issues found

  1 /*
  2  * Copyright (C) 2009 Jonathan Matthew  <jonathan@d14n.org>
  3  *
  4  * This library is free software; you can redistribute it and/or
  5  * modify it under the terms of the GNU Lesser General Public
  6  * License as published by the Free Software Foundation; either
  7  * version 2 of the License, or (at your option) any later version.
  8  *
  9  * This library is distributed in the hope that it will be useful,
 10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 12  * Lesser General Public License for more details.
 13  *
 14  * You should have received a copy of the GNU Lesser General Public
 15  * License along with this library; if not, write to the
 16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 17  * Boston, MA 02111-1307, USA.
 18  */
 19 
 20 #include <string.h>
 21 
 22 #include <glib.h>
 23 #include <glib-object.h>
 24 #include <gio/gunixmounts.h>
 25 
 26 #include "mediaplayerid.h"
 27 #include "mpid-private.h"
 28 
 29 /**
 30  * SECTION:mediaplayerid
 31  * @short_description: Media player device information library
 32  *
 33  * MPID provides access to device information, such as device and vendor names,
 34  * supported formats, and audio folder locations, for USB mass storage media
 35  * player devices.  It queries the operating system (udev or HAL) and reads
 36  * override files from the device filesystem and provides a simple set of
 37  * properties.
 38  */
 39 
 40 /**
 41  * MPIDDevice:
 42  *
 43  * An #MPIDDevice stores a set of information for a particular attached device,
 44  * identified by either a mount point (e.g. /media/device) or a device node
 45  * (e.g. /dev/sdb).
 46  */
 47 
 48 enum
 49 {
 50 	PROP_0,
 51 	PROP_INPUT_PATH,
 52 	PROP_ERROR,
 53 	PROP_SOURCE,
 54 	PROP_MODEL,
 55 	PROP_VENDOR,
 56 	PROP_FS_UUID,
 57 	PROP_SERIAL,
 58 	PROP_DRIVE_TYPE,
 59 	PROP_REQUIRES_EJECT,
 60 	PROP_ACCESS_PROTOCOLS,
 61 	PROP_OUTPUT_FORMATS,
 62 	PROP_INPUT_FORMATS,
 63 	PROP_PLAYLIST_FORMATS,
 64 	PROP_PLAYLIST_PATH,
 65 	PROP_AUDIO_FOLDERS,
 66 	PROP_FOLDER_DEPTH
 67 };
 68 
 69 static void	mpid_device_class_init (MPIDDeviceClass *klass);
 70 static void	mpid_device_init (MPIDDevice *config);
 71 
 72 G_DEFINE_TYPE (MPIDDevice, mpid_device, G_TYPE_OBJECT)
 73 
 74 
 75 void
 76 mpid_device_debug (MPIDDevice *device, const char *what)
 77 {
 78 	mpid_debug ("device information (%s)\n", what);
 79 	switch (device->source) {
 80 	case MPID_SOURCE_NONE:
 81 		mpid_debug ("no information source\n");
 82 		break;
 83 	case MPID_SOURCE_SYSTEM:
 84 		mpid_debug ("information read from system device database\n");
 85 		break;
 86 	case MPID_SOURCE_OVERRIDE:
 87 		mpid_debug ("information read from device override file\n");
 88 		break;
 89 	}
 90 	mpid_debug_str ("model", device->model);
 91 	mpid_debug_str ("vendor", device->vendor);
 92 	mpid_debug_str ("filesystem uuid", device->fs_uuid);
 93 	mpid_debug_str ("drive type", device->drive_type);
 94 	mpid_debug ("requires eject: %s\n", device->requires_eject ? "true" : "false");
 95 	mpid_debug_strv ("access protocols", device->access_protocols);
 96 	mpid_debug_strv ("output formats", device->output_formats);
 97 	mpid_debug_strv ("input formats", device->input_formats);
 98 	mpid_debug_strv ("playlist formats", device->playlist_formats);
 99 	mpid_debug_str ("playlist path", device->playlist_path);
100 	mpid_debug_strv ("audio folders", device->audio_folders);
101 	mpid_debug ("folder depth: %d\n", device->folder_depth);
102 }
103 
104 char *
105 mpid_device_get_mount_point (MPIDDevice *device)
106 {
107 	char *mount_path = NULL;
108 	GUnixMountEntry *mount;
109 	GList *mounts;
110 	GList *i;
111 
112 	if (device->input_path == NULL) {
113 		mpid_debug ("no input path specified, can't find mount point");
114 		return NULL;
115 	}
116 
117 	mount = g_unix_mount_at (device->input_path, NULL);
118 	if (mount != NULL) {
119 		/* path is the mount point */
120 		g_unix_mount_free (mount);
121 		mpid_debug ("%s is already a mount point\n", device->input_path);
122 		return g_strdup (device->input_path);
123 	}
124 
125 	mounts = g_unix_mounts_get (NULL);
126 	for (i = mounts; i != NULL; i = i->next) {
127 		mount = i->data;
128 
129 		if (g_str_equal (g_unix_mount_get_device_path (mount), device->input_path)) {
130 			mount_path = g_strdup (g_unix_mount_get_mount_path (mount));
131 			mpid_debug ("found mount point %s for device path %s\n", mount_path, device->input_path);
132 		}
133 		g_unix_mount_free (mount);
134 	}
135 	g_list_free (mounts);
136 
137 	if (mount_path == NULL) {
138 		mpid_debug ("unable to find mount point for device path %s\n", device->input_path);
139 	}
140 
141 	return mount_path;
142 }
143 
144 char *
145 mpid_device_get_device_path (MPIDDevice *device)
146 {
147 	GUnixMountEntry *mount;
148 	char *mount_path;
149 	char *device_path = NULL;
150 	GList *mounts;
151 	GList *i;
152 
153 	if (device->input_path == NULL) {
154 		mpid_debug ("no input path specified, can't find device path\n");
155 		return NULL;
156 	}
157 
158 	mount_path = g_strdup (device->input_path);
159 	if (mount_path[strlen (mount_path) - 1] == '/') {
160 		mount_path[strlen (mount_path) - 1] = '\0';
161 	}
162 
163 	mount = g_unix_mount_at (mount_path, NULL);
164 	if (mount != NULL) {
165 		device_path = g_strdup (g_unix_mount_get_device_path (mount));
166 		g_unix_mount_free (mount);
167 		mpid_debug ("found device path %s for mount %s\n", device_path, mount_path);
168 		g_free (mount_path);
169 		return device_path;
170 	}
171 
172 	/* it's not a mount point, so check if it's the path to a mounted device */
173 	mounts = g_unix_mounts_get (NULL);
174 	for (i = mounts; i != NULL; i = i->next) {
175 		mount = i->data;
176 
177 		if (g_str_equal (g_unix_mount_get_device_path (mount), mount_path)) {
178 			device_path = g_strdup (mount_path);
179 			mpid_debug ("%s is already a device path\n", device_path);
180 		}
181 		g_unix_mount_free (mount);
182 	}
183 	g_list_free (mounts);
184 	g_free (mount_path);
185 
186 	if (device_path == NULL) {
187 		mpid_debug ("unable to find device path for mount point %s\n", device->input_path);
188 	}
189 
190 	return device_path;
191 }
192 
193 
194 
195 static void
196 mpid_device_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
197 {
198 	MPIDDevice *device = MPID_DEVICE (object);
199 
200 	switch (prop_id) {
201 	case PROP_INPUT_PATH:
202 		device->input_path = g_value_dup_string (value);
203 		break;
204 	default:
205 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
206 		break;
207 	}
208 }
209 
210 static void
211 mpid_device_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
212 {
213 	MPIDDevice *device = MPID_DEVICE (object);
214 
215 	switch (prop_id) {
216 	case PROP_INPUT_PATH:
217 		g_value_set_string (value, device->input_path);
218 		break;
219 	case PROP_ERROR:
220 		g_value_set_enum (value, device->error);
221 		break;
222 	case PROP_SOURCE:
223 		g_value_set_enum (value, device->source);
224 		break;
225 	case PROP_MODEL:
226 		g_value_set_string (value, device->model);
227 		break;
228 	case PROP_VENDOR:
229 		g_value_set_string (value, device->vendor);
230 		break;
231 	case PROP_FS_UUID:
232 		g_value_set_string (value, device->fs_uuid);
233 		break;
234 	case PROP_SERIAL:
235 		g_value_set_string (value, device->serial);
236 		break;
237 	case PROP_DRIVE_TYPE:
238 		g_value_set_string (value, device->drive_type);
239 		break;
240 	case PROP_REQUIRES_EJECT:
241 		g_value_set_boolean (value, device->requires_eject);
242 		break;
243 	case PROP_ACCESS_PROTOCOLS:
244 		g_value_set_boxed (value, device->access_protocols);
245 		break;
246 	case PROP_OUTPUT_FORMATS:
247 		g_value_set_boxed (value, device->output_formats);
248 		break;
249 	case PROP_INPUT_FORMATS:
250 		g_value_set_boxed (value, device->input_formats);
251 		break;
252 	case PROP_PLAYLIST_FORMATS:
253 		g_value_set_boxed (value, device->playlist_formats);
254 		break;
255 	case PROP_PLAYLIST_PATH:
256 		g_value_set_string (value, device->playlist_path);
257 		break;
258 	case PROP_AUDIO_FOLDERS:
259 		g_value_set_boxed (value, device->audio_folders);
260 		break;
261 	case PROP_FOLDER_DEPTH:
262 		g_value_set_int (value, device->folder_depth);
263 		break;
264 	default:
265 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
266 		break;
267 	}
268 }
269 
270 static void
271 mpid_device_finalize (GObject *object)
272 {
273 	MPIDDevice *device = MPID_DEVICE (object);
274 
275 	g_free (device->model);
276 	g_free (device->vendor);
277 	g_free (device->fs_uuid);
278 	g_free (device->drive_type);
279 
280 	g_strfreev (device->access_protocols);
281 
282 	g_strfreev (device->output_formats);
283 	g_strfreev (device->input_formats);
284 	g_strfreev (device->playlist_formats);
285 
286 	g_free (device->playlist_path);
287 	g_strfreev (device->audio_folders);
288 
289 	G_OBJECT_CLASS (mpid_device_parent_class)->finalize (object);
290 }
291 
292 static void
293 mpid_device_init (MPIDDevice *device)
294 {
295 	device->folder_depth = -1;
296 }
297 
298 static void
299 mpid_device_constructed (GObject *object)
300 {
301 	MPIDDevice *device;
302 
303 	if (G_OBJECT_CLASS (mpid_device_parent_class)->constructed) {
304 		G_OBJECT_CLASS (mpid_device_parent_class)->constructed (object);
305 	}
306 
307 	device = MPID_DEVICE (object);
308 
309 	mpid_device_db_lookup (device);
310 	if (device->source == MPID_SOURCE_SYSTEM) {
311 		mpid_device_debug (device, "system database");
312 	}
313 
314 	mpid_device_read_override_file (device);
315 	if (device->source == MPID_SOURCE_OVERRIDE) {
316 		mpid_device_debug (device, "override file");
317 	}
318 }
319 
320 static void
321 mpid_device_class_init (MPIDDeviceClass *klass)
322 {
323 	GObjectClass *object_class = G_OBJECT_CLASS (klass);
324 
325 	object_class->constructed = mpid_device_constructed;
326 	object_class->finalize = mpid_device_finalize;
327 	object_class->get_property = mpid_device_get_property;
328 	object_class->set_property = mpid_device_set_property;
329 
330 	/* install properties */
331 	/**
332 	 * MPIDDevice:input-path:
333 	 *
334 	 * Either the device node path or the mount point path for the device.
335 	 */
336 	g_object_class_install_property (object_class,
337 					 PROP_INPUT_PATH,
338 					 g_param_spec_string ("input-path",
339 							      "input path",
340 							      "Input path (either a device path or a mount point)",
341 							      NULL,
342 							      G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
343 	/**
344 	 * MPIDDevice:error:
345 	 *
346 	 * MPID error code resulting from device detection (see #MPIDError)
347 	 */
348 	g_object_class_install_property (object_class,
349 					 PROP_ERROR,
350 					 g_param_spec_enum ("error",
351 						 	    "error",
352 							    "error code",
353 							    MPID_TYPE_ERROR,
354 							    MPID_ERROR_NONE,
355 							    G_PARAM_READABLE));
356 	/**
357 	 * MPIDDevice:source:
358 	 *
359 	 * The information source used to provide device information (see #MPIDSource)
360 	 */
361 	g_object_class_install_property (object_class,
362 					 PROP_SOURCE,
363 					 g_param_spec_enum ("source",
364 						 	    "information source",
365 							    "information source",
366 							    MPID_TYPE_SOURCE,
367 							    MPID_SOURCE_NONE,
368 							    G_PARAM_READABLE));
369 	/**
370 	 * MPIDDevice:model:
371 	 *
372 	 * The device model name
373 	 */
374 	g_object_class_install_property (object_class,
375 					 PROP_MODEL,
376 					 g_param_spec_string ("model",
377 							      "device model",
378 							      "device model name",
379 							      NULL,
380 							      G_PARAM_READABLE));
381 	/**
382 	 * MPIDDevice:vendor:
383 	 *
384 	 * The device vendor name
385 	 */
386 	g_object_class_install_property (object_class,
387 					 PROP_VENDOR,
388 					 g_param_spec_string ("vendor",
389 							      "device vendor",
390 							      "device vendor name",
391 							      NULL,
392 							      G_PARAM_READABLE));
393 	/**
394 	 * MPIDDevice:fs-uuid:
395 	 *
396 	 * The device filesystem UUID
397 	 */
398 	g_object_class_install_property (object_class,
399 					 PROP_FS_UUID,
400 					 g_param_spec_string ("fs-uuid",
401 							      "device filesystem UUID",
402 							      "device filesystem UUID",
403 							      NULL,
404 							      G_PARAM_READABLE));
405 	/**
406 	 * MPIDDevice:serial:
407 	 *
408 	 * The device serial ID
409 	 */
410 	g_object_class_install_property (object_class,
411 					 PROP_SERIAL,
412 					 g_param_spec_string ("serial",
413 							      "device serial ID",
414 							      "device serial ID",
415 							      NULL,
416 							      G_PARAM_READABLE));
417 	/**
418 	 * MPIDDevice:drive-type:
419 	 *
420 	 * The device drive type
421 	 */
422 	g_object_class_install_property (object_class,
423 					 PROP_DRIVE_TYPE,
424 					 g_param_spec_string ("drive-type",
425 							      "drive type",
426 							      "drive type",
427 							      NULL,
428 							      G_PARAM_READABLE));
429 	/**
430 	 * MPIDDevice:requires-eject:
431 	 *
432 	 * If %TRUE, the device must be ejected rather than unmounted
433 	 */
434 	g_object_class_install_property (object_class,
435 					 PROP_REQUIRES_EJECT,
436 					 g_param_spec_boolean ("requires-eject",
437 							       "requires eject",
438 							       "flag indicating whether the device requires ejection",
439 							       FALSE,
440 							       G_PARAM_READABLE));
441 	/**
442 	 * MPIDDevice:access-protocols:
443 	 *
444 	 * Names of access protocols that can be used to access the device contents
445 	 */
446 	g_object_class_install_property (object_class,
447 					 PROP_ACCESS_PROTOCOLS,
448 					 g_param_spec_boxed ("access-protocols",
449 							     "access protocols",
450 							     "names of protocols supported by the device",
451 							     G_TYPE_STRV,
452 							     G_PARAM_READABLE));
453 	/**
454 	 * MPIDDevice:output-formats:
455 	 *
456 	 * A set of MIME types that the device can play
457 	 */
458 	g_object_class_install_property (object_class,
459 					 PROP_OUTPUT_FORMATS,
460 					 g_param_spec_boxed ("output-formats",
461 							     "output formats",
462 							     "MIME types playable by the device",
463 							     G_TYPE_STRV,
464 							     G_PARAM_READABLE));
465 	/**
466 	 * MPIDDevice:input-formats:
467 	 *
468 	 * A set of MIME types that the device can record
469 	 */
470 	g_object_class_install_property (object_class,
471 					 PROP_INPUT_FORMATS,
472 					 g_param_spec_boxed ("input-formats",
473 							     "input formats",
474 							     "MIME types recorded by the device",
475 							     G_TYPE_STRV,
476 							     G_PARAM_READABLE));
477 	/**
478 	 * MPIDDevice:playlist-formats:
479 	 *
480 	 * A set of playlist format MIME types suppored by the device
481 	 */
482 	g_object_class_install_property (object_class,
483 					 PROP_PLAYLIST_FORMATS,
484 					 g_param_spec_boxed ("playlist-formats",
485 							     "playlist formats",
486 							     "playlist MIME supported by the device",
487 							     G_TYPE_STRV,
488 							     G_PARAM_READABLE));
489 	/**
490 	 * MPIDDevice:playlist-path:
491 	 *
492 	 * Path to playlist files on the device.  May include '%File' to indicate a directory
493 	 * containing any number of playlist files.
494 	 */
495 	g_object_class_install_property (object_class,
496 					 PROP_PLAYLIST_PATH,
497 					 g_param_spec_string ("playlist-path",
498 							      "playlist path",
499 							      "playlist path",
500 							      NULL,
501 							      G_PARAM_READABLE));
502 	/**
503 	 * MPIDDevice:audio-folders:
504 	 *
505 	 * A set of folders (relative to the root of the device) containing audio
506 	 * folders.
507 	 */
508 	g_object_class_install_property (object_class,
509 					 PROP_AUDIO_FOLDERS,
510 					 g_param_spec_boxed ("audio-folders",
511 							     "audio folders",
512 							     "names of folders in which audio files are stored on the device",
513 							     G_TYPE_STRV,
514 							     G_PARAM_READABLE));
515 	/**
516 	 * MPIDDevice:folder-depth:
517 	 *
518 	 * The folder nesting level supported by the device.  -1 indicates there is no limit.
519 	 */
520 	g_object_class_install_property (object_class,
521 					 PROP_FOLDER_DEPTH,
522 					 g_param_spec_int ("folder-depth",
523 						 	   "folder depth",
524 							   "number of levels of folder nesting supported by the device",
525 							   -1, G_MAXINT, -1,
526 							   G_PARAM_READABLE));
527 }
528 
529 /**
530  * mpid_device_new:
531  * @path: the input path (either device node path or mount point)
532  *
533  * Creates a new #MPIDDevice and reads device information for the specified
534  * device node path or mount point path.
535  *
536  * Return value: new #MPIDDevice instance
537  */
538 MPIDDevice *
539 mpid_device_new (const char *path)
540 {
541 	return g_object_new (MPID_TYPE_DEVICE, "input-path", path, NULL);
542 }