1 /*****************************************************************************
2 * upnp_cc.cpp : UPnP discovery module
3 *****************************************************************************
4 * Copyright (C) 2004-2005 the VideoLAN team
7 * Authors: RĂ©mi Denis-Courmont <rem # videolan.org>
9 * Based on original wxWindows patch for VLC, and dependent on CyberLink
11 * Satoshi Konno <skonno@cybergarage.org>
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 2 of the License, or
16 * (at your option) any later version.
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
26 *****************************************************************************/
28 /*****************************************************************************
30 *****************************************************************************/
32 #include <cybergarage/upnp/media/player/MediaPlayer.h>
39 #include <vlc_common.h>
40 #include <vlc_plugin.h>
41 #include <vlc_playlist.h>
42 #include <vlc_services_discovery.h>
44 /* FIXME: thread-safety ?? */
45 /* FIXME: playlist locking */
47 /************************************************************************
48 * Macros and definitions
49 ************************************************************************/
51 using namespace CyberLink
;
53 /*****************************************************************************
55 *****************************************************************************/
58 static int Open ( vlc_object_t
* );
59 static void Close( vlc_object_t
* );
61 VLC_SD_PROBE_HELPER("upnp", N_("Universal Plug'n'Play"), SD_CAT_LAN
)
64 set_shortname( "UPnP")
65 set_description( N_("Universal Plug'n'Play") )
66 set_category( CAT_PLAYLIST
)
67 set_subcategory( SUBCAT_PLAYLIST_SD
)
69 set_capability( "services_discovery", 0 )
70 set_callbacks( Open
, Close
)
72 VLC_SD_PROBE_SUBMODULE
76 /*****************************************************************************
77 * Run: main UPnP thread
78 *****************************************************************************
79 * Processes UPnP events
80 *****************************************************************************/
81 class UPnPHandler
: public MediaPlayer
, public DeviceChangeListener
,
82 /*public EventListener,*/ public SearchResponseListener
85 services_discovery_t
*p_sd
;
87 Device
*GetDeviceFromUSN( const string
& usn
)
89 return getDevice( usn
.substr( 0, usn
.find( "::" ) ).c_str() );
92 playlist_item_t
*FindDeviceNode( Device
*dev
)
94 return playlist_ChildSearchName( p_sd
->p_cat
, dev
->getFriendlyName() );
97 playlist_item_t
*FindDeviceNode( const string
&usn
)
99 return FindDeviceNode( GetDeviceFromUSN( usn
) );
102 playlist_item_t
*AddDevice( Device
*dev
);
103 void AddDeviceContent( Device
*dev
);
104 void AddContent( playlist_item_t
*p_parent
, ContentNode
*node
);
105 void RemoveDevice( Device
*dev
);
107 /* CyberLink callbacks */
108 virtual void deviceAdded( Device
*dev
);
109 virtual void deviceRemoved( Device
*dev
);
111 virtual void deviceSearchResponseReceived( SSDPPacket
*packet
);
112 /*virtual void eventNotifyReceived( const char *uuid, long seq,
114 const char *value );*/
117 UPnPHandler( services_discovery_t
*p_this
)
120 addDeviceChangeListener( this );
121 addSearchResponseListener( this );
122 //addEventListener( this );
126 /*****************************************************************************
127 * Open: initialize and create stuff
128 *****************************************************************************/
129 static int Open( vlc_object_t
*p_this
)
131 services_discovery_t
*p_sd
= ( services_discovery_t
* )p_this
;
133 UPnPHandler
*u
= new UPnPHandler( p_sd
);
135 msg_Dbg( p_sd
, "upnp discovery started" );
142 /*****************************************************************************
144 *****************************************************************************/
145 static void Close( vlc_object_t
*p_this
)
147 UPnPHandler
*u
= (UPnPHandler
*)p_this
->p_private
;
150 msg_Dbg( p_this
, "upnp discovery started" );
154 playlist_item_t
*UPnPHandler::AddDevice( Device
*dev
)
159 /* We are not interested in IGD devices or whatever (at the moment) */
160 if ( !dev
->isDeviceType( MediaServer::DEVICE_TYPE
) )
163 playlist_item_t
*p_item
= FindDeviceNode( dev
);
164 if ( p_item
!= NULL
)
168 * Maybe one day, VLC API will make sensible use of the const keyword;
169 * That day, you will no longer need this strdup().
171 char *str
= strdup( dev
->getFriendlyName( ) );
173 p_item
= playlist_NodeCreate( p_playlist
, str
, p_sd
->p_cat
, 0, NULL
);
174 p_item
->i_flags
&= ~PLAYLIST_SKIP_FLAG
;
175 msg_Dbg( p_sd
, "device %s added", str
);
181 void UPnPHandler::AddDeviceContent( Device
*dev
)
183 playlist_item_t
*p_devnode
= AddDevice( dev
);
185 if( p_devnode
== NULL
)
188 AddContent( p_devnode
, getContentDirectory( dev
) );
191 void UPnPHandler::AddContent( playlist_item_t
*p_parent
, ContentNode
*node
)
196 const char *title
= node
->getTitle();
200 msg_Dbg( p_sd
, "title = %s", title
);
202 if ( node
->isItemNode() )
204 ItemNode
*iNode
= (ItemNode
*)node
;
205 input_item_t
*p_input
= input_item_New( p_sd
, iNode
->getResource(), title
);
206 /* FIXME: playlist_AddInput() can fail */
207 playlist_NodeAddInput( p_playlist
, p_input
, p_parent
,
208 PLAYLIST_APPEND
, PLAYLIST_END
,
210 vlc_gc_decref( p_input
);
211 } else if ( node
->isContainerNode() )
213 ContainerNode
*conNode
= (ContainerNode
*)node
;
215 char* p_name
= strdup(title
); /* See other comment on strdup */
216 playlist_item_t
* p_node
= playlist_NodeCreate( p_playlist
, p_name
,
220 unsigned nContentNodes
= conNode
->getNContentNodes();
222 for( unsigned n
= 0; n
< nContentNodes
; n
++ )
223 AddContent( p_node
, conNode
->getContentNode( n
) );
228 void UPnPHandler::RemoveDevice( Device
*dev
)
230 playlist_item_t
*p_item
= FindDeviceNode( dev
);
233 playlist_NodeDelete( p_playlist
, p_item
, true, true );
237 void UPnPHandler::deviceAdded( Device
*dev
)
239 msg_Dbg( p_sd
, "adding device" );
240 AddDeviceContent( dev
);
244 void UPnPHandler::deviceRemoved( Device
*dev
)
246 msg_Dbg( p_sd
, "removing device" );
251 void UPnPHandler::deviceSearchResponseReceived( SSDPPacket
*packet
)
253 if( !packet
->isRootDevice() )
256 string usn
, nts
, nt
, udn
;
258 packet
->getUSN( usn
);
260 packet
->getNTS( nts
);
261 udn
= usn
.substr( 0, usn
.find( "::" ) );
263 /* Remove existing root device before adding updated one */
265 Device
*dev
= GetDeviceFromUSN( usn
);
268 if( !packet
->isByeBye() )
269 AddDeviceContent( dev
);
272 /*void UPnPHandler::eventNotifyReceived( const char *uuid, long seq,
273 const char *name, const char *value )
275 msg_Dbg( p_sd, "event notify received" );
276 msg_Dbg( p_sd, "uuid = %s, name = %s, value = %s", uuid, name, value );