/// <summary> /// Used by /// <see cref="MediaServerDevice"/> /// to instantiate a root container. /// </summary> /// <param name="info">metadata information for the container</param> /// <returns>the new root container</returns> internal static DvRootContainer CreateRoot(MediaBuilder.container info) { info.ID = "0"; info.IdIsValid = true; DvRootContainer root = new DvRootContainer(); MediaBuilder.SetObjectProperties(root, info); root.TrackMetadataChanges = true; return(root); }
/// <summary> /// If this container changes, this method should be called /// so that the root container of the hierarchy knows that /// the state of the hierarchy has changed. /// </summary> public virtual void NotifyRootOfChange() { this.m_UpdateID++; IDvContainer c = this; while (c.Parent != null) { c = (IDvContainer)c.Parent; } if (c.GetType() == TYPE_DV_ROOT) { DvRootContainer root = (DvRootContainer)c; root.FireOnContainerChanged(this); } }
/// <summary> /// Method executes when the root container indicates that a descendent container has changed. /// Method's purpose is to cause the ContainerUpdateIDs state variable to event /// the change. /// </summary> /// <param name="sender"></param> /// <param name="thisChanged"></param> private void Sink_ContainerChanged(DvRootContainer sender, DvMediaContainer thisChanged) { this.Lock_SystemUpdateID.WaitOne(); this.ContentDirectory.Evented_SystemUpdateID = this.ContentDirectory.Evented_SystemUpdateID + 1; this.Lock_SystemUpdateID.ReleaseMutex(); this.Lock_ContainerUpdateIDs.WaitOne(); StringBuilder sb = new StringBuilder(20); sb.AppendFormat("{0}{1}{2}", thisChanged.ID, Accumulator_ContainerUpdateIDs.Delimitor, thisChanged.UpdateID); this.ContentDirectory.Evented_ContainerUpdateIDs = sb.ToString(); this.Lock_ContainerUpdateIDs.ReleaseMutex(); }
/// <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> /// Used by /// <see cref="MediaServerDevice"/> /// to instantiate a root container. /// </summary> /// <param name="info">metadata information for the container</param> /// <returns>the new root container</returns> internal static DvRootContainer CreateRoot(MediaBuilder.container info) { info.ID = "0"; info.IdIsValid = true; DvRootContainer root = new DvRootContainer(); MediaBuilder.SetObjectProperties(root, info); root.TrackMetadataChanges = true; return root; }