2
* Created on Jan 27, 2009
3
* Created by Paul Gardner
5
* Copyright 2009 Vuze, Inc. All rights reserved.
7
* This program is free software; you can redistribute it and/or modify
8
* it under the terms of the GNU General Public License as published by
9
* the Free Software Foundation; version 2 of the License only.
11
* This program is distributed in the hope that it will be useful,
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
* GNU General Public License for more details.
16
* You should have received a copy of the GNU General Public License
17
* along with this program; if not, write to the Free Software
18
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
22
package com.aelitis.azureus.core.devices.impl;
27
import org.gudy.azureus2.core3.config.COConfigurationManager;
28
import org.gudy.azureus2.core3.config.ParameterListener;
29
import org.gudy.azureus2.core3.util.AEDiagnostics;
30
import org.gudy.azureus2.core3.util.AEDiagnosticsEvidenceGenerator;
31
import org.gudy.azureus2.core3.util.AEDiagnosticsLogger;
32
import org.gudy.azureus2.core3.util.AERunnable;
33
import org.gudy.azureus2.core3.util.AESemaphore;
34
import org.gudy.azureus2.core3.util.AEThread2;
35
import org.gudy.azureus2.core3.util.Debug;
36
import org.gudy.azureus2.core3.util.DelayedEvent;
37
import org.gudy.azureus2.core3.util.FileUtil;
38
import org.gudy.azureus2.core3.util.IndentWriter;
39
import org.gudy.azureus2.core3.util.SimpleTimer;
40
import org.gudy.azureus2.core3.util.TimerEvent;
41
import org.gudy.azureus2.core3.util.TimerEventPerformer;
42
import org.gudy.azureus2.plugins.disk.DiskManagerFileInfo;
43
import org.gudy.azureus2.plugins.ipc.IPCInterface;
45
import com.aelitis.azureus.core.AzureusCore;
46
import com.aelitis.azureus.core.AzureusCoreFactory;
47
import com.aelitis.azureus.core.AzureusCoreLifecycleAdapter;
48
import com.aelitis.azureus.core.devices.*;
49
import com.aelitis.azureus.core.messenger.config.PlatformDevicesMessenger;
50
import com.aelitis.azureus.core.util.*;
54
implements DeviceManager, AEDiagnosticsEvidenceGenerator
56
private static final String LOGGER_NAME = "Devices";
57
private static final String CONFIG_FILE = "devices.config";
58
private static final String AUTO_SEARCH_CONFIG_KEY = "devices.config.auto_search";
60
protected static final int DEVICE_UPDATE_PERIOD = 5*1000;
62
private static DeviceManagerImpl singleton;
69
public static DeviceManager
72
synchronized( DeviceManagerImpl.class ){
74
if ( singleton == null ){
76
singleton = new DeviceManagerImpl();
85
private List<DeviceImpl> device_list = new ArrayList<DeviceImpl>();
86
private Map<String,DeviceImpl> device_map = new HashMap<String, DeviceImpl>();
88
private DeviceManagerUPnPImpl upnp_manager;
90
private CopyOnWriteList<DeviceManagerListener> listeners = new CopyOnWriteList<DeviceManagerListener>();
92
private boolean auto_search;
93
private boolean closing;
95
private boolean config_unclean;
96
private boolean config_dirty;
98
private int explicit_search;
100
private TranscodeManagerImpl transcode_manager;
102
private AEDiagnosticsLogger logger;
107
AEDiagnostics.addEvidenceGenerator( this );
109
upnp_manager = new DeviceManagerUPnPImpl( this );
113
new DeviceiTunesManager( this );
115
transcode_manager = new TranscodeManagerImpl( this );
117
COConfigurationManager.addAndFireParameterListener(
118
AUTO_SEARCH_CONFIG_KEY,
119
new ParameterListener()
125
auto_search = COConfigurationManager.getBooleanParameter( name, true );
129
AzureusCoreFactory.getSingleton().addLifecycleListener(
130
new AzureusCoreLifecycleAdapter()
136
synchronized( DeviceManagerImpl.this ){
138
if ( config_dirty || config_unclean ){
145
transcode_manager.close();
147
DeviceImpl[] devices = getDevices();
149
for ( DeviceImpl device: devices ){
157
upnp_manager.initialise();
159
SimpleTimer.addPeriodicEvent(
160
"DeviceManager:update",
161
DEVICE_UPDATE_PERIOD,
162
new TimerEventPerformer()
164
private int tick_count = 0;
170
List<DeviceImpl> copy;
174
transcode_manager.updateStatus( tick_count );
176
synchronized( DeviceManagerImpl.this ){
178
if( device_list.size() == 0 ){
183
copy = new ArrayList<DeviceImpl>( device_list );
186
for ( DeviceImpl device: copy ){
188
device.updateStatus( tick_count );
194
protected DeviceManagerUPnPImpl
197
return( upnp_manager );
205
throws DeviceManagerException
207
if ( device_type == Device.DT_MEDIA_RENDERER ){
209
DeviceImpl res = new DeviceMediaRendererImpl( this, name );
217
throw( new DeviceManagerException( "Can't manually create this device type" ));
224
final DeviceSearchListener listener )
226
new AEThread2( "DM:search", true )
231
synchronized( DeviceManagerImpl.this ){
236
AESemaphore sem = new AESemaphore( "DM:search" );
238
DeviceManagerListener dm_listener =
239
new DeviceManagerListener()
245
listener.deviceFound( device );
255
deviceAttentionRequest(
268
addListener( dm_listener );
270
upnp_manager.search();
272
sem.reserve( millis );
276
synchronized( DeviceManagerImpl.this ){
281
removeListener( dm_listener );
293
synchronized( this ){
295
return( device_map.get( id ));
303
// for xbox (currently) we automagically replace a manual entry with an auto one as we may have
304
// added the manual one when receiving a previous browse before getting the UPnP renderer details
306
DeviceImpl existing = null;
308
synchronized( this ){
310
existing = device_map.get( device.getID());
312
if ( existing != null ){
314
existing.updateFrom( device );
318
if ( device.getType() == Device.DT_MEDIA_RENDERER ){
320
DeviceMediaRenderer renderer = (DeviceMediaRenderer)device;
322
if ( renderer.getRendererSpecies() == DeviceMediaRenderer.RS_XBOX && !renderer.isManual()){
324
for ( DeviceImpl d: device_list ){
326
if ( d.getType() == Device.DT_MEDIA_RENDERER ){
328
DeviceMediaRenderer r = (DeviceMediaRenderer)d;
330
if ( r.getRendererSpecies() == DeviceMediaRenderer.RS_XBOX && r.isManual()){
334
log( "Merging " + device.getString() + " -> " + existing.getString());
336
String secondary_id = device.getID();
338
existing.setSecondaryID( secondary_id );
340
existing.updateFrom( device );
348
if ( existing == null ){
350
device_list.add( device );
352
device_map.put( device.getID(), device );
356
if ( existing != null ){
358
// don't trigger config save here, if anything has changed it will have been handled
359
// by the updateFrom call above
361
deviceChanged( existing, false );
370
deviceAdded( device );
381
synchronized( this ){
383
DeviceImpl existing = device_map.remove( device.getID());
385
if ( existing == null ){
390
device_list.remove( device );
392
String secondary_id = device.getSecondaryID();
394
if ( secondary_id != null ){
396
device_map.remove( secondary_id );
402
deviceRemoved( device );
410
synchronized( this ){
412
return( device_list.toArray( new DeviceImpl[ device_list.size()] ));
419
return( auto_search );
426
COConfigurationManager.setParameter( AUTO_SEARCH_CONFIG_KEY, auto );
432
synchronized( this ){
434
return( explicit_search > 0 );
447
if ( !FileUtil.resilientConfigFileExists( CONFIG_FILE )){
452
log( "Loading configuration" );
454
synchronized( this ){
456
Map map = FileUtil.readResilientConfigFile( CONFIG_FILE );
458
List l_devices = (List)map.get( "devices" );
460
if ( l_devices != null ){
462
for (int i=0;i<l_devices.size();i++){
464
Map m = (Map)l_devices.get(i);
467
DeviceImpl device = DeviceImpl.importFromBEncodedMapStatic(this, m );
469
device_list.add( device );
471
device_map.put( device.getID(), device );
473
String secondary_id = device.getSecondaryID();
475
if ( secondary_id != null ){
477
device_map.put( secondary_id, device );
482
log( " loaded " + device.getString());
484
}catch( Throwable e ){
486
log( "Failed to import subscription from " + m, e );
496
boolean save_changes )
498
deviceChanged( device, save_changes );
504
synchronized( this ){
514
"Subscriptions:save", 5000,
520
synchronized( DeviceManagerImpl.this ){
522
if ( !config_dirty ){
537
log( "Saving configuration" );
539
synchronized( this ){
543
// to late to try writing
548
config_dirty = false;
549
config_unclean = false;
551
if ( device_list.size() == 0 ){
553
FileUtil.deleteResilientConfigFile( CONFIG_FILE );
557
Map map = new HashMap();
559
List l_devices = new ArrayList();
561
map.put( "devices", l_devices );
563
Iterator<DeviceImpl> it = device_list.iterator();
565
while( it.hasNext()){
567
DeviceImpl device = it.next();
570
Map d = new HashMap();
572
device.exportToBEncodedMap( d );
576
}catch( Throwable e ){
578
log( "Failed to save device " + device.getString(), e );
582
FileUtil.writeResilientConfigFile( CONFIG_FILE, map );
593
// I'd rather put this in a listener, but for now this will ensure
594
// it gets QOS'd even before any listeners are added
596
PlatformDevicesMessenger.qosFoundDevice(device);
597
} catch (Exception e) {
601
for ( DeviceManagerListener listener: listeners ){
604
listener.deviceAdded( device );
606
}catch( Throwable e ){
617
boolean save_changes )
625
config_unclean = true;
628
for ( DeviceManagerListener listener: listeners ){
631
listener.deviceChanged( device );
633
}catch( Throwable e ){
646
for ( DeviceManagerListener listener: listeners ){
649
listener.deviceRemoved( device );
651
}catch( Throwable e ){
662
for ( DeviceManagerListener listener: listeners ){
665
listener.deviceAttentionRequest( device );
667
}catch( Throwable e ){
676
TranscodeFileImpl file )
678
IPCInterface ipc = upnp_manager.getUPnPAVIPC();
683
DiskManagerFileInfo f = file.getTargetFile();
685
String str = (String)ipc.invoke( "getContentURL", new Object[]{ f });
687
if ( str != null && str.length() > 0 ){
689
return( new URL( str ));
691
}catch( Throwable e ){
699
public TranscodeManagerImpl
700
getTranscodeManager()
702
return( transcode_manager );
705
public UnassociatedDevice[]
706
getUnassociatedDevices()
708
return( upnp_manager.getUnassociatedDevices());
713
DeviceManagerListener listener )
715
listeners.add( listener );
720
DeviceManagerListener listener )
722
listeners.remove( listener );
725
protected synchronized AEDiagnosticsLogger
728
if ( logger == null ){
730
logger = AEDiagnostics.getLogger( LOGGER_NAME );
741
AEDiagnosticsLogger diag_logger = getLogger();
743
diag_logger.log( s );
744
diag_logger.log( e );
751
AEDiagnosticsLogger diag_logger = getLogger();
753
diag_logger.log( s );
758
IndentWriter writer )
760
writer.println( "Devices" );
765
DeviceImpl[] devices = getDevices();
767
for ( DeviceImpl device: devices ){
769
device.generate( writer );
772
transcode_manager.generate( writer );