static void
write_album_to_device (RBMtpThread *thread, LIBMTP_album_t *album, gboolean new_album)
{
	if (new_album) {
		if (LIBMTP_Create_New_Album (thread->device, album) != 0) {
			LIBMTP_destroy_album_t (album);
			rb_debug ("LIBMTP_Create_New_Album failed..");
			rb_mtp_thread_report_errors (thread, FALSE);
		}
	} else {
		if (LIBMTP_Update_Album (thread->device, album) != 0) {
			rb_debug ("LIBMTP_Update_Album failed..");
			rb_mtp_thread_report_errors (thread, FALSE);
		}
	}
}
/* this callback runs on the device handling thread, so it can call libmtp directly */
static void
mtp_device_open_cb (LIBMTP_mtpdevice_t *device, RBMtpSource *source)
{
	RBMtpSourcePrivate *priv = MTP_SOURCE_GET_PRIVATE (source);
	DeviceOpenedData *data;

	if (device == NULL) {
		/* can't delete the source on this thread, so move it to the main thread */
		g_idle_add ((GSourceFunc) device_open_failed_idle, g_object_ref (source));
		return;
	}

	/* set the source name to match the device, ignoring some
	 * particular broken device names.
	 */
	data = g_new0 (DeviceOpenedData, 1);
	data->source = g_object_ref (source);
	data->name = LIBMTP_Get_Friendlyname (device);
	if (data->name == NULL || strcmp (data->name, "?????") == 0) {
		g_free (data->name);
		data->name = LIBMTP_Get_Modelname (device);
	}
	if (data->name == NULL) {
		data->name = g_strdup (_("Digital Audio Player"));
	}

	/* get some other device information that doesn't change */
	priv->manufacturer = LIBMTP_Get_Manufacturername (device);
	priv->device_version = LIBMTP_Get_Deviceversion (device);
	priv->model_name = LIBMTP_Get_Modelname (device);
	priv->serial = LIBMTP_Get_Serialnumber (device);

	/* calculate the device capacity */
	priv->capacity = 0;
	if (LIBMTP_Get_Storage (device, LIBMTP_STORAGE_SORTBY_NOTSORTED) == 0) {
		LIBMTP_devicestorage_t *storage;
		for (storage = device->storage;
		     storage != NULL;
		     storage = storage->next) {
			priv->capacity += storage->MaxCapacity;
		}
	}

	update_free_space_cb (device, RB_MTP_SOURCE (source));

	/* figure out the set of formats supported by the device */
	if (LIBMTP_Get_Supported_Filetypes (device, &data->types, &data->num_types) != 0) {
		rb_mtp_thread_report_errors (priv->device_thread, FALSE);
	}

	g_idle_add ((GSourceFunc) device_opened_idle, data);

	/* now get the track list */
	rb_mtp_thread_get_track_list (priv->device_thread, (RBMtpTrackListCallback) mtp_tracklist_cb, g_object_ref (source), g_object_unref);
}
static void
remove_track_from_album (RBMtpThread *thread, RBMtpThreadTask *task)
{
	LIBMTP_album_t *album;
	int i;

	album = g_hash_table_lookup (thread->albums, task->album);
	if (album == NULL) {
		rb_debug ("Couldn't find an album for %s", task->album);
		return;
	}

	for (i = 0; i < album->no_tracks; i++) {
		if (album->tracks[i] == task->track_id) {
			break;
		}
	}

	if (i == album->no_tracks) {
		rb_debug ("Couldn't find track %d in album %d", task->track_id, album->album_id);
		return;
	}

	memmove (album->tracks + i, album->tracks + i + 1, album->no_tracks - (i+1));
	album->no_tracks--;

	if (album->no_tracks == 0) {
		rb_debug ("deleting empty album %d", album->album_id);
		if (LIBMTP_Delete_Object (thread->device, album->album_id) != 0) {
			rb_mtp_thread_report_errors (thread, FALSE);
		}
		g_hash_table_remove (thread->albums, task->album);
	} else {
		rb_debug ("updating album %d: %d tracks remaining", album->album_id, album->no_tracks);
		if (LIBMTP_Update_Album (thread->device, album) != 0) {
			rb_mtp_thread_report_errors (thread, FALSE);
		}
	}
}
Exemple #4
0
static void
update_free_space_cb (LIBMTP_mtpdevice_t *device, RBMtpSource *source)
{
	RBMtpSourcePrivate *priv = MTP_SOURCE_GET_PRIVATE (source);
	LIBMTP_devicestorage_t *storage;
	int ret;

	ret = LIBMTP_Get_Storage (device, LIBMTP_STORAGE_SORTBY_NOTSORTED);
	if (ret != 0) {
		rb_mtp_thread_report_errors (priv->device_thread, FALSE);
	}

	/* probably need a lock for this.. */
	priv->free_space = 0;
	for (storage = device->storage; storage != NULL; storage = storage->next) {
		priv->free_space += storage->FreeSpaceInBytes;
	}
}
static void
set_album_image (RBMtpThread *thread, RBMtpThreadTask *task)
{
	LIBMTP_filesampledata_t *albumart;
	LIBMTP_album_t *album;
	GError *error = NULL;
	char *image_data;
	gsize image_size;
	int ret;
	
	album = g_hash_table_lookup (thread->albums, task->album);
	if (album == NULL) {
		rb_debug ("Couldn't find an album for %s", task->album);
		return;
	}
	
	/* probably should scale the image down, since some devices have a size limit and they all have
	 * tiny displays anyway.
	 */

	if (gdk_pixbuf_save_to_buffer (task->image, &image_data, &image_size, "jpeg", &error, NULL) == FALSE) {
		rb_debug ("unable to convert album art image to a JPEG buffer: %s", error->message);
		g_error_free (error);
		return;
	}

	albumart = LIBMTP_new_filesampledata_t ();
	albumart->filetype = LIBMTP_FILETYPE_JPEG;
	albumart->data = image_data;
	albumart->size = image_size;

	ret = LIBMTP_Send_Representative_Sample (thread->device, album->album_id, albumart);
	if (ret != 0) {
		rb_mtp_thread_report_errors (thread, TRUE);
	} else {
		rb_debug ("successfully set album art for %s (%" G_GSIZE_FORMAT " bytes)", task->album, image_size);
	}

	/* libmtp will try to free this if we don't clear the pointer */
	albumart->data = NULL;
	LIBMTP_destroy_filesampledata_t (albumart);
}
Exemple #6
0
/* this callback runs on the device handling thread, so it can call libmtp directly */
static void
mtp_device_open_cb (LIBMTP_mtpdevice_t *device, RBMtpSource *source)
{
	RBMtpSourcePrivate *priv = MTP_SOURCE_GET_PRIVATE (source);
	gboolean has_audio = FALSE;
	DeviceOpenedData *data;

	if (device == NULL) {
		/* can't delete the source on this thread, so move it to the main thread */
		g_idle_add ((GSourceFunc) device_open_failed_idle, g_object_ref (source));
		return;
	}

	/* set the source name to match the device, ignoring some
	 * particular broken device names.
	 */
	data = g_new0 (DeviceOpenedData, 1);
	data->source = g_object_ref (source);
	data->name = LIBMTP_Get_Friendlyname (device);
	if (data->name == NULL || strcmp (data->name, "?????") == 0) {
		g_free (data->name);
		data->name = LIBMTP_Get_Modelname (device);
	}
	if (data->name == NULL) {
		data->name = g_strdup (_("Digital Audio Player"));
	}

	/* get some other device information that doesn't change */
	priv->manufacturer = LIBMTP_Get_Manufacturername (device);
	priv->device_version = LIBMTP_Get_Deviceversion (device);
	priv->model_name = LIBMTP_Get_Modelname (device);
	priv->serial = LIBMTP_Get_Serialnumber (device);

	/* calculate the device capacity */
	priv->capacity = 0;
	if (LIBMTP_Get_Storage (device, LIBMTP_STORAGE_SORTBY_NOTSORTED) == 0) {
		LIBMTP_devicestorage_t *storage;
		for (storage = device->storage;
		     storage != NULL;
		     storage = storage->next) {
			priv->capacity += storage->MaxCapacity;
		}
	}

	update_free_space_cb (device, RB_MTP_SOURCE (source));

	/* figure out the set of formats supported by the device, ensuring there's at least
	 * one audio format aside from WAV.  the purpose of this is to exclude cameras and other
	 * MTP devices that aren't interesting to us.
	 */
	if (LIBMTP_Get_Supported_Filetypes (device, &data->types, &data->num_types) != 0) {
		rb_mtp_thread_report_errors (priv->device_thread, FALSE);
	} else {
		int i;
		for (i = 0; i < data->num_types; i++) {
			if (data->types[i] != LIBMTP_FILETYPE_WAV && LIBMTP_FILETYPE_IS_AUDIO (data->types[i])) {
				has_audio = TRUE;
				break;
			}
		}
	}

	if (has_audio == FALSE) {
		rb_debug ("device doesn't support any audio formats");
		g_idle_add ((GSourceFunc) device_open_ignore_idle, data);
		return;
	}

	g_idle_add ((GSourceFunc) device_opened_idle, data);

	/* now get the track list */
	rb_mtp_thread_get_track_list (priv->device_thread, (RBMtpTrackListCallback) mtp_tracklist_cb, g_object_ref (source), g_object_unref);
}
static gboolean 
run_task (RBMtpThread *thread, RBMtpThreadTask *task)
{
	char *name = task_name (task);
	rb_debug ("running task: %s", name);
	g_free (name);

	switch (task->task) {
	case OPEN_DEVICE:
		open_device (thread, task);
		break;

	case CLOSE_DEVICE:
		return TRUE;

	case SET_DEVICE_NAME:
		if (LIBMTP_Set_Friendlyname (thread->device, task->name)) {
			rb_mtp_thread_report_errors (thread, TRUE);
		}
		break;

	case THREAD_CALLBACK:
		{
			RBMtpThreadCallback cb = (RBMtpThreadCallback)task->callback;
			cb (thread->device, task->user_data);
		}
		break;

	case ADD_TO_ALBUM:
		add_track_to_album_and_update (thread, task);
		break;

	case REMOVE_FROM_ALBUM:
		remove_track_from_album (thread, task);
		break;

	case SET_ALBUM_IMAGE:
		set_album_image (thread, task);
		break;

	case GET_TRACK_LIST:
		get_track_list (thread, task);
		break;

	case DELETE_TRACK:
		if (LIBMTP_Delete_Object (thread->device, task->track_id)) {
			rb_mtp_thread_report_errors (thread, TRUE);
		}
		break;

	case UPLOAD_TRACK:
		upload_track (thread, task);
		break;

	case DOWNLOAD_TRACK:
		download_track (thread, task);
		break;

	default:
		g_assert_not_reached ();
	}

	return FALSE;
}
static void
get_track_list (RBMtpThread *thread, RBMtpThreadTask *task)
{
	RBMtpTrackListCallback cb = task->callback;
	gboolean device_forgets_albums = TRUE;
	GHashTable *update_albums = NULL;
	LIBMTP_track_t *tracks = NULL;
	LIBMTP_album_t *albums;
	LIBMTP_album_t *album;

	/* get all the albums */
	albums = LIBMTP_Get_Album_List (thread->device);
	rb_mtp_thread_report_errors (thread, FALSE);
	if (albums != NULL) {
		LIBMTP_album_t *album;

		for (album = albums; album != NULL; album = album->next) {
			if (album->name == NULL)
				continue;

			rb_debug ("album: %s, %d tracks", album->name, album->no_tracks);
			g_hash_table_insert (thread->albums, album->name, album);
			if (album->no_tracks != 0) {
				device_forgets_albums = FALSE;
			}
		}

		if (device_forgets_albums) {
			rb_debug ("stupid mtp device detected.  will rebuild all albums.");
		}
	} else {
		rb_debug ("No albums");
		device_forgets_albums = FALSE;
	}

	tracks = LIBMTP_Get_Tracklisting_With_Callback (thread->device, NULL, NULL);
	rb_mtp_thread_report_errors (thread, FALSE);
	if (tracks == NULL) {
		rb_debug ("no tracks on the device");
	} else if (device_forgets_albums) {
		LIBMTP_track_t *track;
	       
		rb_debug ("rebuilding albums");
		update_albums = g_hash_table_new (g_direct_hash, g_direct_equal);
		for (track = tracks; track != NULL; track = track->next) {
			if (track->album != NULL) {
				gboolean new_album = FALSE;
				album = add_track_to_album (thread, track->album, track->item_id, track->storage_id, &new_album);
				g_hash_table_insert (update_albums, album, GINT_TO_POINTER (new_album));
			}
		}
		rb_debug ("finished rebuilding albums");
	}

	cb (tracks, task->user_data);
	/* the callback owns the tracklist */

	if (device_forgets_albums) {
		GHashTableIter iter;
		gpointer album_ptr;
		gpointer new_album_ptr;

		rb_debug ("writing rebuilt albums back to the device");
		g_hash_table_iter_init (&iter, update_albums);
		while (g_hash_table_iter_next (&iter, &album_ptr, &new_album_ptr)) {
			album = album_ptr;
			rb_debug ("writing album \"%s\"", album->name);
			write_album_to_device (thread, album, GPOINTER_TO_INT (new_album_ptr));
		}
		g_hash_table_destroy (update_albums);

		rb_debug ("removing remaining empty albums");
		g_hash_table_iter_init (&iter, thread->albums);
		while (g_hash_table_iter_next (&iter, NULL, &album_ptr)) {
			int ret;

			album = album_ptr;
			if (album->no_tracks == 0) {
				rb_debug ("pruning empty album \"%s\"", album->name); 
				ret = LIBMTP_Delete_Object (thread->device, album->album_id);
				if (ret != 0) {
					rb_mtp_thread_report_errors (thread, FALSE);
				}
				g_hash_table_iter_remove (&iter);
			}
		}

		rb_debug ("finished updating albums on the device");
	}
}