1 /*****************************************************************************
2 * mtp.c : MTP interface module
3 *****************************************************************************
4 * Copyright (C) 2009 the VideoLAN team
6 * Authors: Fabio Ritrovato <exsephiroth87@gmail.com>
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
21 *****************************************************************************/
27 #define VLC_MODULE_LICENSE VLC_LICENSE_GPL_2_PLUS
28 #include <vlc_common.h>
29 #include <vlc_plugin.h>
30 #include <vlc_services_discovery.h>
34 /*****************************************************************************
36 *****************************************************************************/
37 static int Open( vlc_object_t
* );
38 static void Close( vlc_object_t
* );
40 VLC_SD_PROBE_HELPER("mtp", N_("MTP devices"), SD_CAT_DEVICES
)
43 set_shortname( "MTP" )
44 set_description( N_( "MTP devices" ) )
45 set_category( CAT_PLAYLIST
)
46 set_subcategory( SUBCAT_PLAYLIST_SD
)
47 set_capability( "services_discovery", 0 )
48 set_callbacks( Open
, Close
)
49 cannot_unload_broken_library()
51 VLC_SD_PROBE_SUBMODULE
55 /*****************************************************************************
57 *****************************************************************************/
59 static void *Run( void * );
61 static int AddDevice( services_discovery_t
*, LIBMTP_raw_device_t
* );
62 static void AddTrack( services_discovery_t
*, LIBMTP_track_t
*);
63 static void CloseDevice( services_discovery_t
* );
64 static int CountTracks( uint64_t const, uint64_t const, void const * const );
66 /*****************************************************************************
68 *****************************************************************************/
70 struct services_discovery_sys_t
73 input_item_t
**pp_items
;
78 uint16_t i_product_id
;
82 static vlc_mutex_t mtp_lock
= VLC_STATIC_MUTEX
;
83 static bool b_mtp_initialized
= false;
85 /*****************************************************************************
86 * Open: initialize and create stuff
87 *****************************************************************************/
88 static int Open( vlc_object_t
*p_this
)
90 services_discovery_t
*p_sd
= ( services_discovery_t
* )p_this
;
91 services_discovery_sys_t
*p_sys
;
93 if( !( p_sys
= malloc( sizeof( services_discovery_sys_t
) ) ) )
96 p_sd
->description
= _("MTP devices");
97 p_sys
->psz_name
= NULL
;
99 vlc_mutex_lock( &mtp_lock
);
100 if( !b_mtp_initialized
)
103 b_mtp_initialized
= true;
105 vlc_mutex_unlock( &mtp_lock
);
107 if (vlc_clone (&p_sys
->thread
, Run
, p_sd
, VLC_THREAD_PRIORITY_LOW
))
115 /*****************************************************************************
117 *****************************************************************************/
118 static void Close( vlc_object_t
*p_this
)
120 services_discovery_t
*p_sd
= ( services_discovery_t
* )p_this
;
122 free( p_sd
->p_sys
->psz_name
);
123 vlc_cancel( p_sd
->p_sys
->thread
);
124 vlc_join( p_sd
->p_sys
->thread
, NULL
);
128 /*****************************************************************************
130 *****************************************************************************/
131 static void *Run( void *data
)
133 LIBMTP_raw_device_t
*p_rawdevices
;
137 services_discovery_t
*p_sd
= data
;
141 int canc
= vlc_savecancel();
142 i_ret
= LIBMTP_Detect_Raw_Devices( &p_rawdevices
, &i_numrawdevices
);
143 if ( i_ret
== 0 && i_numrawdevices
> 0 && p_rawdevices
!= NULL
&&
146 /* Found a new device, add it */
147 msg_Dbg( p_sd
, "New device found" );
148 if( AddDevice( p_sd
, &p_rawdevices
[0] ) == VLC_SUCCESS
)
155 if ( ( i_ret
!= 0 || i_numrawdevices
== 0 || p_rawdevices
== NULL
)
158 /* The device is not connected anymore, delete it */
159 msg_Info( p_sd
, "Device disconnected" );
164 free( p_rawdevices
);
165 vlc_restorecancel(canc
);
177 /*****************************************************************************
179 *****************************************************************************/
180 static int AddDevice( services_discovery_t
*p_sd
,
181 LIBMTP_raw_device_t
*p_raw_device
)
183 char *psz_name
= NULL
;
184 LIBMTP_mtpdevice_t
*p_device
;
185 LIBMTP_track_t
*p_track
, *p_tmp
;
187 if( ( p_device
= LIBMTP_Open_Raw_Device( p_raw_device
) ) != NULL
)
189 if( !( psz_name
= LIBMTP_Get_Friendlyname( p_device
) ) )
190 if( !( psz_name
= LIBMTP_Get_Modelname( p_device
) ) )
191 if( !( psz_name
= strdup( N_( "MTP Device" ) ) ) )
193 msg_Info( p_sd
, "Found device: %s", psz_name
);
194 p_sd
->p_sys
->i_bus
= p_raw_device
->bus_location
;
195 p_sd
->p_sys
->i_dev
= p_raw_device
->devnum
;
196 p_sd
->p_sys
->i_product_id
= p_raw_device
->device_entry
.product_id
;
197 if( ( p_track
= LIBMTP_Get_Tracklisting_With_Callback( p_device
,
198 CountTracks
, p_sd
) ) == NULL
)
200 msg_Warn( p_sd
, "No tracks on the device" );
201 p_sd
->p_sys
->pp_items
= NULL
;
205 if( !( p_sd
->p_sys
->pp_items
= calloc( p_sd
->p_sys
->i_tracks_num
,
206 sizeof( input_item_t
* ) ) ) )
211 p_sd
->p_sys
->i_count
= 0;
212 while( p_track
!= NULL
)
214 msg_Dbg( p_sd
, "Track found: %s - %s", p_track
->artist
,
216 AddTrack( p_sd
, p_track
);
218 p_track
= p_track
->next
;
219 LIBMTP_destroy_track_t( p_tmp
);
222 p_sd
->p_sys
->psz_name
= psz_name
;
223 LIBMTP_Release_Device( p_device
);
228 msg_Info( p_sd
, "The device seems to be mounted, unmount it first" );
233 static void AddTrack( services_discovery_t
*p_sd
, LIBMTP_track_t
*p_track
)
235 input_item_t
*p_input
;
239 extension
= rindex( p_track
->filename
, '.' );
240 if( asprintf( &psz_string
, "mtp://%"PRIu32
":%"PRIu8
":%"PRIu16
":%d%s",
241 p_sd
->p_sys
->i_bus
, p_sd
->p_sys
->i_dev
,
242 p_sd
->p_sys
->i_product_id
, p_track
->item_id
,
245 msg_Err( p_sd
, "Error adding %s, skipping it", p_track
->filename
);
248 if( ( p_input
= input_item_New( psz_string
, p_track
->title
) ) == NULL
)
250 msg_Err( p_sd
, "Error adding %s, skipping it", p_track
->filename
);
256 input_item_SetArtist( p_input
, p_track
->artist
);
257 input_item_SetGenre( p_input
, p_track
->genre
);
258 input_item_SetAlbum( p_input
, p_track
->album
);
259 if( asprintf( &psz_string
, "%d", p_track
->tracknumber
) != -1 )
261 input_item_SetTrackNum( p_input
, psz_string
);
264 if( asprintf( &psz_string
, "%d", p_track
->rating
) != -1 )
266 input_item_SetRating( p_input
, psz_string
);
269 input_item_SetDate( p_input
, p_track
->date
);
270 p_input
->i_duration
= p_track
->duration
* INT64_C(1000);
271 services_discovery_AddItem( p_sd
, p_input
);
272 p_sd
->p_sys
->pp_items
[p_sd
->p_sys
->i_count
++] = p_input
;
275 static void CloseDevice( services_discovery_t
*p_sd
)
277 input_item_t
**pp_items
= p_sd
->p_sys
->pp_items
;
279 if( pp_items
!= NULL
)
281 for( int i_i
= 0; i_i
< p_sd
->p_sys
->i_count
; i_i
++ )
283 if( pp_items
[i_i
] != NULL
)
285 services_discovery_RemoveItem( p_sd
, pp_items
[i_i
] );
286 input_item_Release( pp_items
[i_i
] );
293 static int CountTracks( uint64_t const sent
, uint64_t const total
,
294 void const * const data
)
297 services_discovery_t
*p_sd
= (services_discovery_t
*)data
;
298 p_sd
->p_sys
->i_tracks_num
= total
;