/// <summary> /// Constructor instantiates a properly behaving UPnP-AV /// MediaServer device that has a root container. /// </summary> /// <param name="info">general information about the MediaServer like manufacturer info</param> /// <param name="isRootDevice">true if the MediaServer has no parent UPnP device</param> /// <param name="enableHttpContentServing"> /// True, if the MediaServer should support the <see cref="MediaResource.AUTOMAPFILE"/> /// convention. /// </param> /// <param name="initialSourceProtocolInfoSet"> /// Comma separated value list of protocolInfo strings for this MediaServer as a source. /// "HTTP-GET:*:*:*" is also allowed, indicating that any HTTP-GET resource is supported on the server. /// Generally, this value should be true unless the application logic for the /// MediaServer will always create resource objects with fully pathed URIs that are /// accessible from the UPNP network. /// </param> /// <param name="initialSinkProtocolInfoSet"> /// Comma separated value list of protocolInfo strings for this MediaServer as a sink. /// This should generally be blank although it may be possible to eventually /// migrate this implementation to behave both as a MediaRenderer and a MediaServer, /// although there may be subtleties that make such a device impossible. /// </param> public MediaServerDevice( DeviceInfo info, UPnPDevice parent, bool enableHttpContentServing, string initialSourceProtocolInfoSet, string initialSinkProtocolInfoSet ) { // enable HTTP webserving of HTTP-GET resource/content? this.EnableHttp = enableHttpContentServing; // Wire up the delegate and weak event used when an HTTP transfer should be // removed from the server's list. // When an HTTP transfer completes it's progress info still needs to be // available for GetTransferProgress action for at least 30 seconds. // LifeTimeMonitor will delay the removal for such a time, and then // execute the delegate. this.LTMDelegate = new LifeTimeMonitor.LifeTimeHandler(this.Sink_OnExpired); this.m_LFT.OnExpired += LTMDelegate; // Create the UPnP device object - no servics are attached yet if (parent == null) { this.Device = UPnPDevice.CreateRootDevice(info.CacheTime, 1.0, info.LocalRootDirectory); if(info.CustomUDN!="") { this.Device.UniqueDeviceName = info.CustomUDN; } } else { Guid udn = System.Guid.NewGuid(); this.Device = UPnPDevice.CreateEmbeddedDevice(1.0, udn.ToString()); parent.AddDevice(this.Device); } // transfer basic info about the device, like serial #, manufacturer, etc. this.Device.HasPresentation = false; this.Device.StandardDeviceType = "MediaServer"; this.Device.FriendlyName = info.FriendlyName; this.Device.Manufacturer = info.Manufacturer; this.Device.ManufacturerURL = info.ManufacturerURL; this.Device.ModelName = info.ModelName; this.Device.ModelDescription = info.ModelDescription; if (info.ModelURL != null) { try { this.Device.ModelURL = new Uri(info.ModelURL); } catch { this.Device.ModelURL = null; } } this.Device.ModelNumber = info.ModelNumber; if (info.INMPR03) { this.Device.AddCustomFieldInDescription("INMPR03", "1.0", ""); } this.ConnectionManager = new DvConnectionManager(); this.ContentDirectory = new DvContentDirectory(); // Set periodic behavior for the moderated state variables. // Only state variables that do not overwrite a pending // value need an accumulator. // this.ContentDirectory.ModerationDuration_SystemUpdateID = 2; this.ContentDirectory.ModerationDuration_ContainerUpdateIDs = 2; this.ContentDirectory.Accumulator_ContainerUpdateIDs = new Accumulator_ContainerUpdateIDs(); // Determine whether the application logic actually // wants control points to have access to content management // related methods. If not, then remove those actions. if (info.AllowRemoteContentManagement==false) { this.ContentDirectory.RemoveAction_CreateObject(); this.ContentDirectory.RemoveAction_CreateReference(); this.ContentDirectory.RemoveAction_DeleteResource(); this.ContentDirectory.RemoveAction_DestroyObject(); this.ContentDirectory.RemoveAction_ImportResource(); this.ContentDirectory.RemoveAction_UpdateObject(); this.ContentDirectory.RemoveAction_ExportResource(); this.ContentDirectory.RemoveAction_GetTransferProgress(); this.ContentDirectory.RemoveAction_StopTransferResource(); } if (info.EnablePrepareForConnection==false) { this.ConnectionManager.RemoveAction_PrepareForConnection(); } if (info.EnableConnectionComplete==false) { this.ConnectionManager.RemoveAction_ConnectionComplete(); } if ( (info.EnablePrepareForConnection==false) && (info.EnableConnectionComplete==false) ) { ProtocolInfoString protInfo = new ProtocolInfoString("http-get:*:*:*"); DvConnectionManager.Enum_A_ARG_TYPE_ConnectionStatus status = DvConnectionManager.Enum_A_ARG_TYPE_ConnectionStatus.UNKNOWN; Connection newConnection = new Connection(GetConnectionID(), -1, -1, -1, protInfo, "/", OpenSource.UPnP.AV.DvConnectionManager.Enum_A_ARG_TYPE_Direction.OUTPUT, OpenSource.UPnP.AV.DvConnectionManager.Enum_A_ARG_TYPE_ConnectionStatus.UNKNOWN); this.AddConnection(newConnection); } if (info.EnableSearch == false) { this.ContentDirectory.RemoveAction_Search(); } this.m_SearchCapabilities = info.SearchCapabilities; this.m_SortCapabilities = info.SortCapabilities; //AVTransport and RendererControl not used...yet. //this.m_AVTransports = new ArrayList(); //this.m_RenderingControls = new ArrayList(); // Set values for each state variable // if (this.ConnectionManager.Evented_CurrentConnectionIDs == null) { this.ConnectionManager.Evented_CurrentConnectionIDs = ""; } // this state variable does not exist until UPNP-AV 1.1 //this.ConnectionManager.Evented_PhysicalConnections = ""; // have the device advertise the protocolInfo strings for // this media server this.UpdateProtocolInfoSet(false, initialSinkProtocolInfoSet); this.UpdateProtocolInfoSet(true, initialSourceProtocolInfoSet); // initialize state varaibles this.ContentDirectory.Evented_ContainerUpdateIDs = ""; this.ContentDirectory.Evented_SystemUpdateID = 0; this.ContentDirectory.Evented_TransferIDs = ""; // Wire up the ContentDirectory and ConnectionManager actions to actual methods // in this class that will actually do the work. this.ConnectionManager.External_ConnectionComplete = new DvConnectionManager.Delegate_ConnectionComplete(this.SinkCm_ConnectionComplete); this.ConnectionManager.External_GetCurrentConnectionIDs = new DvConnectionManager.Delegate_GetCurrentConnectionIDs(this.SinkCm_GetCurrentConnectionIDs); this.ConnectionManager.External_GetCurrentConnectionInfo = new DvConnectionManager.Delegate_GetCurrentConnectionInfo(this.SinkCm_GetCurrentConnectionInfo); this.ConnectionManager.External_GetProtocolInfo = new DvConnectionManager.Delegate_GetProtocolInfo(this.SinkCm_GetProtocolInfo); this.ConnectionManager.External_PrepareForConnection = new DvConnectionManager.Delegate_PrepareForConnection(this.SinkCm_PrepareForConnection); this.ContentDirectory.External_Browse = new DvContentDirectory.Delegate_Browse(this.SinkCd_Browse); this.ContentDirectory.External_CreateObject = new DvContentDirectory.Delegate_CreateObject(this.SinkCd_CreateObject); this.ContentDirectory.External_CreateReference = new DvContentDirectory.Delegate_CreateReference(this.SinkCd_CreateReference); this.ContentDirectory.External_DeleteResource = new DvContentDirectory.Delegate_DeleteResource(this.SinkCd_DeleteResource); this.ContentDirectory.External_DestroyObject = new DvContentDirectory.Delegate_DestroyObject(this.SinkCd_DestroyObject); this.ContentDirectory.External_ExportResource = new DvContentDirectory.Delegate_ExportResource(this.SinkCd_ExportResource); this.ContentDirectory.External_GetSearchCapabilities = new DvContentDirectory.Delegate_GetSearchCapabilities(this.SinkCd_GetSearchCapabilities); this.ContentDirectory.External_GetSortCapabilities = new DvContentDirectory.Delegate_GetSortCapabilities(this.SinkCd_GetSortCapabilities); this.ContentDirectory.External_GetSystemUpdateID = new DvContentDirectory.Delegate_GetSystemUpdateID(this.SinkCd_GetSystemUpdateID); this.ContentDirectory.External_GetTransferProgress = new DvContentDirectory.Delegate_GetTransferProgress(this.SinkCd_GetTransferProgress); this.ContentDirectory.External_ImportResource = new DvContentDirectory.Delegate_ImportResource(this.SinkCd_ImportResource); this.ContentDirectory.External_Search = new DvContentDirectory.Delegate_Search(this.SinkCd_Search); this.ContentDirectory.External_StopTransferResource = new DvContentDirectory.Delegate_StopTransferResource(this.SinkCd_StopTransferResource); this.ContentDirectory.External_UpdateObject = new DvContentDirectory.Delegate_UpdateObject(this.SinkCd_UpdateObject); // add the services to the device - voila, it's now a useful device this.Device.AddService(this.ConnectionManager); this.Device.AddService(this.ContentDirectory); // set up a virtual directory for local webserving - we'll always // have this here, even if HTTP webserving is not enabled because // it really doesn't hurt to have the virtual directory. Interlocked.Increment(ref VirtualDirCounter); m_VirtualDirName = "MediaServerContent_" + VirtualDirCounter.ToString(); this.Device.AddVirtualDirectory(m_VirtualDirName, new UPnPDevice.VirtualDirectoryHandler(this.WebServer_OnHeaderReceiveSink), new UPnPDevice.VirtualDirectoryHandler(this.WebServer_OnPacketReceiveSink)); // create the root container for this media server's content hierarchy. // Prevent control points from modifying this root container or // creating new objects in the root. // Also need to wire up internally visible events so that the MediaServer // will properly event changes in the content hierarchy. MediaBuilder.container rootInfo = new MediaBuilder.container("Root"); rootInfo.Searchable = true; rootInfo.IsRestricted = true; this.m_Root = (DvRootContainer) DvMediaBuilder.CreateRoot(rootInfo); this.m_Root.OnContainerChanged += new DvRootContainer.Delegate_OnContainerChanged(this.Sink_ContainerChanged); // At this point the device is ready to go... simply call the Start() // method to have the device advertise itself. }
/// <summary> /// Method executes when a control point invokes the ContentDirectory.Browse action. /// Depending on the input parameters, the method either returns the metadata /// for the specified object, or the method returns the metadata of all child objects /// if direct children metadata was requested and the specified object is actually /// a container. /// </summary> /// <param name="objectID">Browse the metadata or the children of this object</param> /// <param name="browseFlag">Indicate whether metadata or child object metadata is desired</param> /// <param name="filter">Comma separated value list of metadata properties indicates desired metadata properties to include in response, use * for all.</param> /// <param name="startingIndex">Given the entire possible response set, return a subset beginning with this index in the result set.</param> /// <param name="requestedCount">Given the entire possible response set, return a subset totalling no more than this many.</param> /// <param name="sortCriteria">Specify a comma-separated value list of metadata properties, with a + or - char before each property name to indicate ascending/descending order.</param> /// <param name="Result">DIDL-Lite response for desired result set.</param> /// <param name="numberReturned">Number of media objects returned in the response. 0 if browsing object metadata.</param> /// <param name="totalMatches">Total number of media objects in entire result set. 0 if browsing object metadata.</param> /// <param name="updateID">The UpdateID of the object - ignore if an object.item entry. Applies only to object.container entries.</param> private void SinkCd_Browse(System.String objectID, DvContentDirectory.Enum_A_ARG_TYPE_BrowseFlag browseFlag, System.String filter, System.UInt32 startingIndex, System.UInt32 requestedCount, System.String sortCriteria, out System.String Result, out System.UInt32 numberReturned, out System.UInt32 totalMatches, out System.UInt32 updateID) { try { numberReturned = 0; Result = ""; totalMatches = 0; if (requestedCount == 0) { requestedCount = Convert.ToUInt32(int.MaxValue); } // Get the item identified by the ID, or throw an exception // if the item doesn't exist. // IDvMedia entry = this.GetCdsEntry(objectID); // Issue a browse on the entry if it's a container and we're browing children. // Return the results in entries. Apply sorting if appropriate. // IList entries; if ((entry.IsContainer) && (browseFlag == DvContentDirectory.Enum_A_ARG_TYPE_BrowseFlag.BROWSEDIRECTCHILDREN)) { DvMediaContainer container = (DvMediaContainer) entry; if (sortCriteria.Trim() == "") { entries = container.Browse(startingIndex, requestedCount, out totalMatches); } else { MediaSorter sorter = new MediaSorter(true, sortCriteria); entries = container.BrowseSorted(startingIndex, requestedCount, sorter, out totalMatches); } numberReturned = Convert.ToUInt32(entries.Count); updateID = container.UpdateID; } else { // We're browsing an item or a container's metadata, so simply set the entry to be // the only return value. // entries = new ArrayList(); entries.Add(entry); totalMatches = 1; numberReturned = 1; IDvMedia dvMedia = (IDvMedia) entry; DvMediaContainer container = dvMedia as DvMediaContainer; if (container == null) { container = (DvMediaContainer) dvMedia.Parent; } updateID = container.UpdateID; } // Get the XML response for this result set. // Be sure to grab the list of base URLs. ArrayList properties = GetFilters(filter); string[] baseUrls = GetBaseUrlsByInterfaces(); Result = BuildXmlRepresentation(baseUrls, properties, entries); } catch (Exception e) { Exception ne = new Exception("MediaServerDevice.SinkCd_Browse()", e); throw ne; } this.m_Stats.Browse++; this.FireStatsChange(); }
/// <summary> /// Method executes when a control point invokes the ContentDirectory.GetTransferProgress action. /// This method is to return information about an ExportResource or ImportResource transfer. /// The method searches its list of pending HttpTransfers with the specified transfer ID. /// If it's found then the information is provided. Otherwise, it reports an error. /// </summary> /// <param name="TransferID">desired transfer id</param> /// <param name="TransferStatus">status of the transfer</param> /// <param name="TransferLength">total bytes transfered</param> /// <param name="TransferTotal">expected byte length of transfer</param> private void SinkCd_GetTransferProgress(System.UInt32 TransferID, out DvContentDirectory.Enum_A_ARG_TYPE_TransferStatus TransferStatus, out System.String TransferLength, out System.String TransferTotal) { if (this.m_HttpTransfers.ContainsKey(TransferID)) { HttpTransfer transfer = (HttpTransfer) this.m_HttpTransfers[TransferID]; TransferLength = transfer.Position.ToString(); TransferTotal = transfer.TransferSize.ToString(); TransferStatus = transfer.TransferStatus; } else { throw new Error_NoSuchFileTransfer("("+TransferID.ToString()+")"); } this.m_Stats.GetTransferProgress++; this.FireStatsChange(); }
internal _DvContentDirectory(DvContentDirectory n) { Outer = n; S = BuildUPnPService(); }