Skip to content

Commit

Permalink
Desired latency adjust
Browse files Browse the repository at this point in the history
Now it is possible to adjust desired latency
Circuler buffer sizes are modified
Audio from phone to pc is now lossless
And only drop audio when exceeding desired latency
  • Loading branch information
teamclouday committed Aug 29, 2022
1 parent 08103c6 commit 37cb208
Show file tree
Hide file tree
Showing 15 changed files with 63 additions and 28 deletions.
2 changes: 1 addition & 1 deletion Android/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ android {

defaultConfig {
applicationId "com.example.microphone"
minSdkVersion 19
minSdkVersion 23
targetSdkVersion 32
versionCode 7
versionName "1.8"
Expand Down
2 changes: 1 addition & 1 deletion Android/app/src/main/cpp/OboeRecorder.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

#include "AudioBuffer.h"

#define AUDIO_BUFFER_SIZE 2 * 1024
#define AUDIO_BUFFER_SIZE 5 * 1024

class OboeRecorder {
public:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ class AudioBuffer {
private var regionRight = 0
private var regionSize = 0

val capacity = 3 * 1024
val capacity = 5 * 1024
val buffer = ByteArray(capacity)

private val mutex = Mutex()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,8 @@ class MicAudioManager(ctx: Context) {
val regionOffset = region.second
val bytesWritten = recorder!!.readToBytes(audioBuffer.buffer, regionOffset, regionLen)
audioBuffer.closeWriteRegion(bytesWritten)
Log.d(TAG, "[record] audio data recorded (${bytesWritten} bytes)")
if (bytesWritten > 0)
Log.d(TAG, "[record] audio data recorded (${bytesWritten} bytes)")
}

// start recording
Expand Down
17 changes: 11 additions & 6 deletions Windows/AndroidMic/AdvancedWindow.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,9 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:AndroidMic"
mc:Ignorable="d"
Title="AndroidMic Advanced" Height="600" Width="400" ResizeMode="CanMinimize" Background="#94fffa">
Title="AndroidMic Advanced Configurations" Height="600" Width="400" ResizeMode="CanMinimize" Background="#94fffa">
<Grid>
<Label Content="Audio Filters" HorizontalAlignment="Center" Margin="0,50,0,0" FontWeight="Bold" FontFamily="Bahnschrift"
VerticalAlignment="Top" Width="200" FontSize="20" HorizontalContentAlignment="Center" VerticalContentAlignment="Center"/>
<Expander Header="Pitch Shifter" HorizontalAlignment="Center" VerticalAlignment="Top" Width="300" Margin="0,100,0,0"
<Expander Header="Pitch Shifter" HorizontalAlignment="Center" VerticalAlignment="Top" Width="300" Margin="0,50,0,0"
FontSize="20" FontFamily="Comic Sans MS" Background="#FF93F0FF" Panel.ZIndex="0" x:Name="Expander1"
Expanded="Expander_Expanded" Collapsed="Expander_Collapsed">
<Grid Background="#FFC0FFEB">
Expand All @@ -24,7 +22,7 @@
</DockPanel>
</Grid>
</Expander>
<Expander Header="White Noise" HorizontalAlignment="Center" VerticalAlignment="Top" Width="300" Margin="0,140,0,0"
<Expander Header="White Noise" HorizontalAlignment="Center" VerticalAlignment="Top" Width="300" Margin="0,100,0,0"
FontSize="20" FontFamily="Comic Sans MS" Background="#FF93F0FF" Panel.ZIndex="0" x:Name="Expander2"
Expanded="Expander_Expanded" Collapsed="Expander_Collapsed">
<Grid Background="#FFC0FFEB">
Expand All @@ -39,7 +37,7 @@
</DockPanel>
</Grid>
</Expander>
<Expander Header="Repeat Track" HorizontalAlignment="Center" VerticalAlignment="Top" Width="300" Margin="0,180,0,0"
<Expander Header="Repeat Track" HorizontalAlignment="Center" VerticalAlignment="Top" Width="300" Margin="0,150,0,0"
FontSize="20" FontFamily="Comic Sans MS" Background="#FF93F0FF" Panel.ZIndex="0" x:Name="Expander3"
Expanded="Expander_Expanded" Collapsed="Expander_Collapsed">
<Grid Background="#FFC0FFEB">
Expand All @@ -60,6 +58,13 @@
Background="#FFEFFFA8" Click="SelectFileButton_Click" Width="300" ToolTip="Select Track File" ToolTipService.ShowDuration="2000"/>
</Grid>
</Expander>
<Label Margin="50,220,50,0" VerticalAlignment="Top" FontSize="18" FontFamily="Comic Sans MS">Desired Latency</Label>
<DockPanel Margin="50,270,50,0" VerticalAlignment="Top" ToolTip="Adjust Desired Latency (ms)" ToolTipService.ShowDuration="2000">
<TextBox DockPanel.Dock="Right" Width="60" FontSize="16" HorizontalContentAlignment="Center" VerticalContentAlignment="Center"
Background="#FFCCFFD0" Text="{Binding ElementName=LatencySlider, Path=Value, UpdateSourceTrigger=PropertyChanged, StringFormat=N0}" />
<Slider Maximum="300.0" Minimum="50.0" x:Name="LatencySlider" TickFrequency="5" Value="100.0"
TickPlacement="None" IsSnapToTickEnabled="True" ValueChanged="LatencySlider_PropertyChange"/>
</DockPanel>
<CheckBox Content="Echo Cancellation" VerticalContentAlignment="Center" x:Name="EchoCancelEnableCheckbox"
FontSize="20" FontFamily="Comic Sans MS" VerticalAlignment="Bottom" Width="300"
Checked="EchoCancelEnableCheckbox_StateChanged" Unchecked="EchoCancelEnableCheckbox_StateChanged" Margin="0,0,0,210"/>
Expand Down
15 changes: 15 additions & 0 deletions Windows/AndroidMic/AdvancedWindow.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ namespace AndroidMic
public partial class AdvancedWindow : Window
{
private readonly AudioManager audioM;
private bool windowInitialized = false;

public AdvancedWindow(AudioManager audioM)
{
Expand All @@ -18,6 +19,7 @@ public AdvancedWindow(AudioManager audioM)
InitComponentStates();
// prevent parent hiding on close
Closing += (a, b) => { Application.Current.MainWindow.Activate(); };
windowInitialized = true;
}

// update component states
Expand All @@ -38,6 +40,8 @@ private void InitComponentStates()
TrackRatioSlider.Value = val;
audioM.PipelineFilterConfig(AdvancedFilterType.FRepeatTrack, (int)FilterRepeatTrack.ConfigTypes.ConfigRepeat, ref val, false);
RepeatTrackLoopCheckbox.IsChecked = val == 1.0f;
// desired latency
LatencySlider.Value = audioM.PlayerDesiredLatency;
// init speex states
audioM.SetIndicator(SpeechIndicator);
bool valB = false;
Expand Down Expand Up @@ -178,6 +182,17 @@ private void CloseAllExpanders(Expander exception)
Expander3.IsExpanded = false;
}

// volume slider change callback
private void LatencySlider_PropertyChange(object sender, RoutedPropertyChangedEventArgs<double> e)
{
int desiredLatency = (int)e.NewValue;
if (windowInitialized)
{
audioM.PlayerDesiredLatency = desiredLatency;
Properties.Settings.Default.MainWindow_PlayerDesiredLatency = desiredLatency;
}
}

// noise cancelling enable state changed
private void NoiseCancelEnableCheckbox_StateChanged(object sender, RoutedEventArgs e)
{
Expand Down
3 changes: 3 additions & 0 deletions Windows/AndroidMic/App.config
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,9 @@
<setting name="SelectNetworkWindow_Idx" serializeAs="String">
<value>0</value>
</setting>
<setting name="MainWindow_PlayerDesiredLatency" serializeAs="String">
<value>100</value>
</setting>
</AndroidMic.Properties.Settings>
</userSettings>
</configuration>
1 change: 0 additions & 1 deletion Windows/AndroidMic/Library/Audio/AudioBuffer.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
using System;
using System.Threading;
using System.Collections.Generic;

namespace AndroidMic.Audio
{
Expand Down
10 changes: 5 additions & 5 deletions Windows/AndroidMic/Library/Audio/AudioManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ public class AudioManager
private MMDeviceCollection devices;
private int selectedDeviceIdx;
private IWavePlayer player;
private readonly int playerDesiredLatency = 100; // in milliseconds
public volatile int PlayerDesiredLatency = 100; // in milliseconds
private readonly WaveFormat format;

private readonly BufferedWaveProvider bufferedProvider;
Expand Down Expand Up @@ -63,7 +63,7 @@ public AudioManager(AudioBuffer buffer, SynchronizationContext context)
format = new WaveFormat(16000, 16, 1); // sample rate, bits, channels
var deviceIter = new MMDeviceEnumerator();
devices = deviceIter.EnumerateAudioEndPoints(DataFlow.Render, DeviceState.Active);
player = new WasapiOut(deviceIter.GetDefaultAudioEndpoint(DataFlow.Render, Role.Console), AudioClientShareMode.Shared, false, playerDesiredLatency);
player = new WasapiOut(deviceIter.GetDefaultAudioEndpoint(DataFlow.Render, Role.Console), AudioClientShareMode.Shared, false, PlayerDesiredLatency);
providerPipeline = new ISampleProvider[MAX_FILTERS_COUNT];
providerPipelineStates = new Dictionary<AdvancedFilterType, bool>();
for (int i = 0; i < MAX_FILTERS_COUNT; i++)
Expand Down Expand Up @@ -112,7 +112,7 @@ public void Process()
continue;
}
sharedBuffer.OpenReadRegion(Streaming.Streamer.BUFFER_SIZE, out var count, out var offset);
if (bufferedProvider.BufferedDuration.TotalMilliseconds <= playerDesiredLatency)
if (bufferedProvider.BufferedDuration.TotalMilliseconds <= PlayerDesiredLatency)
{
bufferedProvider.AddSamples(sharedBuffer.Buffer, offset, count);
}
Expand All @@ -133,7 +133,7 @@ public void SelectAudioDevice(int deviceIdx)
// create new player
var deviceIter = new MMDeviceEnumerator();
var device = selectedDeviceIdx < 0 ? deviceIter.GetDefaultAudioEndpoint(DataFlow.Render, Role.Console) : devices[selectedDeviceIdx];
player = new WasapiOut(device, AudioClientShareMode.Shared, false, playerDesiredLatency);
player = new WasapiOut(device, AudioClientShareMode.Shared, false, PlayerDesiredLatency);
bufferedProvider.ClearBuffer();
// start playing
player.Init(volumeProvider);
Expand Down Expand Up @@ -175,7 +175,7 @@ private void BuildPipeline()
// create new player
var deviceIter = new MMDeviceEnumerator();
var device = selectedDeviceIdx < 0 ? deviceIter.GetDefaultAudioEndpoint(DataFlow.Render, Role.Console) : devices[selectedDeviceIdx];
player = new WasapiOut(device, AudioClientShareMode.Shared, false, playerDesiredLatency);
player = new WasapiOut(device, AudioClientShareMode.Shared, false, PlayerDesiredLatency);
bufferedProvider.ClearBuffer();
ISampleProvider source = speexProvider.ToSampleProvider();
for (int i = 0; i < MAX_FILTERS_COUNT; i++)
Expand Down
6 changes: 1 addition & 5 deletions Windows/AndroidMic/Library/Streaming/StreamerBluetooth.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,6 @@ public class StreamerBluetooth : Streamer
private BluetoothClient client;
private BluetoothEndPoint targetDevice;

private byte[] buffer = new byte[BUFFER_SIZE];

private volatile bool isConnectionAllowed;

public StreamerBluetooth()
Expand Down Expand Up @@ -123,9 +121,7 @@ public override void Process(AudioBuffer sharedBuffer)
{
var stream = client.GetStream();
sharedBuffer.OpenWriteRegion(BUFFER_SIZE, out count, out var offset);
int size = stream.Read(buffer, 0, BUFFER_SIZE);
count = Math.Min(Math.Max(size, 0), count);
Array.Copy(buffer, 0, sharedBuffer.Buffer, offset, count);
count = stream.Read(sharedBuffer.Buffer, offset, count);
}
catch (IOException e)
{
Expand Down
6 changes: 1 addition & 5 deletions Windows/AndroidMic/Library/Streaming/StreamerWifi.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,6 @@ public class StreamerWifi : Streamer
private string address;
private int port = 55555;

private byte[] buffer = new byte[BUFFER_SIZE];

private bool isConnectionAllowed = false;

public StreamerWifi()
Expand Down Expand Up @@ -132,9 +130,7 @@ public override void Process(AudioBuffer sharedBuffer)
{
var stream = new NetworkStream(client);
sharedBuffer.OpenWriteRegion(BUFFER_SIZE, out count, out var offset);
int size = stream.Read(buffer, 0, BUFFER_SIZE);
count = Math.Min(Math.Max(size, 0), count);
Array.Copy(buffer, 0, sharedBuffer.Buffer, offset, count);
count = stream.Read(sharedBuffer.Buffer, offset, count);
}
catch (IOException e)
{
Expand Down
2 changes: 1 addition & 1 deletion Windows/AndroidMic/MainWindow.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
<Slider Maximum="5.0" Minimum="0.0" x:Name="VolumeSlider" TickFrequency="0.1" Value="1.0"
TickPlacement="None" IsSnapToTickEnabled="True" ValueChanged="VolumeSlider_PropertyChange"/>
</DockPanel>
<Button x:Name="AdvancedButton" Cursor="Hand" Content="Advanced Effects" HorizontalAlignment="Center" VerticalAlignment="Top"
<Button x:Name="AdvancedButton" Cursor="Hand" Content="Advanced" HorizontalAlignment="Center" VerticalAlignment="Top"
Margin="0,150,0,20" FontSize="18" Padding="6" Background="#FFEFFFA8" Click="AdvancedButton_Click"
ToolTip="Start Server" ToolTipService.ShowDuration="2000" FontFamily="Comic Sans MS" Width="200"/>
<Label Content="Connection" HorizontalAlignment="Center" Margin="0,260,0,0" VerticalAlignment="Top" Width="200"
Expand Down
5 changes: 5 additions & 0 deletions Windows/AndroidMic/MainWindow.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,11 @@ private void LoadUserSettings()
streamM.SetConnectionType(StreamManager.ConnectionType.WIFI);
RadioButton2.IsChecked = true;
}
// MainWindow_PlayerDesiredLatency
{
int latency = settings.MainWindow_PlayerDesiredLatency;
audioM.PlayerDesiredLatency = latency;
}

float val;
// AdvancedWindow_PitchShifterEnabled
Expand Down
14 changes: 13 additions & 1 deletion Windows/AndroidMic/Properties/Settings.Designer.cs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions Windows/AndroidMic/Properties/Settings.settings
Original file line number Diff line number Diff line change
Expand Up @@ -50,5 +50,8 @@
<Setting Name="SelectNetworkWindow_Idx" Type="System.Int32" Scope="User">
<Value Profile="(Default)">0</Value>
</Setting>
<Setting Name="MainWindow_PlayerDesiredLatency" Type="System.Int32" Scope="User">
<Value Profile="(Default)">100</Value>
</Setting>
</Settings>
</SettingsFile>

0 comments on commit 37cb208

Please sign in to comment.