From 9a6354b15230355168ced287f6c97df163fdec60 Mon Sep 17 00:00:00 2001 From: David Antler Date: Tue, 23 Feb 2016 16:49:46 -0800 Subject: [PATCH] [Win32] Add media client, server, GUI examples Change-Id: Ia4c4861ba932692a4ea40c5a2bff46f8791935fa Signed-off-by: David Antler Reviewed-on: https://gerrit.iotivity.org/gerrit/5693 Reviewed-by: Daniel Jay Ferguson Tested-by: jenkins-iotivity --- resource/examples/SConscript | 18 +- resource/examples/mediaserver.cpp | 642 +++++++++++++++++++++++++++++++++++ resource/examples/winuiclient.cpp | 439 ++++++++++++++++++++++++ resource/examples/winuiclient.h | 89 +++++ resource/examples/winuiclientgui.cpp | 368 ++++++++++++++++++++ 5 files changed, 1554 insertions(+), 2 deletions(-) create mode 100644 resource/examples/mediaserver.cpp create mode 100644 resource/examples/winuiclient.cpp create mode 100644 resource/examples/winuiclient.h create mode 100644 resource/examples/winuiclientgui.cpp diff --git a/resource/examples/SConscript b/resource/examples/SConscript index fc95143..a1f3c7d 100644 --- a/resource/examples/SConscript +++ b/resource/examples/SConscript @@ -75,6 +75,10 @@ if target_os in ['darwin', 'ios']: if env.get('LOGGING'): examples_env.AppendUnique(CPPDEFINES = ['TB_LOG']) + +if target_os in ['msys_nt', 'windows']: + examples_env.AppendUnique(LIBS = ['Comctl32', 'Gdi32', 'User32']) + ###################################################################### # Source files and Targets ###################################################################### @@ -102,7 +106,8 @@ clientjson = examples_env.Install(env.get('BUILD_DIR') + '/resource/examples/', env.get('SRC_DIR') + '/resource/examples/' + 'oic_svr_db_client.dat') serverjson = examples_env.Install(env.get('BUILD_DIR') + '/resource/examples/', env.get('SRC_DIR') + '/resource/examples/' + 'oic_svr_db_server.dat') -Alias("examples", [simpleserver, simpleclient, + +examples_array = [simpleserver, simpleclient, simpleserverHQ, simpleclientHQ, fridgeserver, fridgeclient, presenceserver, presenceclient, @@ -113,5 +118,14 @@ Alias("examples", [simpleserver, simpleclient, devicediscoveryserver, devicediscoveryclient, threadingsample, serverjson, clientjson - ]) + ] + +# Add platform-specific examples + +if target_os in ['msys_nt', 'windows']: + winUIClient = examples_env.Program('winUIClient', ['winuiclientgui.cpp', 'winuiclient.cpp']) + mediaserver = examples_env.Program('mediaserver', 'mediaserver.cpp') + examples_array += [winUIClient, mediaserver] + +Alias("examples", examples_array) env.AppendTarget('examples') diff --git a/resource/examples/mediaserver.cpp b/resource/examples/mediaserver.cpp new file mode 100644 index 0000000..0711e7f --- /dev/null +++ b/resource/examples/mediaserver.cpp @@ -0,0 +1,642 @@ +/* **************************************************************** + * + * Copyright 2016 Intel Corporation All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ******************************************************************/ + +/// +/// This sample provides steps to define an interface for a resource +/// (properties and methods) and host this resource on the server. +/// + +#include +#include +#if defined(__msys_nt__) +#include +#elif defined(_VS2015_) +//#include +#define sleep(SECS) Sleep(1000*(SECS)) +#endif +#include + +#include "OCPlatform.h" +#include "OCApi.h" +#include +#include + +#include +#include +#include +#include +#include /* log */ + +#define SAFE_RELEASE(x) \ + if ((x) != NULL) \ + { (x)->Release(); (x) = NULL; } + +using namespace OC; +using namespace std; +namespace PH = std::placeholders; + +int gObservation = 0; +void * ChangeMediaRepresentation (void *param); +void * handleSlowResponse (void *param, std::shared_ptr pRequest); +void playPause(void); +void setVolume(int vol); +int getVolume(void); + +// Specifies where to notify all observers or list of observers +// false: notifies all observers +// true: notifies list of observers +bool isListOfObservers = false; + +// Specifies secure or non-secure +// false: non-secure resource +// true: secure resource +bool isSecure = false; + +/// Specifies whether Entity handler is going to do slow response or not +bool isSlowResponse = false; + + +// Forward declaring the entityHandler + +/// This class represents a single resource named 'MediaResource'. This resource has +/// two simple properties named 'state' and 'volume' + +class MediaResource +{ + +public: + /// Access this property from a TB client + std::string m_name; + bool m_state; + int m_volume; + std::string m_mediaUri; + OCResourceHandle m_resourceHandle; + OCRepresentation m_mediaRep; + ObservationIds m_interestedObservers; + +public: + /// Constructor + MediaResource() + :m_name("Media Player"), m_state(false), m_volume(0), m_mediaUri("/a/media"), + m_resourceHandle(nullptr) + { + // Initialize representation + m_mediaRep.setUri(m_mediaUri); + + m_mediaRep.setValue("state", m_state); + m_mediaRep.setValue("volume", m_volume); + m_mediaRep.setValue("name", m_name); + } + + /* Note that this does not need to be a member function: for classes you do not have + access to, you can accomplish this with a free function: */ + + /// This function internally calls registerResource API. + void createResource() + { + //URI of the resource + std::string resourceURI = m_mediaUri; + //resource type name. In this case, it is media + std::string resourceTypeName = "core.media"; + // resource interface. + std::string resourceInterface = DEFAULT_INTERFACE; + + // OCResourceProperty is defined ocstack.h + uint8_t resourceProperty; + if(isSecure) + { + resourceProperty = OC_DISCOVERABLE | OC_OBSERVABLE | OC_SECURE; + } + else + { + resourceProperty = OC_DISCOVERABLE | OC_OBSERVABLE; + } + EntityHandler cb = std::bind(&MediaResource::entityHandler, this,PH::_1); + + // This will internally create and register the resource. + OCStackResult result = OCPlatform::registerResource( + m_resourceHandle, resourceURI, resourceTypeName, + resourceInterface, cb, resourceProperty); + + if (OC_STACK_OK != result) + { + cout << "Resource creation was unsuccessful\n"; + } + } + + OCResourceHandle getHandle() + { + return m_resourceHandle; + } + + // Puts representation. + // Gets values from the representation and + // updates the internal state + void put(OCRepresentation& rep) + { + try + { + if (rep.getValue("state", m_state)) + { + cout << "\t\t\t\t" << "state: " << m_state << endl; + if(m_state) + { + playPause(); + } + } + else + { + cout << "\t\t\t\t" << "state not found in the representation" << endl; + } + + if (rep.getValue("volume", m_volume)) + { + cout << "\t\t\t\t" << "volume: " << m_volume << endl; + if((0 <= m_volume) && (m_volume <= 100)) + { + setVolume(m_volume); + } + } + else + { + cout << "\t\t\t\t" << "volume not found in the representation" << endl; + } + } + catch (exception& e) + { + cout << e.what() << endl; + } + + } + + // Post representation. + // Post can create new resource or simply act like put. + // Gets values from the representation and + // updates the internal state + OCRepresentation post(OCRepresentation& rep) + { + put(rep); + return get(); + } + + + // gets the updated representation. + // Updates the representation with latest internal state before + // sending out. + OCRepresentation get() + { + m_mediaRep.setValue("state", m_state); + m_mediaRep.setValue("volume", m_volume); + + return m_mediaRep; + } + + void addType(const std::string& type) const + { + OCStackResult result = OCPlatform::bindTypeToResource(m_resourceHandle, type); + if (OC_STACK_OK != result) + { + cout << "Binding TypeName to Resource was unsuccessful\n"; + } + } + + void addInterface(const std::string& intf) const + { + OCStackResult result = OCPlatform::bindInterfaceToResource(m_resourceHandle, intf); + if (OC_STACK_OK != result) + { + cout << "Binding TypeName to Resource was unsuccessful\n"; + } + } + +private: +// This is just a sample implementation of entity handler. +// Entity handler can be implemented in several ways by the manufacturer +OCEntityHandlerResult entityHandler(std::shared_ptr request) +{ + cout << "\tIn Server CPP entity handler:\n"; + OCEntityHandlerResult ehResult = OC_EH_ERROR; + if(request) + { + // Get the request type and request flag + std::string requestType = request->getRequestType(); + int requestFlag = request->getRequestHandlerFlag(); + + if(requestFlag & RequestHandlerFlag::RequestFlag) + { + cout << "\t\trequestFlag : Request\n"; + auto pResponse = std::make_shared(); + pResponse->setRequestHandle(request->getRequestHandle()); + pResponse->setResourceHandle(request->getResourceHandle()); + + // Check for query params (if any) + QueryParamsMap queries = request->getQueryParameters(); + + if (!queries.empty()) + { + cout << "\nQuery processing upto entityHandler" << std::endl; + } + for (auto it : queries) + { + cout << "Query key: " << it.first << " value : " << it.second + << std::endl; + } + + // If the request type is GET + if(requestType == "GET") + { + cout << "\t\t\trequestType : GET\n"; + if(isSlowResponse) // Slow response case + { + static int startedThread = 0; + if(!startedThread) + { + std::thread t(handleSlowResponse, (void *)this, request); + startedThread = 1; + t.detach(); + } + ehResult = OC_EH_SLOW; + } + else // normal response case. + { + pResponse->setErrorCode(200); + pResponse->setResponseResult(OC_EH_OK); + pResponse->setResourceRepresentation(get()); + if(OC_STACK_OK == OCPlatform::sendResponse(pResponse)) + { + ehResult = OC_EH_OK; + } + } + } + else if(requestType == "PUT") + { + cout << "\t\t\trequestType : PUT\n"; + OCRepresentation rep = request->getResourceRepresentation(); + + // Do related operations related to PUT request + // Update the mediaResource + put(rep); + pResponse->setErrorCode(200); + pResponse->setResponseResult(OC_EH_OK); + pResponse->setResourceRepresentation(get()); + if(OC_STACK_OK == OCPlatform::sendResponse(pResponse)) + { + ehResult = OC_EH_OK; + } + } + else if(requestType == "POST") + { + cout << "\t\t\trequestType : POST\n"; + + OCRepresentation rep = request->getResourceRepresentation(); + + // Do related operations related to POST request + OCRepresentation rep_post = post(rep); + pResponse->setResourceRepresentation(rep_post); + pResponse->setErrorCode(200); + if(rep_post.hasAttribute("createduri")) + { + pResponse->setResponseResult(OC_EH_RESOURCE_CREATED); + pResponse->setNewResourceUri(rep_post.getValue("createduri")); + } + else + { + pResponse->setResponseResult(OC_EH_OK); + } + + if(OC_STACK_OK == OCPlatform::sendResponse(pResponse)) + { + ehResult = OC_EH_OK; + } + } + else if(requestType == "DELETE") + { + cout << "Delete request received" << endl; + } + } + + if(requestFlag & RequestHandlerFlag::ObserverFlag) + { + ObservationInfo observationInfo = request->getObservationInfo(); + if(ObserveAction::ObserveRegister == observationInfo.action) + { + m_interestedObservers.push_back(observationInfo.obsId); + } + else if(ObserveAction::ObserveUnregister == observationInfo.action) + { + m_interestedObservers.erase(std::remove( + m_interestedObservers.begin(), + m_interestedObservers.end(), + observationInfo.obsId), + m_interestedObservers.end()); + } + + cout << "\t\trequestFlag : Observer\n"; + gObservation = 1; + static int startedThread = 0; + + // Observation happens on a different thread in ChangeMediaRepresentation function. + // If we have not created the thread already, we will create one here. + + if(!startedThread) + { + std::thread t(ChangeMediaRepresentation, (void *)this); + startedThread = 1; + t.detach(); + } + + ehResult = OC_EH_OK; + } + } + else + { + cout << "Request invalid" << std::endl; + } + + return ehResult; +} + +}; + +// ChangeMediaRepresentaion is an observation function, +// which notifies any changes to the resource to stack +// via notifyObservers +void * ChangeMediaRepresentation (void *param) +{ + int prevVolume = 0; + MediaResource* mediaPtr = (MediaResource*) param; + + // This function continuously monitors for the changes + while (1) + { + Sleep(100); + + if (gObservation) + { + prevVolume = mediaPtr->m_volume; + mediaPtr->m_volume = getVolume(); + if (prevVolume == mediaPtr->m_volume) + continue; + + cout << "Volume changed from " << prevVolume << "% to " << mediaPtr->m_volume << "%\n"; + + // If under observation if there are any changes to the media resource + // we call notifyObservors + // + // For demostration we are changing the volume value and notifying. + + cout << "\nVolume updated to : " << mediaPtr->m_volume << endl; + cout << "Notifying observers with resource handle: " << mediaPtr->getHandle() << endl; + + OCStackResult result = OC_STACK_OK; + + if(isListOfObservers) + { + std::shared_ptr resourceResponse = + {std::make_shared()}; + + resourceResponse->setErrorCode(200); + resourceResponse->setResourceRepresentation(mediaPtr->get(), DEFAULT_INTERFACE); + + result = OCPlatform::notifyListOfObservers( mediaPtr->getHandle(), + mediaPtr->m_interestedObservers, + resourceResponse); + } + else + { + result = OCPlatform::notifyAllObservers(mediaPtr->getHandle()); + } + + if(OC_STACK_NO_OBSERVERS == result) + { + cout << "No More observers, stopping notifications" << endl; + gObservation = 0; + } + } + } + + return NULL; +} + +void * handleSlowResponse (void *param, std::shared_ptr pRequest) +{ + // This function handles slow response case + MediaResource* mediaPtr = (MediaResource*) param; + // Induce a case for slow response by using sleep + cout << "SLOW response" << std::endl; + sleep (10); + + auto pResponse = std::make_shared(); + pResponse->setRequestHandle(pRequest->getRequestHandle()); + pResponse->setResourceHandle(pRequest->getResourceHandle()); + pResponse->setResourceRepresentation(mediaPtr->get()); + pResponse->setErrorCode(200); + pResponse->setResponseResult(OC_EH_OK); + + // Set the slow response flag back to false + isSlowResponse = false; + OCPlatform::sendResponse(pResponse); + return NULL; +} + +void PrintUsage() +{ + cout << std::endl; + cout << "Usage : mediaserver \n"; + cout << " Default - Non-secure resource and notify all observers\n"; + cout << " 1 - Non-secure resource and notify list of observers\n\n"; + cout << " 2 - Secure resource and notify all observers\n"; + cout << " 3 - Secure resource and notify list of observers\n\n"; + cout << " 4 - Non-secure resource, GET slow response, notify all observers\n"; +} + +static FILE* client_open(const char* /*path*/, const char *mode) +{ + return fopen("./oic_svr_db_server.json", mode); +} + +void playPause() +{ + INPUT ip; + + // Set up a generic keyboard event. + ip.type = INPUT_KEYBOARD; + ip.ki.wScan = 0; // hardware scan code for key + ip.ki.time = 0; + ip.ki.dwExtraInfo = 0; + ip.ki.wVk = VK_MEDIA_PLAY_PAUSE; // virtual-key code for the "a" key + ip.ki.dwFlags = 0; // 0 for key press + + SendInput(1, &ip, sizeof(INPUT)); + // Release the "Play/Pause" key + ip.ki.dwFlags = KEYEVENTF_KEYUP; // KEYEVENTF_KEYUP for key release + SendInput(1, &ip, sizeof(INPUT)); +} + +int getVolume() +{ + IAudioEndpointVolume *g_pEndptVol = NULL; + HRESULT hr = S_OK; + IMMDeviceEnumerator *pEnumerator = NULL; + IMMDevice *pDevice = NULL; + OSVERSIONINFO VersionInfo; + + ZeroMemory(&VersionInfo, sizeof(OSVERSIONINFO)); + VersionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); + GetVersionEx(&VersionInfo); + CoInitialize(NULL); + + // Get enumerator for audio endpoint devices. + hr = CoCreateInstance(__uuidof(MMDeviceEnumerator), + NULL, CLSCTX_INPROC_SERVER, + __uuidof(IMMDeviceEnumerator), + (void**)&pEnumerator); + + // Get default audio-rendering device. + hr = pEnumerator->GetDefaultAudioEndpoint(eRender, eConsole, &pDevice); + + hr = pDevice->Activate(__uuidof(IAudioEndpointVolume), + CLSCTX_ALL, NULL, (void**)&g_pEndptVol); + float currentVal; + hr = g_pEndptVol->GetMasterVolumeLevelScalar(¤tVal); + fflush(stdout); // just in case + + SAFE_RELEASE(pEnumerator) + SAFE_RELEASE(pDevice) + SAFE_RELEASE(g_pEndptVol) + CoUninitialize(); + return ((int) round(100 * currentVal)); + +} + +void setVolume(int vol) +{ + IAudioEndpointVolume *g_pEndptVol = NULL; + HRESULT hr = S_OK; + IMMDeviceEnumerator *pEnumerator = NULL; + IMMDevice *pDevice = NULL; + OSVERSIONINFO VersionInfo; + + ZeroMemory(&VersionInfo, sizeof(OSVERSIONINFO)); + VersionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); + GetVersionEx(&VersionInfo); + CoInitialize(NULL); + + // Get enumerator for audio endpoint devices. + hr = CoCreateInstance(__uuidof(MMDeviceEnumerator), + NULL, CLSCTX_INPROC_SERVER, + __uuidof(IMMDeviceEnumerator), + (void**)&pEnumerator); + + // Get default audio-rendering device. + hr = pEnumerator->GetDefaultAudioEndpoint(eRender, eConsole, &pDevice); + + hr = pDevice->Activate(__uuidof(IAudioEndpointVolume), + CLSCTX_ALL, NULL, (void**)&g_pEndptVol); + float got = (float)vol/100.0; // needs to be within 1.0 to 0.0 + hr = g_pEndptVol->SetMasterVolumeLevelScalar(got, NULL); + fflush(stdout); // just in case + + SAFE_RELEASE(pEnumerator) + SAFE_RELEASE(pDevice) + SAFE_RELEASE(g_pEndptVol) + CoUninitialize(); +} + +int main(int argc, char* argv[]) +{ + OCPersistentStorage ps {client_open, fread, fwrite, fclose, unlink }; + + if (argc == 1) + { + isListOfObservers = false; + isSecure = false; + } + else if (argc == 2) + { + int value = atoi(argv[1]); + switch (value) + { + case 1: + isListOfObservers = true; + isSecure = false; + break; + case 2: + isListOfObservers = false; + isSecure = true; + break; + case 3: + isListOfObservers = true; + isSecure = true; + break; + case 4: + isSlowResponse = true; + break; + default: + PrintUsage(); + break; + } + } + else + { + PrintUsage(); + return -1; + } + + // Create PlatformConfig object + PlatformConfig cfg { + OC::ServiceType::InProc, + OC::ModeType::Server, + "0.0.0.0", // By setting to "0.0.0.0", it binds to all available interfaces + 0, // Uses randomly available port + OC::QualityOfService::LowQos, + &ps + }; + + OCPlatform::Configure(cfg); + try + { + // Create the instance of the resource class + // (in this case instance of class 'MediaResource'). + MediaResource myMedia; + + // Invoke createResource function of class media. + myMedia.createResource(); + cout << "Created resource." << std::endl; + + // A condition variable will free the mutex it is given, then do a non- + // intensive block until 'notify' is called on it. In this case, since we + // don't ever call cv.notify, this should be a non-processor intensive version + // of while(true); + std::mutex blocker; + std::condition_variable cv; + std::unique_lock lock(blocker); + cout <<"Waiting" << std::endl; + cv.wait(lock, []{return false;}); + } + catch(OCException &e) + { + cout << "OCException in main : " << e.what() << endl; + } + + // No explicit call to stop the platform. + // When OCPlatform::destructor is invoked, internally we do platform cleanup + + return 0; +} + diff --git a/resource/examples/winuiclient.cpp b/resource/examples/winuiclient.cpp new file mode 100644 index 0000000..59e5d21 --- /dev/null +++ b/resource/examples/winuiclient.cpp @@ -0,0 +1,439 @@ +/* **************************************************************** + * + * Copyright 2016 Intel Corporation All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ******************************************************************/ + +#include +#include "winuiclient.h" +#include +#include +#include + +extern int g_CurSliderVal; +extern HWND hwndVolumeSlider, hwndVolumeExpectedLabel; +using namespace WinUIClient; +void LabelPrintf (HWND hwndEdit, TCHAR * szFormat, ...); + +WinUIClientApp::WinUIClientApp(OCPersistentStorage ps) + : persistentStorage(ps), + OBSERVE_TYPE_TO_USE(ObserveType::Observe) +{ + +} + +WinUIClientApp::~WinUIClientApp() +{ + +} + +void WinUIClientApp::Initialize() +{ + // Create PlatformConfig object + PlatformConfig cfg { + OC::ServiceType::InProc, + OC::ModeType::Both, + "0.0.0.0", + 0, + OC::QualityOfService::LowQos, + &persistentStorage + }; + + OCPlatform::Configure(cfg); +} + +void WinUIClientApp::Run() +{ + try + { + // makes it so that all boolean values are printed as 'true/false' in this stream + std::cout.setf(std::ios::boolalpha); + // Find all resources + std::ostringstream requestURI;// << "?rt=core.media"; + std::string s = OC_RSRVD_WELL_KNOWN_URI; + requestURI << s; + + OCPlatform::findResource("", requestURI.str(), + CT_DEFAULT, std::bind(&WinUIClientApp::foundResource, this, std::placeholders::_1)); + std::cout<< "Finding Resource... " < resource) +{ + std::cout << "In foundResource\n"; + std::string resourceURI; + std::string hostAddress; + try + { + { + std::lock_guard lock(curResourceLock); + if (discoveredResources.find(resource->uniqueIdentifier()) == discoveredResources.end()) + { + std::cout << "Found resource " << resource->uniqueIdentifier() << + " for the first time on server with ID: "<< resource->sid()<uniqueIdentifier()] = resource; + } + else + { + std::cout<<"Found resource "<< resource->uniqueIdentifier() << " again!"<uri(); + std::cout << "\tURI of the resource: " << resourceURI << std::endl; + + // Get the resource host address + hostAddress = resource->host(); + std::cout << "\tHost address of the resource: " << hostAddress << std::endl; + + // Get the resource types + std::cout << "\tList of resource types: " << std::endl; + for(auto &resourceTypes : resource->getResourceTypes()) + { + std::cout << "\t\t" << resourceTypes << std::endl; + } + + // Get the resource interfaces + std::cout << "\tList of resource interfaces: " << std::endl; + for(auto &resourceInterfaces : resource->getResourceInterfaces()) + { + std::cout << "\t\t" << resourceInterfaces << std::endl; + } + + if (resourceURI == "/a/media") + { + curResource = resource; + // Call a local function which will internally invoke get API on the resource pointer + this->GetMediaRepresentation(); + this->BeginObserving(); + } + } + else + { + // Resource is invalid + std::cout << "Resource is invalid" << std::endl; + } + + } + catch(std::exception& e) + { + std::cerr << "Exception in foundResource: "<< e.what() << std::endl; + } +} + +// Local function to get representation of media resource +void WinUIClientApp::GetMediaRepresentation() +{ + if (curResource) + { + std::cout << "Getting Media Representation..."<get(test, std::bind(&WinUIClientApp::onGet, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); + + } + else + { + std::cout << "No Current Resource to GetMediaRepresentation..."<put(rep, QueryParamsMap(), std::bind(&WinUIClientApp::onPut, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); + } +} + +// callback handler on PUT request +void WinUIClientApp::onPut(const HeaderOptions& /*headerOptions*/, const OCRepresentation& rep, const int eCode) +{ + try + { + if (eCode == OC_STACK_OK) + { + std::cout << "PUT request was successful" << std::endl; + + rep.getValue("state", mymedia.m_state); + rep.getValue("volume", mymedia.m_volume); + rep.getValue("name", mymedia.m_name); + + std::cout << "\tstate: " << mymedia.m_state << std::endl; + std::cout << "\tvolume: " << mymedia.m_volume << std::endl; + std::cout << "\tname: " << mymedia.m_name << std::endl; + + } + else + { + std::cout << "onPut Response error: " << eCode << std::endl; + std::exit(-1); + } + } + catch(std::exception& e) + { + std::cout << "Exception: " << e.what() << " in onPut" << std::endl; + } +} + +// Local function to put a different state for this resource +void WinUIClientApp::PostMediaRepresentation() +{ + if (curResource) + { + OCRepresentation rep; + + std::cout << "Posting media representation..."<post(rep, QueryParamsMap(), std::bind(&WinUIClientApp::onPost, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); + } +} + +void WinUIClientApp::onPost(const HeaderOptions& /*headerOptions*/, + const OCRepresentation& rep, const int eCode) +{ + try + { + if (eCode == OC_STACK_OK || eCode == OC_STACK_RESOURCE_CREATED) + { + std::cout << "POST request was successful" << std::endl; + + if (rep.hasAttribute("createduri")) + { + std::cout << "\tUri of the created resource: " + << rep.getValue("createduri") << std::endl; + } + else + { + rep.getValue("state", mymedia.m_state); + rep.getValue("volume", mymedia.m_volume); + rep.getValue("name", mymedia.m_name); + + std::cout << "\tstate: " << mymedia.m_state << std::endl; + std::cout << "\tvolume: " << mymedia.m_volume << std::endl; + std::cout << "\tname: " << mymedia.m_name << std::endl; + } + + } + else + { + std::cout << "onPost Response error: " << eCode << std::endl; + std::exit(-1); + } + } + catch (std::exception& e) + { + std::cout << "Exception: " << e.what() << " in onPost" << std::endl; + } +} + +void WinUIClientApp::onPost2(const HeaderOptions& /*headerOptions*/, + const OCRepresentation& rep, const int eCode) +{ + try + { + if (eCode == OC_STACK_OK || eCode == OC_STACK_RESOURCE_CREATED) + { + std::cout << "POST request was successful" << std::endl; + + if (rep.hasAttribute("createduri")) + { + std::cout << "\tUri of the created resource: " + << rep.getValue("createduri") << std::endl; + } + else + { + rep.getValue("state", mymedia.m_state); + rep.getValue("volume", mymedia.m_volume); + rep.getValue("name", mymedia.m_name); + + std::cout << "\tstate: " << mymedia.m_state << std::endl; + std::cout << "\tvolume: " << mymedia.m_volume << std::endl; + std::cout << "\tname: " << mymedia.m_name << std::endl; + } + + } + else + { + std::cout << "onPost2 Response error: " << eCode << std::endl; + std::exit(-1); + } + } + catch(std::exception& e) + { + std::cout << "Exception: " << e.what() << " in onPost2" << std::endl; + } + +} + +void WinUIClientApp::onObserve(const HeaderOptions /*headerOptions*/, const OCRepresentation& rep, + const int& eCode, const int& sequenceNumber) +{ + try + { + if (eCode == OC_STACK_OK && sequenceNumber != OC_OBSERVE_NO_OPTION) + { + if (sequenceNumber == OC_OBSERVE_REGISTER) + { + std::cout << "Observe registration action is successful" << std::endl; + } + else if (sequenceNumber == OC_OBSERVE_DEREGISTER) + { + std::cout << "Observe De-registration action is successful" << std::endl; + } + + std::cout << "OBSERVE RESULT:"<observe(OBSERVE_TYPE_TO_USE, QueryParamsMap(), std::bind(&WinUIClientApp::onObserve, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4)); +} + +void WinUIClientApp::CancelObserving() +{ + std::cout<<"Cancelling Observe..."<cancelObserve(); +} + +std::shared_ptr WinUIClientApp::GetResource() +{ + return curResource; +} + +int WinUIClientApp::observe_count() +{ + static int oc = 0; + return ++oc; +} + diff --git a/resource/examples/winuiclient.h b/resource/examples/winuiclient.h new file mode 100644 index 0000000..b052e4e --- /dev/null +++ b/resource/examples/winuiclient.h @@ -0,0 +1,89 @@ +/* **************************************************************** + * + * Copyright 2016 Intel Corporation All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ******************************************************************/ + +#ifndef WINUICLIENT_H_ +#define WINUICLIENT_H_ + +#include +#include +#include +#include "OCPlatform.h" +#include "OCApi.h" +#include "OCResource.h" + +using namespace OC; +namespace WinUIClient{ + + class Media + { + public: + + bool m_state; + int m_volume; + std::string m_name; + + Media() : m_state(false), m_volume(0), m_name("") + { + } + }; + + class WinUIClientApp + { + public: + WinUIClientApp(OCPersistentStorage ps); + ~WinUIClientApp(); + + void Initialize(); + void Run(); + void FindResources(); + void GetMediaRepresentation(); + void PutMediaRepresentation(); + void PostMediaRepresentation(); + void BeginObserving(); + void CancelObserving(); + + std::shared_ptr GetResource(); + Media GetMedia(){return mymedia;} + void SetMedia(bool state, int volume){mymedia.m_state = state; mymedia.m_volume=volume;} + bool observing; + + private: + void foundResource(std::shared_ptr resource); + void onGet(const HeaderOptions& /*headerOptions*/, const OCRepresentation& rep, const int eCode); + void onPut(const HeaderOptions& /*headerOptions*/, const OCRepresentation& rep, const int eCode); + void onPost(const HeaderOptions& /*headerOptions*/, const OCRepresentation& rep, const int eCode); + void onPost2(const HeaderOptions& /*headerOptions*/,const OCRepresentation& rep, const int eCode); + void onObserve(const HeaderOptions /*headerOptions*/, const OCRepresentation& rep, const int& eCode, const int& sequenceNumber); + private: + int observe_count(); + + private: + typedef std::map> DiscoveredResourceMap; + + OCPersistentStorage persistentStorage; + Media mymedia; + DiscoveredResourceMap discoveredResources; + std::shared_ptr curResource; + ObserveType OBSERVE_TYPE_TO_USE; + std::mutex curResourceLock; + }; + +} + +#endif + diff --git a/resource/examples/winuiclientgui.cpp b/resource/examples/winuiclientgui.cpp new file mode 100644 index 0000000..c8273a8 --- /dev/null +++ b/resource/examples/winuiclientgui.cpp @@ -0,0 +1,368 @@ +/* **************************************************************** + * + * Copyright 2016 Intel Corporation All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ******************************************************************/ + +#include +#include "winuiclient.h" + +#include +#include + +#define ID_TRACKBAR 0x50505 +#define ID_BUTTONPLAYPAUSE 0xFFF0 +#define ID_BUTTONFIND 0xFFF1 +#define ID_BUTTONGET 0xFFF2 +#define ID_BUTTONPUT 0xFFF3 +#define ID_BUTTONPOST 0xFFF4 +#define ID_BUTTONBEGINOBSERVE 0xFFF5 +#define ID_BUTTONCANCELOBSERVE 0xFFF6 + +int g_CurSliderVal = 0; + +HWND hwnd, icon_button, hwndVolumeSlider, hwndVolumeExpectedLabel; +HWND hwndButtonPlayPause, hwndButtonFind, hwndButtonGet, hwndButtonPut, hwndButtonPost, hwndButtonBeginObserve, hwndButtonCancelObserve; +HINSTANCE hInstance, g_hinstTrackBar, g_hinstVolumeSlider, g_hinstVolumeLabel; +HANDLE Timer, Thread; +HICON hIcon1; +HBRUSH g_BkgndBrush; + +WinUIClient::WinUIClientApp* app = NULL; + +LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); +void LabelPrintf (HWND hwndEdit, TCHAR * szFormat, ...); +HWND WINAPI CreateTrackbar(HWND parent, int x, int y, int w, int h,UINT iMin, UINT iMax, UINT iSelMin, UINT iSelMax); +HWND WINAPI CreateLabel(HWND parent, LPCTSTR lpText, int x, int y, int w, int h); +HWND WINAPI CreateButton(HWND parent, UINT_PTR id, LPCTSTR caption, int x, int y, int w, int h); + +FILE* client_open(const char* /*path*/, const char *mode) +{ + return fopen("./oic_svr_db_client.dat", mode); +} + +int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, + LPSTR lpCmdLine, int nCmdShow ) +{ + MSG msg; + WNDCLASS wc = {sizeof(WNDCLASS)}; + wc.lpszClassName = TEXT( "Static Control" ); + wc.hInstance = hInstance ; + wc.hbrBackground = GetSysColorBrush(COLOR_MENU); + wc.lpfnWndProc = WndProc; + wc.hIcon = LoadIcon (NULL, IDI_APPLICATION); + wc.hCursor = LoadCursor (NULL, IDC_ARROW); + + RegisterClass(&wc); + hwnd = CreateWindow( wc.lpszClassName, TEXT("IoTivity Media Client - Windows UI"), + WS_OVERLAPPEDWINDOW ^ WS_THICKFRAME, + 100, 100, 275, 170, 0, 0, hInstance, 0); + + InitCommonControls(); // loads common control's DLL + + hwndVolumeSlider = + CreateTrackbar(hwnd, + 10,10, + 170,40, + 0,100, + 0,0); + hwndVolumeExpectedLabel = + CreateLabel(hwnd, + "Expected Volume", + 10,50, + 240,30); + + LabelPrintf(hwndVolumeExpectedLabel, + "Expected Volume: %i", + 0); + + hwndButtonPlayPause = + CreateButton(hwnd, + ID_BUTTONPLAYPAUSE, + "PlayPause", + 180,10, + 80,35); + + hwndButtonFind = + CreateButton(hwnd, + ID_BUTTONFIND, + "Find", + 10,75, + 64,25); + + hwndButtonGet = + CreateButton(hwnd, + ID_BUTTONGET, + "Get", + 10,105, + 64,25); + + hwndButtonPut = + CreateButton(hwnd, + ID_BUTTONPUT, + "Put", + 80,75, + 64,25); + + hwndButtonPost = + CreateButton(hwnd, + ID_BUTTONPOST, + "Post", + 80,105, + 64,25); + hwndButtonBeginObserve = + CreateButton(hwnd, + ID_BUTTONBEGINOBSERVE, + "Bgn Obs", + 150,75, + 64,25); + hwndButtonCancelObserve = + CreateButton(hwnd, + ID_BUTTONCANCELOBSERVE, + "Cncl Obs", + 150,105, + 64,25); + + + ShowWindow(hwnd, nCmdShow); + UpdateWindow(hwnd); + + while (GetMessage(&msg, NULL, 0, 0)) + { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + + return (int) msg.wParam; +} + +LRESULT +CALLBACK +WndProc( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam ) +{ + HDC hDC; + RECT rect; + WinUIClient::Media myMedia; + + switch(msg){ + case WM_HSCROLL: + switch (LOWORD(wParam)) { + case TB_ENDTRACK: + g_CurSliderVal = SendMessage(hwndVolumeSlider, TBM_GETPOS, 0, 0); + LabelPrintf(hwndVolumeExpectedLabel,"Volume: %i", g_CurSliderVal); + + myMedia = app->GetMedia(); + myMedia.m_volume = g_CurSliderVal; + app->SetMedia(myMedia.m_state, myMedia.m_volume); + app->PostMediaRepresentation(); + break; + } + break; + case WM_CREATE: + hIcon1 = LoadIcon (NULL, IDI_WARNING); + SendMessage(icon_button,BM_SETIMAGE,IMAGE_ICON,(LPARAM)hIcon1); + GetClientRect(hwnd, &rect); + g_BkgndBrush = GetSysColorBrush(COLOR_MENU); + + app = new WinUIClient::WinUIClientApp({client_open, fread, fwrite, fclose, unlink }); + app->Initialize(); + app->Run(); + + break; + case WM_DESTROY: + + delete app; + + PostQuitMessage(0); + break; + case WM_ERASEBKGND: + GetClientRect(hwnd, &rect); + hDC = GetDC(hwnd); + SelectObject((HDC)wParam, g_BkgndBrush); + Rectangle((HDC)hDC, rect.left, rect.top, rect.right, rect.bottom); + ReleaseDC(hwnd, hDC); + break; + case WM_SIZE: + break; + case WM_RBUTTONDOWN: + case WM_LBUTTONDOWN: + break; + case WM_MOUSELEAVE: + case WM_RBUTTONUP: + case WM_LBUTTONUP: + break; + case WM_COMMAND: + if (HIWORD(wParam) == BN_CLICKED) + { + + switch (LOWORD(wParam)) + { + case ID_BUTTONPLAYPAUSE: + myMedia = app->GetMedia(); + + // HACK: We are using m_state in a stateless way. + // True means "toggle". The server does not have state + // knowledge about whether or not media is playing on the + // system. It's dumb and hits the "PlayPause" key on the + // keyboard. + // + myMedia.m_state = true; + app->SetMedia(myMedia.m_state, myMedia.m_volume); + myMedia.m_state = false; + + app->PutMediaRepresentation(); + break; + case ID_BUTTONFIND: + app->FindResources(); + break; + case ID_BUTTONGET: + app->GetMediaRepresentation(); + break; + case ID_BUTTONPUT: + myMedia = app->GetMedia(); + myMedia.m_volume = g_CurSliderVal; + app->SetMedia(myMedia.m_state, myMedia.m_volume); + app->PutMediaRepresentation(); + break; + case ID_BUTTONPOST: + myMedia = app->GetMedia(); + myMedia.m_volume = g_CurSliderVal; + app->SetMedia(myMedia.m_state, myMedia.m_volume); + app->PostMediaRepresentation(); + break; + case ID_BUTTONBEGINOBSERVE: + app->BeginObserving(); + break; + case ID_BUTTONCANCELOBSERVE: + app->CancelObserving(); + break; + } + } + break; + default: + return DefWindowProc(hwnd, msg, wParam, lParam); + } + + return 0; +} + +#define GWL_HINSTANCE -6 +HWND WINAPI CreateButton(HWND parent, + UINT_PTR id, + LPCTSTR caption , + int x, + int y, + int w, + int h + ) +{ + HWND hwndButton = CreateWindow( + "BUTTON", // Predefined class; Unicode assumed + caption, // Button text + WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON, // Styles + x, // x position + y, // y position + w, // Button width + h, // Button height + parent, // Parent window + (HMENU)id, // No menu. + (HINSTANCE)GetWindowLongPtr(parent, GWL_HINSTANCE), + NULL); // Pointer not needed. + + return hwndButton; +} + +HWND WINAPI CreateLabel( + HWND parent, // handle of parent window + LPCTSTR lpText, + int x, + int y, + int w, + int h +) +{ + HWND hwndPowerLabel = CreateWindow("static", "ST_U", + WS_CHILD | WS_VISIBLE | WS_TABSTOP, + x, y, w, h, + parent, (HMENU)(501), + (HINSTANCE)GetWindowLongPtr(parent, GWL_HINSTANCE), + NULL); + SetWindowText(hwndPowerLabel, lpText); + return hwndPowerLabel; +} + +// CreateTrackbar - creates and initializes a trackbar. +// +// Global variable +// g_hinstTrackBar - instance handle +// +HWND WINAPI CreateTrackbar( + HWND parent, // handle of dialog box (parent window) + int x, + int y, + int w, + int h, + UINT iMin, // minimum value in trackbar range + UINT iMax, // maximum value in trackbar range + UINT iSelMin, // minimum value in trackbar selection + UINT iSelMax) // maximum value in trackbar selection +{ + HWND hwndVolumeSlider = CreateWindowEx( + 0, // no extended styles + TRACKBAR_CLASS, // class name + "Trackbar Control", // title (caption) + WS_CHILD | + WS_VISIBLE | + TBS_AUTOTICKS | + TBS_ENABLESELRANGE, // style + x,y,w,h, // position ,size + parent, // parent window + (HMENU)ID_TRACKBAR, // control identifier + (HINSTANCE)GetWindowLongPtr(parent, GWL_HINSTANCE),// instance + NULL // no WM_CREATE parameter + ); + + SendMessage(hwndVolumeSlider, TBM_SETRANGE, + (WPARAM) TRUE, // redraw flag + (LPARAM) MAKELONG(iMin, iMax)); // min. & max. positions + + SendMessage(hwndVolumeSlider, TBM_SETPAGESIZE, + 0, (LPARAM) 4); // new page size + + SendMessage(hwndVolumeSlider, TBM_SETSEL, + (WPARAM) FALSE, // redraw flag + (LPARAM) MAKELONG(iSelMin, iSelMax)); + + SendMessage(hwndVolumeSlider, TBM_SETPOS, + (WPARAM) TRUE, // redraw flag + (LPARAM) iSelMin); + + SetFocus(hwndVolumeSlider); + + return hwndVolumeSlider; +} + +void LabelPrintf (HWND hwndEdit, TCHAR * szFormat, ...) +{ + TCHAR szBuffer [1024] ; + va_list pArgList ; + + va_start (pArgList, szFormat) ; + wvsprintf (szBuffer, szFormat, pArgList) ; + va_end (pArgList) ; + + SetWindowText(hwndEdit, szBuffer); +} + -- 2.7.4