positional audio (no non positional yet) and leaving and joining
parent
6ac6bb3fc8
commit
e33201593b
|
|
@ -1,15 +0,0 @@
|
||||||
|
|
||||||
|
|
||||||
public class FixedArray
|
|
||||||
{
|
|
||||||
|
|
||||||
public byte[] array;
|
|
||||||
public int count;
|
|
||||||
|
|
||||||
public FixedArray(int max)
|
|
||||||
{
|
|
||||||
array = new byte[max];
|
|
||||||
count = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
@ -1,11 +0,0 @@
|
||||||
fileFormatVersion: 2
|
|
||||||
guid: f944d0dfd77614440ac63de40d533bbe
|
|
||||||
MonoImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
serializedVersion: 2
|
|
||||||
defaultReferences: []
|
|
||||||
executionOrder: 0
|
|
||||||
icon: {instanceID: 0}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
|
|
@ -1,90 +0,0 @@
|
||||||
using System.Collections;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using UnityEngine;
|
|
||||||
using System.Text;
|
|
||||||
using System;
|
|
||||||
using System.IO;
|
|
||||||
public class OutputCapture : MonoBehaviour
|
|
||||||
{
|
|
||||||
public velmicrophone mic;
|
|
||||||
public float[] buffer = new float[100000]; //represents the last 100000 samples (roughly)
|
|
||||||
public int curBufferPos = 0;
|
|
||||||
public double outputTime; //time of curBufferPos
|
|
||||||
int sampleRate;
|
|
||||||
bool isPlaying = false;
|
|
||||||
public long sampleNumber = 0;
|
|
||||||
short[] lastPlayed = new short[512];
|
|
||||||
byte[] lastPlayedBytes = new byte[1024];
|
|
||||||
// Start is called before the first frame update
|
|
||||||
void Awake()
|
|
||||||
{
|
|
||||||
|
|
||||||
sampleRate = AudioSettings.outputSampleRate;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update is called once per frame
|
|
||||||
void Update()
|
|
||||||
{
|
|
||||||
|
|
||||||
isPlaying = Application.isPlaying;
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnAudioFilterRead(float[] data, int channels)
|
|
||||||
{
|
|
||||||
|
|
||||||
for(int i = 0; i < data.Length; i+=2)
|
|
||||||
{
|
|
||||||
lastPlayed[i / 2] = (short)(((data[i] + data[i + 1])/2.0f)*short.MaxValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(mic.filter != null)
|
|
||||||
{
|
|
||||||
Buffer.BlockCopy(lastPlayed, 0, lastPlayedBytes, 0, 1024);
|
|
||||||
lock (mic.filter)
|
|
||||||
{
|
|
||||||
mic.filter.RegisterFramePlayed(lastPlayedBytes);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (!isPlaying)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
lock (buffer)
|
|
||||||
{
|
|
||||||
if (curBufferPos + data.Length < buffer.Length)
|
|
||||||
{
|
|
||||||
System.Array.Copy(data, 0, buffer, curBufferPos, data.Length);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
int numLeft = buffer.Length - curBufferPos;
|
|
||||||
System.Array.Copy(data, 0, buffer, curBufferPos, numLeft);
|
|
||||||
System.Array.Copy(data, buffer.Length - curBufferPos, buffer, 0, data.Length - numLeft);
|
|
||||||
curBufferPos = numLeft;
|
|
||||||
}
|
|
||||||
|
|
||||||
outputTime = AudioSettings.dspTime;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private float getSampleAtTime(double t)
|
|
||||||
{
|
|
||||||
lock (buffer)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
private void OnApplicationQuit()
|
|
||||||
{
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,11 +0,0 @@
|
||||||
fileFormatVersion: 2
|
|
||||||
guid: ba77e7f5139014c4b8c9eab0e405d0f0
|
|
||||||
MonoImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
serializedVersion: 2
|
|
||||||
defaultReferences: []
|
|
||||||
executionOrder: 0
|
|
||||||
icon: {instanceID: 0}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
Binary file not shown.
|
|
@ -1,33 +0,0 @@
|
||||||
fileFormatVersion: 2
|
|
||||||
guid: da4654b5ef2894d40a4b26c9d23c0a0b
|
|
||||||
PluginImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
serializedVersion: 2
|
|
||||||
iconMap: {}
|
|
||||||
executionOrder: {}
|
|
||||||
defineConstraints: []
|
|
||||||
isPreloaded: 0
|
|
||||||
isOverridable: 0
|
|
||||||
isExplicitlyReferenced: 0
|
|
||||||
validateReferences: 1
|
|
||||||
platformData:
|
|
||||||
- first:
|
|
||||||
Any:
|
|
||||||
second:
|
|
||||||
enabled: 1
|
|
||||||
settings: {}
|
|
||||||
- first:
|
|
||||||
Editor: Editor
|
|
||||||
second:
|
|
||||||
enabled: 0
|
|
||||||
settings:
|
|
||||||
DefaultValueInitialized: true
|
|
||||||
- first:
|
|
||||||
Windows Store Apps: WindowsStoreApps
|
|
||||||
second:
|
|
||||||
enabled: 0
|
|
||||||
settings:
|
|
||||||
CPU: AnyCPU
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
Binary file not shown.
|
|
@ -1,33 +0,0 @@
|
||||||
fileFormatVersion: 2
|
|
||||||
guid: 76bc48dbe508b40909b2ad9f22d91658
|
|
||||||
PluginImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
serializedVersion: 2
|
|
||||||
iconMap: {}
|
|
||||||
executionOrder: {}
|
|
||||||
defineConstraints: []
|
|
||||||
isPreloaded: 0
|
|
||||||
isOverridable: 0
|
|
||||||
isExplicitlyReferenced: 0
|
|
||||||
validateReferences: 1
|
|
||||||
platformData:
|
|
||||||
- first:
|
|
||||||
Any:
|
|
||||||
second:
|
|
||||||
enabled: 1
|
|
||||||
settings: {}
|
|
||||||
- first:
|
|
||||||
Editor: Editor
|
|
||||||
second:
|
|
||||||
enabled: 0
|
|
||||||
settings:
|
|
||||||
DefaultValueInitialized: true
|
|
||||||
- first:
|
|
||||||
Windows Store Apps: WindowsStoreApps
|
|
||||||
second:
|
|
||||||
enabled: 0
|
|
||||||
settings:
|
|
||||||
CPU: AnyCPU
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -518,7 +518,7 @@ GameObject:
|
||||||
- component: {fileID: 244561617}
|
- component: {fileID: 244561617}
|
||||||
- component: {fileID: 244561621}
|
- component: {fileID: 244561621}
|
||||||
m_Layer: 5
|
m_Layer: 5
|
||||||
m_Name: Canvas
|
m_Name: NetworkGUI
|
||||||
m_TagString: Untagged
|
m_TagString: Untagged
|
||||||
m_Icon: {fileID: 0}
|
m_Icon: {fileID: 0}
|
||||||
m_NavMeshLayer: 0
|
m_NavMeshLayer: 0
|
||||||
|
|
@ -605,7 +605,7 @@ RectTransform:
|
||||||
- {fileID: 1843597586}
|
- {fileID: 1843597586}
|
||||||
- {fileID: 117638565}
|
- {fileID: 117638565}
|
||||||
m_Father: {fileID: 0}
|
m_Father: {fileID: 0}
|
||||||
m_RootOrder: 5
|
m_RootOrder: 4
|
||||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||||
m_AnchorMin: {x: 0, y: 0}
|
m_AnchorMin: {x: 0, y: 0}
|
||||||
m_AnchorMax: {x: 0, y: 0}
|
m_AnchorMax: {x: 0, y: 0}
|
||||||
|
|
@ -694,7 +694,7 @@ Transform:
|
||||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||||
m_Children: []
|
m_Children: []
|
||||||
m_Father: {fileID: 0}
|
m_Father: {fileID: 0}
|
||||||
m_RootOrder: 6
|
m_RootOrder: 5
|
||||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||||
--- !u!1 &615558651
|
--- !u!1 &615558651
|
||||||
GameObject:
|
GameObject:
|
||||||
|
|
@ -1805,7 +1805,7 @@ Transform:
|
||||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||||
m_Children: []
|
m_Children: []
|
||||||
m_Father: {fileID: 0}
|
m_Father: {fileID: 0}
|
||||||
m_RootOrder: 4
|
m_RootOrder: 3
|
||||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||||
--- !u!114 &1099803616
|
--- !u!114 &1099803616
|
||||||
MonoBehaviour:
|
MonoBehaviour:
|
||||||
|
|
@ -2256,7 +2256,7 @@ GameObject:
|
||||||
- component: {fileID: 1434745022}
|
- component: {fileID: 1434745022}
|
||||||
- component: {fileID: 1434745023}
|
- component: {fileID: 1434745023}
|
||||||
m_Layer: 0
|
m_Layer: 0
|
||||||
m_Name: GameObject
|
m_Name: Dissonance
|
||||||
m_TagString: Untagged
|
m_TagString: Untagged
|
||||||
m_Icon: {fileID: 0}
|
m_Icon: {fileID: 0}
|
||||||
m_NavMeshLayer: 0
|
m_NavMeshLayer: 0
|
||||||
|
|
@ -2275,8 +2275,8 @@ MonoBehaviour:
|
||||||
m_Name:
|
m_Name:
|
||||||
m_EditorClassIdentifier:
|
m_EditorClassIdentifier:
|
||||||
dissonanceId:
|
dissonanceId:
|
||||||
|
comms: {fileID: 0}
|
||||||
manager: {fileID: 1099803616}
|
manager: {fileID: 1099803616}
|
||||||
myPlayer: {fileID: 0}
|
|
||||||
--- !u!4 &1434745020
|
--- !u!4 &1434745020
|
||||||
Transform:
|
Transform:
|
||||||
m_ObjectHideFlags: 0
|
m_ObjectHideFlags: 0
|
||||||
|
|
@ -2308,7 +2308,7 @@ MonoBehaviour:
|
||||||
_isDeafened: 0
|
_isDeafened: 0
|
||||||
_oneMinusBaseRemoteVoiceVolume: 0
|
_oneMinusBaseRemoteVoiceVolume: 0
|
||||||
_playbackPrefab: {fileID: 0}
|
_playbackPrefab: {fileID: 0}
|
||||||
_playbackPrefab2: {fileID: 1000010352696724, guid: 41bbbf1a8ee37a3479d8c133579965e3, type: 3}
|
_playbackPrefab2: {fileID: 1041743830464418, guid: 1d5da08daf134aa41a83590aea0e4caa, type: 3}
|
||||||
_micName:
|
_micName:
|
||||||
_playerPriority: 0
|
_playerPriority: 0
|
||||||
_tokens:
|
_tokens:
|
||||||
|
|
@ -2979,133 +2979,6 @@ CanvasRenderer:
|
||||||
m_PrefabAsset: {fileID: 0}
|
m_PrefabAsset: {fileID: 0}
|
||||||
m_GameObject: {fileID: 1852007162}
|
m_GameObject: {fileID: 1852007162}
|
||||||
m_CullTransparentMesh: 1
|
m_CullTransparentMesh: 1
|
||||||
--- !u!1 &1864637979
|
|
||||||
GameObject:
|
|
||||||
m_ObjectHideFlags: 0
|
|
||||||
m_CorrespondingSourceObject: {fileID: 0}
|
|
||||||
m_PrefabInstance: {fileID: 0}
|
|
||||||
m_PrefabAsset: {fileID: 0}
|
|
||||||
serializedVersion: 6
|
|
||||||
m_Component:
|
|
||||||
- component: {fileID: 1864637981}
|
|
||||||
- component: {fileID: 1864637980}
|
|
||||||
m_Layer: 0
|
|
||||||
m_Name: Audio Source
|
|
||||||
m_TagString: Untagged
|
|
||||||
m_Icon: {fileID: 0}
|
|
||||||
m_NavMeshLayer: 0
|
|
||||||
m_StaticEditorFlags: 0
|
|
||||||
m_IsActive: 1
|
|
||||||
--- !u!82 &1864637980
|
|
||||||
AudioSource:
|
|
||||||
m_ObjectHideFlags: 0
|
|
||||||
m_CorrespondingSourceObject: {fileID: 0}
|
|
||||||
m_PrefabInstance: {fileID: 0}
|
|
||||||
m_PrefabAsset: {fileID: 0}
|
|
||||||
m_GameObject: {fileID: 1864637979}
|
|
||||||
m_Enabled: 0
|
|
||||||
serializedVersion: 4
|
|
||||||
OutputAudioMixerGroup: {fileID: 24300002, guid: fa1da19d935e241119cdd522ceae772c, type: 2}
|
|
||||||
m_audioClip: {fileID: 8300000, guid: 9025272022b502b489850b0f3442455c, type: 3}
|
|
||||||
m_PlayOnAwake: 1
|
|
||||||
m_Volume: 0.098
|
|
||||||
m_Pitch: 1
|
|
||||||
Loop: 1
|
|
||||||
Mute: 0
|
|
||||||
Spatialize: 0
|
|
||||||
SpatializePostEffects: 0
|
|
||||||
Priority: 128
|
|
||||||
DopplerLevel: 1
|
|
||||||
MinDistance: 1
|
|
||||||
MaxDistance: 500
|
|
||||||
Pan2D: 0
|
|
||||||
rolloffMode: 0
|
|
||||||
BypassEffects: 0
|
|
||||||
BypassListenerEffects: 0
|
|
||||||
BypassReverbZones: 0
|
|
||||||
rolloffCustomCurve:
|
|
||||||
serializedVersion: 2
|
|
||||||
m_Curve:
|
|
||||||
- serializedVersion: 3
|
|
||||||
time: 0
|
|
||||||
value: 1
|
|
||||||
inSlope: 0
|
|
||||||
outSlope: 0
|
|
||||||
tangentMode: 0
|
|
||||||
weightedMode: 0
|
|
||||||
inWeight: 0.33333334
|
|
||||||
outWeight: 0.33333334
|
|
||||||
- serializedVersion: 3
|
|
||||||
time: 1
|
|
||||||
value: 0
|
|
||||||
inSlope: 0
|
|
||||||
outSlope: 0
|
|
||||||
tangentMode: 0
|
|
||||||
weightedMode: 0
|
|
||||||
inWeight: 0.33333334
|
|
||||||
outWeight: 0.33333334
|
|
||||||
m_PreInfinity: 2
|
|
||||||
m_PostInfinity: 2
|
|
||||||
m_RotationOrder: 4
|
|
||||||
panLevelCustomCurve:
|
|
||||||
serializedVersion: 2
|
|
||||||
m_Curve:
|
|
||||||
- serializedVersion: 3
|
|
||||||
time: 0
|
|
||||||
value: 0
|
|
||||||
inSlope: 0
|
|
||||||
outSlope: 0
|
|
||||||
tangentMode: 0
|
|
||||||
weightedMode: 0
|
|
||||||
inWeight: 0.33333334
|
|
||||||
outWeight: 0.33333334
|
|
||||||
m_PreInfinity: 2
|
|
||||||
m_PostInfinity: 2
|
|
||||||
m_RotationOrder: 4
|
|
||||||
spreadCustomCurve:
|
|
||||||
serializedVersion: 2
|
|
||||||
m_Curve:
|
|
||||||
- serializedVersion: 3
|
|
||||||
time: 0
|
|
||||||
value: 0
|
|
||||||
inSlope: 0
|
|
||||||
outSlope: 0
|
|
||||||
tangentMode: 0
|
|
||||||
weightedMode: 0
|
|
||||||
inWeight: 0.33333334
|
|
||||||
outWeight: 0.33333334
|
|
||||||
m_PreInfinity: 2
|
|
||||||
m_PostInfinity: 2
|
|
||||||
m_RotationOrder: 4
|
|
||||||
reverbZoneMixCustomCurve:
|
|
||||||
serializedVersion: 2
|
|
||||||
m_Curve:
|
|
||||||
- serializedVersion: 3
|
|
||||||
time: 0
|
|
||||||
value: 1
|
|
||||||
inSlope: 0
|
|
||||||
outSlope: 0
|
|
||||||
tangentMode: 0
|
|
||||||
weightedMode: 0
|
|
||||||
inWeight: 0.33333334
|
|
||||||
outWeight: 0.33333334
|
|
||||||
m_PreInfinity: 2
|
|
||||||
m_PostInfinity: 2
|
|
||||||
m_RotationOrder: 4
|
|
||||||
--- !u!4 &1864637981
|
|
||||||
Transform:
|
|
||||||
m_ObjectHideFlags: 0
|
|
||||||
m_CorrespondingSourceObject: {fileID: 0}
|
|
||||||
m_PrefabInstance: {fileID: 0}
|
|
||||||
m_PrefabAsset: {fileID: 0}
|
|
||||||
m_GameObject: {fileID: 1864637979}
|
|
||||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
|
||||||
m_LocalPosition: {x: 884.16766, y: 275.76804, z: -3.4810386}
|
|
||||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
|
||||||
m_Children: []
|
|
||||||
m_Father: {fileID: 0}
|
|
||||||
m_RootOrder: 3
|
|
||||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
|
||||||
--- !u!1 &1894247852
|
--- !u!1 &1894247852
|
||||||
GameObject:
|
GameObject:
|
||||||
m_ObjectHideFlags: 0
|
m_ObjectHideFlags: 0
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
fileFormatVersion: 2
|
fileFormatVersion: 2
|
||||||
guid: 9fc0d4010bbf28b4594072e72b8655ab
|
guid: 09c6fdabe05be4c86917b1c585ed4a40
|
||||||
|
folderAsset: yes
|
||||||
DefaultImporter:
|
DefaultImporter:
|
||||||
externalObjects: {}
|
externalObjects: {}
|
||||||
userData:
|
userData:
|
||||||
|
|
@ -21,6 +21,7 @@ public class NetworkManager : MonoBehaviour
|
||||||
|
|
||||||
public Action<NetworkPlayer> onJoinedRoom = delegate { };
|
public Action<NetworkPlayer> onJoinedRoom = delegate { };
|
||||||
public Action<NetworkPlayer> onPlayerJoined = delegate { };
|
public Action<NetworkPlayer> onPlayerJoined = delegate { };
|
||||||
|
public Action<NetworkPlayer> onPlayerLeft = delegate { };
|
||||||
#endregion
|
#endregion
|
||||||
// Use this for initialization
|
// Use this for initialization
|
||||||
public class Message
|
public class Message
|
||||||
|
|
@ -3,48 +3,45 @@ using System.Collections.Generic;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System;
|
using System;
|
||||||
|
using Dissonance;
|
||||||
|
|
||||||
public class NetworkPlayer : MonoBehaviour
|
public class NetworkPlayer : MonoBehaviour, Dissonance.IDissonancePlayer
|
||||||
{
|
{
|
||||||
public int userid;
|
public int userid;
|
||||||
public string username;
|
public string username;
|
||||||
public string dissonanceID;
|
|
||||||
public string room;
|
public string room;
|
||||||
public NetworkManager manager;
|
public NetworkManager manager;
|
||||||
Vector3 networkPosition;
|
Vector3 networkPosition;
|
||||||
|
|
||||||
|
|
||||||
bool buffering = false;
|
|
||||||
public List<FixedArray> toSend = new List<FixedArray>();
|
|
||||||
|
|
||||||
public bool isLocal = false;
|
public bool isLocal = false;
|
||||||
int lastSample = 0;
|
|
||||||
int lastPlayTime = 0;
|
|
||||||
int totalbuffered = 0;
|
|
||||||
int totalPlayed = 0;
|
|
||||||
uint lastAudioId = 0;
|
|
||||||
// Start is called before the first frame update
|
|
||||||
public Dissonance.VelCommsNetwork commsNetwork;
|
public Dissonance.VelCommsNetwork commsNetwork;
|
||||||
bool isSpeaking = false;
|
bool isSpeaking = false;
|
||||||
|
uint lastAudioId = 0;
|
||||||
|
public string dissonanceID;
|
||||||
|
//required by dissonance for spatial audio
|
||||||
|
public string PlayerId => dissonanceID;
|
||||||
|
public Vector3 Position => transform.position;
|
||||||
|
public Quaternion Rotation => transform.rotation;
|
||||||
|
public NetworkPlayerType Type => isLocal?NetworkPlayerType.Local:NetworkPlayerType.Remote;
|
||||||
|
public bool IsTracking => true;
|
||||||
|
|
||||||
void Start()
|
void Start()
|
||||||
{
|
{
|
||||||
|
|
||||||
if (manager.userid == userid) //this is me, I send updates
|
if (manager.userid == userid) //this is me, I send updates
|
||||||
{
|
{
|
||||||
StartCoroutine(syncTransformCoroutine());
|
StartCoroutine(syncTransformCoroutine());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Update is called once per frame
|
// Update is called once per frame
|
||||||
void Update()
|
void Update()
|
||||||
{
|
{
|
||||||
|
|
||||||
|
if (!isLocal) //not me, I move to wherever I should
|
||||||
|
|
||||||
if (userid != manager.userid) //not me, I move to wherever I should
|
|
||||||
{
|
{
|
||||||
transform.position = Vector3.Lerp(transform.position, networkPosition, .1f);
|
transform.position = Vector3.Lerp(transform.position, networkPosition, .1f);
|
||||||
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
@ -54,7 +51,7 @@ public class NetworkPlayer : MonoBehaviour
|
||||||
transform.position = transform.position + delta * Time.deltaTime;
|
transform.position = transform.position + delta * Time.deltaTime;
|
||||||
|
|
||||||
//if we're not speaking, and the comms say we are, send a speaking event, which will be received on other network players and sent to their comms accordingly
|
//if we're not speaking, and the comms say we are, send a speaking event, which will be received on other network players and sent to their comms accordingly
|
||||||
if(commsNetwork.comms.FindPlayer(dissonanceID).IsSpeaking != isSpeaking)
|
if(commsNetwork.comms.FindPlayer(dissonanceID).IsSpeaking != isSpeaking) //unfortunately, there does not seem to be an event for this
|
||||||
{
|
{
|
||||||
isSpeaking = !isSpeaking;
|
isSpeaking = !isSpeaking;
|
||||||
manager.sendTo(0, "4," + (isSpeaking?1:0) + ";");
|
manager.sendTo(0, "4," + (isSpeaking?1:0) + ";");
|
||||||
|
|
@ -66,8 +63,6 @@ public class NetworkPlayer : MonoBehaviour
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
IEnumerator syncTransformCoroutine()
|
IEnumerator syncTransformCoroutine()
|
||||||
|
|
@ -80,6 +75,7 @@ public class NetworkPlayer : MonoBehaviour
|
||||||
}
|
}
|
||||||
public void handleMessage(NetworkManager.Message m)
|
public void handleMessage(NetworkManager.Message m)
|
||||||
{
|
{
|
||||||
|
//these are generally things that come from the "owner" and should be enacted locally, where appropriate
|
||||||
//we need to parse the message
|
//we need to parse the message
|
||||||
|
|
||||||
//types of messages
|
//types of messages
|
||||||
|
|
@ -111,13 +107,14 @@ public class NetworkPlayer : MonoBehaviour
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case "3": //dissonance id
|
case "3": //dissonance id (player joined)
|
||||||
{
|
{
|
||||||
if (dissonanceID == "")
|
if (dissonanceID == "")
|
||||||
{
|
{
|
||||||
dissonanceID = sections[1];
|
dissonanceID = sections[1];
|
||||||
//tell the comms network that this player joined the channel
|
//tell the comms network that this player joined the channel
|
||||||
commsNetwork.playerJoined(dissonanceID);
|
commsNetwork.playerJoined(dissonanceID); //tell dissonance
|
||||||
|
commsNetwork.comms.TrackPlayerPosition(this); //tell dissonance to track the remote player
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -140,7 +137,10 @@ public class NetworkPlayer : MonoBehaviour
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void OnDestroy()
|
||||||
|
{
|
||||||
|
commsNetwork.playerLeft(dissonanceID);
|
||||||
|
}
|
||||||
|
|
||||||
public void sendAudioData(ArraySegment<byte> data)
|
public void sendAudioData(ArraySegment<byte> data)
|
||||||
{
|
{
|
||||||
|
|
@ -148,9 +148,10 @@ public class NetworkPlayer : MonoBehaviour
|
||||||
manager.sendTo(0, "2,"+b64_data + ","+ (lastAudioId++) +";");
|
manager.sendTo(0, "2,"+b64_data + ","+ (lastAudioId++) +";");
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setDissonanceID(string id)
|
public void setDissonanceID(string id) //this sort of all initializes dissonance
|
||||||
{
|
{
|
||||||
dissonanceID = id;
|
dissonanceID = id;
|
||||||
manager.sendTo(0, "3," + id+";");
|
manager.sendTo(0, "3," + id+";");
|
||||||
|
commsNetwork.comms.TrackPlayerPosition(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -20,7 +20,7 @@ AudioMixerController:
|
||||||
m_CorrespondingSourceObject: {fileID: 0}
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
m_PrefabInstance: {fileID: 0}
|
m_PrefabInstance: {fileID: 0}
|
||||||
m_PrefabAsset: {fileID: 0}
|
m_PrefabAsset: {fileID: 0}
|
||||||
m_Name: NewAudioMixer
|
m_Name: VelAudioMixer
|
||||||
m_OutputGroup: {fileID: 0}
|
m_OutputGroup: {fileID: 0}
|
||||||
m_MasterGroup: {fileID: 24300002}
|
m_MasterGroup: {fileID: 24300002}
|
||||||
m_Snapshots:
|
m_Snapshots:
|
||||||
|
|
@ -52,26 +52,27 @@ namespace Dissonance
|
||||||
|
|
||||||
manager.onJoinedRoom += (player) =>
|
manager.onJoinedRoom += (player) =>
|
||||||
{
|
{
|
||||||
|
//this is me joining a vel room
|
||||||
myPlayer = player;
|
myPlayer = player;
|
||||||
myPlayer.commsNetwork = this;
|
myPlayer.commsNetwork = this;
|
||||||
myPlayer.setDissonanceID(playerName); //need to let that new player know my dissonance id (tell everyone again)
|
myPlayer.setDissonanceID(playerName); //need to let that new player know my dissonance id (tell everyone again)
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
manager.onPlayerJoined += (player) =>
|
manager.onPlayerJoined += (player) =>
|
||||||
{
|
{
|
||||||
|
//this is someone else joining the vel room
|
||||||
myPlayer.setDissonanceID(playerName); //need to let that new player know my dissonance id (tell everyone again)
|
myPlayer.setDissonanceID(playerName); //need to let that new player know my dissonance id (tell everyone again)
|
||||||
|
|
||||||
player.commsNetwork = this; //this will tell us when various things happen of importance
|
player.commsNetwork = this; //this will tell us when various things happen of importance
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void voiceReceived(string sender,byte[] data,uint sequenceNumber)
|
public void voiceReceived(string sender,byte[] data,uint sequenceNumber)
|
||||||
{
|
{
|
||||||
Debug.Log(sequenceNumber);
|
Debug.Log(sequenceNumber);
|
||||||
VoicePacket vp = new VoicePacket(sender, ChannelPriority.Default, 1, false, new ArraySegment<byte>(data,0,data.Length), sequenceNumber);
|
VoicePacket vp = new VoicePacket(sender, ChannelPriority.Default, 1, true, new ArraySegment<byte>(data,0,data.Length), sequenceNumber);
|
||||||
VoicePacketReceived(vp);
|
VoicePacketReceived(vp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -85,8 +86,6 @@ namespace Dissonance
|
||||||
myPlayer?.sendAudioData(data);
|
myPlayer?.sendAudioData(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Start is called before the first frame update
|
// Start is called before the first frame update
|
||||||
void Start()
|
void Start()
|
||||||
{
|
{
|
||||||
|
|
@ -105,15 +104,23 @@ namespace Dissonance
|
||||||
PlayerEnteredRoom(re);
|
PlayerEnteredRoom(re);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void playerLeft(string id)
|
||||||
|
{
|
||||||
|
RoomEvent re = new RoomEvent();
|
||||||
|
re.Joined = false;
|
||||||
|
re.Room = "Global";
|
||||||
|
re.PlayerName = id;
|
||||||
|
PlayerExitedRoom(re);
|
||||||
|
PlayerLeft(id);
|
||||||
|
}
|
||||||
|
|
||||||
public void playerStartedSpeaking(string id)
|
public void playerStartedSpeaking(string id)
|
||||||
{
|
{
|
||||||
PlayerStartedSpeaking(id);
|
PlayerStartedSpeaking(id);
|
||||||
Debug.Log("player " + id + " started speaking");
|
|
||||||
}
|
}
|
||||||
public void playerStoppedSpeaking(string id)
|
public void playerStoppedSpeaking(string id)
|
||||||
{
|
{
|
||||||
PlayerStoppedSpeaking(id);
|
PlayerStoppedSpeaking(id);
|
||||||
Debug.Log("player " + id + " stopped speaking");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -1,304 +0,0 @@
|
||||||
using System.Collections;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using UnityEngine;
|
|
||||||
using System.IO;
|
|
||||||
using Concentus.Structs;
|
|
||||||
using System.Threading;
|
|
||||||
using System;
|
|
||||||
using AudioProcessingModuleCs.Media.Dsp.WebRtc;
|
|
||||||
using AudioProcessingModuleCs.Media;
|
|
||||||
public class velmicrophone : MonoBehaviour
|
|
||||||
{
|
|
||||||
OpusEncoder opusEncoder;
|
|
||||||
OpusDecoder opusDecoder;
|
|
||||||
public OutputCapture oc = null;
|
|
||||||
//StreamWriter sw;
|
|
||||||
AudioClip clip;
|
|
||||||
float[] tempData;
|
|
||||||
short[] encoderBuffer;
|
|
||||||
List<short[]> frameBuffer;
|
|
||||||
|
|
||||||
List<FixedArray> sendQueue = new List<FixedArray>();
|
|
||||||
List<short[]> encoderArrayPool = new List<short[]>();
|
|
||||||
List<FixedArray> decoderArrayPool = new List<FixedArray>();
|
|
||||||
int lastUsedEncoderPool = 0;
|
|
||||||
int lastUsedDecoderPool = 0;
|
|
||||||
int encoderBufferIndex=0;
|
|
||||||
int lastPosition = 0;
|
|
||||||
string device = "";
|
|
||||||
int encoder_frame_size = 640;
|
|
||||||
double micSampleTime = 1 / 44100.0;
|
|
||||||
double encodeTime = 1 / 16000.0;
|
|
||||||
double lastMicSample; //holds the last mic sample, in case we need to interpolate it
|
|
||||||
double sampleTimer = 0; //increments with every mic sample, but when over the encodeTime, causes a sample and subtracts that encode time
|
|
||||||
EventWaitHandle waiter;
|
|
||||||
float silenceThreshold = .04f; //average volume of packet
|
|
||||||
int numSilent = 0; //number of silent packets detected
|
|
||||||
int minSilencePacketsToStop = 2;
|
|
||||||
double averageVolume = 0;
|
|
||||||
Thread t;
|
|
||||||
public Action<FixedArray> encodedFrameAvailable = delegate { };
|
|
||||||
double micTime = 0;
|
|
||||||
long sampleNumber = 0;
|
|
||||||
public int offset = 512;
|
|
||||||
public double gain = 2.0f;
|
|
||||||
public WebRtcFilter filter = null;
|
|
||||||
// Start is called before the first frame update
|
|
||||||
void Start()
|
|
||||||
{
|
|
||||||
opusEncoder = new OpusEncoder(16000, 1, Concentus.Enums.OpusApplication.OPUS_APPLICATION_VOIP);
|
|
||||||
opusDecoder = new OpusDecoder(16000, 1);
|
|
||||||
encoderBuffer = new short[16000];
|
|
||||||
frameBuffer = new List<short[]>();
|
|
||||||
//string path = Application.persistentDataPath + "/" + "mic.csv"; //this was for writing mic samples
|
|
||||||
//sw = new StreamWriter(path, false);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
for(int i = 0; i < 100; i++) //pre allocate a bunch of arrays for microphone frames (probably will only need 1 or 2)
|
|
||||||
{
|
|
||||||
encoderArrayPool.Add(new short[encoder_frame_size]);
|
|
||||||
decoderArrayPool.Add(new FixedArray(1000));
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
t = new Thread(encodeThread);
|
|
||||||
waiter = new EventWaitHandle(true, EventResetMode.AutoReset);
|
|
||||||
t.Start();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void startMicrophone(string mic)
|
|
||||||
{
|
|
||||||
Debug.Log(mic);
|
|
||||||
device = mic;
|
|
||||||
int minFreq, maxFreq;
|
|
||||||
Microphone.GetDeviceCaps(device, out minFreq, out maxFreq);
|
|
||||||
Debug.Log("Freq: " + minFreq + ":" + maxFreq);
|
|
||||||
clip = Microphone.Start(device, true, 1, 44100);
|
|
||||||
|
|
||||||
|
|
||||||
Debug.Log("Frequency:" + clip.frequency);
|
|
||||||
tempData = new float[clip.samples * clip.channels];
|
|
||||||
Debug.Log("channels: " + clip.channels);
|
|
||||||
|
|
||||||
filter = new WebRtcFilter(256, 640, new AudioFormat(16000), new AudioFormat(48000), false, false, false);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnApplicationQuit()
|
|
||||||
{
|
|
||||||
t.Abort();
|
|
||||||
|
|
||||||
//sw.Flush();
|
|
||||||
//sw.Close();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
short[] getNextEncoderPool()
|
|
||||||
{
|
|
||||||
lastUsedEncoderPool = (lastUsedEncoderPool + 1) % encoderArrayPool.Count;
|
|
||||||
return encoderArrayPool[lastUsedEncoderPool];
|
|
||||||
}
|
|
||||||
|
|
||||||
FixedArray getNextDecoderPool()
|
|
||||||
{
|
|
||||||
lastUsedDecoderPool = (lastUsedDecoderPool + 1) % decoderArrayPool.Count;
|
|
||||||
|
|
||||||
FixedArray toReturn = decoderArrayPool[lastUsedDecoderPool];
|
|
||||||
toReturn.count = 0;
|
|
||||||
return toReturn;
|
|
||||||
}
|
|
||||||
// Update is called once per frame
|
|
||||||
void Update()
|
|
||||||
{
|
|
||||||
if (clip != null)
|
|
||||||
{
|
|
||||||
|
|
||||||
int micPosition = Microphone.GetPosition(device);
|
|
||||||
if(micPosition == lastPosition)
|
|
||||||
{
|
|
||||||
return; //sometimes the microphone will not advance
|
|
||||||
}
|
|
||||||
|
|
||||||
int numSamples = 0;
|
|
||||||
float[] temp;
|
|
||||||
if (micPosition > lastPosition)
|
|
||||||
{
|
|
||||||
numSamples = micPosition - lastPosition;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
//whatever was left
|
|
||||||
numSamples = (tempData.Length - lastPosition) + micPosition;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//Debug.Log(micPosition);
|
|
||||||
temp = new float[numSamples]; //this has to be dynamically allocated because of the way clip.GetData works (annoying...maybe use native mic)
|
|
||||||
|
|
||||||
clip.GetData(temp, lastPosition);
|
|
||||||
lastPosition = micPosition;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//this code does 2 things. 1) it samples the microphone data to be exactly what the encoder wants, 2) it forms encoder packets
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
for (int i = 0; i < temp.Length; i++) //iterate through temp, which contans that mic samples at 44.1khz
|
|
||||||
{
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
sampleTimer += micSampleTime;
|
|
||||||
if(sampleTimer >= encodeTime)
|
|
||||||
{
|
|
||||||
|
|
||||||
//take a sample between the last sample and the current sample
|
|
||||||
|
|
||||||
|
|
||||||
double diff = sampleTimer - encodeTime; //this represents how far past this sample actually is
|
|
||||||
double t = diff / micSampleTime; //this should be between 0 and 1
|
|
||||||
double v = lastMicSample * (1 - t) + temp[i] * t;
|
|
||||||
|
|
||||||
|
|
||||||
sampleTimer -= encodeTime;
|
|
||||||
|
|
||||||
encoderBuffer[encoderBufferIndex++] = (short)(v*short.MaxValue);
|
|
||||||
averageVolume += v > 0 ? v : -v;
|
|
||||||
if(encoderBufferIndex > encoder_frame_size) //this is when a new packet gets created
|
|
||||||
{
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
averageVolume = averageVolume / encoder_frame_size;
|
|
||||||
|
|
||||||
if(averageVolume < silenceThreshold)
|
|
||||||
{
|
|
||||||
numSilent++;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
numSilent = 0;
|
|
||||||
}
|
|
||||||
averageVolume = 0;
|
|
||||||
|
|
||||||
if (numSilent < minSilencePacketsToStop)
|
|
||||||
{
|
|
||||||
|
|
||||||
short[] frame = getNextEncoderPool(); //these are predefined sizes, so we don't have to allocate a new array
|
|
||||||
//lock the frame buffer
|
|
||||||
|
|
||||||
System.Array.Copy(encoderBuffer, frame, encoder_frame_size); //nice and fast
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
byte[] recorded = new byte[frame.Length * 2];
|
|
||||||
Buffer.BlockCopy(frame, 0, recorded, 0, frame.Length * 2);
|
|
||||||
|
|
||||||
lock (filter)
|
|
||||||
{
|
|
||||||
filter.Write(recorded);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
bool moreFrames;
|
|
||||||
|
|
||||||
do
|
|
||||||
{
|
|
||||||
short[] cancelBuffer = new short[encoder_frame_size];
|
|
||||||
lock (filter)
|
|
||||||
{
|
|
||||||
if (filter.Read(cancelBuffer, out moreFrames))
|
|
||||||
{
|
|
||||||
lock (frameBuffer)
|
|
||||||
{
|
|
||||||
|
|
||||||
frameBuffer.Add(cancelBuffer);
|
|
||||||
waiter.Set(); //signal the encode frame
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} while (moreFrames);
|
|
||||||
*/
|
|
||||||
|
|
||||||
lock (frameBuffer)
|
|
||||||
{
|
|
||||||
|
|
||||||
frameBuffer.Add(frame);
|
|
||||||
waiter.Set(); //signal the encode frame
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
encoderBufferIndex = 0;
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
lastMicSample = temp[i]; //remember the last sample, just in case this is the first one next time
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
lock (sendQueue)
|
|
||||||
{
|
|
||||||
foreach(FixedArray f in sendQueue)
|
|
||||||
{
|
|
||||||
encodedFrameAvailable(f);
|
|
||||||
|
|
||||||
}
|
|
||||||
sendQueue.Clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public short[] decodeOpusData(byte[] data)
|
|
||||||
{
|
|
||||||
short[] t = getNextEncoderPool();
|
|
||||||
opusDecoder.Decode(data, 0, data.Length, t, 0, encoder_frame_size);
|
|
||||||
return t;
|
|
||||||
}
|
|
||||||
|
|
||||||
void encodeThread()
|
|
||||||
{
|
|
||||||
|
|
||||||
while (waiter.WaitOne(Timeout.Infinite)) //better to wait on signal
|
|
||||||
{
|
|
||||||
|
|
||||||
List<short[]> toEncode = new List<short[]>();
|
|
||||||
|
|
||||||
|
|
||||||
lock (frameBuffer)
|
|
||||||
{
|
|
||||||
foreach (short[] frame in frameBuffer) {
|
|
||||||
toEncode.Add(frame);
|
|
||||||
}
|
|
||||||
frameBuffer.Clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach(short[] frame in toEncode)
|
|
||||||
{
|
|
||||||
FixedArray a = getNextDecoderPool();
|
|
||||||
int out_data_size = opusEncoder.Encode(frame, 0, encoder_frame_size, a.array, 0, 1000);
|
|
||||||
a.count = out_data_size;
|
|
||||||
//add frame to the send buffer
|
|
||||||
lock (sendQueue)
|
|
||||||
{
|
|
||||||
sendQueue.Add(a);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,11 +0,0 @@
|
||||||
fileFormatVersion: 2
|
|
||||||
guid: b5bc7fc60d7d94f77a1924580a4ff95b
|
|
||||||
MonoImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
serializedVersion: 2
|
|
||||||
defaultReferences: []
|
|
||||||
executionOrder: 0
|
|
||||||
icon: {instanceID: 0}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
|
|
@ -6,6 +6,6 @@ EditorBuildSettings:
|
||||||
serializedVersion: 2
|
serializedVersion: 2
|
||||||
m_Scenes:
|
m_Scenes:
|
||||||
- enabled: 1
|
- enabled: 1
|
||||||
path: Assets/test.unity
|
path: Assets/Scenes/test.unity
|
||||||
guid: e4e43899246c941c78acfc59ce2f664a
|
guid: e4e43899246c941c78acfc59ce2f664a
|
||||||
m_configObjects: {}
|
m_configObjects: {}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue