Skip to content

Commit 34d8240

Browse files
authored
Merged OpenAI package back into mono repo. (#1541)
1 parent ca81a30 commit 34d8240

File tree

165 files changed

+10301
-7
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

165 files changed

+10301
-7
lines changed

README.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,11 @@ This repository is the home of the **SIPSorcery** project - a comprehensive real
2121

2222
| Package | Version | Downloads | Description | README |
2323
|---------|---------|-----------|-------------|---------|
24-
| **SIPSorcery** | [![NuGet](https://img.shields.io/nuget/v/SIPSorcery.svg)](https://www.nuget.org/packages/SIPSorcery) | [![NuGet](https://img.shields.io/nuget/dt/SIPSorcery.svg)](https://www.nuget.org/packages/SIPSorcery) | Core library with SIP, WebRTC, RTP, ICE, STUN, and SDP support | [README](src/) |
25-
| **SIPSorceryMedia.Abstractions** | [![NuGet](https://img.shields.io/nuget/v/SIPSorceryMedia.Abstractions.svg)](https://www.nuget.org/packages/SIPSorceryMedia.Abstractions) | [![NuGet](https://img.shields.io/nuget/dt/SIPSorceryMedia.Abstractions.svg)](https://www.nuget.org/packages/SIPSorceryMedia.Abstractions) | Interfaces for audio/video encoders and device access | [README](SIPSorceryMedia.Abstractions/) |
26-
| **SIPSorceryMedia.Windows** | [![NuGet](https://img.shields.io/nuget/v/SIPSorceryMedia.Windows.svg)](https://www.nuget.org/packages/SIPSorceryMedia.Windows) | [![NuGet](https://img.shields.io/nuget/dt/SIPSorceryMedia.Windows.svg)](https://www.nuget.org/packages/SIPSorceryMedia.Windows) | Windows-specific audio capture and playback and video capture | [README](SIPSorceryMedia.Windows/) |
27-
| **SIPSorceryMedia.FFmpeg** | [![NuGet](https://img.shields.io/nuget/v/SIPSorceryMedia.FFmpeg.svg)](https://www.nuget.org/packages/SIPSorceryMedia.FFmpeg) | [![NuGet](https://img.shields.io/nuget/dt/SIPSorceryMedia.FFmpeg.svg)](https://www.nuget.org/packages/SIPSorceryMedia.FFmpeg) | Cross-platform media support using FFmpeg | [README](SIPSorceryMedia.FFmpeg/) |
24+
| **SIPSorcery** | [![NuGet](https://img.shields.io/nuget/v/SIPSorcery.svg)](https://www.nuget.org/packages/SIPSorcery) | [![NuGet](https://img.shields.io/nuget/dt/SIPSorcery.svg)](https://www.nuget.org/packages/SIPSorcery) | Core library with SIP, WebRTC, RTP, ICE, STUN, and SDP support | [README](src/SIPSorcery) |
25+
| **SIPSorceryMedia.Abstractions** | [![NuGet](https://img.shields.io/nuget/v/SIPSorceryMedia.Abstractions.svg)](https://www.nuget.org/packages/SIPSorceryMedia.Abstractions) | [![NuGet](https://img.shields.io/nuget/dt/SIPSorceryMedia.Abstractions.svg)](https://www.nuget.org/packages/SIPSorceryMedia.Abstractions) | Interfaces for audio/video encoders and device access | [README](src/SIPSorceryMedia.Abstractions/) |
26+
| **SIPSorceryMedia.Windows** | [![NuGet](https://img.shields.io/nuget/v/SIPSorceryMedia.Windows.svg)](https://www.nuget.org/packages/SIPSorceryMedia.Windows) | [![NuGet](https://img.shields.io/nuget/dt/SIPSorceryMedia.Windows.svg)](https://www.nuget.org/packages/SIPSorceryMedia.Windows) | Windows-specific audio capture and playback and video capture | [README](src/SIPSorceryMedia.Windows/) |
27+
| **SIPSorceryMedia.FFmpeg** | [![NuGet](https://img.shields.io/nuget/v/SIPSorceryMedia.FFmpeg.svg)](https://www.nuget.org/packages/SIPSorceryMedia.FFmpeg) | [![NuGet](https://img.shields.io/nuget/dt/SIPSorceryMedia.FFmpeg.svg)](https://www.nuget.org/packages/SIPSorceryMedia.FFmpeg) | Cross-platform media support using FFmpeg | [README](src/SIPSorceryMedia.FFmpeg/) |
28+
| **SIPSorcery.OpenAI.Realtime** | [![NuGet](https://img.shields.io/nuget/v/SIPSorcery.OpenAI.WebRTC.svg)](https://www.nuget.org/packages/SIPSorcery.OpenAI.WebRTC) | [![NuGet](https://img.shields.io/nuget/dt/SIPSorcery.OpenAI.WebRTC.svg)](https://www.nuget.org/packages/SIPSorcery.OpenAI.WebRTC) | Support for OpenAI's Realtime WebRTC and SIP end points | [README](src/SIPSorcery.OpenAI.Realtime/) |
2829
| **VP8.Net** | | | Experimental pure C# VP8 codec implementation | [README](VP8.Net/) |
2930

3031
### Related Repositories
@@ -34,8 +35,6 @@ The SIPSorcery ecosystem includes several companion projects hosted in separate
3435
- **[SIPSorceryMedia.Encoders](https://github.com/sipsorcery-org/SIPSorceryMedia.Encoders)** - Windows-specific wrappers for VP8 and other video codecs [![NuGet](https://img.shields.io/nuget/dt/SIPSorceryMedia.Encoders.svg)](https://www.nuget.org/packages/SIPSorceryMedia.Encoders)
3536
- **[SIPSorceryMedia.SDL2](https://github.com/sipsorcery-org/SIPSorceryMedia.SDL2)** - Cross-platform audio/video using SDL2
3637
- **[signalrtc](https://github.com/sipsorcery-org/signalrtc)** - Real-time signaling server for WebRTC
37-
- **[SIPSorcery.OpenAI.WebRTC](https://github.com/sipsorcery-org/SIPSorcery.OpenAI.WebRTC)** - OpenAI real-time API integration for WebRTC
38-
- **[SIPSorcery.OpenAI.SIP](https://github.com/sipsorcery-org/SIPSorcery.OpenAI.SIP)** - OpenAI real-time API integration for SIP
3938

4039
### Examples
4140

@@ -46,6 +45,7 @@ This repository includes **[70+ example projects](examples/)** demonstrating var
4645
- **[SIP Scenarios](examples/SIPScenarios/)** - Call transfers, load testing, complex call flows ([README](examples/SIPScenarios/README.md))
4746
- **[WebRTC Scenarios](examples/WebRTCScenarios/)** - Advanced WebRTC use cases ([README](examples/WebRTCScenarios/README.md))
4847
- **[Softphone](examples/Softphone/)** - Full-featured Windows Forms softphone application ([README](examples/Softphone/README.md))
48+
- **[OpenAI](examples/OpenAIExamples/)** - Example applications for interacting with OpenAI's Realtime WebRTC and SIP end poiints ([README](examples/OpenAIExamples/GetStarted/README.md))
4949

5050
---
5151

SIPSorcery.OpenAI.Realtime.slnf

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"solution": {
3+
"path": "SIPSorcery.slnx",
4+
"projects": [
5+
"src\\SIPSorcery.OpenAI.Realtime\\SIPSorcery.OpenAI.Realtime.csproj",
6+
"test\\SIPSorcery.OpenAI.Realtime.UnitTest\\SIPSorcery.OpenAI.Realtime.UnitTests.csproj"
7+
]
8+
}
9+
}

SIPSorcery.slnx

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
<Project Path="test/FFmpegTranscodeTest/FFmpegTranscodeTest.csproj" />
1414
<Project Path="test/FFmpegWebRtcReceiver/FFmpegWebRTCReceiver.csproj" />
1515
<Project Path="test/integration/SIPSorcery.IntegrationTests.csproj" />
16+
<Project Path="test/SIPSorcery.OpenAI.Realtime.UnitTest/SIPSorcery.OpenAI.Realtime.UnitTests.csproj" />
1617
<Project Path="test/SIPSorceryMedia.Abstractions.UnitTest/SIPSorceryMedia.Abstractions.UnitTest.csproj" />
1718
<Project Path="test/unit/SIPSorcery.UnitTests.csproj" />
1819
<Project Path="test/VideoCaptureTest/VideoCaptureTest.csproj" />
@@ -31,6 +32,17 @@
3132
<Folder Name="/examples/Miscellaneous/">
3233
<Project Path="examples/Miscellaneous/SctpClientTestConsole/SctpClientTestConsole.csproj" />
3334
</Folder>
35+
<Folder Name="/examples/OpenAI/">
36+
<Project Path="examples/OpenAIExamples/AliceAndBob/AliceAndBob.csproj" />
37+
<Project Path="examples/OpenAIExamples/AspNetGetStarted/AspNetGetStarted.csproj" />
38+
<Project Path="examples/OpenAIExamples/AspNetLocalFunction/AspNetLocalFunction.csproj" />
39+
<Project Path="examples/OpenAIExamples/GetPaid/GetPaid.csproj" />
40+
<Project Path="examples/OpenAIExamples/GetStarted/GetStarted.csproj" />
41+
<Project Path="examples/OpenAIExamples/GetStartedDI/GetStartedDI.csproj" />
42+
<Project Path="examples/OpenAIExamples/GetStartedSIP/GetStartedSIP.csproj" />
43+
<Project Path="examples/OpenAIExamples/GetStartedWebRTCAndSIP/GetStartedWebRTCAndSIP.csproj" />
44+
<Project Path="examples/OpenAIExamples/LocalFunctions/LocalFunctions.csproj" />
45+
</Folder>
3446
<Folder Name="/examples/SIPExamples/">
3547
<Project Path="examples/SIPExamples/AndroidSIPGetStarted/AndroidSIPGetStarted.csproj" />
3648
<Project Path="examples/SIPExamples/AsteriskIce/AsteriskIce.csproj" />
@@ -119,6 +131,7 @@
119131
<Project Path="examples/WebRTCScenarios/DataChannelStressTest/DataChannelStressTest.csproj" />
120132
</Folder>
121133
<Folder Name="/src/">
134+
<Project Path="src/SIPSorcery.OpenAI.Realtime/SIPSorcery.OpenAI.Realtime.csproj" />
122135
<Project Path="src/SIPSorcery/SIPSorcery.csproj" />
123136
<Project Path="src/SIPSorceryMedia.Abstractions/SIPSorceryMedia.Abstractions.csproj" />
124137
<Project Path="src/SIPSorceryMedia.FFmpeg/SIPSorceryMedia.FFmpeg.csproj" />
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<OutputType>Exe</OutputType>
5+
<TargetFramework>net10.0-windows10.0.17763.0</TargetFramework>
6+
<UseWindowsForms>true</UseWindowsForms>
7+
<DisableWinExeOutputInference>true</DisableWinExeOutputInference>
8+
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
9+
<LangVersion>12.0</LangVersion>
10+
<Nullable>enable</Nullable>
11+
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
12+
</PropertyGroup>
13+
14+
<ItemGroup>
15+
<PackageReference Include="LanguageExt.Core" Version="4.4.9" />
16+
<PackageReference Include="MathNet.Filtering" Version="0.7.0" />
17+
<PackageReference Include="MathNet.Numerics" Version="5.0.0" />
18+
<PackageReference Include="Microsoft.Extensions.Logging" Version="9.0.0" />
19+
<PackageReference Include="Serilog.Extensions.Logging" Version="3.0.1" />
20+
<PackageReference Include="Serilog.Sinks.Console" Version="3.1.1" />
21+
<PackageReference Include="SharpGL.WinForms" Version="3.1.1" />
22+
<PackageReference Include="SIPSorceryMedia.Windows" Version="8.0.14" />
23+
</ItemGroup>
24+
25+
<ItemGroup>
26+
<ProjectReference Include="..\..\..\src\SIPSorcery.OpenAI.Realtime\SIPSorcery.OpenAI.Realtime.csproj" />
27+
</ItemGroup>
28+
29+
<ItemGroup>
30+
<None Update="shaders\clear\clear.frag">
31+
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
32+
</None>
33+
<None Update="shaders\clear\clear.vert">
34+
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
35+
</None>
36+
<None Update="shaders\line\line.frag">
37+
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
38+
</None>
39+
<None Update="shaders\line\line.geom">
40+
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
41+
</None>
42+
<None Update="shaders\line\line.vert">
43+
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
44+
</None>
45+
</ItemGroup>
46+
47+
</Project>
Lines changed: 196 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,196 @@
1+
//-----------------------------------------------------------------------------
2+
// Filename: AudioScope.cs
3+
//
4+
// Description: Implementation of a Hilbert filter to visualise audio input.
5+
// Originally based on https://github.com/conundrumer/visual-music-workshop.
6+
7+
// Author(s):
8+
// Aaron Clauson (aaron@sipsorcery.com)
9+
//
10+
// History:
11+
// 29 Feb 2020 Aaron Clauson Created, Dublin, Ireland.
12+
//
13+
// License:
14+
// BSD 3-Clause "New" or "Revised" License, see included LICENSE.md file.
15+
//-----------------------------------------------------------------------------
16+
17+
using System;
18+
using System.Linq;
19+
using System.Numerics;
20+
using MathNet.Numerics;
21+
using MathNet.Numerics.IntegralTransforms;
22+
23+
namespace AudioScope
24+
{
25+
public class LowPassFilter
26+
{
27+
private readonly float _k;
28+
private readonly float _norm;
29+
private readonly float _a0;
30+
private readonly float _a1;
31+
private readonly float _a2;
32+
private readonly float _b1;
33+
private readonly float _b2;
34+
35+
private float _w1 = 0.0f;
36+
private float _w2 = 0.0f;
37+
38+
public LowPassFilter(float n, float q)
39+
{
40+
_k = (float)Math.Tan((0.5 * n * Math.PI));
41+
_norm = 1.0f / (1.0f + _k / q + _k * _k);
42+
_a0 = _k * _k * _norm;
43+
_a1 = 2.0f * _a0;
44+
_a2 = _a0;
45+
_b1 = 2.0f * (_k * _k - 1.0f) * _norm;
46+
_b2 = (1.0f - _k / q + _k * _k) * _norm;
47+
}
48+
49+
public float Apply(float x)
50+
{
51+
float w0 = x - _b1 * _w1 - _b2 * _w2;
52+
float y = _a0 * w0 + _a1 * _w1 + _a2 * _w2;
53+
_w2 = _w1;
54+
_w1 = w0;
55+
56+
return y;
57+
}
58+
}
59+
60+
public class AudioScope
61+
{
62+
public const int NUM_CHANNELS = 1;
63+
public const int SAMPLE_RATE = 44100;
64+
public const float maxAmplitude = 4.0F;
65+
public const int B = (1 << 16) - 1;
66+
public const int M = 4;
67+
public const int FFT_SIZE = 1024;
68+
public const int MID = (FFT_SIZE - 1) / 2;
69+
public const float DELAY_TIME = MID / SAMPLE_RATE;
70+
public const float GAIN = 1.0f;
71+
public const int BUFFER_SIZE = 256;
72+
public const int CIRCULAR_BUFFER_SAMPLES = 3;
73+
public const float CUTOFF_FREQ = 0.5f;
74+
75+
private const int DISPLAY_ARRAY_STRIDE = 4; // Each element sent to the display function needs to have 4 floats.
76+
private const int PREVIOUS_SAMPLES_LENGTH = 3 * DISPLAY_ARRAY_STRIDE;
77+
78+
private Complex[] _analytic;
79+
private LowPassFilter _angleLowPass;
80+
private LowPassFilter _noiseLowPass;
81+
82+
private Complex[] _timeRingBuffer = new Complex[2 * FFT_SIZE];
83+
private int _timeIndex = 0;
84+
private float[] _previousResults = new float[3 * 4];
85+
private Complex _prevInput = new Complex(0.0f, 0.0f);
86+
private Complex _prevDiff = new Complex(0.0f, 0.0f);
87+
private float[] _lastSample = [];
88+
89+
public AudioScope()
90+
{
91+
uint n = FFT_SIZE;
92+
if (n % 2 == 0)
93+
{
94+
n -= 1;
95+
}
96+
97+
_analytic = MakeAnalytic(n, FFT_SIZE);
98+
_angleLowPass = new LowPassFilter(0.01f, 0.5f);
99+
_noiseLowPass = new LowPassFilter(0.5f, 0.7f);
100+
}
101+
102+
public float[] GetSample()
103+
{
104+
return _lastSample;
105+
}
106+
107+
/// <summary>
108+
/// Called to process the audio input once the required number of samples are available.
109+
/// </summary>
110+
public void ProcessSample(Complex[] samples)
111+
{
112+
Array.Copy(samples, 0, _timeRingBuffer, _timeIndex, samples.Length > FFT_SIZE ? FFT_SIZE : samples.Length);
113+
Array.Copy(samples, 0, _timeRingBuffer, _timeIndex + FFT_SIZE, samples.Length > (_timeRingBuffer.Length/2 - _timeIndex) ? _timeRingBuffer.Length / 2 - _timeIndex : samples.Length);
114+
115+
_timeIndex = (_timeIndex + samples.Length) % FFT_SIZE;
116+
117+
var freqBuffer = _timeRingBuffer.Skip(_timeIndex).Take(FFT_SIZE).ToArray();
118+
119+
Fourier.Forward(freqBuffer, FourierOptions.NoScaling);
120+
121+
for (int j = 0; j < freqBuffer.Length; j++)
122+
{
123+
freqBuffer[j] = freqBuffer[j] * _analytic[j];
124+
}
125+
126+
Fourier.Inverse(freqBuffer, FourierOptions.NoScaling);
127+
128+
float scale = (float)FFT_SIZE;
129+
130+
var complexAnalyticBuffer = freqBuffer.Skip(FFT_SIZE - BUFFER_SIZE).Take(BUFFER_SIZE).ToArray();
131+
var data = new float[BUFFER_SIZE * DISPLAY_ARRAY_STRIDE + PREVIOUS_SAMPLES_LENGTH];
132+
133+
for (int k = 0; k < complexAnalyticBuffer.Length; k++)
134+
{
135+
var diff = complexAnalyticBuffer[k] - _prevInput;
136+
_prevInput = complexAnalyticBuffer[k];
137+
138+
var angle = (float)Math.Max(Math.Log(Math.Abs(GetAngle(diff, _prevDiff)), 2.0f), -1.0e12);
139+
_prevDiff = diff;
140+
var output = _angleLowPass.Apply(angle);
141+
142+
data[k * DISPLAY_ARRAY_STRIDE] = (float)(complexAnalyticBuffer[k].Real / scale);
143+
data[k * DISPLAY_ARRAY_STRIDE + 1] = (float)(complexAnalyticBuffer[k].Imaginary / scale);
144+
data[k * DISPLAY_ARRAY_STRIDE + 2] = (float)Math.Pow(2, output); // Smoothed angular velocity.
145+
data[k * DISPLAY_ARRAY_STRIDE + 3] = _noiseLowPass.Apply((float)Math.Abs(angle - output)); // Average angular noise.
146+
}
147+
148+
Array.Copy(_previousResults, 0, data, 0, PREVIOUS_SAMPLES_LENGTH);
149+
_lastSample = data;
150+
151+
_previousResults = data.Skip(data.Length - PREVIOUS_SAMPLES_LENGTH).ToArray();
152+
}
153+
154+
public static float GetAngle(Complex v, Complex u)
155+
{
156+
var len_v_mul_u = v.Norm() * u;
157+
var len_u_mul_v = u.Norm() * v;
158+
var left = (len_v_mul_u - len_u_mul_v).Norm();
159+
var right = (len_v_mul_u + len_u_mul_v).Norm();
160+
161+
return (float)(Math.Atan2(left, right) / Math.PI);
162+
}
163+
164+
private static Complex[] MakeAnalytic(uint n, uint m)
165+
{
166+
var impulse = new Complex[m];
167+
168+
var mid = (n - 1) / 2;
169+
170+
impulse[mid] = new Complex(1.0f, 0.0f);
171+
float re = -1.0f / (mid - 1);
172+
for (int i = 1; i < mid + 1; i++)
173+
{
174+
if (i % 2 == 0)
175+
{
176+
impulse[mid + i] = new Complex(re, impulse[mid + i].Imaginary);
177+
impulse[mid - i] = new Complex(re, impulse[mid - i].Imaginary);
178+
}
179+
else
180+
{
181+
float im = (float)(2.0 / Math.PI / i);
182+
impulse[mid + i] = new Complex(impulse[mid + i].Real, im);
183+
impulse[mid - i] = new Complex(impulse[mid - i].Real, -im);
184+
}
185+
// hamming window
186+
var k = 0.53836 + 0.46164 * Math.Cos(i * Math.PI / (mid + 1));
187+
impulse[mid + i] = new Complex((float)(impulse[mid + i].Real * k), (float)(impulse[mid + i].Imaginary * k));
188+
impulse[mid - i] = new Complex((float)(impulse[mid - i].Real * k), (float)(impulse[mid - i].Imaginary * k));
189+
}
190+
191+
Fourier.Forward(impulse, FourierOptions.NoScaling);
192+
193+
return impulse;
194+
}
195+
}
196+
}

0 commit comments

Comments
 (0)