From 28e95d952263556120384f4a5d17dd6400e930b9 Mon Sep 17 00:00:00 2001
From: Jean-Baptiste Kempf <jb@videolan.org>
Date: Wed, 17 Dec 2014 14:06:01 +0100
Subject: [PATCH 2/2] RSSDK modules

---
 modules/control/Modules.am               |   4 +
 modules/control/rssdk/rssdk_common.cpp   | 112 ++++++++++++++++++
 modules/control/rssdk/rssdk_common.h     |  63 +++++++++++
 modules/control/rssdk/rssdk_gestures.cpp | 189 +++++++++++++++++++++++++++++++
 modules/control/rssdk/rssdk_voice.cpp    | 155 +++++++++++++++++++++++++
 5 files changed, 523 insertions(+)
 create mode 100644 modules/control/rssdk/rssdk_common.cpp
 create mode 100644 modules/control/rssdk/rssdk_common.h
 create mode 100644 modules/control/rssdk/rssdk_gestures.cpp
 create mode 100644 modules/control/rssdk/rssdk_voice.cpp

diff --git a/modules/control/Modules.am b/modules/control/Modules.am
index 88693de..5b4cd72 100644
--- a/modules/control/Modules.am
+++ b/modules/control/Modules.am
@@ -1,4 +1,6 @@
 SOURCES_dummy = dummy.c
+SOURCES_rssdk_v = rssdk/rssdk_voice.cpp rssdk/rssdk_common.cpp
+SOURCES_rssdk_g = rssdk/rssdk_gestures.cpp rssdk/rssdk_common.cpp
 SOURCES_gestures = gestures.c
 SOURCES_netsync = netsync.c
 SOURCES_ntservice = ntservice.c
@@ -26,6 +28,8 @@ control_LTLIBRARIES += \
 	libgestures_plugin.la \
 	libnetsync_plugin.la \
 	libhotkeys_plugin.la \
+	librssdk_v_plugin.la \
+	librssdk_g_plugin.la \
 	liboldrc_plugin.la
 
 if HAVE_WIN32
diff --git a/modules/control/rssdk/rssdk_common.cpp b/modules/control/rssdk/rssdk_common.cpp
new file mode 100644
index 0000000..4e3dccb
--- /dev/null
+++ b/modules/control/rssdk/rssdk_common.cpp
@@ -0,0 +1,112 @@
+/*****************************************************************************
+ * intf_rssdk.c: rssdk interface plugin
+ *****************************************************************************
+ * Copyright (C) 2013 the VideoLAN team
+ * $Id$
+ *
+ * Authors: JB Kempf
+ *
+ * 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.
+ *
+ * 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; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
+/*****************************************************************************
+ * Preamble
+ *****************************************************************************/
+
+
+#include "rssdk_common.h"
+#include <vlc_plugin.h>
+#include <vlc_interface.h>
+#include <vlc_charset.h>
+
+pxcStatus LoadPCXLibrary(wchar_t *libname, PXCSession **instance)
+{
+
+    if( !instance )
+        return PXC_STATUS_HANDLE_INVALID;
+
+    pxcStatus sts = PXC_STATUS_FEATURE_UNSUPPORTED;
+
+    HMODULE module = LoadLibrary(libname);
+    if( module )
+    {
+        typedef pxcStatus (PXCAPI *FUNC_PXCSession_Create)(PXCSession **instance);
+        FUNC_PXCSession_Create our_PXCSession_Create =
+            (FUNC_PXCSession_Create)GetProcAddress(module, "PXCSession_Create");
+        if( our_PXCSession_Create )
+        {
+            sts = (*our_PXCSession_Create)(instance);
+        }
+        else
+            return PXC_STATUS_ITEM_UNAVAILABLE;
+    }
+    return sts;
+}
+
+#define PCSDK_REGISTRY_KEY TEXT("Software\\Intel\\RSSDK\\v4\\Dispatch")
+wchar_t *PXC_GetPath()
+{
+    HKEY key;
+    if( RegOpenKeyEx(HKEY_LOCAL_MACHINE, PCSDK_REGISTRY_KEY, 0, KEY_READ, &key)
+            != ERROR_SUCCESS )
+        return NULL;
+
+    wchar_t libname[256] = L"";
+    DWORD size = sizeof(libname);
+    DWORD type = 0;
+
+    if( RegGetValue(key, 0, L"Core", RRF_RT_REG_SZ, &type, libname, &size)
+            != ERROR_SUCCESS)
+    {
+        RegCloseKey( key );
+        return NULL;
+    }
+    return wcsdup(libname);
+}
+
+/*****************************************************************************
+ * Open: initialize rssdk interface
+ *****************************************************************************/
+int OpenCommon( vlc_object_t *p_this )
+{
+    intf_thread_t *p_intf = (intf_thread_t*) p_this;
+
+    msg_Info( p_intf, "Loading the rssdk interface module..." );
+
+    intf_sys_t *p_sys = p_intf->p_sys = (intf_sys_t*)malloc( sizeof( intf_sys_t ) );
+    if( unlikely(!p_sys) )
+        return VLC_ENOMEM;
+
+    wchar_t *w_path = PXC_GetPath();
+    msg_Info( p_intf, "using the rssdk interface library: %s", FromT(w_path) );
+    if( w_path == NULL )
+        return VLC_EGENERIC;
+
+    pxcStatus sts = LoadPCXLibrary(w_path, &p_sys->instance );
+    if( sts < PXC_STATUS_NO_ERROR )
+        return VLC_EGENERIC;
+
+    msg_Info( p_intf, "using the rssdk interface module... %i", sts );
+
+    for( int i = 0; ; i++ ) {
+        PXCSession::ImplDesc desc;
+        sts = p_sys->instance->QueryImpl( NULL, i, &desc);
+        if( sts < PXC_STATUS_NO_ERROR )
+            break;
+        msg_Info( p_intf, "Module: %s, iuid=0x%x", FromWide(desc.friendlyName), desc.iuid);
+    }
+    return VLC_SUCCESS;
+}
+
diff --git a/modules/control/rssdk/rssdk_common.h b/modules/control/rssdk/rssdk_common.h
new file mode 100644
index 0000000..5dc29db
--- /dev/null
+++ b/modules/control/rssdk/rssdk_common.h
@@ -0,0 +1,63 @@
+/*****************************************************************************
+ * intf_pcsdk.c: pcsdk interface plugin
+ *****************************************************************************
+ * Copyright (C) 2013 the VideoLAN team
+ * $Id$
+ *
+ * Authors: JB Kempf
+ *
+ * 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.
+ *
+ * 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; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
+/*****************************************************************************
+ * Preamble
+ *****************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <vlc_common.h>
+
+#include <windows.h>
+#include <tchar.h>
+
+#include "rssdk/pxcsession.h"
+
+#include "rssdk/pxccapturemanager.h"
+#include "rssdk/pxcspeechrecognition.h"
+
+#include "rssdk/pxcsensemanager.h"
+#include "rssdk/pxchanddata.h"
+
+pxcStatus LoadPCXLibrary(wchar_t *libname, PXCSession **instance);
+wchar_t *PXC_GetPath();
+int OpenCommon( vlc_object_t *p_this );
+
+struct intf_sys_t
+{
+    vlc_thread_t thread;
+    /* Main Instance */
+    PXCSession *instance;
+
+    /* Gestures */
+    PXCHandData *hdata;
+    PXCSenseManager *sm;
+
+    /* Voice */
+    PXCSpeechRecognition *rec;
+
+    bool b_quit; /* Needed for PXCSenseManager, that is not thread-safe */
+};
diff --git a/modules/control/rssdk/rssdk_gestures.cpp b/modules/control/rssdk/rssdk_gestures.cpp
new file mode 100644
index 0000000..2d12af2
--- /dev/null
+++ b/modules/control/rssdk/rssdk_gestures.cpp
@@ -0,0 +1,189 @@
+/*****************************************************************************
+ * intf_rssdk.c: rssdk interface plugin
+ *****************************************************************************
+ * Copyright (C) 2013-2015 JB Kempf
+ * $Id$
+ *
+ * Authors: JB Kempf
+ *
+ * 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.
+ *
+ * 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; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
+/*****************************************************************************
+ * Preamble
+ *****************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <vlc_common.h>
+#include <vlc_plugin.h>
+#include <vlc_interface.h>
+#include <vlc_charset.h>
+#include <vlc_playlist.h>
+#include <iostream>
+
+#include <windows.h>
+#include <tchar.h>
+
+#include "rssdk_common.h"
+
+#include "rssdk/pxcsession.h"
+#include "rssdk/pxccapturemanager.h"
+#include "rssdk/pxcspeechrecognition.h"
+
+#include "rssdk/pxcsensemanager.h"
+#include "rssdk/pxchandconfiguration.h"
+#include "rssdk/pxchanddata.h"
+
+
+static int OpenGestures( vlc_object_t * );
+static void Close( vlc_object_t * );
+
+vlc_module_begin ()
+    set_shortname( N_("rssdk2") )
+    set_category( CAT_INTERFACE )
+    set_subcategory( SUBCAT_INTERFACE_CONTROL )
+    set_description( N_("RSSDK Gesture Recognition") )
+    set_capability( "interface", 0 )
+    set_callbacks( OpenGestures, Close )
+vlc_module_end ()
+
+class MyGesture: public PXCHandConfiguration::GestureHandler {
+
+public:
+    MyGesture(playlist_t *_p, intf_thread_t *_i) : PXCHandConfiguration::GestureHandler(),
+                            p_playlist( _p ), p_intf( _i ) {};
+
+    virtual void PXCAPI OnFiredGesture(const PXCHandData::GestureData &data) {
+        if( !data.state )
+            return;
+
+        msg_Info( p_intf, "Gestures %s", FromWide(data.name) );
+
+        if     (p_intf->p_sys->hdata->IsGestureFired(L"wave",    const_cast<PXCHandData::GestureData&>(data)))
+            playlist_Stop( p_playlist );
+        else if( p_intf->p_sys->hdata->IsGestureFired(L"swipe",  const_cast<PXCHandData::GestureData&>(data)))
+            playlist_Next( p_playlist );
+        else if( p_intf->p_sys->hdata->IsGestureFired(L"v_sign", const_cast<PXCHandData::GestureData&>(data)))
+            playlist_Prev( p_playlist );
+        else if( p_intf->p_sys->hdata->IsGestureFired(L"tap",    const_cast<PXCHandData::GestureData&>(data)))
+        {
+            if( playlist_Status( p_playlist ) == PLAYLIST_RUNNING )
+                playlist_Pause( p_playlist );
+	    else if( playlist_Status( p_playlist ) == PLAYLIST_PAUSED )
+                playlist_Play( p_playlist );
+        }
+        else if( p_intf->p_sys->hdata->IsGestureFired(L"thumb_up",   const_cast<PXCHandData::GestureData&>(data)))
+            playlist_VolumeUp( p_playlist, 1, NULL );
+        else if( p_intf->p_sys->hdata->IsGestureFired(L"thumb_down", const_cast<PXCHandData::GestureData&>(data)))
+            playlist_VolumeDown( p_playlist, 1, NULL );
+        else if( p_intf->p_sys->hdata->IsGestureFired(L"full_pinch", const_cast<PXCHandData::GestureData&>(data)))
+            playlist_MuteToggle( p_playlist );
+        else
+            msg_Info( p_intf, "Command not recognized." );
+    }
+
+private:
+    playlist_t *p_playlist;
+    intf_thread_t *p_intf;
+};
+
+static void* RunGesture(void* opaque)
+{
+    intf_thread_t *p_intf = (intf_thread_t*)opaque;
+    intf_sys_t *p_sys = p_intf->p_sys;
+
+    PXCHandData::GestureData gestureData;
+    PXCHandData *outputData = p_sys->hdata;
+    while (p_sys->sm->AcquireFrame(true)>=PXC_STATUS_NO_ERROR && p_sys->b_quit == false) {
+        outputData->Update();
+
+        if(outputData->QueryFiredGesturesNumber()>0){
+            memset(&gestureData,0,sizeof(gestureData));
+            if(outputData->QueryFiredGestureData(0,gestureData)==PXC_STATUS_NO_ERROR) {
+                // get hand data related to fired gesture
+                PXCHandData::IHand* handData;
+                if(outputData->QueryHandDataById(gestureData.handId,handData) == PXC_STATUS_NO_ERROR)
+                {
+                    // save gesture only if you know that its right/left hand
+                    if(!handData->QueryBodySide() == PXCHandData::BODY_SIDE_UNKNOWN)
+                        wprintf_s(L"Hand is %d\n", handData->QueryBodySide() );
+                }
+            }
+        }
+        // release or unlock the current frame to go fetch the next frame
+        p_sys->sm->ReleaseFrame();
+    }
+    // close the last opened stream and release any session and processing module instances
+    p_sys->sm->Release();
+    return NULL;
+}
+
+static int OpenGestures( vlc_object_t *p_this )
+{
+    if( OpenCommon( p_this ) != VLC_SUCCESS )
+        return VLC_EGENERIC;
+
+    intf_thread_t *p_intf = (intf_thread_t*) p_this;
+    intf_sys_t *p_sys = p_intf->p_sys;
+    p_sys->b_quit = false;
+
+    PXCSenseManager *sm = p_sys->instance->CreateSenseManager();
+
+    if( !sm )
+        return VLC_EGENERIC;
+
+    p_sys->sm = sm;
+    pxcStatus sts = sm->EnableHand();
+    PXCHandModule *hand = sm->QueryHand();
+
+    if( !hand || sts != PXC_STATUS_NO_ERROR || sm->Init() )
+        return VLC_EGENERIC;
+
+    PXCHandData *handData = hand->CreateOutput();
+    if( !handData )
+        return VLC_EGENERIC;
+
+    PXCHandConfiguration *config = hand->CreateActiveConfiguration();
+    if( !config )
+        return VLC_EGENERIC;
+    config->EnableNormalizedJoints(false);
+
+    p_sys->hdata = handData;
+
+    config->EnableAllGestures();
+    config->SubscribeGesture( new MyGesture( pl_Get(p_intf), p_intf ));
+    config->ApplyChanges();
+    config->Update();
+
+    msg_Info( p_intf, "using the rssdk interface module... %i", sts );
+    if (vlc_clone(&p_sys->thread, RunGesture, p_intf, VLC_THREAD_PRIORITY_LOW))
+    {
+        msg_Info( p_intf, "Error in the rssdk interface module... %i", sts );
+    }
+
+    return VLC_SUCCESS;
+}
+
+static void Close ( vlc_object_t *p_this )
+{
+    intf_thread_t *p_intf = (intf_thread_t *)p_this;
+    intf_sys_t *p_sys = p_intf->p_sys;
+    p_sys->b_quit = true;
+    vlc_join( p_sys->thread, NULL );
+    free( p_sys );
+}
diff --git a/modules/control/rssdk/rssdk_voice.cpp b/modules/control/rssdk/rssdk_voice.cpp
new file mode 100644
index 0000000..a791a03
--- /dev/null
+++ b/modules/control/rssdk/rssdk_voice.cpp
@@ -0,0 +1,155 @@
+/*****************************************************************************
+ * intf_rssdk.c: rssdk interface plugin
+ *****************************************************************************
+ * Copyright (C) 2013-2015 JB Kempf
+ * $Id$
+ *
+ * Authors: JB Kempf
+ *
+ * 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.
+ *
+ * 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; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
+/*****************************************************************************
+ * Preamble
+ *****************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <vlc_common.h>
+#include <vlc_plugin.h>
+#include <vlc_interface.h>
+#include <vlc_charset.h>
+#include <vlc_playlist.h>
+#include <iostream>
+
+#include <windows.h>
+#include <tchar.h>
+
+#include "rssdk_common.h"
+
+
+static int OpenVoice( vlc_object_t * );
+static void Close( vlc_object_t * );
+
+vlc_module_begin ()
+    set_shortname( N_("rssdk") )
+    set_category( CAT_INTERFACE )
+    set_subcategory( SUBCAT_INTERFACE_CONTROL )
+    set_description( N_("RSSDK Voice Recognition") )
+    set_capability( "interface", 0 )
+    set_callbacks( OpenVoice, Close )
+vlc_module_end ()
+
+enum CONTROL_PCSDK_COMMANDS
+{
+    CONTROL_PCSDK_PLAY = 0,
+    CONTROL_PCSDK_PAUSE,
+    CONTROL_PCSDK_STOP,
+    CONTROL_PCSDK_NEXT,
+    CONTROL_PCSDK_PREVIOUS,
+    CONTROL_PCSDK_VOLUME_UP,
+    CONTROL_PCSDK_VOLUME_DOWN,
+};
+
+class MyRec: public PXCSpeechRecognition::Handler {
+
+public:
+    MyRec(playlist_t *_p, intf_thread_t *_i) : PXCSpeechRecognition::Handler(),
+                            p_playlist( _p ), p_intf( _i ) {};
+
+    virtual void PXCAPI OnRecognition( const PXCSpeechRecognition::RecognitionData *data ) {
+
+        if (data->scores[0].label < 0)
+            return;
+
+        msg_Dbg( p_intf, "OnRecognized..." );
+        for (size_t i = 0; i < sizeof(data->scores)/sizeof(data->scores[0]); i++) {
+            if (data->scores[i].label<0 || data->scores[i].confidence==0) continue;
+            msg_Dbg( p_intf, "Values: %d %d %d",i, data->scores[i].label,data->scores[i].confidence);
+        }
+        msg_Dbg( p_intf, "Done. Best value: %d", data->scores[0].confidence);
+        if (data->scores[0].confidence > 50) {
+            msg_Info( p_intf, "Found command %d (%d)\n", data->scores[0].label, data->scores[0].confidence);
+            int label = data->scores[0].label;
+            switch( label ) {
+                case CONTROL_PCSDK_PLAY:
+                    playlist_Play( p_playlist );
+                    break;
+                case CONTROL_PCSDK_PAUSE:
+                    playlist_Pause( p_playlist );
+                    break;
+                case CONTROL_PCSDK_STOP:
+                    playlist_Stop( p_playlist );
+                    break;
+                case CONTROL_PCSDK_NEXT:
+                    playlist_Next( p_playlist );
+                    break;
+                case CONTROL_PCSDK_PREVIOUS:
+                    playlist_Prev( p_playlist );
+                    break;
+                default:
+                    printf( "Action not implemented %d\n", label );
+                    break;
+            }
+        }
+        else
+            msg_Info( p_intf, "Command not recognized." );
+    }
+
+private:
+    playlist_t *p_playlist;
+    intf_thread_t *p_intf;
+};
+
+static int OpenVoice( vlc_object_t *p_this )
+{
+    if( OpenCommon( p_this ) != VLC_SUCCESS )
+        return VLC_EGENERIC;
+
+    intf_thread_t *p_intf = (intf_thread_t*) p_this;
+    intf_sys_t *p_sys = p_intf->p_sys;
+
+    PXCSpeechRecognition *rec = NULL;
+    pxcStatus sts = p_sys->instance->CreateImpl<PXCSpeechRecognition>(&rec);
+    p_sys->rec = rec;
+    msg_Info( p_intf, "using the rssdk interface module... %i", sts );
+
+    PXCSpeechRecognition::ProfileInfo pinfo;
+    rec->QueryProfile( 0, &pinfo );
+    pinfo.language = PXCSpeechRecognition::LANGUAGE_US_ENGLISH;
+    sts = rec->SetProfile(&pinfo);
+    msg_Info( p_intf, "using the rssdk interface module 2... %i", sts );
+
+    /* Set grammar */
+    pxcUID gid = 1;
+    pxcCHAR *cmds[7]={ L"Play", L"Pause", L"Stop", L"Next", L"Previous", L"Volume Up", L"Volume Down" };
+    rec->BuildGrammarFromStringList(gid, cmds, 0, 7);
+    rec->SetGrammar(gid);
+
+    sts = rec->StartRec(NULL, new MyRec(pl_Get(p_intf), p_intf )) ;
+    msg_Info( p_intf, "using the rssdk interface module 3... %i", sts );
+
+    return VLC_SUCCESS;
+}
+
+static void Close ( vlc_object_t *p_this )
+{
+    intf_thread_t *p_intf = (intf_thread_t *)p_this;
+    intf_sys_t *p_sys = p_intf->p_sys;
+    p_sys->rec->StopRec();
+    free( p_sys );
+}
-- 
2.1.4

