Randomizing a Playlist

You can randomize a playlist to change the user experience each time a client connects. The following example illustrates how to randomly order the media elements in a playlist. The Shuffle subroutine is called recursively so that all nested child elements of a media element are also randomly ordered.

Visual Basic .NET Example

Imports Microsoft.WindowsMediaServices.Interop
Imports interop_msxml

Private Sub RandomizePlylst()

  ' Declare variables.
  Dim Playlist As IXMLDOMDocument
  Dim Root_Node As IXMLDOMNode
  Dim Server As WMSServer

  Try
    ' Create the WMSServer object.
    Server = New WMSServer()

    ' Load an existing playlist.
    Playlist = Server.CreatePlaylist
    Playlist.load("c:\wmpub\wmroot\Playlist.wsx")

    ' Find the root node. The root node is the smil element.
    Root_Node = Playlist.documentElement

    ' Call the Shuffle() subroutine.
    Call Shuffle(Root_Node)

    ' Save the modified playlist.
    Playlist.save("c:\wmpub\wmroot\ModifiedPlaylist.wsx")

  Catch Err As Exception
    ' TODO: Exception handler goes here.

  Finally
    ' TODO: Clean-up code goes here.

  End Try

End Sub

Private Sub Shuffle(ByVal ParentNode As IXMLDOMNode)

  ' Declare variables.
  Dim bHasChildren As Boolean
  Dim ChildList As IXMLDOMNodeList
  Dim lNumChildren As Long
  Dim lNumChildrenInArray As Long
  Dim lIndex As Long
  Dim ChildNode As IXMLDOMNode
  Dim NextRandomChildNode As IXMLDOMNode
  Dim OldChild As IXMLDOMNode
  Dim RandomList() As IXMLDOMNode

  Try
    ' Determine whether the parent node has children. If so,
    ' the children must be shuffled. Exit the subroutine if 
    ' the parent has no children.
    bHasChildren = ParentNode.hasChildNodes
    If Not bHasChildren Then Exit Sub

    ' Retrieve the child nodes.
    ChildList = ParentNode.childNodes
    lNumChildren = ChildList.length
    If lNumChildren = 0 Then Exit Sub

    ' Dimension the RandomList() array.
    ReDim RandomList(lNumChildren - 1)

    ' Remove all of the children so that you can
    ' insert them back later in a different order.
    For lIndex = 0 To lNumChildren - 1

      ' When you remove a child, the number of children
      ' is decremented by one. Therefore, you must 
      ' delete the first child.
      ChildNode = ChildList.item(0)
      OldChild = ParentNode.removeChild(ChildNode)

      ' Recursively randomize all children of the child
      ' element.
      Call Shuffle(ChildNode)

      ' Store the children in an array.
      RandomList(lIndex) = ChildNode

      ChildNode = Nothing
    Next

    ' Initialize the random number generator.
    Randomize()

    ' Randomly insert each child into the playlist.
    lNumChildrenInArray = lNumChildren
    Do While lNumChildrenInArray > 0

      ' Randomly pick a child to insert.
      lIndex = Int((lNumChildrenInArray - 1) * Rnd())
      NextRandomChildNode = RandomList(lIndex)

      ' Append the child to the parent node.
      OldChild = Nothing
      OldChild = ParentNode.appendChild(NextRandomChildNode)

      ' Compact the child node list.
      If lIndex = lNumChildrenInArray - 1 Then
        RandomList(lIndex) = Nothing
      Else
        RandomList(lIndex) = Nothing
        RandomList(lIndex) = RandomList(lNumChildrenInArray - 1)
        RandomList(lNumChildrenInArray - 1) = Nothing
      End If

      ' Decrement the loop counter.
      lNumChildrenInArray = lNumChildrenInArray - 1

    Loop

  Catch Err As Exception
    ' TODO: Exception handler goes here.

  Finally
    ' TODO: Clean-up code goes here.

  End Try

End Sub

C# Example

using Microsoft.WindowsMediaServices.Interop;
using interop_msxml;

private void Randomize()
{
  // Declare variables.
  IXMLDOMDocument Playlist;
  IXMLDOMNode Root_Node;
  WMSServer Server;

  try
  {
    // Create the WMSServer object.
    Server = new WMSServerClass();

    // Load an existing playlist.
    Playlist = Server.CreatePlaylist();
    Playlist.load("c:\\wmpub\\wmroot\\Playlist.wsx");

    // Find the root node. The root node is the smil element.
    Root_Node = Playlist.documentElement;

    // Call the Shuffle() subroutine.
    Shuffle(Root_Node);

    // Save the modified playlist.
    Playlist.save("c:\\wmpub\\wmroot\\ModifiedPlaylist.wsx");
  }

  catch (Exception)
  {
    // TODO: Exception handler goes here.
  }

  finally
  {
    // TODO: Clean-up code goes here.
  }
}
private void Shuffle(IXMLDOMNode ParentNode)
{
  // Declare variables.
  bool bHasChildren;
  long lNumChildren;
  long lNumChildrenInArray;
  long lIndex;
  Random r = new Random();
  IXMLDOMNodeList ChildList;
  IXMLDOMNode ChildNode;
  IXMLDOMNode NextRandomChildNode;
  IXMLDOMNode OldChild;
  IXMLDOMNode[] RandomList;

  try
  {
    // Determine whether the parent node has children. If so,
    // the children must be shuffled. Exit the subroutine if 
    // the parent has no children.
    bHasChildren = ParentNode.hasChildNodes();
    if (!bHasChildren)
      return;

    // Retrieve the child nodes.
    ChildList = ParentNode.childNodes;
    lNumChildren = ChildList.length;
    if (lNumChildren == 0)
      return;

    // Dimension the RandomList() array.
    RandomList = new IXMLDOMNode[lNumChildren];

    // Remove all of the children so that you can
    // insert them back later in a different order.
    for (lIndex=0; lIndex<lNumChildren; lIndex++)
    {
      // When you remove a child, the number of children
      // is decremented by one. Therefore, you must 
      // delete the first child.
      ChildNode = ChildList[0];
      OldChild = ParentNode.removeChild(ChildNode);

      // Recursively randomize all children of the child
      // element.
      Shuffle(ChildNode);

      // Store the children in an array.
      RandomList[lIndex] = ChildNode;

      ChildNode = null;
    }

    // Randomly insert each child into the playlist.
    lNumChildrenInArray = lNumChildren;
    while (lNumChildrenInArray > 0)
    {
        
      // Randomly pick a child to insert.
      lIndex = r.Next(0, (int)(lNumChildrenInArray - 1));
      NextRandomChildNode = RandomList[lIndex];

      // Append the child to the parent node.
      OldChild = null;
      OldChild = ParentNode.appendChild(NextRandomChildNode);

      // Compact the child node list.
      if (lIndex == lNumChildrenInArray - 1) 
      {
        RandomList[lIndex] = null;
      }
      else
      {
        RandomList[lIndex] = null;
        RandomList[lIndex] = RandomList[lNumChildrenInArray - 1];
        RandomList[lNumChildrenInArray - 1] = null;
      }

      // Decrement the loop counter.
      lNumChildrenInArray = lNumChildrenInArray - 1;
    }
  }

  catch (Exception)
  {
    // TODO: Exception handler goes here.
  }
  finally
  {
    // TODO: Clean-up code 
  }
}

C++ Example

// Include header files.
#include <windows.h>
#include "wmsserver.h"
#include <atlbase.h>    // Includes CComBSTR and CComVariant.
#include <time.h>

// Declare functions.
void Randomize();
void Shuffle(IXMLDOMNode *pParentNode);


void Randomize()
{
  // Declare variables.
  IXMLDOMDocument  *pPlaylist;
  IXMLDOMNode      *pRoot_Node;
  IWMSServer       *pServer;
  CComVariant      varFile, varPath;
  VARIANT_BOOL     bVal;
  HRESULT          hr;

  // Initialize the COM library and retrieve a pointer
  // to an IWMSServer interface.
  hr = CoInitialize(NULL);
  if (FAILED(hr)) goto EXIT;

  hr = CoCreateInstance(CLSID_WMSServer,
            NULL,
            CLSCTX_ALL,
            IID_IWMSServer,
            (void **)&pServer);
  if (FAILED(hr)) goto EXIT;

  // Create a playlist object.
  hr = pServer->CreatePlaylist(&pPlaylist);
  if (FAILED(hr)) goto EXIT;

  // Load an existing playlist.
  varFile = "c:\\wmpub\\wmroot\\playlist.wsx";
  hr = pPlaylist->load(varFile, &bVal);
  if (FAILED(hr)) goto EXIT;

  // Find the root node. The root node of a server-side
  // playlist must be the smil element.
  hr = pPlaylist->get_documentElement((IXMLDOMElement**)&pRoot_Node);
  if (FAILED(hr)) goto EXIT;

  // Call the Shuffle() subroutine.
  Shuffle(pRoot_Node);

  // Save the playlist.
  varPath = "c:\\wmpub\\wmroot\\modifiedplaylist.wsx";
  hr = pPlaylist->save(varPath);
  if (FAILED(hr)) goto EXIT;

  EXIT:
    // TODO: Release temporary COM objects and uninitialize COM.

  return;
}

void Shuffle(IXMLDOMNode *pParentNode)
{

  // Declare variables.
  IXMLDOMNodeList  *pChildList;
  IXMLDOMNode      *pChildNode, *pNextRandomChildNode, *pOldChild, *pRandomList[256];
  VARIANT_BOOL     bHasChildren;
  long             lNumChildren, lNumChildrenInArray, lIndex, iFound[256];
  HRESULT          hr;
  double           r,x;
  bool             bFound = true;
  int              i;

  // Initialize the array of "found" random integers to -1.
  for (i=0; i<256; i++)
    {
      iFound[i] = -1;
    }

  // Determine whether the parent node has children. If so,
  // the children must be shuffled. Exit the subroutine if 
  // the parent has no children.
  hr = pParentNode->hasChildNodes(&bHasChildren);
  if (FAILED(hr)) goto EXIT;
  if (!bHasChildren)
    return;

  // Retrieve the child nodes.
  hr = pParentNode->get_childNodes(&pChildList);
  hr = pChildList->get_length(&lNumChildren);
  if (FAILED(hr)) goto EXIT;
  if (lNumChildren == 0)
    return;

  // Remove all of the children so that you can
  // insert them back later in a different order.
  for (lIndex=0; lIndex<lNumChildren; lIndex++)
  {
    // When you remove a child, the number of children
    // is decremented by one. Therefore, you must 
    // delete the first child.
    hr = pChildList->get_item(0, &pChildNode);
    hr = pParentNode->removeChild(pChildNode, &pOldChild);
    if (FAILED(hr)) goto EXIT;

    // Recursively randomize all children of the child
    // element.
    Shuffle(pChildNode);

    // Store the children in an array.
    pRandomList[lIndex] = pChildNode;
    
    pChildNode = NULL;
  }

  // Randomly insert each child into the playlist.
  srand((unsigned)time(NULL));
  lNumChildrenInArray = lNumChildren;

  while (lNumChildrenInArray > 0)
  {
    // Randomly pick a child to insert.
    do
    {
      r = ((double)rand() / (double)(RAND_MAX+1));
      x = (r * (lNumChildren));
      lIndex = (long)x;

      // Search for the index value.
      for (i=0; i<256; i++)
      {
        if (lIndex == iFound[i])
        {
          bFound = true;
          break;
        }
      }
      if (i == 256)
        bFound = false;
    } while (bFound == true);

    // Reset bFound for the next iteration 
    bFound = true;

    // Place the new index in the iFound array. This array
    // identifies all of the random values used.
    for (i=0; i<256; i++)
    {
      if (iFound[i] == -1)
      {
        iFound[i] = lIndex;
        break;
      }
    }

     pNextRandomChildNode = pRandomList[lIndex];

    // Append the child to the parent node.
    pOldChild = NULL;
    pParentNode->appendChild(pNextRandomChildNode, &pOldChild);

    // Decrement the loop counter.
    lNumChildrenInArray = lNumChildrenInArray - 1;
  }

  EXIT:
    // TODO: Release temporary COM objects and uninitialize COM.

  return;
}

See Also (General)

See Also (Visual Basic .NET)

See Also (C#)

See Also (C++)