Example #1
0
/*----------------------------------------------------------------------
|   CMediaCrawler::OnBrowseRoot
+---------------------------------------------------------------------*/
NPT_Result
CMediaCrawler::OnBrowseRoot(PLT_ActionReference& action)
{
    NPT_String browseFlagValue;
    if (NPT_FAILED(action->GetArgumentValue("BrowseFlag", browseFlagValue))) {
        NPT_LOG_WARNING("PLT_FileMediaServer::OnBrowse - invalid arguments.");
        return NPT_FAILURE;
    }

    /* extract browseFlag */
    BrowseFlags browseFlag;
    if (NPT_FAILED(GetBrowseFlag(browseFlagValue, browseFlag))) {
        /* error */
        NPT_LOG_WARNING("PLT_FileMediaServer::OnBrowseRoot - BrowseFlag value not allowed.");
        action->SetError(402,"Invalid BrowseFlag arg.");
        return NPT_FAILURE;
    }

    if (browseFlag == BROWSEMETADATA) {
        PLT_MediaContainer item;
        item.m_Title = "Root";
        item.m_ParentID = "-1";
        item.m_ObjectID = "0";
        item.m_ChildrenCount = GetMediaServers().GetItemCount();
        item.m_ObjectClass.type = "object.container";

        /* convert item to didl */
        NPT_String filter;
        action->GetArgumentValue("Filter", filter);
        NPT_String tmp;
        NPT_CHECK_SEVERE(PLT_Didl::ToDidl(item, filter, tmp));

        /* add didl header and footer */
        NPT_String didl = didl_header + tmp + didl_footer;

        action->SetArgumentValue("Result", didl);
        action->SetArgumentValue("NumberReturned", "1");
        action->SetArgumentValue("TotalMatches", "1");

        // update ID may be wrong here, it should be the one of the container?
        action->SetArgumentValue("UpdateId", "1");
        // TODO: We need to keep track of the overall updateID of the CDS
    } else {
        NPT_String startingInd;
        NPT_String reqCount;
        NPT_String filter;

        NPT_CHECK_SEVERE(action->GetArgumentValue("StartingIndex", startingInd));
        NPT_CHECK_SEVERE(action->GetArgumentValue("RequestedCount", reqCount));   
        NPT_CHECK_SEVERE(action->GetArgumentValue("Filter", filter));

        unsigned long start_index, req_count;
        if (NPT_FAILED(startingInd.ToInteger(start_index)) ||
            NPT_FAILED(reqCount.ToInteger(req_count))) {
            return NPT_FAILURE;
        }   
                    
        unsigned long cur_index = 0;
        unsigned long num_returned = 0;
        unsigned long total_matches = 0;
        //unsigned long update_id = 0;
        PLT_MediaContainer item;
        NPT_String tmp;
        NPT_String didl = didl_header;

		{
			// populate a list of containers (one container per known servers)
			const NPT_Lock<PLT_DeviceDataReferenceList>& devices = GetMediaServers();
			NPT_AutoLock lock((NPT_Mutex&)devices);

			NPT_Lock<PLT_DeviceDataReferenceList>::Iterator entry = devices.GetFirstItem();
			while (entry) {
				PLT_DeviceDataReference device = (*entry);
				item.m_Title = device->GetFriendlyName();
				item.m_ObjectID = FormatObjectId(device->GetUUID(), "0");
				item.m_ParentID = "0";
				item.m_ObjectClass.type = "object.container";

				if ((cur_index >= start_index) && ((num_returned < req_count) || (req_count == 0))) {
					NPT_CHECK_SEVERE(PLT_Didl::ToDidl(item, filter, tmp));

					didl += tmp;
					num_returned++;
				}
				cur_index++;
				total_matches++;  

				++entry;
			}
		}

        didl += didl_footer;

        action->SetArgumentValue("Result", didl);
        action->SetArgumentValue("NumberReturned", NPT_String::FromInteger(num_returned));
        action->SetArgumentValue("TotalMatches", NPT_String::FromInteger(total_matches));
        action->SetArgumentValue("UpdateId", "1");
    }

    return NPT_SUCCESS;
}
Example #2
0
/*----------------------------------------------------------------------
|   CMediaCrawler::OnBrowseDevice
+---------------------------------------------------------------------*/
NPT_Result
CMediaCrawler::OnBrowseDevice(PLT_ActionReference&          action, 
                              const char*                   server_uuid, 
                              const char*                   server_object_id, 
                              const NPT_HttpRequestContext& context)
{
    NPT_Result res;
    PLT_DeviceDataReference device;

    {
        // look for device first
        const NPT_Lock<PLT_DeviceDataReferenceList>& devices = GetMediaServers();
        NPT_AutoLock lock((NPT_Mutex&)devices);

        if (NPT_FAILED(NPT_ContainerFind(devices, PLT_DeviceDataFinder(server_uuid), device))) {
            /* error */
            NPT_LOG_WARNING("CMediaCrawler::OnBrowseDevice - device not found.");
            action->SetError(701, "No Such Object.");
            return NPT_FAILURE;
        } 
    }

    // look for args and convert them
    NPT_String browseFlagValue;
    NPT_String startingInd;
    NPT_String reqCount;
    NPT_String filter;
    NPT_String sort;

    NPT_CHECK_SEVERE(action->GetArgumentValue("BrowseFlag", browseFlagValue));
    NPT_CHECK_SEVERE(action->GetArgumentValue("StartingIndex", startingInd));
    NPT_CHECK_SEVERE(action->GetArgumentValue("RequestedCount", reqCount));   
    NPT_CHECK_SEVERE(action->GetArgumentValue("Filter", filter));
    NPT_CHECK_SEVERE(action->GetArgumentValue("SortCriteria", sort));

    unsigned long start_index, req_count;
    if (NPT_FAILED(startingInd.ToInteger(start_index)) ||
        NPT_FAILED(reqCount.ToInteger(req_count))) {
        return NPT_FAILURE;
    } 

    // create a container for our result
    // this will be filled in by OnBrowseResponse
    CMediaCrawlerBrowseInfoReference browse_info(new CMediaCrawlerBrowseInfo());
    browse_info->shared_var.SetValue(0);

    // send off the browse packet.  Note that this will
    // not block.  The shared variable is used to block
    // until the response has been received.
    res = Browse(device,
        server_object_id,
        start_index,
        req_count,
        (browseFlagValue == "BrowseMetadata")?1:0,
        filter,
        sort,
        new CMediaCrawlerBrowseInfoReference(browse_info));		
    NPT_CHECK_SEVERE(res);

    // wait 30 secs for response
    res = browse_info->shared_var.WaitUntilEquals(1, 30000);
    NPT_CHECK_SEVERE(res);

    // did the browse fail?
    if (NPT_FAILED(browse_info->res)) {
        action->SetError(browse_info->code, "");
        return NPT_FAILURE;
    }    
   
    action->SetArgumentValue("Result", UpdateDidl(server_uuid, browse_info->didl, &context.GetLocalAddress()));
    action->SetArgumentValue("NumberReturned", browse_info->nr);
    action->SetArgumentValue("TotalMatches", browse_info->tm);
    action->SetArgumentValue("UpdateId", browse_info->uid);
    action->SetArgumentValue("ObjectID", FormatObjectId(server_uuid, browse_info->object_id));
    
    return NPT_SUCCESS;
}
/*----------------------------------------------------------------------
|   NPT_BufferedInputStream::Read
+---------------------------------------------------------------------*/
NPT_Result 
NPT_BufferedInputStream::Read(void*     buffer, 
                              NPT_Size  bytes_to_read, 
                              NPT_Size* bytes_read)
{
    NPT_Result result = NPT_SUCCESS;
    NPT_Size   total_read = 0;
    NPT_Size   buffered;

    // check for a possible shortcut
    if (bytes_to_read == 0) return NPT_SUCCESS;

    // skip a newline char if needed
    if (m_SkipNewline) {
        m_SkipNewline = false;
        result = Read(buffer, 1, NULL);
        if (NPT_FAILED(result)) goto done;
        NPT_Byte c = *(NPT_Byte*)buffer;
        if (c != '\n') {
            buffer = (void*)((NPT_Byte*)buffer+1);
            --bytes_to_read;
            total_read = 1;
        }
    }

    // compute how much is buffered
    buffered = m_Buffer.valid-m_Buffer.offset;
    if (bytes_to_read > buffered) {
        // there is not enough in the buffer, take what's there
        if (buffered) {
            NPT_CopyMemory(buffer, 
                           m_Buffer.data + m_Buffer.offset,
                           buffered);
            buffer = (void*)((NPT_Byte*)buffer+buffered);
            m_Buffer.offset += buffered;
            bytes_to_read -= buffered;
            total_read += buffered;
            goto done;
        }
        
        // read the rest from the source
        if (m_Buffer.size == 0) {
            // unbuffered mode, read directly into the supplied buffer
            if (m_Buffer.data != NULL) ReleaseBuffer(); // cleanup if necessary
            NPT_Size local_read = 0;
            result = m_Source->Read(buffer, bytes_to_read, &local_read);
            if (NPT_SUCCEEDED(result)) {
                total_read += local_read; 
            }
            goto done;
        } else {
            // refill the buffer
            result = FillBuffer();
            if (NPT_FAILED(result)) goto done;
            buffered = m_Buffer.valid;
            if (bytes_to_read > buffered) bytes_to_read = buffered;
        }
    }

    // get what we can from the buffer
    if (bytes_to_read) {
        NPT_CopyMemory(buffer, 
                       m_Buffer.data + m_Buffer.offset,
                       bytes_to_read);
        m_Buffer.offset += bytes_to_read;
        total_read += bytes_to_read;
    }
    
done:
    m_Position += total_read;
    if (bytes_read) *bytes_read = total_read;
    if (result == NPT_ERROR_EOS) { 
        m_Eos = true;
        if (total_read != 0) {
            // we have reached the end of the stream, but we have read
            // some chars, so do not return EOS now
            return NPT_SUCCESS;
        }
    }
    return result;
}
Example #4
0
/*----------------------------------------------------------------------
|   CUPnPRenderer::UpdateState
+---------------------------------------------------------------------*/
void
CUPnPRenderer::UpdateState()
{
    NPT_AutoLock lock(m_state);

    PLT_Service *avt;

    if (NPT_FAILED(FindServiceByType("urn:schemas-upnp-org:service:AVTransport:1", avt)))
        return;

    /* don't update state while transitioning */
    NPT_String state;
    avt->GetStateVariableValue("TransportState", state);
    if(state == "TRANSITIONING")
        return;

    avt->SetStateVariable("TransportStatus", "OK");

    if (g_application.IsPlaying() || g_application.IsPaused()) {
        avt->SetStateVariable("NumberOfTracks", "1");
        avt->SetStateVariable("CurrentTrack", "1");

        CStdString buffer = g_infoManager.GetCurrentPlayTime(TIME_FORMAT_HH_MM_SS);
        avt->SetStateVariable("RelativeTimePosition", buffer.c_str());
        avt->SetStateVariable("AbsoluteTimePosition", buffer.c_str());

        buffer = g_infoManager.GetDuration(TIME_FORMAT_HH_MM_SS);
        if (buffer.length() > 0) {
          avt->SetStateVariable("CurrentTrackDuration", buffer.c_str());
          avt->SetStateVariable("CurrentMediaDuration", buffer.c_str());
        } else {
          avt->SetStateVariable("CurrentTrackDuration", "00:00:00");
          avt->SetStateVariable("CurrentMediaDuration", "00:00:00");
        }

    } else if (g_windowManager.GetActiveWindow() == WINDOW_SLIDESHOW) {
        avt->SetStateVariable("TransportState", "PLAYING");

        avt->SetStateVariable("AVTransportURI" , g_infoManager.GetPictureLabel(SLIDE_FILE_PATH));
        avt->SetStateVariable("CurrentTrackURI", g_infoManager.GetPictureLabel(SLIDE_FILE_PATH));
        avt->SetStateVariable("TransportPlaySpeed", "1");

        CGUIWindowSlideShow *slideshow = (CGUIWindowSlideShow *)g_windowManager.GetWindow(WINDOW_SLIDESHOW);
        if (slideshow)
        {
          CStdString index;
          index.Format("%d", slideshow->NumSlides());
          avt->SetStateVariable("NumberOfTracks", index.c_str());
          index.Format("%d", slideshow->CurrentSlide());
          avt->SetStateVariable("CurrentTrack", index.c_str());

        }

        avt->SetStateVariable("CurrentTrackMetadata", "");
        avt->SetStateVariable("AVTransportURIMetaData", "");

    } else {
        avt->SetStateVariable("TransportState", "STOPPED");
        avt->SetStateVariable("TransportPlaySpeed", "1");
        avt->SetStateVariable("NumberOfTracks", "0");
        avt->SetStateVariable("CurrentTrack", "0");
        avt->SetStateVariable("RelativeTimePosition", "00:00:00");
        avt->SetStateVariable("AbsoluteTimePosition", "00:00:00");
        avt->SetStateVariable("CurrentTrackDuration", "00:00:00");
        avt->SetStateVariable("CurrentMediaDuration", "00:00:00");
    }
}
/*----------------------------------------------------------------------
|   NPT_BufferedInputStream::ReadLine
+---------------------------------------------------------------------*/
NPT_Result
NPT_BufferedInputStream::ReadLine(char*     buffer, 
                                  NPT_Size  size, 
                                  NPT_Size* chars_read,
                                  bool      break_on_cr)
{
    NPT_Result result = NPT_SUCCESS;
    char*      buffer_start = buffer;
    char*      buffer_end   = buffer_start+size-1;
    bool       skip_newline = false;

    // check parameters
    if (buffer == NULL || size < 1) {
        if (chars_read) *chars_read = 0;
        return NPT_ERROR_INVALID_PARAMETERS;
    }

    // read until EOF or newline
    for (;;) {
        while (m_Buffer.offset != m_Buffer.valid) {
            // there is some data left in the buffer
            NPT_Byte c = m_Buffer.data[m_Buffer.offset++];
            if (c == '\r') {
                if (break_on_cr) {
                    skip_newline = true;
                    goto done;
                }
            } else if (c == '\n') {
                if (m_SkipNewline && (buffer == buffer_start)) {
                    continue;
                }
                goto done;
            } else {
                if (buffer == buffer_end) {
                    result = NPT_ERROR_NOT_ENOUGH_SPACE;
                    goto done;
                }
                *buffer++ = c;
            }
        }

        if (m_Buffer.size == 0 && !m_Eos) {
            // unbuffered mode
            if (m_Buffer.data != NULL) ReleaseBuffer();
            while (NPT_SUCCEEDED(result = m_Source->Read(buffer, 1, NULL))) {
                if (*buffer == '\r') {
                    if (break_on_cr) {
                        skip_newline = true;
                        goto done;
                    }
                } else if (*buffer == '\n') {
                    goto done;
                } else {
                    if (buffer == buffer_end) {
                        result = NPT_ERROR_NOT_ENOUGH_SPACE;
                        goto done;
                    }
                    ++buffer;
                }
            }
        } else {
            // refill the buffer
            result = FillBuffer();
        }
        if (NPT_FAILED(result)) goto done;
    }

done:
    // update the newline skipping state
    m_SkipNewline = skip_newline;

    // NULL-terminate the line
    *buffer = '\0';

    // return what we have
    m_Position += (NPT_Size)(buffer-buffer_start);
    if (chars_read) *chars_read = (NPT_Size)(buffer-buffer_start);
    if (result == NPT_ERROR_EOS) {
        m_Eos = true;
        if (buffer != buffer_start) {
            // we have reached the end of the stream, but we have read
            // some chars, so do not return EOS now
            return NPT_SUCCESS;
        }
    }
    return result;
}
NPT_Result
GPAC_MediaRenderer::OnAction(PLT_ActionReference&          action, 
                            const PLT_HttpRequestContext& context)
{
    NPT_COMPILER_UNUSED(context);

    /* parse the action name */
    NPT_String name = action->GetActionDesc().GetName();

	m_ip_src = context.GetRemoteAddress().GetIpAddress().ToString();

	/* Is it a ConnectionManager Service Action ? */
    if (name.Compare("GetCurrentConnectionIDs", true) == 0) {
        if (NPT_FAILED(action->SetArgumentsOutFromStateVariable())) {
            return NPT_FAILURE;
        }
        return NPT_SUCCESS;
    }
    if (name.Compare("GetProtocolInfo", true) == 0) {
        if (NPT_FAILED(action->SetArgumentsOutFromStateVariable())) {
            return NPT_FAILURE;
        }
        return NPT_SUCCESS;
    }    
    if (name.Compare("GetCurrentConnectionInfo", true) == 0) {
        return OnGetCurrentConnectionInfo(action);
    }  
    if (name.Compare("StopForMigration", true) == 0) {
		NPT_String res = m_pUPnP->OnMigrate();
        m_pMigrationService->SetStateVariable("MigrationStatus", "OK");
        m_pMigrationService->SetStateVariable("MigrationMetaData", res);

		if (NPT_FAILED(action->SetArgumentsOutFromStateVariable())) {
            return NPT_FAILURE;
        }
        return NPT_SUCCESS;
    }  

    /* Is it a AVTransport Service Action ? */

    // since all actions take an instance ID and we only support 1 instance
    // verify that the Instance ID is 0 and return an error here now if not
    NPT_String serviceType = action->GetActionDesc().GetService()->GetServiceType();
    if (serviceType.Compare("urn:schemas-upnp-org:service:AVTransport:1", true) == 0) {
        if (NPT_FAILED(action->VerifyArgumentValue("InstanceID", "0"))) {
            action->SetError(802,"Not valid InstanceID.");
            return NPT_FAILURE;
        }
    }

    if (name.Compare("GetCurrentTransportActions", true) == 0) {
        if (NPT_FAILED(action->SetArgumentsOutFromStateVariable())) {
            return NPT_FAILURE;
        }
        return NPT_SUCCESS;
    }
    if (name.Compare("GetDeviceCapabilities", true) == 0) {
        if (NPT_FAILED(action->SetArgumentsOutFromStateVariable())) {
            return NPT_FAILURE;
        }
        return NPT_SUCCESS;
    }
    if (name.Compare("GetMediaInfo", true) == 0) {
        if (NPT_FAILED(action->SetArgumentsOutFromStateVariable())) {
            return NPT_FAILURE;
        }
        return NPT_SUCCESS;
    }
    if (name.Compare("GetPositionInfo", true) == 0) {
		if (m_pUPnP->m_pTerm->root_scene) {
			char szVal[100];

			m_pAVService->SetStateVariable("CurrentTrack", "0");
			format_time_string(szVal, m_Duration);
			m_pAVService->SetStateVariable("CurrentTrackDuration", szVal);

			m_pAVService->SetStateVariable("CurrentTrackMetadata", "");
			m_pAVService->SetStateVariable("CurrentTrackURI", "");
			format_time_string(szVal, m_Time);
			m_pAVService->SetStateVariable("RelativeTimePosition", szVal); 
			m_pAVService->SetStateVariable("AbsoluteTimePosition", szVal);
			m_pAVService->SetStateVariable("RelativeCounterPosition", "2147483647"); // means NOT_IMPLEMENTED
			m_pAVService->SetStateVariable("AbsoluteCounterPosition", "2147483647"); // means NOT_IMPLEMENTED
		} else {
			if (NPT_FAILED(action->SetArgumentsOutFromStateVariable())) {
				return NPT_FAILURE;
			}
		}
        return NPT_SUCCESS;
    }
    if (name.Compare("GetTransportInfo", true) == 0) {
        if (NPT_FAILED(action->SetArgumentsOutFromStateVariable())) {
            return NPT_FAILURE;
        }
        return NPT_SUCCESS;
    }
    if (name.Compare("GetTransportSettings", true) == 0) {
        if (NPT_FAILED(action->SetArgumentsOutFromStateVariable())) {
            return NPT_FAILURE;
        }
        return NPT_SUCCESS;
    }
    if (name.Compare("Next", true) == 0) {
        return OnNext(action);
    }
    if (name.Compare("Pause", true) == 0) {
        return OnPause(action);
    }
    if (name.Compare("Play", true) == 0) {
        return OnPlay(action);
    }
    if (name.Compare("Previous", true) == 0) {
        return OnPrevious(action);
    }
    if (name.Compare("Seek", true) == 0) {
        return OnSeek(action);
    }
    if (name.Compare("Stop", true) == 0) {
        return OnStop(action);
    }
    if (name.Compare("SetAVTransportURI", true) == 0) {
        return OnSetAVTransportURI(action);
    }
    if (name.Compare("SetPlayMode", true) == 0) {
        return OnSetPlayMode(action);
    }

    /* Is it a RendererControl Service Action ? */
    if (serviceType.Compare("urn:schemas-upnp-org:service:RenderingControl:1", true) == 0) {
        /* we only support master channel */
        if (NPT_FAILED(action->VerifyArgumentValue("Channel", "Master"))) {
            action->SetError(402,"Invalid Args.");
            return NPT_FAILURE;
        }
    }

    if ((name.Compare("GetVolume", true) == 0) || (name.Compare("GetVolumeRangeDB", true) == 0) ) {
        NPT_CHECK_SEVERE(action->SetArgumentsOutFromStateVariable());
        return NPT_SUCCESS;
    }

    if (name.Compare("GetMute", true) == 0) {
        NPT_CHECK_SEVERE(action->SetArgumentsOutFromStateVariable());
        return NPT_SUCCESS;
    }

    if (name.Compare("SetVolume", true) == 0) {
          return OnSetVolume(action);
    }
    if (name.Compare("SetVolumeDB", true) == 0) {
          return OnSetVolumeDB(action);
    }

    if (name.Compare("SetMute", true) == 0) {
          return OnSetMute(action);
    }

    action->SetError(401,"No Such Action.");
    return NPT_FAILURE;
}
/*----------------------------------------------------------------------
|   PLT_MediaServer::OnSearch
+---------------------------------------------------------------------*/
NPT_Result
PLT_MediaServer::OnSearch(PLT_ActionReference&          action, 
                          const PLT_HttpRequestContext& context)
{
    NPT_COMPILER_UNUSED(context);

    NPT_Result res;
    NPT_String container_id;
    NPT_String search;
	NPT_String filter;
    NPT_String start;
    NPT_String count;
    NPT_String sort;
    NPT_List<NPT_String> sort_list;

    if (NPT_FAILED(action->GetArgumentValue("ContainerId", container_id)) ||
        NPT_FAILED(action->GetArgumentValue("SearchCriteria", search)) || 
		NPT_FAILED(action->GetArgumentValue("Filter",  filter)) ||
        NPT_FAILED(action->GetArgumentValue("StartingIndex",  start)) || 
        NPT_FAILED(action->GetArgumentValue("RequestedCount",  count)) || 
        NPT_FAILED(action->GetArgumentValue("SortCriteria",  sort))) {
        NPT_LOG_WARNING("Missing arguments");
        action->SetError(402, "Invalid args");
        return NPT_SUCCESS;
    }
    
    /* convert index and counts to int */
    NPT_UInt32 starting_index, requested_count;
    if (NPT_FAILED(start.ToInteger(starting_index)) ||
        NPT_FAILED(count.ToInteger(requested_count))) {       
        NPT_LOG_WARNING_2("Invalid arguments (%s, %s)", 
            start.GetChars(), count.GetChars());
        action->SetError(402, "Invalid args");
        return NPT_FAILURE;
    }
    
    /* parse sort criteria */
    if (NPT_FAILED(ParseSort(sort, sort_list))) {
        NPT_LOG_WARNING_1("Unsupported or invalid sort criteria error (%s)", 
            sort.GetChars());
        action->SetError(709, "Unsupported or invalid sort criteria error");
        return NPT_FAILURE;
    }
    
    NPT_LOG_INFO_5("Processing Search from %s with id=\"%s\", search=\"%s\", start=%d, count=%d", 
                   (const char*)context.GetRemoteAddress().GetIpAddress().ToString(),
                   (const char*)container_id,
                   (const char*)search,
                   starting_index,
                   requested_count);
                       
    if (search.IsEmpty() || search == "*") {
        res = OnBrowseDirectChildren(
            action, 
            container_id,
			filter,
            starting_index, 
            requested_count, 
            sort, 
            context);
    } else {
        res = OnSearchContainer(
            action, 
            container_id, 
            search, 
			filter,
            starting_index, 
            requested_count, 
            sort,
            context);
    }

    if (NPT_FAILED(res) && (action->GetErrorCode() == 0)) {
        action->SetError(800, "Internal error");
    }

    return res;
}
/*----------------------------------------------------------------------
|   PLT_MediaServer::OnBrowse
+---------------------------------------------------------------------*/
NPT_Result
PLT_MediaServer::OnBrowse(PLT_ActionReference&          action, 
                          const PLT_HttpRequestContext& context)
{
    NPT_Result res;
    NPT_String object_id;
    NPT_String browse_flag_val;    
    NPT_String filter;
    NPT_String start;
    NPT_String count;
    NPT_String sort;
    NPT_List<NPT_String> sort_list;

    if (NPT_FAILED(action->GetArgumentValue("ObjectId", object_id)) || 
        NPT_FAILED(action->GetArgumentValue("BrowseFlag",  browse_flag_val)) || 
        NPT_FAILED(action->GetArgumentValue("Filter",  filter)) || 
        NPT_FAILED(action->GetArgumentValue("StartingIndex",  start)) || 
        NPT_FAILED(action->GetArgumentValue("RequestedCount",  count)) || 
        NPT_FAILED(action->GetArgumentValue("SortCriteria",  sort))) {
        NPT_LOG_WARNING("Missing arguments");
        action->SetError(402, "Invalid args");
        return NPT_SUCCESS;
    }

    /* extract flag */
    BrowseFlags flag;
    if (NPT_FAILED(ParseBrowseFlag(browse_flag_val, flag))) {
        /* error */
        NPT_LOG_WARNING_1("BrowseFlag value not allowed (%s)", (const char*)browse_flag_val);
        action->SetError(402, "Invalid args");
        return NPT_SUCCESS;
    }
    
    /* convert index and counts to int */
    NPT_UInt32 starting_index, requested_count;
    if (NPT_FAILED(start.ToInteger(starting_index)) ||
        NPT_FAILED(count.ToInteger(requested_count)) ||
        PLT_Didl::ConvertFilterToMask(filter) == 0) {       
        NPT_LOG_WARNING_3("Invalid arguments (%s, %s, %s)", 
            start.GetChars(), count.GetChars(), filter.GetChars());
        action->SetError(402, "Invalid args");
        return NPT_FAILURE;
    }
    
    /* parse sort criteria for validation */
    if (NPT_FAILED(ParseSort(sort, sort_list))) {
        NPT_LOG_WARNING_1("Unsupported or invalid sort criteria error (%s)", 
            sort.GetChars());
        action->SetError(709, "Unsupported or invalid sort criteria error");
        return NPT_FAILURE;
    }
    
    NPT_LOG_INFO_6("Processing %s from %s with id=\"%s\", filter=\"%s\", start=%d, count=%d", 
                   (const char*)browse_flag_val, 
                   (const char*)context.GetRemoteAddress().GetIpAddress().ToString(),
                   (const char*)object_id,
                   (const char*)filter,
                   starting_index,
                   requested_count);

    /* Invoke the browse function */
    if (flag == BROWSEMETADATA) {
        res = OnBrowseMetadata(
            action, 
            object_id, 
            filter, 
            starting_index, 
            requested_count, 
            sort, 
            context);
    } else {
        res = OnBrowseDirectChildren(
            action, 
            object_id, 
            filter, 
            starting_index, 
            requested_count, 
            sort, 
            context);
    }

    if (NPT_FAILED(res) && (action->GetErrorCode() == 0)) {
        action->SetError(800, "Internal error");
    }

    return res;
}
/*----------------------------------------------------------------------
|   PLT_FileMediaServer::OnBrowseDirectChildren
+---------------------------------------------------------------------*/
NPT_Result
PLT_FileMediaServer::OnBrowseDirectChildren(PLT_ActionReference& action, 
                                            const char*          object_id, 
                                            NPT_SocketInfo*      info /* = NULL */)
{
    /* locate the file from the object ID */
    NPT_String dir;
    if (NPT_FAILED(GetFilePath(object_id, dir))) {
        /* error */
        NPT_LOG_WARNING("PLT_FileMediaServer::OnBrowse - ObjectID not found.");
        action->SetError(701, "No Such Object.");
        return NPT_FAILURE;
    }

    /* retrieve the item type */
    NPT_DirectoryEntryInfo entry_info;
    NPT_Result res = NPT_DirectoryEntry::GetInfo(dir, entry_info);
    if (NPT_FAILED(res)) {
        /* Object does not exist */
        action->SetError(800, "Can't retrieve info " + dir);
        return NPT_FAILURE;
    }

    if (entry_info.type != NPT_DIRECTORY_TYPE) {
        /* error */
        NPT_LOG_WARNING("PLT_FileMediaServer::OnBrowse - BROWSEDIRECTCHILDREN not allowed on an item.");
        action->SetError(710, "item is not a container.");
        return NPT_FAILURE;
    }

    NPT_String filter;
    NPT_String startingInd;
    NPT_String reqCount;

    NPT_CHECK_SEVERE(action->GetArgumentValue("Filter", filter));
    NPT_CHECK_SEVERE(action->GetArgumentValue("StartingIndex", startingInd));
    NPT_CHECK_SEVERE(action->GetArgumentValue("RequestedCount", reqCount));   

    unsigned long start_index, req_count;
    if (NPT_FAILED(startingInd.ToInteger(start_index)) ||
        NPT_FAILED(reqCount.ToInteger(req_count))) {
        return NPT_FAILURE;
    }

    NPT_String path = dir;
    if (!path.EndsWith(m_DirDelimiter)) {
        path += m_DirDelimiter;
    }

    /* start iterating through the directory */
    NPT_Directory directory(path);
    NPT_String    entryName;
    res = directory.GetNextEntry(entryName);
    if (NPT_FAILED(res)) {
        NPT_LOG_WARNING_1("PLT_FileMediaServer::OnBrowseDirectChildren - failed to open dir %s", (const char*) path);
        return res;
    }

    unsigned long cur_index = 0;
    unsigned long num_returned = 0;
    unsigned long total_matches = 0;
    //unsigned long update_id = 0;
    NPT_String didl = didl_header;
    PLT_MediaObjectReference item;
    do {
        item = BuildFromFilePath(path + entryName, true, info);
        if (!item.IsNull()) {
            if ((cur_index >= start_index) && ((num_returned < req_count) || (req_count == 0))) {
                NPT_String tmp;
                NPT_CHECK_SEVERE(PLT_Didl::ToDidl(*item.AsPointer(), filter, tmp));

                didl += tmp;
                num_returned++;
            }
            cur_index++;
            total_matches++;        
        }
        res = directory.GetNextEntry(entryName);
    } while (NPT_SUCCEEDED(res));

    didl += didl_footer;

    NPT_CHECK_SEVERE(action->SetArgumentValue("Result", didl));

    NPT_CHECK_SEVERE(action->SetArgumentValue("NumberReturned", NPT_String::FromInteger(num_returned)));

    NPT_CHECK_SEVERE(action->SetArgumentValue("TotalMatches", NPT_String::FromInteger(total_matches)));

    NPT_CHECK_SEVERE(action->SetArgumentValue("UpdateId", "1"));

    return NPT_SUCCESS;
}