/* 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); }
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; }
/* 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 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; }