2
* Created on Jan 28, 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;
25
import java.io.IOException;
26
import java.lang.ref.WeakReference;
27
import java.lang.reflect.Constructor;
29
import java.text.SimpleDateFormat;
32
import org.gudy.azureus2.core3.config.COConfigurationManager;
33
import org.gudy.azureus2.core3.internat.MessageText;
34
import org.gudy.azureus2.core3.util.AERunnable;
35
import org.gudy.azureus2.core3.util.ByteFormatter;
36
import org.gudy.azureus2.core3.util.Debug;
37
import org.gudy.azureus2.core3.util.DelayedEvent;
38
import org.gudy.azureus2.core3.util.FileUtil;
39
import org.gudy.azureus2.core3.util.IndentWriter;
40
import org.gudy.azureus2.core3.util.LightHashMap;
41
import org.gudy.azureus2.core3.util.SystemProperties;
42
import org.gudy.azureus2.core3.util.SystemTime;
43
import org.gudy.azureus2.plugins.disk.DiskManagerFileInfo;
45
import com.aelitis.azureus.core.devices.Device;
46
import com.aelitis.azureus.core.devices.DeviceMediaRenderer;
47
import com.aelitis.azureus.core.devices.TranscodeException;
48
import com.aelitis.azureus.core.devices.TranscodeFile;
49
import com.aelitis.azureus.core.devices.TranscodeProfile;
50
import com.aelitis.azureus.core.devices.TranscodeProvider;
51
import com.aelitis.azureus.core.devices.TranscodeTarget;
52
import com.aelitis.azureus.core.devices.TranscodeTargetListener;
53
import com.aelitis.azureus.core.util.CopyOnWriteList;
54
import com.aelitis.azureus.util.ImportExportUtils;
60
private static final String MY_PACKAGE = "com.aelitis.azureus.core.devices.impl";
62
protected static DeviceImpl
63
importFromBEncodedMapStatic(
64
DeviceManagerImpl manager,
69
String impl = ImportExportUtils.importString( map, "_impl" );
71
if ( impl.startsWith( "." )){
73
impl = MY_PACKAGE + impl;
77
Class<DeviceImpl> cla = (Class<DeviceImpl>) Class.forName( impl );
79
Constructor<DeviceImpl> cons = cla.getDeclaredConstructor( DeviceManagerImpl.class, Map.class );
81
cons.setAccessible( true );
83
return( cons.newInstance( manager, map ));
85
}catch( Throwable e ){
87
Debug.out( "Can't construct device for " + impl, e );
89
throw( new IOException( "Construction failed: " + Debug.getNestedExceptionMessage(e)));
93
private static final String PP_REND_WORK_DIR = "tt_work_dir";
94
private static final String PP_REND_DEF_TRANS_PROF = "tt_def_trans_prof";
95
private static final String PP_REND_TRANS_REQ = "tt_req";
96
private static final String PP_REND_TRANS_CACHE = "tt_always_cache";
98
protected static final String PP_IP_ADDRESS = "rend_ip";
99
protected static final String TP_IP_ADDRESS = "DeviceUPnPImpl:ip"; // transient
100
protected static final String PP_FILTER_FILES = "rend_filter";
102
protected static final String PP_COPY_OUTSTANDING = "copy_outstanding";
103
protected static final String PP_AUTO_START = "auto_start";
105
protected static final boolean PR_AUTO_START_DEFAULT = true;
107
private static final String GENERIC = "generic";
110
private DeviceManagerImpl manager;
113
private String secondary_uid;
115
private boolean manual;
117
private boolean hidden;
118
private long last_seen;
120
private boolean online;
122
private boolean transcoding;
124
private Map<String,Object> persistent_properties = new LightHashMap<String, Object>(1);
126
private Map<Object,Object> transient_properties = new LightHashMap<Object, Object>(1);
128
private long device_files_last_mod;
129
private boolean device_files_dirty;
130
private Map<String,Map<String,?>> device_files;
132
private WeakReference<Map<String,Map<String,?>>> device_files_ref;
134
private CopyOnWriteList<TranscodeTargetListener> listeners = new CopyOnWriteList<TranscodeTargetListener>();
136
private Map<Object,String> errors = new HashMap<Object, String>();
137
private Map<Object,String> infos = new HashMap<Object, String>();
141
DeviceManagerImpl _manager,
156
DeviceManagerImpl _manager,
163
type = (int)ImportExportUtils.importLong( map, "_type" );
164
uid = ImportExportUtils.importString( map, "_uid" );
165
name = ImportExportUtils.importString( map, "_name" );
167
secondary_uid = ImportExportUtils.importString( map, "_suid" );
169
last_seen = ImportExportUtils.importLong( map, "_ls" );
170
hidden = ImportExportUtils.importBoolean( map, "_hide" );
171
manual = ImportExportUtils.importBoolean( map, "_man" );
173
if ( map.containsKey( "_pprops" )){
175
persistent_properties = (Map<String,Object>)map.get( "_pprops" );
185
String cla = this.getClass().getName();
187
if ( cla.startsWith( MY_PACKAGE )){
189
cla = cla.substring( MY_PACKAGE.length());
192
ImportExportUtils.exportString( map, "_impl", cla );
193
ImportExportUtils.exportLong( map, "_type", new Long( type ));
194
ImportExportUtils.exportString( map, "_uid", uid );
195
ImportExportUtils.exportString( map, "_name", name );
197
if ( secondary_uid != null ){
199
ImportExportUtils.exportString( map, "_suid", secondary_uid );
202
ImportExportUtils.exportLong( map, "_ls", new Long( last_seen ));
203
ImportExportUtils.exportBoolean( map, "_hide", hidden );
204
ImportExportUtils.exportBoolean( map, "_man", manual );
206
map.put( "_pprops", persistent_properties );
213
if ( type != other.type ){
215
Debug.out( "Inconsistent update operation (type)" );
220
String o_uid = other.uid;
221
String o_suid = other.secondary_uid;
223
if ( !uid.equals( o_uid )){
225
boolean borked = false;
227
if ( secondary_uid == null && o_suid == null ){
231
}else if ( secondary_uid == null && uid.equals( o_suid ) ||
232
o_suid == null && o_uid.equals( secondary_uid ) ||
233
o_suid.equals( secondary_uid )){
242
Debug.out( "Inconsistent update operation (uids)" );
249
if ( !name.equals( other.name )){
256
if ( manual != other.manual ){
258
manual = other.manual;
301
return( secondary_uid );
317
getShortDescription()
319
if ( getRendererSpecies() == DeviceMediaRenderer.RS_ITUNES ){
321
return( "iPhone, iPod, Apple TV" );
330
// note, overridden in itunes
332
if ( name.equalsIgnoreCase( "PS3" )){
334
return( DeviceMediaRenderer.RS_PS3 );
336
}else if ( name.equalsIgnoreCase( "XBox 360" )){
338
return( DeviceMediaRenderer.RS_XBOX );
340
}else if ( name.equalsIgnoreCase( "Wii" )){
342
return( DeviceMediaRenderer.RS_WII );
344
}else if ( name.equalsIgnoreCase( "Browser" )){
346
return( DeviceMediaRenderer.RS_BROWSER );
350
return( DeviceMediaRenderer.RS_OTHER );
355
getDeviceClassification()
357
// note, overridden in itunes
359
switch( getRendererSpecies()){
361
case DeviceMediaRenderer.RS_PS3:{
363
return( "sony.PS3" );
365
case DeviceMediaRenderer.RS_XBOX:{
367
return( "microsoft.XBox" );
369
case DeviceMediaRenderer.RS_WII:{
371
return( "nintendo.Wii" );
373
case DeviceMediaRenderer.RS_BROWSER:{
375
return( "browser.generic" );
377
case DeviceMediaRenderer.RS_OTHER:{
382
Debug.out( "Unknown classification" );
392
return( getDeviceClassification() == GENERIC );
424
last_seen = SystemTime.getCurrentTime();
457
boolean save_changes )
459
manager.configDirty( this, save_changes );
471
manager.requestAttention( this );
474
public TranscodeFileImpl[]
478
synchronized( this ){
480
if ( device_files == null ){
485
List<TranscodeFile> result = new ArrayList<TranscodeFile>();
487
Iterator<Map.Entry<String,Map<String,?>>> it = device_files.entrySet().iterator();
489
while( it.hasNext()){
491
Map.Entry<String,Map<String,?>> entry = it.next();
494
TranscodeFileImpl tf = new TranscodeFileImpl( this, entry.getKey(), device_files );
498
}catch( Throwable e ){
502
log( "Failed to deserialise transcode file", e );
506
return( result.toArray( new TranscodeFileImpl[ result.size() ]));
508
}catch( Throwable e ){
512
return( new TranscodeFileImpl[0] );
516
public TranscodeFileImpl
518
TranscodeProfile profile,
520
DiskManagerFileInfo file,
523
throws TranscodeException
525
TranscodeFileImpl result = null;
528
synchronized( this ){
530
if ( device_files == null ){
535
String key = ByteFormatter.encodeString( file.getDownloadHash() ) + ":" + file.getIndex() + ":" + profile.getUID();
537
if ( device_files.containsKey( key )){
540
result = new TranscodeFileImpl( this, key, device_files );
542
}catch( Throwable e ){
544
device_files.remove( key );
546
log( "Failed to deserialise transcode file", e );
550
if ( result == null ){
552
String ext = profile.getFileExtension();
554
String target_file = file.getFile().getName();
556
if ( ext != null && !no_xcode ){
558
int pos = target_file.lastIndexOf( '.' );
562
target_file = target_file.substring( 0, pos );
568
target_file = allocateUniqueFileName( target_file );
570
File output_file = getWorkingDirectory();
572
output_file = new File( output_file.getAbsoluteFile(), target_file );
574
result = new TranscodeFileImpl( this, key, profile.getName(), device_files, output_file, for_job );
576
result.setSourceFile( file );
582
result.setSourceFile( file );
584
result.setProfileName( profile.getName());
587
}catch( Throwable e ){
589
throw( new TranscodeException( "File allocation failed", e ));
592
for ( TranscodeTargetListener l: listeners ){
595
l.fileAdded( result );
597
}catch( Throwable e ){
607
allocateUniqueFileName(
610
Set<String> name_set = new HashSet<String>();
612
for (Map<String,?> entry: device_files.values()){
615
name_set.add( new File( ImportExportUtils.importString( entry, TranscodeFileImpl.KEY_FILE )).getName());
617
}catch( Throwable e ){
623
for (int i=0;i<1024;i++){
625
String test_name = i==0?str:( i + "_" + str);
627
if ( !name_set.contains( test_name )){
640
TranscodeFileImpl tf )
642
throws TranscodeException
644
File cache_file = tf.getCacheFile();
646
if ( cache_file.exists()){
648
Debug.out( "Cache file already allocated, can't rename" );
653
File source_file = tf.getSourceFile().getFile();
655
String original_name = source_file.getName();
657
int pos = original_name.indexOf('.');
664
String cf_name = cache_file.getName();
666
if ( cf_name.endsWith( original_name.substring(pos))){
672
synchronized( this ){
674
if ( device_files == null ){
679
String reverted_name = allocateUniqueFileName( original_name );
681
tf.setCacheFile( new File( cache_file.getParentFile(), reverted_name ));
683
}catch( Throwable e ){
685
throw( new TranscodeException( "File name revertion failed", e ));
689
public TranscodeFileImpl
691
TranscodeProfile profile,
692
DiskManagerFileInfo file )
695
synchronized( this ){
697
if ( device_files == null ){
702
String key = ByteFormatter.encodeString( file.getDownloadHash() ) + ":" + file.getIndex() + ":" + profile.getUID();
704
if ( device_files.containsKey( key )){
707
return( new TranscodeFileImpl( this, key, device_files ));
709
}catch( Throwable e ){
711
device_files.remove( key );
713
log( "Failed to deserialise transcode file", e );
717
}catch( Throwable e ){
723
protected TranscodeFileImpl
728
synchronized( this ){
730
if ( device_files == null ){
735
if ( device_files.containsKey( key )){
739
return( new TranscodeFileImpl( this, key, device_files ));
741
} catch( Throwable e ){
743
device_files.remove( key );
745
log( "Failed to deserialise transcode file", e );
749
}catch( Throwable e ){
756
getWorkingDirectory()
758
String result = getPersistentStringProperty( PP_REND_WORK_DIR );
760
if ( result.length() == 0 ){
762
String def_dir = COConfigurationManager.getStringParameter( "Default save path" );
764
File f = new File( def_dir, "transcodes" );
768
String name = FileUtil.convertOSSpecificChars( getName(), true );
770
for (int i=0;i<1024;i++){
772
String test_name = name + (i==0?"":("_"+i));
774
File test_file = new File( f, test_name );
776
if ( !test_file.exists()){
784
result = f.getAbsolutePath();
786
setPersistentStringProperty( PP_REND_WORK_DIR, result );
789
File f_result = new File( result );
791
if ( !f_result.exists()){
803
setPersistentStringProperty( PP_REND_WORK_DIR, directory.getAbsolutePath());
806
public TranscodeProfile[]
807
getTranscodeProfiles()
809
List<TranscodeProfile> profiles = new ArrayList<TranscodeProfile>();
811
DeviceManagerImpl dm = getManager();
813
TranscodeManagerImpl tm = dm.getTranscodeManager();
815
TranscodeProvider[] providers = tm.getProviders();
817
String classification = getDeviceClassification();
819
for ( TranscodeProvider provider: providers ){
821
TranscodeProfile[] ps = provider.getProfiles();
823
for ( TranscodeProfile p : ps ){
825
String c = p.getDeviceClassification();
829
log( "Device classification missing for " + p.getName());
832
if ( c.toLowerCase().startsWith( classification.toLowerCase())){
840
return( profiles.toArray( new TranscodeProfile[profiles.size()] ));
843
public TranscodeProfile
844
getDefaultTranscodeProfile()
846
String uid = getPersistentStringProperty( PP_REND_DEF_TRANS_PROF );
848
DeviceManagerImpl dm = getManager();
850
TranscodeManagerImpl tm = dm.getTranscodeManager();
852
TranscodeProfile profile = tm.getProfileFromUID( uid );
854
if ( profile != null ){
863
setDefaultTranscodeProfile(
864
TranscodeProfile profile )
866
if ( profile == null ){
868
removePersistentProperty( PP_REND_DEF_TRANS_PROF );
872
setPersistentStringProperty( PP_REND_DEF_TRANS_PROF, profile.getUID());
878
boolean _transcoding )
880
transcoding = _transcoding;
882
manager.deviceChanged( this, false );
888
return( transcoding );
892
getTranscodeRequirement()
894
return( getPersistentIntProperty( PP_REND_TRANS_REQ, TranscodeTarget.TRANSCODE_WHEN_REQUIRED ));
898
setTranscodeRequirement(
901
setPersistentIntProperty( PP_REND_TRANS_REQ, req );
905
getAlwaysCacheFiles()
907
return( getPersistentBooleanProperty( PP_REND_TRANS_CACHE, false ));
912
boolean always_cache )
914
setPersistentBooleanProperty( PP_REND_TRANS_CACHE, always_cache );
918
getDisplayProperties()
920
List<String[]> dp = new ArrayList<String[]>();
922
getDisplayProperties( dp );
924
String[][] res = new String[2][dp.size()];
928
for ( String[] entry: dp ){
930
res[0][pos] = entry[0];
931
res[1][pos] = entry[1];
940
getDisplayProperties(
943
addDP( dp, "TableColumn.header.name", name );
947
addDP( dp, "azbuddy.ui.table.online", online );
949
addDP( dp, "device.lastseen", last_seen==0?"":new SimpleDateFormat().format(new Date( last_seen )));
954
getTTDisplayProperties(
957
addDP( dp, "devices.xcode.working_dir", getWorkingDirectory().getAbsolutePath());
959
addDP( dp, "devices.xcode.prof_def", getDefaultTranscodeProfile());
961
addDP( dp, "devices.xcode.profs", getTranscodeProfiles());
963
int tran_req = getTranscodeRequirement();
967
if ( tran_req == TranscodeTarget.TRANSCODE_ALWAYS ){
969
tran_req_str = "device.xcode.always";
971
}else if ( tran_req == TranscodeTarget.TRANSCODE_NEVER ){
973
tran_req_str = "device.xcode.never";
976
tran_req_str = "device.xcode.whenreq";
979
addDP( dp, "device.xcode", MessageText.getString( tran_req_str ));
988
dp.add( new String[]{ name, value });
999
for ( String v: values ){
1001
value += (value.length()==0?"":",") + v;
1004
dp.add( new String[]{ name, value });
1013
dp.add( new String[]{ name, MessageText.getString( value?"GeneralView.yes":"GeneralView.no" ) });
1021
TranscodeProfile value )
1023
addDP( dp, name, value==null?"":value.getName());
1030
TranscodeProfile[] values )
1032
String[] names = new String[values.length];
1034
for (int i=0;i<values.length;i++){
1036
names[i] = values[i].getName();
1039
addDP( dp, name, names);
1051
manager.removeDevice( this );
1055
getPersistentStringProperty(
1058
return( getPersistentStringProperty( prop, "" ));
1062
getPersistentStringProperty(
1066
synchronized( persistent_properties ){
1069
byte[] value = (byte[])persistent_properties.get( prop );
1071
if ( value == null ){
1076
return( new String( value, "UTF-8" ));
1078
}catch( Throwable e ){
1080
Debug.printStackTrace(e);
1088
setPersistentStringProperty(
1092
boolean dirty = false;
1094
synchronized( persistent_properties ){
1096
String existing = getPersistentStringProperty( prop );
1098
if ( !existing.equals( value )){
1101
persistent_properties.put( prop, value.getBytes( "UTF-8" ));
1105
}catch( Throwable e ){
1107
Debug.printStackTrace(e);
1119
removePersistentProperty(
1122
boolean dirty = false;
1124
synchronized( persistent_properties ){
1126
String existing = getPersistentStringProperty( prop );
1128
if ( existing != null ){
1131
persistent_properties.remove( prop );
1135
}catch( Throwable e ){
1137
Debug.printStackTrace(e);
1150
synchronized( errors ){
1152
if ( errors.size() == 0 ){
1159
for ( String s: errors.values()){
1161
res += (res.length()==0?"":"; ") + s;
1173
boolean changed = false;
1175
if ( error == null || error.length() == 0 ){
1177
synchronized( errors ){
1179
changed = errors.remove( key ) != null;
1185
synchronized( errors ){
1187
existing = errors.put( key, error );
1190
changed = existing == null || !existing.equals( error );
1195
manager.deviceChanged( this, false );
1202
synchronized( infos ){
1204
if ( infos.size() == 0 ){
1211
for ( String s: infos.values()){
1213
res += (res.length()==0?"":"; ") + s;
1225
boolean changed = false;
1227
if ( info == null || info.length() == 0 ){
1229
synchronized( infos ){
1231
changed = infos.remove( key ) != null;
1237
synchronized( infos ){
1239
existing = infos.put( key, info );
1242
changed = existing == null || !existing.equals( info );
1247
manager.deviceChanged( this, false );
1252
getPersistentBooleanProperty(
1256
return( getPersistentStringProperty( prop, def?"true":"false" ).equals( "true" ));
1260
setPersistentBooleanProperty(
1264
setPersistentStringProperty(prop, value?"true":"false" );
1268
getPersistentIntProperty(
1272
return( Integer.parseInt( getPersistentStringProperty( prop, String.valueOf(def) )));
1276
setPersistentIntProperty(
1280
setPersistentStringProperty(prop, String.valueOf( value ));
1284
getPersistentStringListProperty(
1287
synchronized( persistent_properties ){
1290
List<byte[]> values = (List<byte[]>)persistent_properties.get( prop );
1292
if ( values == null ){
1294
return( new String[0] );
1297
String[] res = new String[values.size()];
1301
for (byte[] value: values ){
1303
res[pos++] = new String( value, "UTF-8" );
1308
}catch( Throwable e ){
1310
Debug.printStackTrace(e);
1312
return( new String[0] );
1318
setPersistentStringListProperty(
1322
boolean dirty = false;
1324
synchronized( persistent_properties ){
1327
List<byte[]> values_list = new ArrayList<byte[]>();
1329
for (String value: values ){
1331
values_list.add( value.getBytes( "UTF-8" ));
1334
persistent_properties.put( prop, values_list );
1338
}catch( Throwable e ){
1340
Debug.printStackTrace(e);
1351
setTransientProperty(
1355
synchronized( transient_properties ){
1357
if ( value == null ){
1359
transient_properties.remove( key );
1363
transient_properties.put( key, value );
1369
getTransientProperty(
1372
synchronized( transient_properties ){
1374
return( transient_properties.get( key ));
1379
setTransientProperty(
1384
synchronized( transient_properties ){
1386
Map<Object,Object> l1 = (Map<Object,Object>)transient_properties.get( key1 );
1390
if ( value == null ){
1395
l1 = new HashMap<Object, Object>();
1397
transient_properties.put( key1, l1 );
1400
if ( value == null ){
1404
if ( l1.size() == 0 ){
1406
transient_properties.remove( key1 );
1410
l1.put( key2, value );
1416
getTransientProperty(
1420
synchronized( transient_properties ){
1422
Map<Object,Object> l1 = (Map<Object,Object>)transient_properties.get( key1 );
1429
return( l1.get( key2 ));
1436
synchronized( this ){
1438
if ( device_files_dirty ){
1450
device_files_last_mod = SystemTime.getMonotonousTime();
1452
if ( device_files_ref != null ){
1454
device_files = device_files_ref.get();
1457
if ( device_files == null ){
1459
Map map = FileUtil.readResilientFile( getDeviceFile());
1461
device_files = (Map<String,Map<String,?>>)map.get( "files" );
1463
if ( device_files == null ){
1465
device_files = new HashMap<String, Map<String,?>>();
1468
device_files_ref = new WeakReference<Map<String,Map<String,?>>>( device_files );
1470
log( "Loaded device file for " + getName() + ": files=" + device_files.size());
1473
final int GC_TIME = 15000;
1483
synchronized( DeviceImpl.this ){
1485
if ( SystemTime.getMonotonousTime() - device_files_last_mod >= GC_TIME ){
1487
if ( device_files_dirty ){
1492
device_files = null;
1496
new DelayedEvent( "Device:gc2", GC_TIME, this );
1505
TranscodeFileImpl file )
1507
return( manager.getStreamURL( file ));
1512
TranscodeFileImpl file,
1513
boolean delete_contents,
1516
throws TranscodeException
1518
if ( file.isDeleted()){
1523
if ( delete_contents ){
1525
File f = file.getCacheFile();
1529
while( f.exists() && !f.delete()){
1533
log( "Failed to remove file '" + f.getAbsolutePath() + "'" );
1542
}catch( Throwable e ){
1554
synchronized( this ){
1556
if ( device_files == null ){
1562
device_files_last_mod = SystemTime.getMonotonousTime();
1565
device_files.remove( file.getKey());
1567
device_files_dirty = true;
1570
for ( TranscodeTargetListener l: listeners ){
1573
l.fileRemoved( file );
1575
}catch( Throwable e ){
1580
}catch( Throwable e ){
1582
throw( new TranscodeException( "Delete failed", e ));
1589
TranscodeFileImpl file,
1594
synchronized( this ){
1596
if ( device_files == null ){
1602
device_files_last_mod = SystemTime.getMonotonousTime();
1606
device_files_dirty = true;
1608
}catch( Throwable e ){
1610
Debug.out( "Failed to load device file", e );
1613
for ( TranscodeTargetListener l: listeners ){
1616
l.fileChanged( file, type, data );
1618
}catch( Throwable e ){
1628
device_files_dirty = false;
1633
if ( device_files == null || device_files.size()==0 ){
1635
FileUtil.deleteResilientFile( getDeviceFile());
1638
Map map = new HashMap();
1640
map.put( "files", device_files );
1642
FileUtil.writeResilientFile( getDeviceFile(), map );
1644
}catch( Throwable e ){
1646
Debug.out( "Failed to save device file", e );
1655
File dir = getDevicesDir();
1657
return( new File( dir, FileUtil.convertOSSpecificChars(getID(),false) + ".dat" ));
1665
File dir = new File(SystemProperties.getUserPath());
1667
dir = new File( dir, "devices" );
1669
if ( !dir.exists()){
1671
if ( !dir.mkdirs()){
1673
throw( new IOException( "Failed to create '" + dir + "'" ));
1680
protected DeviceManagerImpl
1688
TranscodeTargetListener listener )
1690
if (!listeners.contains(listener)) {
1691
listeners.add( listener );
1697
TranscodeTargetListener listener )
1699
listeners.remove( listener );
1714
manager.log( str, e );
1720
return( "type=" + type + ",uid=" + uid + ",name=" + name );
1725
IndentWriter writer )
1727
writer.println( getName() + "/" + getID() + "/" + type );
1733
"hidden=" + hidden +
1734
", last_seen=" + new SimpleDateFormat().format(new Date(last_seen)) +
1735
", online=" + online +
1736
", transcoding=" + transcoding );
1738
writer.println( "p_props=" + persistent_properties );
1739
writer.println( "t_props=" + transient_properties );
1741
writer.println( "errors=" + errors );
1742
writer.println( "infos=" + infos );
1751
IndentWriter writer )
1753
TranscodeFileImpl[] files = getFiles();
1760
for ( TranscodeFileImpl f: files ){
1762
if ( f.isComplete()){
1767
if ( f.isCopiedToDevice()){
1772
if ( f.isDeleted()){
1777
if ( f.isTemplate()){
1783
writer.println( "files=" + files.length + ", comp=" + complete + ", copied=" + copied + ", deleted=" + deleted + ", template=" + template );
1788
implements browseLocation
1790
private String name;