Search Unity

AudioStream - an audio streaming solution for all and everywhere

Discussion in 'Assets and Asset Store' started by r618, Jun 19, 2016.

  1. r618

    r618

    Joined:
    Jan 19, 2009
    Posts:
    1,084
    heh, wasn't aware of that limitation

    I have tested with the above mentioned input source just calculating signal energy separately for channel 0 and 1 in one of the included demo scenes ( the script there needs to be changed to calculate energy for each channel separately - as it is now it just sums all available channels... )

    So you should be good, if you encounter any problem don't hesitate to ask
    Cheers!
     
  2. EmeralLotus

    EmeralLotus

    Joined:
    Aug 10, 2012
    Posts:
    1,353
    Hi, I just update FMOD to fmodstudio11000_v2 and getting lots of errors.
    Unity2017.1.0p4 on a mac.
     
  3. r618

    r618

    Joined:
    Jan 19, 2009
    Posts:
    1,084
    Hi @rocki,

    yeah, it is a known issue with latest 1.10.00 version ( the C# API was changed )
    if possible, please use previous version until the package is updated:



    if you need latest please PM me, I can supply you with preliminary package
     
  4. r618

    r618

    Joined:
    Jan 19, 2009
    Posts:
    1,084
    Just notice:
    apart from C# API change in 1.10.00, FMOD also merged a bugfix for string parameters handling on github which will be in the next release of their integration
    I will therefore wait until it's there ( otherwise I'd have to work around tags retrieval in some not comfortable ways ) and release another major-ish 1.7 version since the new API is not backward compatible, too.

    Meanwhile please use 1.09.08 as depicted above and mentioned in OP

    Thanks!
     
  5. blaher

    blaher

    Joined:
    Oct 21, 2013
    Posts:
    62
    I finally got a chance to look at windows LASP. Have you considered wrapping LASP for AudioStreamInput2D instead of FMOD?

    Just curious. I really like what you have done w FMOD... but LASP latency is great for what I am doing.
     
  6. r618

    r618

    Joined:
    Jan 19, 2009
    Posts:
    1,084
    No, I haven't since it's not really feasible to have hard dependency on another library as part of the package and it lacks features compared to the rest of package, too. For example apart from being able to record only from default device, it can do so only in mono, and it can't open some devices which FMOD can. It also supports only standalone platforms.

    Thanks!

    Then I don't see a problem using it - unless something really significant escapes me that should not be a problem.


    I just had a closer look at how to integrate LASP with Unity some more, all you really need is just get audio buffer from it, this sample is fully usable without AudioStream:
    https://gist.github.com/r618/d74f07b6049fce20f1dc0dfa546bda89

    - I had to patch LASP a little to pass it Time.frameCount which is updated in Update/corourtine - since Time.frameCount can't be accessed from other than main thread (in earlier Unity versions I tested with), and made GetSampleRate accessible from it too (it's needed for audio clip).
     
  7. r618

    r618

    Joined:
    Jan 19, 2009
    Posts:
    1,084
    I've managed to successfully test pushing AudioSource audio data as source to an Icecast server -
    it's rough around the edges ( no parametrization, only raw audio stream, so bitrate is very high ), but... it works ! ಠ⌣ಠ

    I hope to get it out in next (1.7) release - should be just one component which can be added to any AudioSource.

    With this any Unity application can be used as source for streaming URL, has probably more sense for local networks though, since all points need to be directly accessible (more advanced networking such as NAT traversals/punching and such are not present).
    Should find its uses hopefully anyway.
    ~
     
  8. polytropoi

    polytropoi

    Joined:
    Aug 16, 2006
    Posts:
    681
    Love the plugin, but when running on ios 11.1 beta 4 or 5 I get scary, overdriven digital clipping when playing any AudioStream, even AudioStream demo scenes built from a clean project. I didn't see this behavior before upping to AudioStream v 1.6. I turned off bitcode as indicated in the readme. Not using GVR, should I try to remove that?
     
  9. r618

    r618

    Joined:
    Jan 19, 2009
    Posts:
    1,084
    hi @polytropoi,
    please replace line 188 in AudioStreamSupport.cs file with this:

    Code (CSharp):
    1. return (float)(short)result;
    major sorry for the inconvenience !
    This slipped through cracks, yes, it was due to 1.6.

    And yes, you can remove GVR (libgvraudio library file for iOS) from the build/project, if you don't use it, it's loaded only on demand when requested.
     
  10. polytropoi

    polytropoi

    Joined:
    Aug 16, 2006
    Posts:
    681
    Thanks @r618, that did the trick - keep up the good work!
     
    r618 likes this.
  11. r618

    r618

    Joined:
    Jan 19, 2009
    Posts:
    1,084
    Glad to hear it, thanks !
     
  12. rickomax

    rickomax

    Joined:
    Jun 11, 2013
    Posts:
    606
    Hi. Does this plugin supports mixing AudioListener and Microphone (AudioSource) input?
    I have scenario where I need to record game audio input and microphone without microphone playback.
    This data should be avaliable "real-time", just like the "OnAudioFilterRead" function.
    Do you think your plugin fits these needs?
     
    ROBYER1 likes this.
  13. r618

    r618

    Joined:
    Jan 19, 2009
    Posts:
    1,084
    hi @rickomax
    it's not provided out of the box, but it is possible:
    currently there are two input components ( AudioStreamInput, and AudioStreamInput2D ), both of them have hard dependency on AudioSource -
    While AudioStreamInput can't be used for mixing with AudioListener in this way since it creates its own clip, AudioStreamInput2D can be since it operates on the existing buffer only via OnAudioFilterRead -

    You would need to patch it though, but not much - it's about 4 lines of code - let me know if needed, I will provide it.

    You should have combined signal via OnAudioFilterRead function in custom script attached to listener / main camera this way.
     
  14. rickomax

    rickomax

    Joined:
    Jun 11, 2013
    Posts:
    606
    @r618. Are you able to offer a stripped-down version of audiostream only containing the game audio + microphone audio recording and the "OnAudioFilterRead" callback with the mixed content? I mean, I would not use all of your plugin features, only these I just told you. If you cannot, and be able to prepare a sample using these resources, that would be good anyway.
     
    ROBYER1 likes this.
  15. r618

    r618

    Joined:
    Jan 19, 2009
    Posts:
    1,084
    While possible, I think it wouldn't be fair to all existing and future developers who purchase/d this. Not to mention that it would require _some_ work to package everything properly.

    If by "a sample using these resources" you mean testing build, I'll see what I can do. You didn't mention what platform you would like to run this on, though.
     
  16. rickomax

    rickomax

    Joined:
    Jun 11, 2013
    Posts:
    606
    Windows only, at the moment.

     
  17. SiliconDroid

    SiliconDroid

    Joined:
    Feb 20, 2017
    Posts:
    302
    Great asset, loving the low CPU cost and GC compared to NAudio solutions.

    I've made a class that controls an AudioStreamMinimal.
    It's the same class I used to control a previous NAudio based solution.
    To handle intermitent network: It polls AudioStreamMinimal.isPlaying; When it sees no longer playing it stops and restarts.

    When running in editor everything works great.
    When running on Android phone it runs super sweet until my class attempts reconnect: then I notice render thread hang for seconds during reconnect attempt.

    I think it's getting stuck in AudioStreamBase.Stop_Internal.
    I may workaround by turning AudioStreamBase.Stop_Internal into a coroutine and then add func: bool HasStopped() which I poll to wait for stop.

    EDIT: oh it's deeper than I thought AudioStreamBase.Stop_Internal should only block for 100ms max because you only iterate 5x max.

    Code (CSharp):
    1. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    2. //   ____ ___ _     ___ ____ ___  _   _   ____  ____   ___ ___ ____
    3. //  / ___|_ _| |   |_ _/ ___/ _ \| \ | | |  _ \|  _ \ / _ \_ _|  _ \
    4. //  \___ \| || |    | | |  | | | |  \| | | | | | |_) | | | | || | | |
    5. //   ___) | || |___ | | |__| |_| | |\  | | |_| |  _ <| |_| | || |_| |
    6. //  |____/___|_____|___\____\___/|_| \_| |____/|_| \_\\___/___|____/
    7. //
    8. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    9.  
    10. using System.Diagnostics;
    11. using System.Collections;
    12. using System.Collections.Generic;
    13. using UnityEngine;
    14. using AudioStream;
    15.  
    16. namespace SiliconDroid
    17. {
    18.     //#####################################################################################################################
    19.     //    CLASS: lib_radio
    20.     //#####################################################################################################################
    21.     public class lib_radio : SD_MonoBehaviour
    22.     {
    23.         ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    24.         //    CONSTANTS
    25.         private const int K_I_STATE_TIMEOUT_SECS = 10;
    26.         private const int K_I_STREAM_TIMEOUT_SECS = 2;
    27.         private const int K_I_WAIT_FOR_STABLE_STATE_SECS = 2;
    28.         private const float K_F_STI_PERIOD = 0.5f;
    29.         private const string K_S_RECONNECT = "Radio stream reconnecting...";
    30.  
    31.         private enum STATE
    32.         {
    33.             IDLE,
    34.             STOPPING1,
    35.             STOPPING2,
    36.             STARTING,
    37.             PLAYING,
    38.             RESTARTING,
    39.         }
    40.  
    41.         ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    42.         //    WORKING DATA
    43.         private class WORKING_DATA
    44.         {
    45.             public AudioStreamMinimal cStream = null;
    46.             public string sTrack_name = "";
    47.             public STATE eState = STATE.IDLE;
    48.             public string sNeedToPlayUrl = "";
    49.             public string sNeedToPlayUrl_last = "";
    50.             public object oCallback = null;
    51.             public string sCallback = "";
    52.             public Stopwatch oStopwatchTimeout = new Stopwatch();
    53.             public Stopwatch oStopwatchWait = new Stopwatch();
    54.             public float fTimeLastGoodStream = 0.0f;
    55.             public float fVolume;
    56.             public bool bFinalMixable = true;
    57.             public string sArtist_set = "";
    58.             public string sTitle_set = "";
    59.             public bool bShowingReconnectScroller = false;
    60.         }
    61.         WORKING_DATA v = new WORKING_DATA();
    62.  
    63.         ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    64.         //    AWAKE
    65.         void Awake()
    66.         {
    67.             InitRadio();
    68.             v.oStopwatchTimeout.Stop();
    69.             InvokeRepeating("STI", 0.0f, K_F_STI_PERIOD);
    70.         }
    71.  
    72.         ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    73.         //    QUIT
    74.         void OnApplicationQuit()
    75.         {
    76.             StopPlaying();
    77.         }
    78.  
    79.         ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    80.         //   ____  _   _ ____  _     ___ ____   ___ _   _ _____ _____ ____  _____ _    ____ _____
    81.         //  |  _ \| | | | __ )| |   |_ _/ ___| |_ _| \ | |_   _| ____|  _ \|  ___/ \  / ___| ____|
    82.         //  | |_) | | | |  _ \| |    | | |      | ||  \| | | | |  _| | |_) | |_ / _ \| |   |  _|
    83.         //  |  __/| |_| | |_) | |___ | | |___   | || |\  | | | | |___|  _ <|  _/ ___ \ |___| |___
    84.         //  |_|    \___/|____/|_____|___\____| |___|_| \_| |_| |_____|_| \_\_|/_/   \_\____|_____|
    85.         //
    86.         ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    87.  
    88.         ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    89.         //    PLAY A URL
    90.         public bool PlayUrl(string sUrl, object oCallback = null, string sCallback = "")
    91.         {
    92.             v.oCallback = oCallback;
    93.             v.sCallback = sCallback;
    94.             v.oStopwatchTimeout.Reset();
    95.             v.oStopwatchTimeout.Start();
    96.             StopPlaying();
    97.             v.sNeedToPlayUrl = sUrl;
    98.             v.sNeedToPlayUrl_last = v.sNeedToPlayUrl;
    99.             return true;
    100.         }
    101.  
    102.         ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    103.         //    STOP PLAYING
    104.         public bool StopPlaying(bool bRestarting = false)
    105.         {
    106.             v.cStream.Stop();
    107.             v.eState = STATE.STOPPING1;
    108.  
    109.             if(bRestarting)
    110.             {
    111.                 SetScrollerText(K_S_RECONNECT);
    112.             }
    113.             else
    114.             {
    115.                 SetScrollerText("");
    116.             }
    117.             v.sArtist_set = "";
    118.             v.sTitle_set = "";
    119.             return true;
    120.         }
    121.  
    122.         ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    123.         //    SET VOLUME
    124.         public bool SetVolume(float fVolume = 777.7f)
    125.         {
    126.             if (fVolume == 777.7f)
    127.             {
    128.                 fVolume = SD_PlayerPrefs.GetInt(PREFS.RADIO_I_VOLUME, 50) * 0.01f;
    129.             }
    130.             fVolume = Mathf.Clamp01(fVolume);
    131.  
    132.             if (v.cStream)
    133.             {
    134.                 v.cStream.volume = fVolume;
    135.             }
    136.             v.fVolume = fVolume;
    137.  
    138.             return true;
    139.         }
    140.  
    141.         ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    142.         //    SET MIXABLE
    143.         public void SetFinalMixable(bool bFinalMixable)
    144.         {
    145.             v.bFinalMixable = bFinalMixable;
    146.         }
    147.  
    148.         ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    149.         //    SET MIX VOLUME
    150.         public void SetFinalMixVolume(float fMix)
    151.         {
    152.             if (!v.bFinalMixable)
    153.             {
    154.                 return;
    155.             }
    156.             if (v.cStream)
    157.             {
    158.                 v.cStream.volume = v.fVolume * fMix;
    159.             }
    160.         }
    161.  
    162.         ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    163.         //    IS IDLE
    164.         public bool IsIdle()
    165.         {
    166.             return (v.eState == STATE.IDLE);
    167.         }
    168.  
    169.         ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    170.         //    IS PLAYING
    171.         public bool IsPlaying()
    172.         {
    173.             return (v.eState == STATE.PLAYING);
    174.         }
    175.  
    176.         ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    177.         //   ____  ____  _____     ___  _____ _____   _   _ _____ _     ____  _____ ____  ____
    178.         //  |  _ \|  _ \|_ _\ \   / / \|_   _| ____| | | | | ____| |   |  _ \| ____|  _ \/ ___|
    179.         //  | |_) | |_) || | \ \ / / _ \ | | |  _|   | |_| |  _| | |   | |_) |  _| | |_) \___ \
    180.         //  |  __/|  _ < | |  \ V / ___ \| | | |___  |  _  | |___| |___|  __/| |___|  _ < ___) |
    181.         //  |_|   |_| \_\___|  \_/_/   \_\_| |_____| |_| |_|_____|_____|_|   |_____|_| \_\____/
    182.         //                                                                          
    183.         ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    184.  
    185.         ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    186.         //    STI
    187.         private void STI()
    188.         {
    189.  
    190.             //  CHECK FOR TIMEOUT
    191.             if (v.oStopwatchTimeout.IsRunning)
    192.             {
    193.                 if (v.oStopwatchTimeout.Elapsed.Seconds > K_I_STATE_TIMEOUT_SECS)
    194.                 {
    195.                     v.oStopwatchTimeout.Stop();
    196.                     v.cStream.Stop();
    197.                     InformPlayCaller();
    198.                     LOGW("TIMED OUT AFTER " + K_I_STATE_TIMEOUT_SECS + " SECONDS IN STATE: " + v.eState);
    199.                     SetScrollerText("");
    200.                     v.eState = STATE.IDLE;
    201.                 }
    202.             }
    203.  
    204.             //---------------------------------------------------------------------------------------------------------------------
    205.             //    IDLE
    206.             if (v.eState == STATE.IDLE)
    207.             {
    208.             }
    209.             //---------------------------------------------------------------------------------------------------------------------
    210.             //    STOPPING 1
    211.             else if (v.eState == STATE.STOPPING1)
    212.             {
    213.                 if (!v.cStream.isPlaying)
    214.                 {
    215.                     LOGM("STOPPED PLAYING");
    216.                     v.eState = STATE.STOPPING2;
    217.                     v.oStopwatchWait.Reset();
    218.                     v.oStopwatchWait.Start();
    219.                 }
    220.             }
    221.             //---------------------------------------------------------------------------------------------------------------------
    222.             //    STOPPING 2
    223.             else if (v.eState == STATE.STOPPING2)
    224.             {
    225.                 if (v.oStopwatchWait.Elapsed.Seconds > K_I_WAIT_FOR_STABLE_STATE_SECS)
    226.                 {
    227.                     //  START PLAYING REQUESTED URL
    228.                     if (v.sNeedToPlayUrl.Length > 0)
    229.                     {
    230.                         LOGM("STARTING...");
    231.                         v.cStream.url = v.sNeedToPlayUrl;
    232.                         v.cStream.Play();
    233.                         v.eState = STATE.STARTING;
    234.                         v.oStopwatchWait.Reset();
    235.                         v.oStopwatchWait.Start();
    236.                     }
    237.                     //  BACK TO IDLE
    238.                     else
    239.                     {
    240.                         v.eState = STATE.IDLE;
    241.                         v.oStopwatchWait.Stop();
    242.                     }
    243.                 }
    244.             }
    245.             //---------------------------------------------------------------------------------------------------------------------
    246.             //    STARTING
    247.             else if (v.eState == STATE.STARTING)
    248.             {
    249.                 //  PLAYING OK
    250.                 if (v.cStream.isPlaying)
    251.                 {
    252.                     LOGM("STARTED PLAYING");
    253.                     v.oStopwatchTimeout.Stop();
    254.                     v.sNeedToPlayUrl = "";
    255.                     v.eState = STATE.PLAYING;
    256.                     InformPlayCaller();
    257.                     if(v.bShowingReconnectScroller)
    258.                     {
    259.                         SetScrollerText("");
    260.                     }
    261.                 }
    262.             }
    263.             //---------------------------------------------------------------------------------------------------------------------
    264.             //    PLAYING
    265.             else if (v.eState == STATE.PLAYING)
    266.             {
    267.                 if (v.cStream.isPlaying && !v.cStream.starving)
    268.                 {
    269.                     v.fTimeLastGoodStream = Time.time;
    270.                 }
    271.                 else if (Time.time - v.fTimeLastGoodStream > K_I_STREAM_TIMEOUT_SECS)
    272.                 {
    273.                     LOGW("LOST STREAM FOR " + K_I_STREAM_TIMEOUT_SECS + "s");
    274.                     v.eState = STATE.RESTARTING;
    275.                 }
    276.             }
    277.             //---------------------------------------------------------------------------------------------------------------------
    278.             //    RESTARTING
    279.             else if (v.eState == STATE.RESTARTING)
    280.             {
    281.                 LOGM("RESTARTING...");
    282.                 StopPlaying(true);
    283.                 v.sNeedToPlayUrl = v.sNeedToPlayUrl_last;
    284.             }
    285.         }
    286.  
    287.         ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    288.         //    INIT
    289.         private bool InitRadio()
    290.         {
    291.             this.name = main.K_S_NAME_RADIO;
    292.  
    293.             //  FMOD STREAM
    294.             v.cStream = this.gameObject.AddComponent<AudioStreamMinimal>();
    295.             v.cStream.logLevel = LogLevel.ERROR;
    296.             v.cStream.playOnStart = false;
    297.  
    298.             //  REGISTER LISTENERS
    299.             v.cStream.OnPlaybackStarted = new EventWithStringParameter();
    300.             v.cStream.OnPlaybackStarted.AddListener((sString) => { OnPlaybackStarted(sString); });
    301.  
    302.             v.cStream.OnPlaybackPaused = new EventWithStringBoolParameter();
    303.             v.cStream.OnPlaybackPaused.AddListener((sString, bBool) => { OnPlaybackPaused(sString, bBool); });
    304.  
    305.             v.cStream.OnPlaybackStopped = new EventWithStringParameter();
    306.             v.cStream.OnPlaybackStopped.AddListener((sString) => { OnPlaybackStopped(sString); });
    307.  
    308.             v.cStream.OnTagChanged = new EventWithStringStringStringParameter();
    309.             v.cStream.OnTagChanged.AddListener((sString1, sString2, sString3) => { OnTagChanged(sString1, sString2, sString3); });
    310.  
    311.             v.cStream.OnError = new EventWithStringStringParameter();
    312.             v.cStream.OnError.AddListener((sString1, sString2) => { OnError(sString1, sString2); });
    313.  
    314.             //  DONE
    315.             return true;
    316.         }
    317.  
    318.         ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    319.         //    HANDLER:    STARTED
    320.         private void OnPlaybackStarted(string sString)
    321.         {
    322.             //LOGW(sString);
    323.         }
    324.  
    325.         ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    326.         //    HANDLER:    STOPPED
    327.         private void OnPlaybackStopped(string sString)
    328.         {
    329.             //LOGW(sString);
    330.         }
    331.  
    332.         ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    333.         //    HANDLER:    PAUSED
    334.         private void OnPlaybackPaused(string sString, bool bBool)
    335.         {
    336.             //LOGW(sString + ", " + bBool);
    337.         }
    338.  
    339.         ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    340.         //    HANDLER:    ERROR
    341.         private void OnError(string sString1, string sString2)
    342.         {
    343.             LOGW("ERROR: " + sString1 + ", " + sString2);
    344.             v.eState = STATE.RESTARTING;
    345.         }
    346.  
    347.         ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    348.         //    HANDLER:    TAG CHANGED
    349.         private const float K_F_TAG_RX_TIME_FILTER = 0.2f;
    350.         private string sArtist, sTitle;
    351.         private float fTimeRX;
    352.         private void OnTagChanged(string sString1, string sString2, string sString3)
    353.         {
    354.             LOGW(sString1 + ", " + sString2 + ", " + sString3);
    355.  
    356.             //  TEMPORAL FILTER
    357.             if ((Time.time - fTimeRX) > K_F_TAG_RX_TIME_FILTER)
    358.             {
    359.                 sArtist = "";
    360.                 sTitle = "";
    361.             }
    362.             fTimeRX = Time.time;
    363.  
    364.             //  ARTIST
    365.             if (sString2 == "ARTIST")
    366.             {
    367.                 if(sTitle != "" && (Time.time - fTimeRX) < K_F_TAG_RX_TIME_FILTER)
    368.                 {
    369.                     SetArtistTitle(sString3, sTitle);
    370.                     sArtist = "";
    371.                     sTitle = "";
    372.                 }
    373.                 else
    374.                 {
    375.                     sArtist = sString3;
    376.                 }
    377.             }
    378.             //  TITLE
    379.             else if (sString2 == "TITLE")
    380.             {
    381.                 if (sArtist != "" && (Time.time - fTimeRX) < K_F_TAG_RX_TIME_FILTER)
    382.                 {
    383.                     SetArtistTitle(sArtist, sString3);
    384.                     sArtist = "";
    385.                     sTitle = "";
    386.                 }
    387.                 else
    388.                 {
    389.                     sTitle = sString3;
    390.                 }
    391.             }
    392.         }
    393.  
    394.         ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    395.         //  SET ARTIST TITLE
    396.         private void SetArtistTitle(string sArtist, string sTitle)
    397.         {
    398.             const string K_S_DIVIDER = "     ";
    399.  
    400.             //  PREVENT ERRANT SHORT STRINGS COMING IN
    401.             if (v.sArtist_set.Contains(sArtist) && v.sTitle_set.Contains(sTitle))
    402.             {
    403.                 return;
    404.             }
    405.             v.sArtist_set = sArtist;
    406.             v.sTitle_set = sTitle;
    407.             SetScrollerText(sArtist + K_S_DIVIDER + sTitle);
    408.         }
    409.  
    410.         ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    411.         //    SET COCKPIT SCROLLER TEXT
    412.         lib_gui_root cGui = null;
    413.         private void SetScrollerText(string sText)
    414.         {
    415.             //  SHOWING RECON
    416.             v.bShowingReconnectScroller = sText == K_S_RECONNECT;
    417.  
    418.             //  SET GUI
    419.             if (!cGui)
    420.             {
    421.                 if (main.v.cMechPlayer)
    422.                 {
    423.                     if (main.v.cMechPlayer.GetComputerRoot())
    424.                     {
    425.                         cGui = main.v.cMechPlayer.GetComputerRoot().v.cGui;
    426.                     }
    427.                 }
    428.             }
    429.             if(!cGui)
    430.             {
    431.                 LOGW("CANT GET GUI");
    432.             }
    433.             cGui.SetScrollerText(sText);
    434.         }
    435.  
    436.         ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    437.         //    INFORM PLAY CALLER
    438.         private void InformPlayCaller()
    439.         {
    440.             v.oCallback.GetType().GetMethod(v.sCallback).Invoke(v.oCallback, new object[] { IsPlaying() });
    441.         }
    442.     }
    443. }
     
    Last edited: Oct 27, 2017
  18. r618

    r618

    Joined:
    Jan 19, 2009
    Posts:
    1,084
    hey @SiliconDroid,
    funnily enough I was thinking about adding automatic retries when the connection is dropped to the streaming itself, but realized that this might work better when left for the user code to handle

    so you're doing it right - except I maybe handle OnPlaybackStopped callback, too - that is invoked when it stops due to lack of data from stream - this happens for (hosted) files without any error, in your case with streaming radio probably doesn't matter since erroneous network update will invoke both OnError and OnPlaybackStopped; OnPlaybackStopped might be a better indication that the stream is dead, and is ready to re/start again, though.

    As for the Sleeps - yea, it's a bit unfortunate; you might get away by releasing channel and sound immediately, without any error checking; - I played this safe according to FMOD sample code where they use it - but I'll test this some more to see what can I safely assume since FMOD got quite a few updates since those samples were written.

    Whole second does not sound right though: the Stop_Internal is called also when starting - it tries to cleanup any startup in progress (this was added due to a user clicking on e.g. Start button quickly more than one time in succession) - when network has problems the whole timeout is exhausted which should add up 200 ms overall since you're stopping it, too, I guess. Not sure where the rest is coming from, but I think startup state should be handled more cleverly as it is now.

    btw good choice with AudioStreamMinimal when you don't need extra AudioSource functionality, too 0 it has more consistent network behavior across platforms, especially for drops/starvation.

    Thanks for feedback, I'll look into these!
     
    SiliconDroid likes this.
  19. SiliconDroid

    SiliconDroid

    Joined:
    Feb 20, 2017
    Posts:
    302
    I did not mention in my previous post but: the freeze did not happen every restart attempt, just some, when I was stress testing using poor network.

    When the issue happens I presume AudioStreamBase.Stop internal function is timing out, and thus exiting without closing stuff.

    I've since made AudioStreamBase.Stop_Internal into a coroutine in which i put a 1000 frame timeout (~16 secs).
    I also put in logic to prevent start/stop state overlap (user stop start repeat fast).
    This has almost removed the problem, I only saw it once over an hour testing, I presume coroutine couldn't release the stuff before it's 1000 frames were up?

    I changed it to only call if the stream is established.

    Thx for further info. I will try and act on OnPlaybackStopped.

    P.S. any expected date for when you will update AudioStream to work with FMOD 1.10.00?
     
  20. r618

    r618

    Joined:
    Jan 19, 2009
    Posts:
    1,084
    Hard to tell exactly - there are more points of failure when network is unreliable - I'll look into the codes and possibly try to simplify it. I think better option might be to always start from scratch with new system (cleaning old unsuccessful attempt completely), although that would introduce another latency for users who want to play local files quickly - so I'm not sure yet;

    I'm waiting as impatiently as you are - I'll PM you package with changes for 1.10.00 once I (hopefully) merge it / also fmod wrapper needs to be patched, but it is literally two lines for tags to be working /
     
    SiliconDroid likes this.
  21. SiliconDroid

    SiliconDroid

    Joined:
    Feb 20, 2017
    Posts:
    302
    So like?:
    1. instantiate a gameobject and add AudioStreamMinimal to it.
    2. Play stream on it.
    3. If stream stops playing (OnStoppedPlaying) destroy it and goto 1
     
  22. r618

    r618

    Joined:
    Jan 19, 2009
    Posts:
    1,084
    Yea - system is now cleared in
    Code (CSharp):
    1. OnDisable
    , so if you destroy GO with component on it it should go away completely.
     
    SiliconDroid likes this.
  23. r618

    r618

    Joined:
    Jan 19, 2009
    Posts:
    1,084
    Decided to submit 1.7 for review, despite the fact that FMOD needs to be manually patched for tags to work.

    V 1.7 112017
    - changes for FMOD Studio Unity Integrations 1.10.00 (warning: Versions prior to 1.10.00 are no longer supported.)
    - for tags support and 1.10.00 please see 'General Unity / mobile / FMOD plugin notes'
    - AudioStreamInput2D has now hard dependency on AudioSource removed - you can mix input signal with e.g. AudioListener buffer
    - Autodetect stream format option - it is default, but you *have* to select proper format on iOS
    - fixes, optimizations and better exception handling
    - due to minimal supported version of Unity on macOS's APFS being 5.5.4p5, AudioStream is submitted with this version
     
    SiliconDroid likes this.
  24. Johnfred_Fredjohns

    Johnfred_Fredjohns

    Joined:
    Sep 7, 2017
    Posts:
    2
    Hello,
    I am currently working on a project with the goal of supporting bidirectional audio communication via an icecast server. Audio would need to be received from the server. Also would need the ability to stream incoming microphone input from Unity to the server. Is this something that this asset can support?
    Thank you in advance for any feedback!
     
  25. r618

    r618

    Joined:
    Jan 19, 2009
    Posts:
    1,084
    Hi @JFLCSERL -
    Icecast -> Unity works now - you just point AudioStream component url to the server url and it will play it
    Second part is in the works but not yet available - I have partial solution where any AudioSource in Unity can be setup as an Icecast source, but has limitation that it has no encoding support right now providing raw PCM data only - resulting in network bandwidth rather wide - i.e. 100-200 kB/s.
    If you don't find anything else and don't mind the above let me know - I can PM you IcecastSource component.
    Hard to tell when proper encoding support will be ready.
     
    Last edited: Nov 3, 2017
  26. r618

    r618

    Joined:
    Jan 19, 2009
    Posts:
    1,084
    The update is live ~-

    FMOD Studio 1.10.01 was released today as well with some fixes, so no workarounds on c# part are needed for now.
     
    SiliconDroid likes this.
  27. SiliconDroid

    SiliconDroid

    Joined:
    Feb 20, 2017
    Posts:
    302
    Awesome!
     
    r618 likes this.
  28. r618

    r618

    Joined:
    Jan 19, 2009
    Posts:
    1,084
    Hey @SiliconDroid, glad you like it ! :)

    But I also spoke too soon -)

    - there is an issue building on iOS with latest 1.10.01, unfortunately - seems like some newly added functionality didn't make it all the way into static library and link step fails hopelessly - it's enough to comment out the DllImported offender in fmod_studio.cs though and it will run without problems. (AudioStream does not use the function).

    Other platforms are unaffected.

    Feel free to ask if anything's not clear when building for iOS, I will provide exact lines.
     
  29. SiliconDroid

    SiliconDroid

    Joined:
    Feb 20, 2017
    Posts:
    302
    iOS is not on my target list, so I'm fine.:)
     
  30. jcaravana

    jcaravana

    Joined:
    Jun 1, 2015
    Posts:
    5
    Hello, I'm working on a project where I need to create a server to distribute audio to the devices.
    I saw in your answer above that you would have a partial solution where any AudioSource in Unity can be configured as a source .

    You would need to make audiosource available as an audio stream.

    Could you help me with this?

    Thank you very much in advance!
     
  31. r618

    r618

    Joined:
    Jan 19, 2009
    Posts:
    1,084
    Hi @jcaravana

    I've just submitted for review 1.7.1 which contains new IcecastSource component which enables any AudioSource to become an Icecast source, using PCM, or OGGVORBIS encoding.

    Check it out and let me know how it goes once it's live !
     
  32. jcaravana

    jcaravana

    Joined:
    Jun 1, 2015
    Posts:
    5
    [QUOTE = "r618, post: 3281638, membro: 4884"] Olá [USER = 852514] @jcaravana [/ USER]

    Acabei de enviar para revisão 1.7.1 que contém o novo componente IcecastSource que permite que qualquer AudioSource se torne uma fonte Icecast, usando a codificação PCM ou OGGVORBIS.

    Confira e me avise como vai uma vez que esteja ao vivo! [/ QUOTE]
    Great news!

    I will await the availability of the update in the asset store for testing and give you the implementation feedback.

    Thanks in advance for the support!
     
  33. r618

    r618

    Joined:
    Jan 19, 2009
    Posts:
    1,084
    Here's changelog:

    v 1.7.1 112017
    - bugfix for AudioSource stopping imediately when set to (default) automatic start
    - more startup stability fixes esp. for iOS
    - new IcecastSource component and demo scene providing PCM and OGGVORBIS encoded stream from any AudioSource to an Icecast 2.4.0+ mountpoint (see README for details)

    I'll post here once it's live.
     
  34. polytropoi

    polytropoi

    Joined:
    Aug 16, 2006
    Posts:
    681
    @r618, what is needed to build on ios? I'm getting the build error you mentioned above...
     
  35. r618

    r618

    Joined:
    Jan 19, 2009
    Posts:
    1,084
    @polytropoi the recent linker error on iOS is caused by not including newly added FMOD_Studio_EventInstance_SetParameterValuesByIndices in iOS static library, it's enough to just comment it out at lines 1173 and 1174 in fmod_studio.cs:
    Code (CSharp):
    1. // [DllImport(STUDIO_VERSION.dll)]
    2. // private static extern RESULT FMOD_Studio_EventInstance_SetParameterValuesByIndices (IntPtr _event, int[] indices, float[] values, int count);
    and change also caling function setParameterValuesByIndices at line 1091:
    Code (CSharp):
    1. return RESULT.OK; // FMOD_Studio_EventInstance_SetParameterValuesByIndices(this.handle, indices, values, count);
    according to FMOD they should have it fixed in next release
     
    Last edited: Nov 13, 2017
  36. polytropoi

    polytropoi

    Joined:
    Aug 16, 2006
    Posts:
    681
    Cool, that did it, thanks again... btw, small correction to your post above, the second change is on line 1091, not 1191.
     
    r618 likes this.
  37. r618

    r618

    Joined:
    Jan 19, 2009
    Posts:
    1,084
    right, corrected, sorry :)
     
  38. r618

    r618

    Joined:
    Jan 19, 2009
    Posts:
    1,084
    seems like the update made it
    feel free to check it out @jcaravana and let me know if you encounter any troubles setting it up

    I should mention that Vorbis encoder used is not lightweight and requires rather some computation to be handled in realtime quickly, so good CPU is a must.
    And since it can handle only 44k+ outputs currently. it does not run on mobiles with their 24k something samplerates.

    In any case, I hope it will be useful on standalones at least!

    Edit: PCM can be streamed to Icecast mount point even from mobiles though
     
    Last edited: Nov 14, 2017
  39. jcaravana

    jcaravana

    Joined:
    Jun 1, 2015
    Posts:
    5
    Thank you very much, my friend.

    I would just like you to show me an example of a scene where I create my icecast provider from an audiosource and in the other scene I consume the icecast provider created by playing in an audiosource.
    The idea is to play an audiosource from my server application in the client application.
    Thanks in advance for the immense support.
     
  40. jcaravana

    jcaravana

    Joined:
    Jun 1, 2015
    Posts:
    5
    Sorry for my ignorance.
    Disregard my last post.
    I installed icecast server http://icecast.org, and set up mountpoint.

    Your component worked beautifully by replicating the audio to the server.

    I did the test of the PC for the android phone.

    I'll tell you that was one of the best acquisitions I made in the asset store.

    Congratulations on the beautiful work!
     
    r618 likes this.
  41. r618

    r618

    Joined:
    Jan 19, 2009
    Posts:
    1,084
    Glad to hear you had positive experience and thanks for letting me know!
    (was about to write a lengthy post explaining the setup, but seems like it's not needed :)

    Good luck with the project and feel free to ask anytime something's not clear )
     
  42. Divistri

    Divistri

    Joined:
    Oct 1, 2015
    Posts:
    9
    Hello! I've recently bought your asset, but am running into an issue with version 1.7 112017 running on Unity 2017.2.0f3. Every time I run the project an error of FMOD Studio: Build path not set is displayed. Though I don't need the entire FMOD Studio program and only need it for the AudioStream asset.

    Would you be able to help me with this? Thanks!
     
    Last edited: Nov 19, 2017
  43. r618

    r618

    Joined:
    Jan 19, 2009
    Posts:
    1,084
    @Divistri yes you don't need everything from the FMOD Unity Integrations package - just C# wrapper for native plugins is needed.
    The parts you can safely delete from the project after importing FMOD package are hopefully in great detail described in the first or so paragraph of the README file, but in essence you need only all source files in Plugins/FMOD/Wrapper, and all native plugins in Plugins ( except Plugins/Editor ). You can delete everything else including generated configuration files in e.g. StreamingAssets.

    You can also import only the required assets from the package when importing it:

    upload_2017-11-19_7-8-30.png

    ( you should include LICENSE.txt file, too and fmodplugins.cpp is needed for GoogleVR on iOS - it is harmless on other platforms - that's why they are included in the screenshot )

    Hope this helps, let me know if you encounter anything else to be not clear enough !
     
    Divistri likes this.
  44. Divistri

    Divistri

    Joined:
    Oct 1, 2015
    Posts:
    9
    Thank you for the incredibly quick response! That definitely helped clarify the assets I needed to keep for AudioStream. On that note, I had another question on the functionality of AudioStream. I'm attempting to stream an audio file from the StreamingAssets folder in Unity, however on Android this is hidden under an .apk archive. I found a Unity Answer that states to access these types of files you need to use Unity's WWW class rather than System.IO.FileInfo. Does this affect AudioStream's ability to stream an audio file from the StreamingAssets folder on Android?
     
  45. r618

    r618

    Joined:
    Jan 19, 2009
    Posts:
    1,084
    Yes, on Android StreamingAssets are (unfortunately) incorporated in the apk archive and to access anything in it you have to use Unity's provided file functions present in the WWW API (*) currently, which can access and extract resources from it.
    AudioStream needs a final location of a file/url to be able to play it, so I'd extract the file in some writable location and pass that as url to it; you can do something like this (the AndroidStreamingAssets script should be attached to the same GO as AudioStream, provide your file name / possibly look for all relevant files in StreamingAssets etc):

    Code (CSharp):
    1. using System.Collections;
    2. using System.IO;
    3. using UnityEngine;
    4.  
    5. public class AndroidStreamingAssets : MonoBehaviour
    6. {
    7.     IEnumerator Start()
    8.     {
    9.         var astream = this.GetComponent<AudioStream.AudioStream>();
    10.  
    11.         while (!astream.ready)
    12.             yield return null;
    13.  
    14.         var fileName =  "YOUR_FILE.mp3";
    15.  
    16.         var sourcePath = Path.Combine(Application.streamingAssetsPath, fileName);
    17.  
    18.         if ( Application.platform == RuntimePlatform.Android )
    19.         {
    20.             using (AndroidJavaClass jcEnvironment = new AndroidJavaClass("android.os.Environment"))
    21.             using (AndroidJavaObject joExDir = jcEnvironment.CallStatic<AndroidJavaObject>("getExternalStorageDirectory"))
    22.             {
    23.                 var destinationDirectory = joExDir.Call<string>("toString");
    24.                 var destinationPath = Path.Combine(destinationDirectory, fileName);
    25.  
    26.                 using (WWW www = new WWW(sourcePath))
    27.                 {
    28.                     yield return www;
    29.  
    30.                     if ( !string.IsNullOrEmpty(www.error) )
    31.                     {
    32.                         Debug.LogError(www.error);
    33.                         yield break;
    34.                     }
    35.  
    36.                     File.WriteAllBytes(destinationPath, www.bytes);
    37.                     sourcePath = destinationPath;
    38.                 }
    39.             }
    40.         }
    41.  
    42.         astream.url = sourcePath;
    43.         astream.Play();
    44.     }
    45. }
    The Android project needs write permission to (external? I think) card to be able to extract the file.

    (*) I was testing this on Unity 5.5.x; WWW got deprecated in newer versions by UnityWebRequest, but the idea is the same.
     
  46. r618

    r618

    Joined:
    Jan 19, 2009
    Posts:
    1,084
    AudioStream is part of the current autumn Mage Sale being 25% OFF
     
  47. hebi1977

    hebi1977

    Joined:
    Nov 28, 2017
    Posts:
    1
    Thanks for your AudioStream.
    In your AudioStreamInputDemo, it well detects the microphone devices,but on the phone(in my case galaxy s8) I could no find a microphone device. Is there another way on android phone or it could not work on galaxy s8?

    Thanks in advance,
    best regards,
     
  48. r618

    r618

    Joined:
    Jan 19, 2009
    Posts:
    1,084
    hello @hebi1977, thanks!

    it's not phone specific, the inputs cannot seem to be enumerated on Android right now, unfortunately :-/

    But: Unity's built in Microphone class seems to be working OK for default microphone on Android - if possible do please try to use that - let me know if you need help, depending on what you're trying to do I might provide assistance.

    I'm trying to find out what's the reason FMOD can't see input devices on Android meanwhile.
     
  49. Butok

    Butok

    Joined:
    Dec 6, 2017
    Posts:
    2
    Does this asset support background audio now?
     
  50. r618

    r618

    Joined:
    Jan 19, 2009
    Posts:
    1,084
    Hi, I don't understand what you mean by 'now', but it's a good question !
    It's worth looking into now - which I will do for iOS - proper full Android support won't come for some time still probably.
     
unityunity