/***************************************************************** | | Platinum - Miccro Media Controller | | Copyright (c) 2004-2010, Plutinosoft, LLC. | All rights reserved. | http://www.plutinosoft.com | | This program is free software; you can redistribute it and/or | modify it under the terms of the GNU General Public License | as published by the Free Software Foundation; either version 2 | of the License, or (at your option) any later version. | | OEMs, ISVs, VARs and other distributors that combine and | distribute commercially licensed software with Platinum software | and do not wish to distribute the source code for the commercially | licensed software under version 2, or (at your option) any later | version, of the GNU General Public License (the "GPL") must enter | into a commercial license agreement with Plutinosoft, LLC. | licensing@plutinosoft.com | | This program is distributed in the hope that it will be useful, | but WITHOUT ANY WARRANTY; without even the implied warranty of | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | GNU General Public License for more details. | | You should have received a copy of the GNU General Public License | along with this program; see the file LICENSE.txt. If not, write to | the Free Software Foundation, Inc., | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | http://www.gnu.org/licenses/gpl-2.0.html | ****************************************************************/ /*---------------------------------------------------------------------- | includes +---------------------------------------------------------------------*/ #include "PltMicroMediaController.h" #include "PltLeaks.h" #include "PltDownloader.h" #include #include #include //NPT_SET_LOCAL_LOGGER("platinum.tests.micromediacontroller") /*---------------------------------------------------------------------- | PLT_MicroMediaController::PLT_MicroMediaController +---------------------------------------------------------------------*/ PLT_MicroMediaController::PLT_MicroMediaController(PLT_CtrlPointReference& ctrlPoint) : PLT_SyncMediaBrowser(ctrlPoint), PLT_MediaController(ctrlPoint) { // create the stack that will be the directory where the // user is currently browsing. // push the root directory onto the directory stack. m_CurBrowseDirectoryStack.Push("0"); PLT_MediaController::SetDelegate(this); } /*---------------------------------------------------------------------- | PLT_MicroMediaController::PLT_MicroMediaController +---------------------------------------------------------------------*/ PLT_MicroMediaController::~PLT_MicroMediaController() { } /* * Remove trailing white space from a string */ static void strchomp(char* str) { if (!str) return; char* e = str+NPT_StringLength(str)-1; while (e >= str && *e) { if ((*e != ' ') && (*e != '\t') && (*e != '\r') && (*e != '\n')) { *(e+1) = '\0'; break; } --e; } } /*---------------------------------------------------------------------- | PLT_MicroMediaController::ChooseIDFromTable +---------------------------------------------------------------------*/ /* * Presents a list to the user, allows the user to choose one item. * * Parameters: * PLT_StringMap: A map that contains the set of items from * which the user should choose. The key should be a unique ID, * and the value should be a string describing the item. * returns a NPT_String with the unique ID. */ const char* PLT_MicroMediaController::ChooseIDFromTable(PLT_StringMap& table) { printf("Select one of the following:\n"); NPT_List entries = table.GetEntries(); if (entries.GetItemCount() == 0) { printf("None available\n"); } else { // display the list of entries NPT_List::Iterator entry = entries.GetFirstItem(); int count = 0; while (entry) { printf("%d)\t%s (%s)\n", ++count, (const char*)(*entry)->GetValue(), (const char*)(*entry)->GetKey()); ++entry; } int index, watchdog = 3; char buffer[1024]; // wait for input while (watchdog > 0) { fgets(buffer, 1024, stdin); strchomp(buffer); if (1 != sscanf(buffer, "%d", &index)) { printf("Please enter a number\n"); } else if (index < 0 || index > count) { printf("Please choose one of the above, or 0 for none\n"); watchdog--; index = 0; } else { watchdog = 0; } } // find the entry back if (index != 0) { entry = entries.GetFirstItem(); while (entry && --index) { ++entry; } if (entry) { return (*entry)->GetKey(); } } } return NULL; } /*---------------------------------------------------------------------- | PLT_MicroMediaController::PopDirectoryStackToRoot +---------------------------------------------------------------------*/ void PLT_MicroMediaController::PopDirectoryStackToRoot(void) { NPT_String val; while (NPT_SUCCEEDED(m_CurBrowseDirectoryStack.Peek(val)) && val.Compare("0")) { m_CurBrowseDirectoryStack.Pop(val); } } /*---------------------------------------------------------------------- | PLT_MicroMediaController::OnMSAdded +---------------------------------------------------------------------*/ bool PLT_MicroMediaController::OnMSAdded(PLT_DeviceDataReference& device) { // Issue special action upon discovering MediaConnect server PLT_Service* service; if (NPT_SUCCEEDED(device->FindServiceByType("urn:microsoft.com:service:X_MS_MediaReceiverRegistrar:*", service))) { PLT_ActionReference action; PLT_SyncMediaBrowser::m_CtrlPoint->CreateAction( device, "urn:microsoft.com:service:X_MS_MediaReceiverRegistrar:1", "IsAuthorized", action); if (!action.IsNull()) { action->SetArgumentValue("DeviceID", ""); PLT_SyncMediaBrowser::m_CtrlPoint->InvokeAction(action, 0); } PLT_SyncMediaBrowser::m_CtrlPoint->CreateAction( device, "urn:microsoft.com:service:X_MS_MediaReceiverRegistrar:1", "IsValidated", action); if (!action.IsNull()) { action->SetArgumentValue("DeviceID", ""); PLT_SyncMediaBrowser::m_CtrlPoint->InvokeAction(action, 0); } } return true; } /*---------------------------------------------------------------------- | PLT_MicroMediaController::OnMRAdded +---------------------------------------------------------------------*/ bool PLT_MicroMediaController::OnMRAdded(PLT_DeviceDataReference& device) { NPT_String uuid = device->GetUUID(); // test if it's a media renderer PLT_Service* service; if (NPT_SUCCEEDED(device->FindServiceByType("urn:schemas-upnp-org:service:AVTransport:*", service))) { NPT_AutoLock lock(m_MediaRenderers); m_MediaRenderers.Put(uuid, device); } return true; } /*---------------------------------------------------------------------- | PLT_MicroMediaController::OnMRRemoved +---------------------------------------------------------------------*/ void PLT_MicroMediaController::OnMRRemoved(PLT_DeviceDataReference& device) { NPT_String uuid = device->GetUUID(); { NPT_AutoLock lock(m_MediaRenderers); m_MediaRenderers.Erase(uuid); } { NPT_AutoLock lock(m_CurMediaRendererLock); // if it's the currently selected one, we have to get rid of it if (!m_CurMediaRenderer.IsNull() && m_CurMediaRenderer == device) { m_CurMediaRenderer = NULL; } } } /*---------------------------------------------------------------------- | PLT_MicroMediaController::OnMRStateVariablesChanged +---------------------------------------------------------------------*/ void PLT_MicroMediaController::OnMRStateVariablesChanged(PLT_Service* service, NPT_List* vars) { NPT_String uuid = service->GetDevice()->GetUUID(); NPT_List::Iterator var = vars->GetFirstItem(); while (var) { printf("Received state var \"%s:%s:%s\" changes: \"%s\"\n", (const char*)uuid, (const char*)service->GetServiceID(), (const char*)(*var)->GetName(), (const char*)(*var)->GetValue()); ++var; } } /*---------------------------------------------------------------------- | PLT_MicroMediaController::ChooseIDGetCurMediaServerFromTable +---------------------------------------------------------------------*/ void PLT_MicroMediaController::GetCurMediaServer(PLT_DeviceDataReference& server) { NPT_AutoLock lock(m_CurMediaServerLock); if (m_CurMediaServer.IsNull()) { printf("No server selected, select one with setms\n"); } else { server = m_CurMediaServer; } } /*---------------------------------------------------------------------- | PLT_MicroMediaController::GetCurMediaRenderer +---------------------------------------------------------------------*/ void PLT_MicroMediaController::GetCurMediaRenderer(PLT_DeviceDataReference& renderer) { NPT_AutoLock lock(m_CurMediaRendererLock); if (m_CurMediaRenderer.IsNull()) { printf("No renderer selected, select one with setmr\n"); } else { renderer = m_CurMediaRenderer; } } /*---------------------------------------------------------------------- | PLT_MicroMediaController::DoBrowse +---------------------------------------------------------------------*/ NPT_Result PLT_MicroMediaController::DoBrowse(const char* object_id, /* = NULL */ bool metadata /* = false */) { NPT_Result res = NPT_FAILURE; PLT_DeviceDataReference device; GetCurMediaServer(device); if (!device.IsNull()) { NPT_String cur_object_id; m_CurBrowseDirectoryStack.Peek(cur_object_id); // send off the browse packet and block res = BrowseSync( device, object_id?object_id:(const char*)cur_object_id, m_MostRecentBrowseResults, metadata); } return res; } /*---------------------------------------------------------------------- | PLT_MicroMediaController::HandleCmd_getms +---------------------------------------------------------------------*/ void PLT_MicroMediaController::HandleCmd_getms() { PLT_DeviceDataReference device; GetCurMediaServer(device); if (!device.IsNull()) { printf("Current media server: %s\n", (const char*)device->GetFriendlyName()); } else { // this output is taken care of by the GetCurMediaServer call } } /*---------------------------------------------------------------------- | PLT_MicroMediaController::HandleCmd_getmr +---------------------------------------------------------------------*/ void PLT_MicroMediaController::HandleCmd_getmr() { PLT_DeviceDataReference device; GetCurMediaRenderer(device); if (!device.IsNull()) { printf("Current media renderer: %s\n", (const char*)device->GetFriendlyName()); } else { // this output is taken care of by the GetCurMediaRenderer call } } /*---------------------------------------------------------------------- | PLT_MicroMediaController::ChooseDevice +---------------------------------------------------------------------*/ PLT_DeviceDataReference PLT_MicroMediaController::ChooseDevice(const NPT_Lock& deviceList) { PLT_StringMap namesTable; PLT_DeviceDataReference* result = NULL; NPT_String chosenUUID; NPT_AutoLock lock(m_MediaServers); // create a map with the device UDN -> device Name const NPT_List& entries = deviceList.GetEntries(); NPT_List::Iterator entry = entries.GetFirstItem(); while (entry) { PLT_DeviceDataReference device = (*entry)->GetValue(); NPT_String name = device->GetFriendlyName(); namesTable.Put((*entry)->GetKey(), name); ++entry; } // ask user to choose chosenUUID = ChooseIDFromTable(namesTable); if (chosenUUID.GetLength()) { deviceList.Get(chosenUUID, result); } return result?*result:PLT_DeviceDataReference(); // return empty reference if not device was selected } /*---------------------------------------------------------------------- | PLT_MicroMediaController::HandleCmd_setms +---------------------------------------------------------------------*/ void PLT_MicroMediaController::HandleCmd_setms() { NPT_AutoLock lock(m_CurMediaServerLock); PopDirectoryStackToRoot(); m_CurMediaServer = ChooseDevice(GetMediaServersMap()); } /*---------------------------------------------------------------------- | PLT_MicroMediaController::HandleCmd_setmr +---------------------------------------------------------------------*/ void PLT_MicroMediaController::HandleCmd_setmr() { NPT_AutoLock lock(m_CurMediaRendererLock); m_CurMediaRenderer = ChooseDevice(m_MediaRenderers); } /*---------------------------------------------------------------------- | PLT_MicroMediaController::HandleCmd_ls +---------------------------------------------------------------------*/ void PLT_MicroMediaController::HandleCmd_ls() { DoBrowse(); if (!m_MostRecentBrowseResults.IsNull()) { printf("There were %d results\n", m_MostRecentBrowseResults->GetItemCount()); NPT_List::Iterator item = m_MostRecentBrowseResults->GetFirstItem(); while (item) { if ((*item)->IsContainer()) { printf("Container: %s (%s)\n", (*item)->m_Title.GetChars(), (*item)->m_ObjectID.GetChars()); } else { printf("Item: %s (%s)\n", (*item)->m_Title.GetChars(), (*item)->m_ObjectID.GetChars()); } ++item; } m_MostRecentBrowseResults = NULL; } } /*---------------------------------------------------------------------- | PLT_MicroMediaController::HandleCmd_info +---------------------------------------------------------------------*/ void PLT_MicroMediaController::HandleCmd_info() { NPT_String object_id; PLT_StringMap tracks; PLT_DeviceDataReference device; // issue a browse DoBrowse(); if (!m_MostRecentBrowseResults.IsNull()) { // create a map item id -> item title NPT_List::Iterator item = m_MostRecentBrowseResults->GetFirstItem(); while (item) { if (!(*item)->IsContainer()) { tracks.Put((*item)->m_ObjectID, (*item)->m_Title); } ++item; } // let the user choose which one object_id = ChooseIDFromTable(tracks); if (object_id.GetLength()) { // issue a browse with metadata DoBrowse(object_id, true); // look back for the PLT_MediaItem in the results PLT_MediaObject* track = NULL; if (!m_MostRecentBrowseResults.IsNull() && NPT_SUCCEEDED(NPT_ContainerFind(*m_MostRecentBrowseResults, PLT_MediaItemIDFinder(object_id), track))) { // display info printf("Title: %s \n", track->m_Title.GetChars()); printf("OjbectID: %s\n", track->m_ObjectID.GetChars()); printf("Class: %s\n", track->m_ObjectClass.type.GetChars()); printf("Creator: %s\n", track->m_Creator.GetChars()); printf("Date: %s\n", track->m_Date.GetChars()); for (NPT_List::Iterator iter = track->m_ExtraInfo.album_arts.GetFirstItem(); iter; iter++) { printf("Art Uri: %s\n", (*iter).uri.GetChars()); printf("Art Uri DLNA Profile: %s\n", (*iter).dlna_profile.GetChars()); } for (NPT_Cardinal i=0;im_Resources.GetItemCount(); i++) { printf("\tResource[%d].uri: %s\n", i, track->m_Resources[i].m_Uri.GetChars()); printf("\tResource[%d].profile: %s\n", i, track->m_Resources[i].m_ProtocolInfo.ToString().GetChars()); printf("\tResource[%d].duration: %d\n", i, track->m_Resources[i].m_Duration); printf("\tResource[%d].size: %d\n", i, (int)track->m_Resources[i].m_Size); printf("\n"); } printf("Didl: %s\n", (const char*)track->m_Didl); } else { printf("Couldn't find the track\n"); } } m_MostRecentBrowseResults = NULL; } } /*---------------------------------------------------------------------- | PLT_MicroMediaController::HandleCmd_download +---------------------------------------------------------------------*/ void PLT_MicroMediaController::HandleCmd_download() { NPT_String object_id; PLT_StringMap tracks; PLT_DeviceDataReference device; // issue a browse DoBrowse(); if (!m_MostRecentBrowseResults.IsNull()) { // create a map item id -> item title NPT_List::Iterator item = m_MostRecentBrowseResults->GetFirstItem(); while (item) { if (!(*item)->IsContainer()) { tracks.Put((*item)->m_ObjectID, (*item)->m_Title); } ++item; } // let the user choose which one object_id = ChooseIDFromTable(tracks); if (object_id.GetLength()) { // issue a browse with metadata DoBrowse(object_id, true); // look back for the PLT_MediaItem in the results PLT_MediaObject* track = NULL; if (!m_MostRecentBrowseResults.IsNull() && NPT_SUCCEEDED(NPT_ContainerFind(*m_MostRecentBrowseResults, PLT_MediaItemIDFinder(object_id), track))) { if (track->m_Resources.GetItemCount() > 0) { printf("\tResource[0].uri: %s\n", track->m_Resources[0].m_Uri.GetChars()); printf("\n"); NPT_HttpUrl url(track->m_Resources[0].m_Uri.GetChars()); if (url.IsValid()) { // Extract filename from URL NPT_String filename = NPT_FilePath::BaseName(url.GetPath(true).GetChars(), false); NPT_String extension = NPT_FilePath::FileExtension(url.GetPath(true).GetChars()); printf("Downloading %s%s\n", filename.GetChars(), extension.GetChars()); for (int i=0; i<3; i++) { NPT_String filepath = NPT_String::Format("%s_%d%s", filename.GetChars(), i, extension.GetChars()); // Open file for writing NPT_File file(filepath); file.Open(NPT_FILE_OPEN_MODE_WRITE | NPT_FILE_OPEN_MODE_CREATE | NPT_FILE_OPEN_MODE_TRUNCATE); NPT_OutputStreamReference output; file.GetOutputStream(output); // trigger 3 download PLT_Downloader* downloader = new PLT_Downloader(url, output); NPT_TimeInterval delay(5.); m_DownloadTaskManager.StartTask(downloader, &delay); } } } else { printf("No resources found"); } } else { printf("Couldn't find the track\n"); } } m_MostRecentBrowseResults = NULL; } } /*---------------------------------------------------------------------- | PLT_MicroMediaController::HandleCmd_cd +---------------------------------------------------------------------*/ void PLT_MicroMediaController::HandleCmd_cd(const char* command) { NPT_String newobject_id; PLT_StringMap containers; // if command has parameter, push it to stack and return NPT_String id = command; NPT_List args = id.Split(" "); if (args.GetItemCount() >= 2) { args.Erase(args.GetFirstItem()); id = NPT_String::Join(args, " "); m_CurBrowseDirectoryStack.Push(id); return; } // list current directory to let user choose DoBrowse(); if (!m_MostRecentBrowseResults.IsNull()) { NPT_List::Iterator item = m_MostRecentBrowseResults->GetFirstItem(); while (item) { if ((*item)->IsContainer()) { containers.Put((*item)->m_ObjectID, (*item)->m_Title); } ++item; } newobject_id = ChooseIDFromTable(containers); if (newobject_id.GetLength()) { m_CurBrowseDirectoryStack.Push(newobject_id); } m_MostRecentBrowseResults = NULL; } } /*---------------------------------------------------------------------- | PLT_MicroMediaController::HandleCmd_cdup +---------------------------------------------------------------------*/ void PLT_MicroMediaController::HandleCmd_cdup() { // we don't want to pop the root off now.... NPT_String val; m_CurBrowseDirectoryStack.Peek(val); if (val.Compare("0")) { m_CurBrowseDirectoryStack.Pop(val); } else { printf("Already at root\n"); } } /*---------------------------------------------------------------------- | PLT_MicroMediaController::HandleCmd_pwd +---------------------------------------------------------------------*/ void PLT_MicroMediaController::HandleCmd_pwd() { NPT_Stack tempStack; NPT_String val; while (NPT_SUCCEEDED(m_CurBrowseDirectoryStack.Peek(val))) { m_CurBrowseDirectoryStack.Pop(val); tempStack.Push(val); } while (NPT_SUCCEEDED(tempStack.Peek(val))) { tempStack.Pop(val); printf("%s/", (const char*)val); m_CurBrowseDirectoryStack.Push(val); } printf("\n"); } /*---------------------------------------------------------------------- | PLT_MicroMediaController::HandleCmd_open +---------------------------------------------------------------------*/ void PLT_MicroMediaController::HandleCmd_open() { NPT_String object_id; PLT_StringMap tracks; PLT_DeviceDataReference device; GetCurMediaRenderer(device); if (!device.IsNull()) { // get the protocol info to try to see in advance if a track would play on the device // issue a browse DoBrowse(); if (!m_MostRecentBrowseResults.IsNull()) { // create a map item id -> item title NPT_List::Iterator item = m_MostRecentBrowseResults->GetFirstItem(); while (item) { if (!(*item)->IsContainer()) { tracks.Put((*item)->m_ObjectID, (*item)->m_Title); } ++item; } // let the user choose which one object_id = ChooseIDFromTable(tracks); if (object_id.GetLength()) { // look back for the PLT_MediaItem in the results PLT_MediaObject* track = NULL; if (NPT_SUCCEEDED(NPT_ContainerFind(*m_MostRecentBrowseResults, PLT_MediaItemIDFinder(object_id), track))) { if (track->m_Resources.GetItemCount() > 0) { // look for best resource to use by matching each resource to a sink advertised by renderer NPT_Cardinal resource_index = 0; if (NPT_FAILED(FindBestResource(device, *track, resource_index))) { printf("No matching resource\n"); return; } // invoke the setUri printf("Issuing SetAVTransportURI with url=%s & didl=%s", (const char*)track->m_Resources[resource_index].m_Uri, (const char*)track->m_Didl); SetAVTransportURI(device, 0, track->m_Resources[resource_index].m_Uri, track->m_Didl, NULL); } else { printf("Couldn't find the proper resource\n"); } } else { printf("Couldn't find the track\n"); } } m_MostRecentBrowseResults = NULL; } } } /*---------------------------------------------------------------------- | PLT_MicroMediaController::HandleCmd_play +---------------------------------------------------------------------*/ void PLT_MicroMediaController::HandleCmd_play() { PLT_DeviceDataReference device; GetCurMediaRenderer(device); if (!device.IsNull()) { Play(device, 0, "1", NULL); } } /*---------------------------------------------------------------------- | PLT_MicroMediaController::HandleCmd_seek +---------------------------------------------------------------------*/ void PLT_MicroMediaController::HandleCmd_seek(const char* command) { PLT_DeviceDataReference device; GetCurMediaRenderer(device); if (!device.IsNull()) { // remove first part of command ("seek") NPT_String target = command; NPT_List args = target.Split(" "); if (args.GetItemCount() < 2) return; args.Erase(args.GetFirstItem()); target = NPT_String::Join(args, " "); Seek(device, 0, (target.Find(":")!=-1)?"REL_TIME":"X_DLNA_REL_BYTE", target, NULL); } } /*---------------------------------------------------------------------- | PLT_MicroMediaController::HandleCmd_stop +---------------------------------------------------------------------*/ void PLT_MicroMediaController::HandleCmd_stop() { PLT_DeviceDataReference device; GetCurMediaRenderer(device); if (!device.IsNull()) { Stop(device, 0, NULL); } } /*---------------------------------------------------------------------- | PLT_MicroMediaController::HandleCmd_mute +---------------------------------------------------------------------*/ void PLT_MicroMediaController::HandleCmd_mute() { PLT_DeviceDataReference device; GetCurMediaRenderer(device); if (!device.IsNull()) { SetMute(device, 0, "Master", true, NULL); } } /*---------------------------------------------------------------------- | PLT_MicroMediaController::HandleCmd_unmute +---------------------------------------------------------------------*/ void PLT_MicroMediaController::HandleCmd_unmute() { PLT_DeviceDataReference device; GetCurMediaRenderer(device); if (!device.IsNull()) { SetMute(device, 0, "Master", false, NULL); } } /*---------------------------------------------------------------------- | PLT_MicroMediaController::HandleCmd_help +---------------------------------------------------------------------*/ void PLT_MicroMediaController::HandleCmd_help() { printf("\n\nNone of the commands take arguments. The commands with a * \n"); printf("signify ones that will prompt the user for more information once\n"); printf("the command is called\n\n"); printf("The available commands are:\n\n"); printf(" quit - shutdown the Control Point\n"); printf(" exit - same as quit\n"); printf(" setms - * select a media server to become the active media server\n"); printf(" getms - print the friendly name of the active media server\n"); printf(" ls - list the contents of the current directory on the active \n"); printf(" media server\n"); printf(" info - display media info\n"); printf(" down - download media to current directory\n"); printf(" cd - * traverse down one level in the content tree on the active\n"); printf(" media server\n"); printf(" cd .. - traverse up one level in the content tree on the active\n"); printf(" media server\n"); printf(" pwd - print the path from the root to your current position in the \n"); printf(" content tree on the active media server\n"); printf(" setmr - * select a media renderer to become the active media renderer\n"); printf(" getmr - print the friendly name of the active media renderer\n"); printf(" open - set the uri on the active media renderer\n"); printf(" play - play the active uri on the active media renderer\n"); printf(" stop - stop the active uri on the active media renderer\n"); printf(" seek - issue a seek command\n"); printf(" mute - mute the active media renderer\n"); printf(" unmute - unmute the active media renderer\n"); printf(" help - print this help message\n\n"); } /*---------------------------------------------------------------------- | PLT_MicroMediaController::ProcessCommandLoop +---------------------------------------------------------------------*/ void PLT_MicroMediaController::ProcessCommandLoop() { char command[2048]; bool abort = false; command[0] = '\0'; while (!abort) { printf("command> "); fflush(stdout); fgets(command, 2048, stdin); strchomp(command); if (0 == strcmp(command, "quit") || 0 == strcmp(command, "exit")) { abort = true; } else if (0 == strcmp(command, "setms")) { HandleCmd_setms(); } else if (0 == strcmp(command, "getms")) { HandleCmd_getms(); } else if (0 == strncmp(command, "ls", 2)) { HandleCmd_ls(); } else if (0 == strcmp(command, "info")) { HandleCmd_info(); } else if (0 == strcmp(command, "down")) { HandleCmd_download(); } else if (0 == strcmp(command, "cd")) { HandleCmd_cd(command); } else if (0 == strcmp(command, "cd ..")) { HandleCmd_cdup(); } else if (0 == strcmp(command, "pwd")) { HandleCmd_pwd(); } else if (0 == strcmp(command, "setmr")) { HandleCmd_setmr(); } else if (0 == strcmp(command, "getmr")) { HandleCmd_getmr(); } else if (0 == strcmp(command, "open")) { HandleCmd_open(); } else if (0 == strcmp(command, "play")) { HandleCmd_play(); } else if (0 == strcmp(command, "stop")) { HandleCmd_stop(); } else if (0 == strncmp(command, "seek", 4)) { HandleCmd_seek(command); } else if (0 == strcmp(command, "mute")) { HandleCmd_mute(); } else if (0 == strcmp(command, "unmute")) { HandleCmd_mute(); } else if (0 == strcmp(command, "help")) { HandleCmd_help(); } else if (0 == strcmp(command, "")) { // just prompt again } else { printf("Unrecognized command: %s\n", command); HandleCmd_help(); } } }