static LIBMTP_track_t * transfer_track (RBMtpSource *source, LIBMTP_mtpdevice_t *device, RhythmDBEntry *entry, const char *filename, guint64 filesize, const char *mimetype) { LIBMTP_track_t *trackmeta = LIBMTP_new_track_t (); GDate d; int ret; trackmeta->title = rhythmdb_entry_dup_string (entry, RHYTHMDB_PROP_TITLE); trackmeta->album = rhythmdb_entry_dup_string (entry, RHYTHMDB_PROP_ALBUM); trackmeta->artist = rhythmdb_entry_dup_string (entry, RHYTHMDB_PROP_ARTIST); trackmeta->genre = rhythmdb_entry_dup_string (entry, RHYTHMDB_PROP_GENRE); trackmeta->filename = g_path_get_basename (filename); if (rhythmdb_entry_get_ulong (entry, RHYTHMDB_PROP_DATE) > 0) { /* Entries without a date returns 0, g_date_set_julian don't accept that */ g_date_set_julian (&d, rhythmdb_entry_get_ulong (entry, RHYTHMDB_PROP_DATE)); trackmeta->date = gdate_to_char (&d); } trackmeta->tracknumber = rhythmdb_entry_get_ulong (entry, RHYTHMDB_PROP_TRACK_NUMBER); trackmeta->duration = rhythmdb_entry_get_ulong (entry, RHYTHMDB_PROP_DURATION) * 1000; trackmeta->rating = rhythmdb_entry_get_double (entry, RHYTHMDB_PROP_RATING) * 20; trackmeta->usecount = rhythmdb_entry_get_ulong (entry, RHYTHMDB_PROP_PLAY_COUNT); trackmeta->filesize = filesize; if (mimetype == NULL) { mimetype = rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_MIMETYPE); } trackmeta->filetype = mimetype_to_filetype (source, mimetype); rb_debug ("using libmtp filetype %d (%s) for source media type %s", trackmeta->filetype, LIBMTP_Get_Filetype_Description (trackmeta->filetype), mimetype); #ifdef HAVE_LIBMTP_030 ret = LIBMTP_Send_Track_From_File (device, filename, trackmeta, NULL, NULL); #else ret = LIBMTP_Send_Track_From_File (device, filename, trackmeta, NULL, NULL, 0); #endif rb_debug ("LIBMTP_Send_Track_From_File (%s) returned %d", filename, ret); if (ret != 0) { report_libmtp_errors (device, TRUE); LIBMTP_destroy_track_t (trackmeta); return NULL; } if (strcmp (trackmeta->album, _("Unknown")) != 0) { add_track_to_album (source, trackmeta->album, trackmeta); } return trackmeta; }
bool MtpDevice::GetSupportedFiletypes(QList<Song::FileType>* ret, LIBMTP_mtpdevice_t* device) { uint16_t* list = nullptr; uint16_t length = 0; if (LIBMTP_Get_Supported_Filetypes(device, &list, &length) || !list || !length) return false; for (int i = 0; i < length; ++i) { switch (LIBMTP_filetype_t(list[i])) { case LIBMTP_FILETYPE_WAV: *ret << Song::Type_Wav; break; case LIBMTP_FILETYPE_MP2: case LIBMTP_FILETYPE_MP3: *ret << Song::Type_Mpeg; break; case LIBMTP_FILETYPE_WMA: *ret << Song::Type_Asf; break; case LIBMTP_FILETYPE_MP4: case LIBMTP_FILETYPE_M4A: case LIBMTP_FILETYPE_AAC: *ret << Song::Type_Mp4; break; case LIBMTP_FILETYPE_FLAC: *ret << Song::Type_Flac; *ret << Song::Type_OggFlac; break; case LIBMTP_FILETYPE_OGG: *ret << Song::Type_OggVorbis; *ret << Song::Type_OggSpeex; *ret << Song::Type_OggFlac; break; default: qLog(Error) << "Unknown MTP file format" << LIBMTP_Get_Filetype_Description( LIBMTP_filetype_t(list[i])); break; } } free(list); return true; }
static char * impl_build_dest_uri (RBRemovableMediaSource *source, RhythmDBEntry *entry, const char *mimetype, const char *extension) { gulong id; char *uri; LIBMTP_filetype_t filetype; if (mimetype == NULL) { mimetype = rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_MIMETYPE); } filetype = mimetype_to_filetype (RB_MTP_SOURCE (source), mimetype); rb_debug ("using libmtp filetype %d (%s) for source media type %s", filetype, LIBMTP_Get_Filetype_Description (filetype), mimetype); /* the prepare-sink callback needs the entry ID to set up the * upload data, and we want to use the supplied extension for * the filename on the device. * * this is pretty ugly - it'd be much nicer to have a source-defined * structure that got passed around (or was accessible from) the various * hooks and methods called during the track transfer process. probably * something to address in my horribly stalled track transfer rewrite.. * * the structure would either be created when queuing the track for transfer, * or here; passed to any prepare-source or prepare-sink callbacks for the * encoder; and then passed to whatever gets called when the transfer is complete. */ id = rhythmdb_entry_get_ulong (entry, RHYTHMDB_PROP_ENTRY_ID); if (extension == NULL) { extension = ""; } uri = g_strdup_printf ("xrbmtp://%lu/%s/%d", id, extension, filetype); return uri; }
static void dump_fileinfo(LIBMTP_file_t *file) { printf("File ID: %u\n", file->item_id); if (file->filename != NULL) printf(" Filename: %s\n", file->filename); // This is sort of special... if (file->filesize == (uint32_t) -1) { printf(" None. (abstract file, size = -1)\n"); } else { #ifdef __WIN32__ printf(" File size %llu (0x%016I64X) bytes\n", file->filesize, file->filesize); #else printf(" File size %llu (0x%016llX) bytes\n", (long long unsigned int) file->filesize, (long long unsigned int) file->filesize); #endif } printf(" Parent ID: %u\n", file->parent_id); printf(" Storage ID: 0x%08X\n", file->storage_id); printf(" Filetype: %s\n", LIBMTP_Get_Filetype_Description(file->filetype)); }
int sendtrack_function(char * from_path, char * to_path, char *partist, char *palbumartist, char *ptitle, char *pgenre, char *palbum, char *pcomposer, uint16_t tracknum, uint16_t length, uint16_t year, uint32_t storageid, uint16_t quiet) { char *filename, *parent; char artist[80], albumartist[80], title[80], genre[80], album[80], composer[80]; char num[80]; uint64_t filesize; uint32_t parent_id = 0; struct stat sb; LIBMTP_track_t *trackmeta; LIBMTP_album_t *albuminfo; int ret; printf("Sending track %s to %s\n", from_path, to_path); trackmeta = LIBMTP_new_track_t(); albuminfo = LIBMTP_new_album_t(); parent = dirname(strdup(to_path)); filename = basename(strdup(to_path)); parent_id = parse_path (parent,files,folders); if (parent_id == -1) { printf("Parent folder could not be found, skipping\n"); return 1; } if (stat(from_path, &sb) == -1) { fprintf(stderr, "%s: ", from_path); perror("stat"); return 1; } if (!S_ISREG(sb.st_mode)) return 0; filesize = sb.st_size; trackmeta->filetype = find_filetype (from_path); if (!LIBMTP_FILETYPE_IS_TRACK(trackmeta->filetype)) { printf("Not a valid track codec: \"%s\"\n", LIBMTP_Get_Filetype_Description(trackmeta->filetype)); return 1; } if ((ptitle == NULL) && (quiet == 0)) { if ( (ptitle = prompt("Title", title, 80, 0)) != NULL ) if (!strlen(ptitle)) ptitle = NULL; } if ((palbum == NULL) && (quiet == 0)) { if ( (palbum = prompt("Album", album, 80, 0)) != NULL ) if (!strlen(palbum)) palbum = NULL; } if ((palbumartist == NULL) && (quiet == 0)) { if ( (palbumartist = prompt("Album artist", albumartist, 80, 0)) != NULL ) if (!strlen(palbumartist)) palbumartist = NULL; } if ((partist == NULL) && (quiet == 0)) { if ( (partist = prompt("Artist", artist, 80, 0)) != NULL ) if (!strlen(partist)) partist = NULL; } if ((pcomposer == NULL) && (quiet == 0)) { if ( (pcomposer = prompt("Writer or Composer", composer, 80, 0)) != NULL ) if (!strlen(pcomposer)) pcomposer = NULL; } if ((pgenre == NULL) && (quiet == 0)) { if ( (pgenre = prompt("Genre", genre, 80, 0)) != NULL ) if (!strlen(pgenre)) pgenre = NULL; } if ((tracknum == 0) && (quiet == 0)) { char *pnum; if ( (pnum = prompt("Track number", num, 80, 0)) == NULL ) tracknum = 0; else tracknum = strtoul(pnum, 0, 10); } if ((year == 0) && (quiet == 0)) { char *pnum; if ( (pnum = prompt("Year", num, 80, 0)) == NULL ) year = 0; else year = strtoul(pnum, 0, 10); } if ((length == 0) && (quiet == 0)) { char *pnum; if ( (pnum = prompt("Length", num, 80, 0)) == NULL ) length = 0; else length = strtoul(pnum, 0, 10); } printf("Sending track:\n"); printf("Codec: %s\n", LIBMTP_Get_Filetype_Description(trackmeta->filetype)); if (ptitle) { printf("Title: %s\n", ptitle); trackmeta->title = strdup(ptitle); } if (palbum) { printf("Album: %s\n", palbum); trackmeta->album = strdup(palbum); albuminfo->name = strdup(palbum); } if (palbumartist) { printf("Album artist: %s\n", palbumartist); albuminfo->artist = strdup(palbumartist); } if (partist) { printf("Artist: %s\n", partist); trackmeta->artist = strdup(partist); if (palbumartist == NULL) albuminfo->artist = strdup(partist); } if (pcomposer) { printf("Writer or Composer: %s\n", pcomposer); trackmeta->composer = strdup(pcomposer); albuminfo->composer = strdup(pcomposer); } if (pgenre) { printf("Genre: %s\n", pgenre); trackmeta->genre = strdup(pgenre); albuminfo->genre = strdup(pgenre); } if (year > 0) { char tmp[80]; printf("Year: %d\n", year); snprintf(tmp, sizeof(tmp)-1, "%4d0101T0000.0", year); tmp[sizeof(tmp)-1] = '\0'; trackmeta->date = strdup(tmp); } if (tracknum > 0) { printf("Track no: %d\n", tracknum); trackmeta->tracknumber = tracknum; } if (length > 0) { printf("Length: %d\n", length); // Multiply by 1000 since this is in milliseconds trackmeta->duration = length * 1000; } // We should always have this if (filename != NULL) { trackmeta->filename = strdup(filename); } trackmeta->filesize = filesize; trackmeta->parent_id = parent_id; { int rc; char *desc = NULL; LIBMTP_devicestorage_t *pds = NULL; if (0 != (rc=LIBMTP_Get_Storage(device, LIBMTP_STORAGE_SORTBY_NOTSORTED))) { perror("LIBMTP_Get_Storage()"); exit(-1); } for (pds = device->storage; pds != NULL; pds = pds->next) { if (pds->id == storageid) { desc = strdup(pds->StorageDescription); break; } } if (NULL != desc) { printf("Storage ID: %s (%u)\n", desc, storageid); free(desc); } else printf("Storage ID: %u\n", storageid); trackmeta->storage_id = storageid; } printf("Sending track...\n"); ret = LIBMTP_Send_Track_From_File(device, from_path, trackmeta, progress, NULL); printf("\n"); if (ret != 0) { printf("Error sending track.\n"); LIBMTP_Dump_Errorstack(device); LIBMTP_Clear_Errorstack(device); ret = 1; } else { printf("New track ID: %d\n", trackmeta->item_id); } /* Add here add to album call */ if (palbum) ret = add_track_to_album(albuminfo, trackmeta); LIBMTP_destroy_album_t(albuminfo); LIBMTP_destroy_track_t(trackmeta); return ret; }
static gboolean device_opened_idle (DeviceOpenedData *data) { RBMtpSourcePrivate *priv = MTP_SOURCE_GET_PRIVATE (data->source); int i; gboolean has_mp3 = FALSE; if (data->name != NULL) { g_object_set (data->source, "name", data->name, NULL); } /* when the source name changes after this, try to update the device name */ g_signal_connect (G_OBJECT (data->source), "notify::name", (GCallback)rb_mtp_source_name_changed_cb, NULL); rb_media_player_source_load (RB_MEDIA_PLAYER_SOURCE (data->source)); for (i = 0; i < data->num_types; i++) { const char *mediatype; if (i <= LIBMTP_FILETYPE_UNKNOWN) { priv->supported_types[data->types[i]] = 1; } /* this has to work with the remapping done in * rb-removable-media-source.c:impl_paste. */ switch (data->types[i]) { case LIBMTP_FILETYPE_WAV: mediatype = "audio/x-wav"; break; case LIBMTP_FILETYPE_MP3: /* special handling for mp3: always put it at the front of the list * if it's supported. */ has_mp3 = TRUE; mediatype = NULL; break; case LIBMTP_FILETYPE_WMA: mediatype = "audio/x-ms-wma"; break; case LIBMTP_FILETYPE_OGG: mediatype = "application/ogg"; break; case LIBMTP_FILETYPE_MP4: case LIBMTP_FILETYPE_M4A: case LIBMTP_FILETYPE_AAC: mediatype = "audio/aac"; break; case LIBMTP_FILETYPE_WMV: mediatype = "audio/x-ms-wmv"; break; case LIBMTP_FILETYPE_ASF: mediatype = "video/x-ms-asf"; break; case LIBMTP_FILETYPE_FLAC: mediatype = "audio/flac"; break; case LIBMTP_FILETYPE_JPEG: rb_debug ("JPEG (album art) supported"); mediatype = NULL; priv->album_art_supported = TRUE; break; default: rb_debug ("unknown libmtp filetype %s supported", LIBMTP_Get_Filetype_Description (data->types[i])); mediatype = NULL; break; } if (mediatype != NULL) { rb_debug ("media type %s supported", mediatype); priv->mediatypes = g_list_prepend (priv->mediatypes, g_strdup (mediatype)); } } if (has_mp3) { rb_debug ("audio/mpeg supported"); priv->mediatypes = g_list_prepend (priv->mediatypes, g_strdup ("audio/mpeg")); } g_object_unref (data->source); free (data->types); g_free (data->name); g_free (data); return FALSE; }
static RhythmDBEntry * add_mtp_track_to_db (RBMtpSource *source, RhythmDB *db, LIBMTP_track_t *track) { RhythmDBEntry *entry = NULL; RhythmDBEntryType *entry_type; RBMtpSourcePrivate *priv = MTP_SOURCE_GET_PRIVATE (source); char *name = NULL; /* ignore everything except audio (allow audio/video types too, since they're probably pretty common) */ if (!(LIBMTP_FILETYPE_IS_AUDIO (track->filetype) || LIBMTP_FILETYPE_IS_AUDIOVIDEO (track->filetype))) { rb_debug ("ignoring non-audio item %d (filetype %s)", track->item_id, LIBMTP_Get_Filetype_Description (track->filetype)); return NULL; } /* Set URI */ g_object_get (G_OBJECT (source), "entry-type", &entry_type, NULL); name = g_strdup_printf ("xrbmtp://%i/%s", track->item_id, track->filename); entry = rhythmdb_entry_new (RHYTHMDB (db), entry_type, name); g_free (name); g_object_unref (entry_type); if (entry == NULL) { rb_debug ("cannot create entry %i", track->item_id); g_object_unref (G_OBJECT (db)); return NULL; } /* Set track number */ if (track->tracknumber != 0) { GValue value = {0, }; g_value_init (&value, G_TYPE_ULONG); g_value_set_ulong (&value, track->tracknumber); rhythmdb_entry_set (RHYTHMDB (db), entry, RHYTHMDB_PROP_TRACK_NUMBER, &value); g_value_unset (&value); } /* Set length */ if (track->duration != 0) { GValue value = {0, }; g_value_init (&value, G_TYPE_ULONG); g_value_set_ulong (&value, track->duration/1000); rhythmdb_entry_set (RHYTHMDB (db), entry, RHYTHMDB_PROP_DURATION, &value); g_value_unset (&value); } /* Set file size */ if (track->filesize != 0) { GValue value = {0, }; g_value_init (&value, G_TYPE_UINT64); g_value_set_uint64 (&value, track->filesize); rhythmdb_entry_set (RHYTHMDB (db), entry, RHYTHMDB_PROP_FILE_SIZE, &value); g_value_unset (&value); } /* Set playcount */ if (track->usecount != 0) { GValue value = {0, }; g_value_init (&value, G_TYPE_ULONG); g_value_set_ulong (&value, track->usecount); rhythmdb_entry_set (RHYTHMDB (db), entry, RHYTHMDB_PROP_PLAY_COUNT, &value); g_value_unset (&value); } /* Set rating */ if (track->rating != 0) { GValue value = {0, }; g_value_init (&value, G_TYPE_DOUBLE); g_value_set_double (&value, track->rating/20); rhythmdb_entry_set (RHYTHMDB (db), entry, RHYTHMDB_PROP_RATING, &value); g_value_unset (&value); } /* Set release date */ if (track->date != NULL && track->date[0] != '\0') { GTimeVal tv; if (g_time_val_from_iso8601 (track->date, &tv)) { GDate d; GValue value = {0, }; g_value_init (&value, G_TYPE_ULONG); g_date_set_time_val (&d, &tv); g_value_set_ulong (&value, g_date_get_julian (&d)); rhythmdb_entry_set (RHYTHMDB (db), entry, RHYTHMDB_PROP_DATE, &value); g_value_unset (&value); } } /* Set title */ entry_set_string_prop (RHYTHMDB (db), entry, RHYTHMDB_PROP_TITLE, track->title); /* Set album, artist and genre from MTP */ entry_set_string_prop (RHYTHMDB (db), entry, RHYTHMDB_PROP_ARTIST, track->artist); entry_set_string_prop (RHYTHMDB (db), entry, RHYTHMDB_PROP_ALBUM, track->album); entry_set_string_prop (RHYTHMDB (db), entry, RHYTHMDB_PROP_GENRE, track->genre); g_hash_table_insert (priv->entry_map, entry, track); rhythmdb_commit (RHYTHMDB (db)); return entry; }
static gboolean device_opened_idle (DeviceOpenedData *data) { RBMtpSourcePrivate *priv = MTP_SOURCE_GET_PRIVATE (data->source); int i; GstEncodingTarget *target; GList *profiles = NULL; if (data->name != NULL) { g_object_set (data->source, "name", data->name, NULL); } /* when the source name changes after this, try to update the device name */ g_signal_connect (G_OBJECT (data->source), "notify::name", (GCallback)rb_mtp_source_name_changed_cb, NULL); rb_media_player_source_load (RB_MEDIA_PLAYER_SOURCE (data->source)); for (i = 0; i < data->num_types; i++) { const char *mediatype; gboolean prepend; if (i <= LIBMTP_FILETYPE_UNKNOWN) { priv->supported_types[data->types[i]] = 1; } mediatype = NULL; prepend = FALSE; switch (data->types[i]) { case LIBMTP_FILETYPE_WAV: /*mediatype = "audio/x-wav";*/ /* don't bother including this? */ break; case LIBMTP_FILETYPE_MP3: mediatype = "audio/mpeg"; prepend = TRUE; /* always goes first if supported */ break; case LIBMTP_FILETYPE_WMA: mediatype = "audio/x-wma"; break; case LIBMTP_FILETYPE_OGG: mediatype = "audio/x-vorbis"; break; case LIBMTP_FILETYPE_MP4: case LIBMTP_FILETYPE_M4A: case LIBMTP_FILETYPE_AAC: mediatype = "audio/x-aac"; break; case LIBMTP_FILETYPE_WMV: mediatype = "audio/x-ms-wmv"; /* media type? */ break; case LIBMTP_FILETYPE_ASF: mediatype = "video/x-ms-asf"; /* media type? */ break; case LIBMTP_FILETYPE_FLAC: mediatype = "audio/x-flac"; break; case LIBMTP_FILETYPE_JPEG: rb_debug ("JPEG (album art) supported"); priv->album_art_supported = TRUE; break; default: rb_debug ("unknown libmtp filetype %s supported", LIBMTP_Get_Filetype_Description (data->types[i])); break; } if (mediatype != NULL) { GstEncodingProfile *profile; profile = rb_gst_get_encoding_profile (mediatype); if (profile != NULL) { rb_debug ("media type %s supported", mediatype); if (prepend) { profiles = g_list_prepend (profiles, profile); } else { profiles = g_list_append (profiles, profile); } } else { rb_debug ("no encoding profile for supported media type %s", mediatype); } } } if (priv->album_art_supported) { priv->art_store = rb_ext_db_new ("album-art"); } target = gst_encoding_target_new ("mtpdevice", "device", "", profiles); g_object_set (data->source, "encoding-target", target, NULL); g_object_unref (data->source); free (data->types); g_free (data->name); g_free (data); return FALSE; }
static GObject * rb_mtp_source_constructor (GType type, guint n_construct_properties, GObjectConstructParam *construct_properties) { RBMtpSource *source; RBMtpSourcePrivate *priv; RBEntryView *tracks; GtkIconTheme *theme; GdkPixbuf *pixbuf; gint size; guint16 *types = NULL; guint16 num_types= 0; source = RB_MTP_SOURCE (G_OBJECT_CLASS (rb_mtp_source_parent_class)-> constructor (type, n_construct_properties, construct_properties)); tracks = rb_source_get_entry_view (RB_SOURCE (source)); rb_entry_view_append_column (tracks, RB_ENTRY_VIEW_COL_RATING, FALSE); rb_entry_view_append_column (tracks, RB_ENTRY_VIEW_COL_LAST_PLAYED, FALSE); /* icon */ theme = gtk_icon_theme_get_default (); gtk_icon_size_lookup (GTK_ICON_SIZE_LARGE_TOOLBAR, &size, NULL); pixbuf = gtk_icon_theme_load_icon (theme, "multimedia-player", size, 0, NULL); rb_source_set_pixbuf (RB_SOURCE (source), pixbuf); g_object_unref (pixbuf); g_signal_connect (G_OBJECT (source), "notify::name", (GCallback)rb_mtp_source_name_changed_cb, NULL); /* figure out supported file types */ priv = MTP_SOURCE_GET_PRIVATE (source); if (LIBMTP_Get_Supported_Filetypes(priv->device, &types, &num_types) == 0) { int i; gboolean has_mp3 = FALSE; for (i = 0; i < num_types; i++) { const char *mediatype; if (i <= LIBMTP_FILETYPE_UNKNOWN) { priv->supported_types[types[i]] = 1; } /* this has to work with the remapping done in * rb-removable-media-source.c:impl_paste. */ switch (types[i]) { case LIBMTP_FILETYPE_WAV: mediatype = "audio/x-wav"; break; case LIBMTP_FILETYPE_MP3: /* special handling for mp3: always put it at the front of the list * if it's supported. */ has_mp3 = TRUE; mediatype = NULL; break; case LIBMTP_FILETYPE_WMA: mediatype = "audio/x-ms-wma"; break; case LIBMTP_FILETYPE_OGG: mediatype = "application/ogg"; break; case LIBMTP_FILETYPE_MP4: case LIBMTP_FILETYPE_M4A: case LIBMTP_FILETYPE_AAC: mediatype = "audio/aac"; break; case LIBMTP_FILETYPE_WMV: mediatype = "audio/x-ms-wmv"; break; case LIBMTP_FILETYPE_ASF: mediatype = "video/x-ms-asf"; break; case LIBMTP_FILETYPE_FLAC: mediatype = "audio/flac"; break; case LIBMTP_FILETYPE_JPEG: rb_debug ("JPEG (album art) supported"); mediatype = NULL; priv->album_art_supported = TRUE; break; default: rb_debug ("unknown libmtp filetype %s supported", LIBMTP_Get_Filetype_Description (types[i])); mediatype = NULL; break; } if (mediatype != NULL) { rb_debug ("media type %s supported", mediatype); priv->mediatypes = g_list_prepend (priv->mediatypes, g_strdup (mediatype)); } } if (has_mp3) { rb_debug ("audio/mpeg supported"); priv->mediatypes = g_list_prepend (priv->mediatypes, g_strdup ("audio/mpeg")); } } else { report_libmtp_errors (priv->device, FALSE); } if (priv->album_art_supported) { RhythmDB *db; db = get_db_for_source (source); g_signal_connect_object (db, "entry-extra-metadata-notify::rb:coverArt", G_CALLBACK (artwork_notify_cb), source, 0); g_object_unref (db); } rb_mtp_source_load_tracks (source); return G_OBJECT (source); }
int main (int argc, char **argv) { LIBMTP_raw_device_t * rawdevices; int numrawdevices; LIBMTP_error_number_t err; int i; int opt; extern int optind; extern char *optarg; while ((opt = getopt(argc, argv, "d")) != -1 ) { switch (opt) { case 'd': LIBMTP_Set_Debug(LIBMTP_DEBUG_PTP | LIBMTP_DEBUG_DATA); break; } } argc -= optind; argv += optind; LIBMTP_Init(); fprintf(stdout, "libmtp version: " LIBMTP_VERSION_STRING "\n\n"); fprintf(stdout, "Listing raw device(s)\n"); err = LIBMTP_Detect_Raw_Devices(&rawdevices, &numrawdevices); switch(err) { case LIBMTP_ERROR_NO_DEVICE_ATTACHED: fprintf(stdout, " No raw devices found.\n"); return 0; case LIBMTP_ERROR_CONNECTING: fprintf(stderr, "Detect: There has been an error connecting. Exiting\n"); return 1; case LIBMTP_ERROR_MEMORY_ALLOCATION: fprintf(stderr, "Detect: Encountered a Memory Allocation Error. Exiting\n"); return 1; case LIBMTP_ERROR_NONE: { int i; fprintf(stdout, " Found %d device(s):\n", numrawdevices); for (i = 0; i < numrawdevices; i++) { if (rawdevices[i].device_entry.vendor != NULL || rawdevices[i].device_entry.product != NULL) { fprintf(stdout, " %s: %s (%04x:%04x) @ bus %d, dev %d\n", rawdevices[i].device_entry.vendor, rawdevices[i].device_entry.product, rawdevices[i].device_entry.vendor_id, rawdevices[i].device_entry.product_id, rawdevices[i].bus_location, rawdevices[i].devnum); } else { fprintf(stdout, " %04x:%04x @ bus %d, dev %d\n", rawdevices[i].device_entry.vendor_id, rawdevices[i].device_entry.product_id, rawdevices[i].bus_location, rawdevices[i].devnum); } } } break; case LIBMTP_ERROR_GENERAL: default: fprintf(stderr, "Unknown connection error.\n"); return 1; } /* Iterate over connected MTP devices */ fprintf(stdout, "Attempting to connect device(s)\n"); for (i = 0; i < numrawdevices; i++) { LIBMTP_mtpdevice_t *device; LIBMTP_devicestorage_t *storage; char *friendlyname; char *syncpartner; char *sectime; char *devcert; uint16_t *filetypes; uint16_t filetypes_len; uint8_t maxbattlevel; uint8_t currbattlevel; int ret; device = LIBMTP_Open_Raw_Device_Uncached(&rawdevices[i]); if (device == NULL) { fprintf(stderr, "Unable to open raw device %d\n", i); continue; } LIBMTP_Dump_Errorstack(device); LIBMTP_Clear_Errorstack(device); LIBMTP_Dump_Device_Info(device); printf("MTP-specific device properties:\n"); // The friendly name friendlyname = LIBMTP_Get_Friendlyname(device); if (friendlyname == NULL) { fprintf(stdout, " Friendly name: (NULL)\n"); } else { fprintf(stdout, " Friendly name: %s\n", friendlyname); free(friendlyname); } syncpartner = LIBMTP_Get_Syncpartner(device); if (syncpartner == NULL) { fprintf(stdout, " Synchronization partner: (NULL)\n"); } else { fprintf(stdout, " Synchronization partner: %s\n", syncpartner); free(syncpartner); } // Some battery info ret = LIBMTP_Get_Batterylevel(device, &maxbattlevel, &currbattlevel); if (ret == 0) { fprintf(stdout, " Battery level %d of %d (%d%%)\n",currbattlevel, maxbattlevel, (int) ((float) currbattlevel/ (float) maxbattlevel * 100.0)); } else { // Silently ignore. Some devices does not support getting the // battery level. LIBMTP_Clear_Errorstack(device); } ret = LIBMTP_Get_Supported_Filetypes(device, &filetypes, &filetypes_len); if (ret == 0) { uint16_t i; printf("libmtp supported (playable) filetypes:\n"); for (i = 0; i < filetypes_len; i++) { fprintf(stdout, " %s\n", LIBMTP_Get_Filetype_Description(filetypes[i])); } } else { LIBMTP_Dump_Errorstack(device); LIBMTP_Clear_Errorstack(device); } // Secure time XML fragment ret = LIBMTP_Get_Secure_Time(device, §ime); if (ret == 0 && sectime != NULL) { fprintf(stdout, "\nSecure Time:\n%s\n", sectime); free(sectime); } else { // Silently ignore - there may be devices not supporting secure time. LIBMTP_Clear_Errorstack(device); } // Device certificate XML fragment if (rawdevices[i].device_entry.vendor_id == 0x041e) { /* * This code is currently disabled except for vendors we * know does support it: all devices say that * they support getting a device certificate but a lot of * them obviously doesn't, instead they crash when you try * to obtain it. */ ret = LIBMTP_Get_Device_Certificate(device, &devcert); if (ret == 0 && devcert != NULL) { fprintf(stdout, "\nDevice Certificate:\n%s\n", devcert); free(devcert); } else { fprintf(stdout, "Unable to acquire device certificate, perhaps this device " "does not support this\n"); LIBMTP_Dump_Errorstack(device); LIBMTP_Clear_Errorstack(device); } } /* Try to get Media player device info XML file... */ /* Loop over storages */ for (storage = device->storage; storage != 0; storage = storage->next) { LIBMTP_file_t *files; /* Get file listing for the root directory, no other dirs */ files = LIBMTP_Get_Files_And_Folders(device, storage->id, 0); if (files != NULL) { LIBMTP_file_t *file, *tmp; file = files; while (file != NULL) { if (!strcmp(file->filename, "WMPInfo.xml") || !strcmp(file->filename, "WMPinfo.xml") || !strcmp(file->filename, "default-capabilities.xml")) { if (file->item_id != 0) { /* Dump this file */ FILE *xmltmp = tmpfile(); int tmpfiledescriptor = fileno(xmltmp); if (tmpfiledescriptor != -1) { int ret = LIBMTP_Get_Track_To_File_Descriptor(device, file->item_id, tmpfiledescriptor, NULL, NULL); if (ret == 0) { uint8_t *buf = NULL; uint32_t readbytes; buf = malloc(XML_BUFSIZE); if (buf == NULL) { printf("Could not allocate %08x bytes...\n", XML_BUFSIZE); LIBMTP_Dump_Errorstack(device); LIBMTP_Clear_Errorstack(device); free(rawdevices); return 1; } lseek(tmpfiledescriptor, 0, SEEK_SET); readbytes = read(tmpfiledescriptor, (void*) buf, XML_BUFSIZE); if (readbytes >= 2 && readbytes < XML_BUFSIZE) { fprintf(stdout, "\n%s file contents:\n", file->filename); dump_xml_fragment(buf, readbytes); } else { perror("Unable to read file"); LIBMTP_Dump_Errorstack(device); LIBMTP_Clear_Errorstack(device); } free(buf); } else { LIBMTP_Dump_Errorstack(device); LIBMTP_Clear_Errorstack(device); } fclose(xmltmp); } } } tmp = file; file = file->next; LIBMTP_destroy_file_t(tmp); } } } LIBMTP_Release_Device(device); } /* End For Loop */ free(rawdevices); printf("OK.\n"); return 0; }