use enhanced MTP commands to create playlists and demo program for creating new playlists
diff --git a/ChangeLog b/ChangeLog
index 6a2ade9..1c9e7ea 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+2006-11-19 Robert Reardon <rreardon@monkshatch.vispa.com>
+
+ * src/libmtp.c: use enhanced MTP commands to create playlists
+ * examples/newplaylist.c: demo program for creating new playlists
+
2006-11-19 Daniel <danielw@iinet.net.au>
* src/libusb-glue.c: fix error on reconnect.
diff --git a/examples/Makefile.am b/examples/Makefile.am
index f7c3bb6..399afc4 100644
--- a/examples/Makefile.am
+++ b/examples/Makefile.am
@@ -1,6 +1,6 @@
bin_PROGRAMS=connect detect tracks files hotplug \
folders trexist playlists getplaylist \
- format albumart albums
+ format albumart albums newplaylist
connect_SOURCES=connect.c delfile.c getfile.c newfolder.c sendfile.c sendtr.c pathutils.c common.h
detect_SOURCES=detect.c common.h
@@ -11,6 +11,7 @@
trexist_SOURCES=trexist.c common.h
playlists_SOURCES=playlists.c common.h
getplaylist_SOURCES=getplaylist.c common.h
+newplaylist_SOURCES=newplaylist.c common.h
format_SOURCES=format.c common.h
albumart_SOURCES=albumart.c common.h
albums_SOURCES=albums.c common.h
@@ -25,3 +26,4 @@
ln -f -s $(DESTDIR)$(bindir)/mtp-connect $(DESTDIR)$(bindir)/mtp-newfolder
ln -f -s $(DESTDIR)$(bindir)/mtp-connect $(DESTDIR)$(bindir)/mtp-sendfile
ln -f -s $(DESTDIR)$(bindir)/mtp-connect $(DESTDIR)$(bindir)/mtp-sendtr
+
diff --git a/examples/newplaylist.c b/examples/newplaylist.c
new file mode 100644
index 0000000..2126238
--- /dev/null
+++ b/examples/newplaylist.c
@@ -0,0 +1,79 @@
+#include "common.h"
+#include "string.h"
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+
+static void usage(void) {
+ printf("Usage: newplaylist -i <fileid/trackid> -n <playlistname>\n");
+ exit(0);
+}
+
+int main (int argc, char **argv) {
+ int opt;
+ extern int optind;
+ extern char *optarg;
+ LIBMTP_mtpdevice_t *device = NULL;
+ int idcount = 0;
+ uint32_t *ids = NULL;
+ uint32_t *tmp = NULL;
+ char *playlistname = NULL;
+
+ while ( (opt = getopt(argc, argv, "hn:i:")) != -1 ) {
+ switch (opt) {
+ case 'h':
+ usage();
+ case 'i':
+ idcount++;
+ if ((tmp = realloc(ids, sizeof(uint32_t) * (idcount))) == NULL) {
+ printf("realloc failed\n");
+ return 1;
+ }
+ ids = tmp;
+ ids[(idcount-1)] = atoi(strdup(optarg));
+ break;
+ case 'n':
+ playlistname = strdup(optarg);
+ break;
+ default:
+ usage();
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ if ( playlistname == NULL) {
+ printf("You need to supply a playlist name.\n");
+ usage();
+ }
+
+ if (idcount == 0) {
+ printf("You need to supply one or more track IDs\n");
+ usage();
+ }
+
+
+ LIBMTP_Init();
+ device = LIBMTP_Get_First_Device();
+ if (device == NULL) {
+ printf("No devices.\n");
+ return 0;
+ }
+
+ LIBMTP_playlist_t *playlist = LIBMTP_new_playlist_t();
+ playlist->name = playlistname;
+ playlist->no_tracks = idcount;
+ playlist->tracks = ids;
+ int ret = LIBMTP_Create_New_Playlist(device,playlist,0);
+ if (ret != 0) {
+ printf("Couldn't create album object\n");
+ }
+ else {
+ printf("Created new playlist: %u\n", playlist->playlist_id);
+ }
+
+ LIBMTP_Release_Device(device);
+ printf("OK.\n");
+ return 0;
+}
+
diff --git a/src/libmtp.c b/src/libmtp.c
index 5a4ab78..42d33c5 100644
--- a/src/libmtp.c
+++ b/src/libmtp.c
@@ -933,7 +933,8 @@
tmpdevice->default_music_folder = params->handles.Handler[i];
remaining_directories--;
continue;
- } else if (!strcmp(oi.Filename, "My Playlists")) {
+ } else if ((!strcmp(oi.Filename, "My Playlists")) ||
+ (!strcmp(oi.Filename, "Playlists"))) {
tmpdevice->default_playlist_folder = params->handles.Handler[i];
remaining_directories--;
continue;
@@ -3739,6 +3740,10 @@
uint16_t ret;
uint32_t store = 0;
PTPObjectInfo new_pl;
+ uint16_t *props = NULL;
+ uint32_t propcnt = 0;
+ uint8_t nonconsumable = 0x00U; /* By default it is consumable */
+ int i;
PTPParams *params = (PTPParams *) device->params;
uint32_t localph = parenthandle;
char fname[256];
@@ -3772,19 +3777,113 @@
new_pl.ObjectCompressedSize = 1;
new_pl.ObjectFormat = PTP_OFC_MTP_AbstractAudioVideoPlaylist;
- // Create the object
- ret = ptp_sendobjectinfo(params, &store, &localph, &metadata->playlist_id, &new_pl);
- if (ret != PTP_RC_OK) {
- ptp_perror(params, ret);
- printf("LIBMTP_New_Playlist(): Could not send object info (the playlist itself)\n");
- if (ret == PTP_RC_AccessDenied) {
- printf("ACCESS DENIED.\n");
- } else {
- printf("Return code: 0x%04x (look this up in ptp.h for an explanation).\n", ret);
- }
- return -1;
- }
+#ifdef ENABLE_MTP_ENHANCED
+ if (ptp_operation_issupported(params,PTP_OC_MTP_SendObjectPropList)) {
+
+ MTPPropList *proplist = NULL;
+ MTPPropList *prop = NULL;
+ MTPPropList *previous = NULL;
+ ret = ptp_mtp_getobjectpropssupported(params, PTP_OFC_MTP_AbstractAudioVideoPlaylist, &propcnt, &props);
+
+ for (i=0;i<propcnt;i++) {
+ switch (props[i]) {
+ case PTP_OPC_ObjectFileName:
+ prop = New_MTP_Prop_Entry();
+ prop->property = PTP_OPC_ObjectFileName;
+ prop->datatype = PTP_DTC_STR;
+ prop->propval.str = strdup(new_pl.Filename);
+
+ if (previous != NULL)
+ previous->next = prop;
+ else
+ proplist = prop;
+ previous = prop;
+ prop->next = NULL;
+ break;
+ case PTP_OPC_ProtectionStatus:
+ prop = New_MTP_Prop_Entry();
+ prop->property = PTP_OPC_ProtectionStatus;
+ prop->datatype = PTP_DTC_UINT16;
+ prop->propval.u16 = 0x0000U; /* Not protected */
+
+ if (previous != NULL)
+ previous->next = prop;
+ else
+ proplist = prop;
+ previous = prop;
+ prop->next = NULL;
+ break;
+ case PTP_OPC_NonConsumable:
+ prop = New_MTP_Prop_Entry();
+ prop->property = PTP_OPC_NonConsumable;
+ prop->datatype = PTP_DTC_UINT8;
+ prop->propval.u8 = nonconsumable;
+
+ if (previous != NULL)
+ previous->next = prop;
+ else
+ proplist = prop;
+ previous = prop;
+ prop->next = NULL;
+ break;
+ case PTP_OPC_Name:
+ prop = New_MTP_Prop_Entry();
+ prop->property = PTP_OPC_Name;
+ prop->datatype = PTP_DTC_STR;
+ prop->propval.str = strdup(metadata->name);
+
+ if (previous != NULL)
+ previous->next = prop;
+ else
+ proplist = prop;
+ previous = prop;
+ prop->next = NULL;
+ break;
+ }
+ }
+ free(props);
+
+ ret = ptp_mtp_sendobjectproplist(params, &store, &localph, &metadata->playlist_id,
+ PTP_OFC_MTP_AbstractAudioVideoPlaylist,
+ new_pl.ObjectCompressedSize, proplist);
+
+ /* Free property list */
+ prop = proplist;
+ while (prop != NULL) {
+ previous = prop;
+ prop = prop->next;
+ Destroy_MTP_Prop_Entry(previous);
+ }
+
+ if (ret != PTP_RC_OK) {
+ ptp_perror(params, ret);
+ printf("LIBMTP_Create_New_Playlist(): Could not send object property list.\n");
+ if (ret == PTP_RC_AccessDenied) {
+ printf("ACCESS DENIED.\n");
+ } else {
+ printf("Return code: 0x%04x (look this up in ptp.h for an explanation).\n", ret);
+ }
+ return -1;
+ }
+ } else if (ptp_operation_issupported(params,PTP_OC_SendObjectInfo)) {
+#else // !ENABLE_MTP_ENHANCED
+ {
+#endif // ENABLE_MTP_ENHANCED
+
+ // Create the object
+ ret = ptp_sendobjectinfo(params, &store, &localph, &metadata->playlist_id, &new_pl);
+ if (ret != PTP_RC_OK) {
+ ptp_perror(params, ret);
+ printf("LIBMTP_New_Playlist(): Could not send object info (the playlist itself)\n");
+ if (ret == PTP_RC_AccessDenied) {
+ printf("ACCESS DENIED.\n");
+ } else {
+ printf("Return code: 0x%04x (look this up in ptp.h for an explanation).\n", ret);
+ }
+ return -1;
+ }
+ }
/*
* We have to send this one blank data byte.
* If we don't, the handle will not be created and thus there is no playlist.
@@ -4044,7 +4143,7 @@
PTPParams *params = (PTPParams *) device->params;
uint32_t localph = parenthandle;
char fname[256];
- uint8_t data[1];
+ uint8_t data[2];
uint16_t *props = NULL;
uint32_t propcnt = 0;
uint8_t nonconsumable = 0x00U; /* By default it is consumable */
@@ -4065,7 +4164,7 @@
// Use a default folder if none given
if (localph == 0) {
- localph = device->default_music_folder;
+ localph = device->default_album_folder;
}
new_alb.Filename = NULL;
@@ -4095,9 +4194,6 @@
ret = ptp_mtp_getobjectpropssupported(params, PTP_OFC_MTP_AbstractAudioAlbum, &propcnt, &props);
- /* Send an object property list of that is supported */
- localph = 0xFFFFFFFFU; // Set to -1
-
for (i=0;i<propcnt;i++) {
switch (props[i]) {
case PTP_OPC_ObjectFileName:
@@ -4159,6 +4255,7 @@
ret = ptp_mtp_sendobjectproplist(params, &store, &localph, &metadata->album_id,
PTP_OFC_MTP_AbstractAudioAlbum,
new_alb.ObjectCompressedSize, proplist);
+
/* Free property list */
prop = proplist;
@@ -4192,6 +4289,7 @@
}
}
data[0] = '\0';
+ data[1] = '\0';
ret = ptp_sendobject(params, data, 1);
if (ret != PTP_RC_OK) {
ptp_perror(params, ret);
@@ -4274,7 +4372,7 @@
// go ahead and send the data
ret = ptp_mtp_setobjectpropvalue(params,id,PTP_OPC_RepresentativeSampleData,
- &propval,PTP_DTC_AUINT8);
+ &propval,PTP_DTC_AUINT8);
if (ret != PTP_RC_OK) {
printf("LIBMTP_Send_Album_Art(): could not send album art\n");
printf("Return code: 0x%04x (look this up in ptp.h for an explanation).\n", ret);