Search Unity

[Released] Stream Deck Integration

Discussion in 'Assets and Asset Store' started by Adam_Carballo, Oct 6, 2020.

  1. Adam_Carballo

    Adam_Carballo

    Joined:
    Jun 1, 2014
    Posts:
    34
    Stream Deck Integration
    Editor & Build support for Stream Deck Hardware

    icon.png

    Asset StoreDocsPlugin SourcePublisher Website

    Stream Deck Integration allows any official Stream Deck hardware running official software to interact and communicate with the Unity Editor and/or built Unity projects.

    Improve your Editor workflow with the added benefit of the infinite button layout that a Stream Deck provides!
    Show up your game or experience without any visual debug menus or interfering with the experience by using a Stream Deck as a build controller / debug screen!

    This extension includes full support to call any menu item, expose any field, property or method, no matter if they are private or public, to be called by any supported Stream Deck hardware.
    Editor, fully built project, Windows or macOS, everything works!​

    • Features
    • Full Unity Editor and built project support
    • Play mode editor control with visual feedback
    • Pause mode editor control with visual feedback
    • Execute any menu item, built-in or custom
    • Invoke any method with up to one parameter
    • Set any field and/or property
    • Supports all main base types (int, float, bool, string)

    • Current Limitations
    • You must use an official Stream Deck hardware unit and the official software. This includes Stream Deck, Stream Deck Mini, Stream Deck XL, and the mobile app.
    • The hardware unit and the software must be connected to the machine running the built project or the Unity editor.
    • No Linux support. This is a Stream Deck limitation, as it has no official supported software for Linux systems.
    • The "Unity Integration" plugin must be installed and used to use any of the features.
    Screenshot_1.png
    You can use this thread for any questions or feedback you may have about the asset. For direct support please send an email to support@f10.dev.
    Thanks!
     
    Last edited: Feb 26, 2021
  2. Adam_Carballo

    Adam_Carballo

    Joined:
    Jun 1, 2014
    Posts:
    34
    Update v1.1.0

    This version brings support for dynamically changing the title and icon/image visible on a specific action in the Stream Deck, among other small fixes.
    • Added support for setTitle, setImage endpoints.
    • Removed web-socket message limitation.
    • Improved offline documentation.
    • Fixed wrong Debug.Log usages.
     
    dan_wipf likes this.
  3. dan_wipf

    dan_wipf

    Joined:
    Jan 30, 2017
    Posts:
    314
    754C9DA1-8D5A-4EB8-832D-1646E2A81B61.png Thanks for this!

    Works perfect!
    7F91F1D6-49C0-410C-BA34-3F2990C7812F.png
     
    Adam_Carballo likes this.
  4. dan_wipf

    dan_wipf

    Joined:
    Jan 30, 2017
    Posts:
    314
    Would it be possible to expose more settings? like all font style (alignment, size color etc?
     
  5. Adam_Carballo

    Adam_Carballo

    Joined:
    Jun 1, 2014
    Posts:
    34
  6. dan_wipf

    dan_wipf

    Joined:
    Jan 30, 2017
    Posts:
    314
    well never mind ;-) i can design my own textures with the titel included

    but what you allready did with the settings is really handy and awesome!
     
    Adam_Carballo likes this.
  7. Adam_Carballo

    Adam_Carballo

    Joined:
    Jun 1, 2014
    Posts:
    34
    As a quick heads-up, for anyone not being able to access the online documentation, the data was hosted using OVH servers in Europe, which got completely destroyed in today's fire.

    I will try to spin up a new instance as soon as possible and re-generate the documentation. Until then, I would suggest using the offline documentation provided with the assets.

    EDIT: SG3 group (VPS where the documentation is hosted) is expected to be back up without data loss after the 19th of March.
     
    Last edited: Mar 11, 2021
    dan_wipf likes this.
  8. dan_wipf

    dan_wipf

    Joined:
    Jan 30, 2017
    Posts:
    314
    oh damn that sucks!
     
  9. dan_wipf

    dan_wipf

    Joined:
    Jan 30, 2017
    Posts:
    314
    There is a bug in Build, which not occurs in the Editor.

    If i press one button, any action gets invoked 8 times..
    See videos.

    Video 1: Button behaviour

    Video 2: Button hit counter
     
  10. Adam_Carballo

    Adam_Carballo

    Joined:
    Jun 1, 2014
    Posts:
    34
    Hey Dan, any specific flow you may be doing? I mean, are you using the "StreamDeckRuntime" type, or something custom? - If you use "StreamDeckRuntime", keep in mind that by default it will not be destroyed on scene load, so you could have multiple runtime instances at once.

    Also, what happens if you build the Demo scene included with the package?

    I'll test the runtime flow again now, just to make sure.
     
    Last edited: Mar 15, 2021
  11. dan_wipf

    dan_wipf

    Joined:
    Jan 30, 2017
    Posts:
    314
    1. we only have one scene.
    2. i use the runtime script from you
    3. we use the buttons to controll a show, so forward back, play stop and pause

    we have 4 streamdecks (currently tested everything with 2 streamdecks, bug happens on both streamdecks)

    but i will try to use your demoscene and see what happens.
     
    Adam_Carballo likes this.
  12. dan_wipf

    dan_wipf

    Joined:
    Jan 30, 2017
    Posts:
    314
    Tested it with this:

    Code (CSharp):
    1. using F10.StreamDeckIntegration;
    2. using F10.StreamDeckIntegration.Attributes;
    3. using UnityEngine;
    4.  
    5. public class StreamDeckCustomExample : MonoBehaviour
    6. {
    7.     public Texture2D[] tex;
    8.     private Texture2D GetIcon => tex[Random.Range(0, tex.Length - 1)];
    9.     private int nextCounter = 0, lastCounter = 0;
    10.     private void OnEnable() {
    11.         // Registers this class as a StreamDeck enabled class
    12.         StreamDeck.Add(this);
    13.        
    14.         StreamDeckSettings.SetButtonImage(GetIcon, "SIGNEXT0");
    15.         StreamDeckSettings.SetButtonTitle(nextCounter.ToString(), "SIGNEXT0");
    16.         StreamDeckSettings.SetButtonImage(GetIcon, "SIGLAST0");
    17.         StreamDeckSettings.SetButtonTitle(lastCounter.ToString(), "SIGLAST0");
    18.     }
    19.  
    20.     private void OnDisable() {
    21.         // Removes this class as a StreamDeck enabled class
    22.         StreamDeck.Remove(this);
    23.     }
    24.     [StreamDeckButton]
    25.     public void SIGNEXT0()
    26.     {
    27.         nextCounter++;
    28.         StreamDeckSettings.SetButtonImage(GetIcon, "SIGNEXT0");
    29.         StreamDeckSettings.SetButtonTitle(nextCounter.ToString(), "SIGNEXT0");
    30.     }
    31.    
    32.     [StreamDeckButton]
    33.     public void SIGLAST0()
    34.     {
    35.         lastCounter++;
    36.         StreamDeckSettings.SetButtonImage(GetIcon, "SIGLAST0");
    37.         StreamDeckSettings.SetButtonTitle(lastCounter.ToString(), "SIGLAST0");
    38.     }
    39. }
    40.  
    and buttons got called 5x
    upload_2021-3-15_13-24-8.png upload_2021-3-15_13-24-20.png
     
  13. Adam_Carballo

    Adam_Carballo

    Joined:
    Jun 1, 2014
    Posts:
    34
    @dan_wipf Tested locally, and I can't manage to reproduce this behavior. What I tested:

    Code (CSharp):
    1. public class StreamDeckExample : MonoBehaviour {
    2.  
    3.         [SerializeField]
    4.         private Text _text;
    5.  
    6.         private int rep = 0;
    7.  
    8.         private void OnEnable() {
    9.             // Registers this class as a StreamDeck enabled class
    10.             StreamDeck.Add(this);
    11.         }
    12.  
    13.         private void OnDisable() {
    14.             // Removes this class as a StreamDeck enabled class
    15.             StreamDeck.Remove(this);
    16.         }
    17.  
    18.         [StreamDeckButton]
    19.         private void TestRep() {
    20.             rep++;
    21.             _text.text = rep.ToString();
    22.         }
    23.     }
    The scene consists of a Canvas with a text object, and a single GameObject with this "StreamDeckExample" component, and the "StreamDeckRuntime" component. All of this tested on Windows.

    Seems like it could be an issue with multiple Stream Decks? I haven't tested this situation, as I only have one unit.
    Also, it seems now it repeats only x5 times? Seeing how it's now apparently going from x8 to x5, I would first think that there is something going on with your specific project, but I'm honestly not sure what could be causing this behaviour
     
  14. dan_wipf

    dan_wipf

    Joined:
    Jan 30, 2017
    Posts:
    314
    managed it to work with coroutines.. but still not really a solid way i think...


    Code (CSharp):
    1. public Texture2D[] tex;
    2.         private Texture2D GetIcon => tex[Random.Range(0, tex.Length - 1)];
    3.         public int nextCounter = 0, lastCounter = 0;
    4.         public bool buttonPressed = false;
    5.         private void OnEnable() {
    6.             // Registers this class as a StreamDeck enabled class
    7.             StreamDeck.Add(this);
    8.         }
    9.  
    10.         private void Start()
    11.         {
    12.             StreamDeckSettings.SetButtonImage(GetIcon, "SIGNEXT0", immediate:true);
    13.             StreamDeckSettings.SetButtonTitle(nextCounter.ToString(), "SIGNEXT0", immediate:true);
    14.             StreamDeckSettings.SetButtonImage(GetIcon, "SIGLAST0", immediate:true);
    15.             StreamDeckSettings.SetButtonTitle(lastCounter.ToString(), "SIGLAST0", immediate:true);
    16.         }
    17.  
    18.         private void OnDisable() {
    19.             // Removes this class as a StreamDeck enabled class
    20.             StreamDeck.Remove(this);
    21.         }
    22.  
    23.         private Coroutine nextCR, previousCR;
    24.        
    25.         [StreamDeckButton]
    26.         public void SIGNEXT0()
    27.         {
    28.             if(nextCR == null)
    29.                 nextCR = StartCoroutine(next());
    30.         }
    31.  
    32.         IEnumerator next()
    33.         {
    34.             nextCounter++;
    35.             StreamDeckSettings.SetButtonImage(GetIcon, "SIGNEXT0", immediate:true);
    36.             StreamDeckSettings.SetButtonTitle(nextCounter.ToString(), "SIGNEXT0", immediate:true);
    37.             yield return new WaitForEndOfFrame();
    38.             nextCR = null;
    39.         }
    40.         [StreamDeckButton]
    41.         public void SIGLAST0()
    42.         {
    43.             if(previousCR == null)
    44.                 previousCR = StartCoroutine(previous());
    45.         }
    46.  
    47.         IEnumerator previous()
    48.         {
    49.             lastCounter++;
    50.             StreamDeckSettings.SetButtonImage(GetIcon, "SIGLAST0");
    51.             StreamDeckSettings.SetButtonTitle(lastCounter.ToString(), "SIGLAST0");
    52.  
    53.             yield return new WaitForEndOfFrame();
    54.             previousCR = null;
    55.         }
     
  15. dan_wipf

    dan_wipf

    Joined:
    Jan 30, 2017
    Posts:
    314
    Ok tested some more, even with one streamdeck it jumps, (now it was two times) but as mentioned above, the solution with locking a coroutine and realease it after one frame is working stable :)

    the settings working now all with just a millisecond lag, which is fine because they all apply now on the same time!
     
  16. Adam_Carballo

    Adam_Carballo

    Joined:
    Jun 1, 2014
    Posts:
    34
    I'm glad you could make it work. Seeing the code, you are clearly mitigating whatever is causing the method to be called multiple times per frame. If you ever find out what's causing this you can let me know, but everything I tried ends up with only one trigger for me.

    I also see you found the immediate parameter :). By default messages are queued to be sent at one per frame, but in your case, you want things to update immediately, so as long as you don't send A LOT of data on the same frame, you'll be good.
     
  17. dan_wipf

    dan_wipf

    Joined:
    Jan 30, 2017
    Posts:
    314
    Some proof of evidence =)


    i send those data at once:


    Code (CSharp):
    1. /// <summary>
    2.         /// StreamDeck Button Settings (Icon & Title) coroutine
    3.         /// </summary>
    4.         /// <param name="isActive">is StreamDeck active?</param>
    5.         /// <param name="ExhibitionID">Exhibition to change</param>
    6.         /// <param name="invoke">wait for one frame?</param>
    7.         /// <returns></returns>
    8.         public IEnumerator SetButtons(bool isActive, int ExhibitionID = -1, bool invoke = false)
    9.         {
    10.             var sequencerStatus = SequencerStatus.isStopped;
    11.            
    12.  
    13.             if (invoke)
    14.                 yield return new WaitForEndOfFrame();
    15.            
    16.            
    17.            
    18.             for (var i = 0; i < 4; i++)
    19.             {
    20.                 if (i == ExhibitionID && isActive) continue;
    21.  
    22.                 SetTitle("", SIGNEXT, i);
    23.                 SetTitle("", SIGPREVIOUS, i);
    24.                 SetTitle("", SIGCLIP, i);
    25.                 SetTitle($"{InfoTitle} {(i + 1)}", SIGINFO, i);
    26.                 SetTitle(PlayTitle, SIGPLAY, i);
    27.                 SetTitle("", SIGSTOP, i);
    28.  
    29.                 SetIcon(EmptyTexture, SIGPREVIOUS, i);
    30.                 SetIcon(EmptyTexture, SIGNEXT, i);
    31.                 SetIcon(EmptyTexture, SIGCLIP, i);
    32.                 SetIcon(EmptyTexture, SIGINFO, i);
    33.                 SetIcon(PlayTexture, SIGPLAY, i);
    34.                 SetIcon(EmptyTexture, SIGSTOP, i);
    35.             }
    36.  
    37.             if (!isActive)
    38.             {
    39.                 yield return new WaitForEndOfFrame();
    40.                
    41.                 lockButton = null;
    42.                 yield break;
    43.             }
    44.            
    45.             controller.GetSequencerStatus(ExhibitionID);
    46.             sequencerStatus = controller.sequencerStatus;
    47.            
    48.             var clipStatus = GetClipStatus(ExhibitionID);
    49.            
    50.             SetTitle(NextTitle, SIGNEXT, ExhibitionID);
    51.             SetTitle(PreviousTitle, SIGPREVIOUS, ExhibitionID);
    52.            
    53.             SetTitle($"{ClipTitle} {clipStatus.x}/{clipStatus.y}", SIGCLIP, ExhibitionID);
    54.             SetTitle($"{InfoTitle} {(ExhibitionID + 1)}", SIGINFO, ExhibitionID);
    55.            
    56.             SetTitle(StopTitle, SIGSTOP, ExhibitionID);
    57.  
    58.             SetIcon(clipStatus.x == 1 ? PreviousTextureDisabled : PreviousTexture, SIGPREVIOUS, ExhibitionID);
    59.             SetIcon(clipStatus.x == clipStatus.y ? NextTextureDisabled : NextTexture, SIGNEXT, ExhibitionID);
    60.            
    61.            
    62.             switch (sequencerStatus)
    63.             {
    64.                 case SequencerStatus.isPlaying:
    65.                     SetIcon(PauseTexture, SIGPLAY, ExhibitionID);
    66.                     SetTitle(PauseTitle, SIGPLAY, ExhibitionID);
    67.                     break;
    68.                 case SequencerStatus.isPausing:
    69.                     SetIcon(PlayTexture, SIGPLAY, ExhibitionID);
    70.                     SetTitle(PlayTitle, SIGPLAY, ExhibitionID);
    71.                     break;
    72.                 case SequencerStatus.isImage:
    73.                     SetIcon(PlayTextureDisabled, SIGPLAY, ExhibitionID);
    74.                     SetTitle(PlayTitle, SIGPLAY, ExhibitionID);
    75.                     break;
    76.                
    77.             }
    78.            
    79.             SetIcon(StopTexture, SIGSTOP, ExhibitionID);
    80.  
    81.             yield return new WaitForEndOfFrame();
    82.             lockButton = null;
    83.         }
     
    Adam_Carballo likes this.
  18. Bilbono

    Bilbono

    Joined:
    Feb 8, 2021
    Posts:
    2
    Will you add the switchToProfile function listed in elgato sdk documentation?
     
  19. Adam_Carballo

    Adam_Carballo

    Joined:
    Jun 1, 2014
    Posts:
    34
    Hmm, you mean this? (https://developer.elgato.com/documentation/stream-deck/sdk/events-sent/#switchtoprofile)
    • Note that a plugin can only switch to read-only profiles that are declared in its manifest.json file

    As far as I understand from profiles, apps can only switch to read-only profiles, that already come bundled with the app (manifest.json). Currently, the "Stream Deck Integration" app has no profiles set up. So, it would be useless to support this, as there is nothing to switch to... unless I misunderstood you
     
  20. Bilbono

    Bilbono

    Joined:
    Feb 8, 2021
    Posts:
    2
    Yes, I'm talking about this feature.

    I would like to create multiple profiles and be able to switch from one to another at runtime.
    Could I create my own manifest.json and handle it with your asset ?
     
  21. Adam_Carballo

    Adam_Carballo

    Joined:
    Jun 1, 2014
    Posts:
    34
    No, sorry. As far as I know, there is no profile switching support other than using the "Switch Profile" action on your Stream Deck (as a button itself).

    The only API available is switchToProfile, but it only supports plugin-owned profiles. You could modify the manifest.json of the plugin and add your own profiles, although this is not a supported behavior.

    I will look into "dummy profiles" though, maybe I can include some empty ones and hard-wire them to be used in this sense.
     
  22. Quatum1000

    Quatum1000

    Joined:
    Oct 5, 2014
    Posts:
    889
    Hi,

    I'd like to use Stream Deck to control an application was made by Unity on Windows10.
    Is there a integration to use Stream Deck inside a build executable (not in editor) ... like a controller?

    +And is it possible to configure the button freely and pass some mini images to the displays as well?

    Thank you..
     
  23. Adam_Carballo

    Adam_Carballo

    Joined:
    Jun 1, 2014
    Posts:
    34
    Yes, you can use a Stream Deck to control any built project in the same system. In your case, you can either use the internal API calls to update the events manually or use the StreamDeckRuntime script on any scene to enable the same events you could trigger during editor mode.

    And yes, the last version supports custom icons and titles for actions. Any Texture2D will work, so you could even send your entire camera viewport, if you really wanted to do that :)
     
    Quatum1000 likes this.
  24. Quatum1000

    Quatum1000

    Joined:
    Oct 5, 2014
    Posts:
    889
    Ah cool!

    BTW.. I would love to have a Fader and a Knob at the Elgato Desk. But that would never happen, I think. ;)
     
  25. Adam_Carballo

    Adam_Carballo

    Joined:
    Jun 1, 2014
    Posts:
    34
  26. Quatum1000

    Quatum1000

    Joined:
    Oct 5, 2014
    Posts:
    889
    Thank you. I want to control a pc 3D game vehicle with the elgato.

    I think a midi controller is to massive and most doesn't own real buttons. They mostly have pads.

    Currently it's possible to steer a vehicle with a big steering wheel. Otherwise you can not do this exactly with a keyboard.

    Aimos produce a usb knob controller.
    If it would be able use this knob to steer a game vehicle, this would be amazing.
    Aimos say it's completely programmable.

    https://www.amazon.ca/AIMOS-Multimedia-Controller-Device-Control/dp/B07SZDYPVR

    No idea if this would technically work. :)
     
  27. Xelnath

    Xelnath

    Joined:
    Jan 31, 2015
    Posts:
    402
    I'm attempting to send a 64x64 pixel image (Randomly generated) over as a test... and getting disconnected immediately. Here's the code:


    Code (CSharp):
    1.         var randomColors = new Color[64*64];
    2.         for (int i = 0; i < randomColors.Length; i++) {
    3.             randomColors[i] = UnityEngine.Random.ColorHSV(0, 1);
    4.         }
    5.  
    6.         var randomImage = new Texture2D(64, 64);
    7.         randomImage.SetPixels(randomColors);
    8.  
    9.         StreamDeckSettings.SetButtonImage(randomImage, "MemberId", null, true);
    StreamDeck - Disconnected - An exception has occurred while receiving.
    UnityEngine.Debug:Log (object)
    F10.StreamDeckIntegration.Log:Info (string) (at Assets/plugins/StreamDeckIntegration/Scripts/Log.cs:31)
    F10.StreamDeckIntegration.StreamDeckSocket:OnClose (object,WebSocketSharp.CloseEventArgs) (at Assets/plugins/StreamDeckIntegration/Scripts/StreamDeckSocket.cs:96)
    WebSocketSharp.Ext:Emit<WebSocketSharp.CloseEventArgs> (System.EventHandler`1<WebSocketSharp.CloseEventArgs>,object,WebSocketSharp.CloseEventArgs)
    WebSocketSharp.WebSocket:close (WebSocketSharp.CloseEventArgs,bool,bool,bool)
    WebSocketSharp.WebSocket:fatal (string,WebSocketSharp.CloseStatusCode)
    WebSocketSharp.WebSocket:fatal (string,System.Exception)
    WebSocketSharp.WebSocket/<>c__DisplayClass17:<startReceiving>b__16 (System.Exception)
    WebSocketSharp.Ext/<>c__DisplayClass9:<ReadBytesAsync>b__8 (System.IAsyncResult)
    System.Threading._ThreadPoolWaitCallback:performWaitCallback ()
     
  28. Xelnath

    Xelnath

    Joined:
    Jan 31, 2015
    Posts:
    402
    Note that the 2x2 pixel version works just fine.
     
  29. Adam_Carballo

    Adam_Carballo

    Joined:
    Jun 1, 2014
    Posts:
    34
    Can you make sure you enable all logs (https://docs.f10.dev/streamdeckintegration/manual/preferences.html), maybe some more info is available.

    Also, can you try to send an empty image instead?

    Code (CSharp):
    1. var image = new Texture2D(64,64);
    2. StreamDeckSettings.SetButtonImage(image, "MemberId", null, true);
     
  30. Xelnath

    Xelnath

    Joined:
    Jan 31, 2015
    Posts:
    402
    I am able to send solid colors without problems and some larger texture2d without a problem.

    I also decoded the Base64 string being sent and it looked Ok.
     
    Last edited: Oct 13, 2021
  31. Xelnath

    Xelnath

    Joined:
    Jan 31, 2015
    Posts:
    402
    I enabled all logging and no more information appeared:
    Code (CSharp):
    1. StreamDeck - Disconnected - An exception has occurred while receiving.
    2. UnityEngine.Debug:Log (object)
    3. F10.StreamDeckIntegration.Log:Info (string) (at Assets/plugins/StreamDeckIntegration/Scripts/Log.cs:31)
    4. F10.StreamDeckIntegration.StreamDeckSocket:OnClose (object,WebSocketSharp.CloseEventArgs) (at Assets/plugins/StreamDeckIntegration/Scripts/StreamDeckSocket.cs:96)
    5. WebSocketSharp.Ext:Emit<WebSocketSharp.CloseEventArgs> (System.EventHandler`1<WebSocketSharp.CloseEventArgs>,object,WebSocketSharp.CloseEventArgs)
    6. WebSocketSharp.WebSocket:close (WebSocketSharp.CloseEventArgs,bool,bool,bool)
    7. WebSocketSharp.WebSocket:fatal (string,WebSocketSharp.CloseStatusCode)
    8. WebSocketSharp.WebSocket:fatal (string,System.Exception)
    9. WebSocketSharp.WebSocket/<>c__DisplayClass17:<startReceiving>b__16 (System.Exception)
    10. WebSocketSharp.Ext/<>c__DisplayClass9:<ReadBytesAsync>b__8 (System.IAsyncResult)
    11. System.Threading._ThreadPoolWaitCallback:PerformWaitCallback ()
    It also may be worth mentioning that unity freezes up when I run this.
     
  32. Adam_Carballo

    Adam_Carballo

    Joined:
    Jun 1, 2014
    Posts:
    34
    The freezing makes sense, as this code runs on the main thread, either on the update loop or if immediate is true, it's immediately executed. On normal circumstances it's unoticable, but if the socket hangs, you get freezing.

    It sounds like the Stream Deck websocket may not be able to handle your generated texture. Is the base64 of the 64px random color image considerably larger in size than a random 64px texture? I've been able to break the socket with really large payloads in the past, but not something as small as 64px.
     
  33. Xelnath

    Xelnath

    Joined:
    Jan 31, 2015
    Posts:
    402
    Here's the exact texture I was sending:

    Code (CSharp):
    1. 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
     
  34. Xelnath

    Xelnath

    Joined:
    Jan 31, 2015
    Posts:
    402
    Ooops, now with attached image :)
     
  35. Xelnath

    Xelnath

    Joined:
    Jan 31, 2015
    Posts:
    402
    How large can these payloads be?
     
  36. Adam_Carballo

    Adam_Carballo

    Joined:
    Jun 1, 2014
    Posts:
    34
    Unknown. Elgato and Stream Deck don't really disclose that info on the SDK documentation. I had it crash with 1024x1024 images before, which kinda makes sense, as the actual button "resolution" is around ~80px, so anything bigger won't really show any differences.
     
  37. adrian-miasik

    adrian-miasik

    Joined:
    Feb 18, 2022
    Posts:
    5
    First off, this is a really great asset!
    I managed to get it working with my project very quickly and am able to control my timer app using it. So many thanks for developing this! It gives the StreamDeck quite a bit more value.

    I do have a question though, is there any way to execute or invoke a method on button key up / button release?
    I've looked into the Elgato StreamDeck SDK and they do have a KeyUp event, so I was wondering if perhaps something can be done similar using this asset? I got this asset just yesterday so I haven't explored much of the source code yet, but I got some ideas I'd want to try if this functionality is possible.
     
  38. Adam_Carballo

    Adam_Carballo

    Joined:
    Jun 1, 2014
    Posts:
    34
    Yes, that could be possible with an update to the plugin (StreamDeck plugin, not the Unity integration).

    The plugin already uses the key up event for some functionality, and most likely it would just need to be implemented as a choice (probably a toggle in the UI) to trigger actions on key up instead of key down, although the entire plugin architecture is based on key down events, so I can't be fully sure it would be a clean integration.

    If you have some valid use cases I can look into it and try to come up with something to make it possible.

    BTW, the Stream Deck plugin itself is actually open-source, if you want to take a look at how it works: https://github.com/AdamCarballo/streamdeck-unity-plugin
     
  39. Soaryn

    Soaryn

    Joined:
    Apr 17, 2015
    Posts:
    328
    Hey! I was trying to figure out a way to setup a streamdeck to have predetermined actions available for the end user on a built runtime. I am currently trying your solution out, but was so far uncertain if there was a way the build app could provide a drop down list of valid methods from within streamdeck configuration.

    Example: User starts up the built unity app, from within stream deck, they could drag an `invoke method` button on to the grid, then would see a drop down appear on the method id to let them select which method is the target.

    If they have already run the app and have a button, the ids would not be overwritten
     
  40. Adam_Carballo

    Adam_Carballo

    Joined:
    Jun 1, 2014
    Posts:
    34
    Hmm, that's some next-level setup idea :)

    The integration itself does not have any feasible way to do this, as the only data Unity provides to the Stream Deck is play/pause mode signals, and when you use the API to change text or action images.

    You could technically expand the plugin side (https://github.com/AdamCarballo/streamdeck-unity-plugin) to support sending whatever data you want to the Stream Deck, but I'm not sure you can modify the plugin's UI dynamically.

    The best I could come up with is to send to the plugin an address to a middle man (aka, put whatever you want in a file, and send the path), and then have the JS side of the plugin pull that information when trying to draw the plugin's UI

    Although this is "doable", it feels quite over-engineered to me. If you just want to support runtime (so, only when your app is built - end-user / player) you could fork the plugin, and build your own actions on top of the current ones, without any settings, so that you end up with a list of already setup actions with meaningful names. You can even distribute a Stream Deck layout along with your app so that the setup is done automatically.

    But yes, if you need something more complex/dynamic, you will have to go with the first route of a middle man. The Stream Deck Integration was never really designed to support this kind of use case, it was mostly to aid with project development
     
  41. Soaryn

    Soaryn

    Joined:
    Apr 17, 2015
    Posts:
    328
    Hmmm alright. I'll see what I can work out. I'll likely need to sit down with elgato then to ensure it is possible. If it isn't then I'll push for it to be

    Thanks for your help! I can at least utilize what tou have for now. On a side note, I meant to check but forgot, can invoke methods pressed on the stream deck activate when ot focued on the built app? Say I open note pad, and hit methodInvokeA, I'd assume it'd play due to the websocket event.
     
  42. Adam_Carballo

    Adam_Carballo

    Joined:
    Jun 1, 2014
    Posts:
    34
    Exactly, since it's a WebSocket focus is not required, either on the editor or in the runtime application (assuming the application has support for running on the background of course)
     
  43. Soaryn

    Soaryn

    Joined:
    Apr 17, 2015
    Posts:
    328
    Actually before contacting them, I do have a hypothesis for the app, in this case unity could provide more information to the streamdeck grid, as they do that now for the key lights. Which devices are present to turn on or modify. In this case, the method id would essentially a light, no?
     
  44. Adam_Carballo

    Adam_Carballo

    Joined:
    Jun 1, 2014
    Posts:
    34
    Not fully sure what you mean, but technically speaking Unity can send any data to the Stream Deck, the WebSocket contract is custom made for the integration.
     
  45. bjornsyse

    bjornsyse

    Joined:
    Mar 28, 2017
    Posts:
    102
    Hi. Getting compile problems related to Newtonsoft. I'm allready including this package via nuget, because I depend on a specific version of it. Have you bundled it with the plugin? Can it be decoupled?
     
  46. Adam_Carballo

    Adam_Carballo

    Joined:
    Jun 1, 2014
    Posts:
    34
    I double checked the source code, but as I can see Newtonsoft is not used anywhere (directly). There’s a custom minimal json parser for the specific data that needs to be sent and received, and that’s it.

    Although, the plugin does use websocket-sharp, an open source third-party websocket library. I checked their source (as the plugin has it as a dll) but I can’t find anything regarding JSON parsing either.

    I may be missing something, but I don’t think the plugin can cause conflicts with Newtonsoft, as there’s no usage of it for what I can see.

    Do you get the conflicts when you add the plugin and only the plugin? And are you sure it’s Newtonsoft and not the websocket-sharp plugin? As that one is also released through nuget, so maybe there’s some dependency somewhere.
     
  47. bjornsyse

    bjornsyse

    Joined:
    Mar 28, 2017
    Posts:
    102
    Hi Adam

    My bad, This was not even your plugin causing it. It just happened coincidently at the same time I added StreamDeckIntegration so I figured that's where it originated. Everything is solved here on my end, really sorry for wasting your time!

    Regards
    Björn
     
    Adam_Carballo likes this.
  48. adiuva

    adiuva

    Joined:
    Jan 21, 2017
    Posts:
    2
    Hey Adam!
    Just bought this and I love it so far. But when it comes to usability, I see some room for improvement. Unless I'm missing something, the end users need to know the function names they can use with the Stream Deck.

    Is it possible to either have a dropdown of all available functions (like for example in the OBS-Studio Stream Deck plugin, where you get a dropdown of all available Scenes if you add this)

    upload_2023-4-6_16-5-32.png

    Or write a custom Stream Deck plugin based on yours which offers the users ready-to-use buttons for the available functions in the game?

    And you mentioned a Discord server for support in a Review reply, but I can't find a link to it anywhere.

    Thanks
    Stefan
     
  49. Adam_Carballo

    Adam_Carballo

    Joined:
    Jun 1, 2014
    Posts:
    34
    Hi Stefan, sorry for the Discord link, I see it's not anymore in the description of the asset on the store, I think it got reverted at some point, I'll have to update it, here's the link (although it's just there to give more support options, I try to be a bit everywhere)

    The idea of the integration was more for development, as in, you definitely know the names of your methods, but I see how it could be used by someone as a client / player, as it allows usage even in runtime on built projects.

    I can recommend you to try to make a custom profile on the Stream Deck software and "distribute" that, where all methods are configured, but again, I can see how that may be a bit weird for the end user.

    I will check what limitations exist on the StreamDeck side, and try to send all known methods through the websocket to be displayed on a dropdown, maybe it works as expected and there aren't much changes required :)
     
  50. skeegee123

    skeegee123

    Joined:
    Aug 30, 2021
    Posts:
    4
    Does this asset currently support the StreamDeck+ and Unity 2021.3.*?