07/Nov/2012 How to command the MultiStream ASIO Player remotely --------------------------------------------------- // Hint: It's easy! The controller application needs the following... HWND hwDispatch = NULL; COPYDATASTRUCT MyCDS; char command[64]; // a buffer that gets the command from UI or a phone app or something // Here are functions to validate commands before they are sent to the player // Get filename extension and convert to lower case char *FileExt2Lower(char *pFilename) { char *ptr; char *pExt = strrchr(pFilename, '.'); if(pExt != NULL) { // Convert extension to lower case... ptr = pExt + 1; while(*ptr != '\0') { *ptr = tolower(*ptr); ++ptr; } } return pExt; } bool isValidCommand(char *pCmd) { if((*pCmd == '/') && (pCmd[1] == 'P'))return true; if((*pCmd == '/') && (pCmd[1] == 'R'))return true; if((*pCmd == '/') && (pCmd[1] == 'S'))return true; if((*pCmd == '/') && (pCmd[1] == '+'))return true; if((*pCmd == '/') && (pCmd[1] == '-'))return true; // Is it an /ADD command followed by a valid pathname? if((*pCmd == '/') && (pCmd[1] == 'A') && (pCmd[2] == 'D') && (pCmd[2] == 'D')) { // Is it a valid pathname? // First we'll check to see if it has a .wav, .mp3 or .m3u extension // Convert extension to lower case... char *pExt = FileExt2Lower(pCmd); if(pExt == NULL) { return false; // No extension! } if(!strcmp(pExt, ".wav")) { return true; } if(!strcmp(pExt, ".mp3")) { return true; } if(!strcmp(pExt, ".m3u")) { return true; } } return false; } // Note: The "/ADD pathname.ext" command allows you to add files to the play list. // Obviously these files will only play if they already physically exist on the computer running MStream, // but you could have a database of the pathnames of such files on the remote device, // or you could even have an independent method of actually sending files to the computer // before you add them to the play list. To prepare to send messages to the player, do this... hwDispatch = FindWindowA(NULL, "MultiStream ASIO Player..."); while(hwDispatch == NULL) { if(IDCANCEL == MessageBoxA(hApp, "Open the MultiStream ASIO Player, then click OK", "Controller", MB_OKCANCEL | MB_ICONSTOP)) { PostMessage(hApp, WM_CLOSE, 0, 0); return; } hwDispatch = FindWindowA(NULL, "MultiStream ASIO Player..."); } // Found MStream window: Handle now in hwDispatch; ZeroMemory(&MyCDS, sizeof(COPYDATASTRUCT)); // So later, you have a command from somewhere. // Validate it and send if valid... if(isValidCommand(command)) { MyCDS.lpData = command; MyCDS.cbData = strlen(command); SendMessage(hwDispatch, WM_COPYDATA, (WPARAM)(HWND)0,(LPARAM)(LPVOID)&MyCDS); } Meanwhile, in the MStream player Windows Message processing loop... This is the actual code that processes remote commands sent to the MStream Player LRESULT CMStreamDlg::WindowProc(UINT message, WPARAM wParam, LPARAM lParam) { switch (message) { ... ... case WM_COPYDATA: if( ((COPYDATASTRUCT *)lParam)->cbData == 0) { return 0; // No data! } // Copy the command to our 256 char buffer... strncpy(sCmdLine, (char *)((COPYDATASTRUCT *)lParam)->lpData, ( ((COPYDATASTRUCT *)lParam)->cbData > 255) ? 255 : ((COPYDATASTRUCT *)lParam)->cbData); // Ensure string is null-terminated... sCmdLine[( ((COPYDATASTRUCT *)lParam)->cbData > 255) ? 255 : ((COPYDATASTRUCT *)lParam)->cbData] = 0; if(*sCmdLine == '/') { // WM_COPYDATA found forward slash! char cmd = *(sCmdLine + 1); // It's a command! - maybe with garbage after the word? // Maybe "/PAUSE" or "/PLAY"? if(cmd == 'P') { OnBtnPlayPause(); // Toggle play/pause }else if(cmd == 'A') // It's /ADD to playlist, followed by a pathname { // Passing true to PlayCmdLineFile allows // it to simply add the files of the .m3u name passed // to current playlist, without disrupting what is there now // However, we need to pass a pointer to the filename that follows "/ADD " PlayCmdLineFile(true, &sCmdLine[5]); }else if(cmd == 'R') // Restart { OnBtnPrev(); }else if(cmd == 'S') // Skip { OnBtnNext(); }else if(cmd == '+') // vol up { int vol = m_SlidVolume.GetPos(); // Range = (0, 8); if(vol < 8) { ++vol; m_SlidVolume.SetPos(vol); pAudioStreams->SetGlobalAttenuation(8 - m_SlidVolume.GetPos()); } }else if(cmd == '-') // vol down { int vol = m_SlidVolume.GetPos(); if(vol > 0) { --vol; m_SlidVolume.SetPos(vol); pAudioStreams->SetGlobalAttenuation(8 - m_SlidVolume.GetPos()); } } } // End if(*sCmdLine == '/') return 0; } // End switch (message) }