/// <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();
        }
Example #4
0
 internal _DvContentDirectory(DvContentDirectory n)
 {
     Outer = n;
     S = BuildUPnPService();
 }