Skip to content

Commit 888a920

Browse files
committed
FSClient 1.4 Major Changes
Made contact plugin loading happen in UI thread. Added conference settings closes #3 Updated for FreesSWITCH 1.6/1.7 (HEAD) closes #4 Hopefully handled UE better, and more plugin error handling closes #5 Fixed crash if plugin folder doesn't exist closes #6 Updated to .net 4.5.2 for Async sorry Windows XP users. Removed mod_celt (no longer builds on windows) and mod_speex (build into core) Added async calls where appropriate on SimpleContactPluginBaseAsync class, should be backwards compatible due to a shim class. Sorry for the massive commit, was an easier squash.
1 parent c05c830 commit 888a920

28 files changed

+566
-374
lines changed

App.xaml.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ public App() {
1313

1414
void App_DispatcherUnhandledException(object sender, System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e) {
1515
MessageBox.Show("Dispatcher exception of: " + e.Exception.Message, "Dispatcher Exception", MessageBoxButton.OK, MessageBoxImage.Error);
16+
e.Handled = true;
1617
}
1718
}
1819
}

Broker.cs

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
using System.Net;
77
using System.Text;
88
using System.Threading;
9+
using System.Threading.Tasks;
910
using System.Windows;
1011
using System.Windows.Controls;
1112
using System.Xml;
@@ -31,7 +32,12 @@ private Broker() {
3132
Call.CallStateChanged += CallStateChangedHandler;
3233

3334
init_us();
34-
DelayedFunction.DelayedCall("LoadContactManager", initContactManager, 1000);
35+
loaded();
36+
}
37+
38+
private async void loaded() {
39+
await Task.Delay(1000);
40+
initContactManager();
3541
}
3642

3743
public bool fully_loaded;
@@ -141,6 +147,8 @@ private void init_us() {
141147
else
142148
event_socket = new EventSocket();
143149

150+
if (Properties.Settings.Default.Conference != null)
151+
conference = Properties.Settings.Default.Conference.GetConference();
144152
}
145153
catch (Exception e) {
146154
MessageBoxResult res = MessageBox.Show(
@@ -377,6 +385,7 @@ public void SaveSettings() {
377385
Properties.Settings.Default.ContactPlugins = contact_plugin_manager.GetSettings();
378386
Properties.Settings.Default.HeadsetPlugins = headset_plugin_manager.GetSettings();
379387
Properties.Settings.Default.EventSocket = new SettingsEventSocket(event_socket);
388+
Properties.Settings.Default.Conference = new SettingsConference(conference);
380389
Properties.Settings.Default.Save();
381390
}
382391
catch (Exception e) {//if there is an error doing saving lets skip saving any settings to avoid overriding something else
@@ -709,6 +718,9 @@ public void edit_sofia() {
709718
public void edit_event_socket() {
710719
event_socket.edit();
711720
}
721+
public void edit_conference() {
722+
conference.edit();
723+
}
712724
public void edit_plugins() {
713725
PluginOptionsWindow window = new PluginOptionsWindow();
714726
window.ShowDialog();
@@ -766,6 +778,8 @@ private string xml_search(FreeSWITCH.SwitchXmlSearchBinding.XmlBindingArgs args)
766778
return generate_xml_config(args.KeyValue, "Sofia Endpoint", sofia.gen_config);
767779
case "event_socket.conf":
768780
return generate_xml_config(args.KeyValue, "Socket Client", event_socket.gen_config);
781+
case "conference.conf":
782+
return generate_xml_config(args.KeyValue, "Audio Conference", conference.gen_config);
769783
}
770784
return null;
771785

@@ -783,10 +797,10 @@ private void fs_core_init() {
783797
uint flags = UPNPNAT ? (uint)(switch_core_flag_enum_t.SCF_USE_AUTO_NAT) : 0;
784798
if (! String.IsNullOrWhiteSpace(Environment.CommandLine) && Environment.CommandLine.Contains("--sql"))
785799
flags |= (uint)switch_core_flag_enum_t.SCF_USE_SQL;
786-
freeswitch.switch_core_init(flags, switch_bool_t.SWITCH_FALSE, ref err);
800+
freeswitch.switch_core_init(flags, switch_bool_t.SWITCH_FALSE, out err);
787801
search_bind = FreeSWITCH.SwitchXmlSearchBinding.Bind(xml_search, switch_xml_section_enum_t.SWITCH_XML_SECTION_CONFIG);
788802
event_bind = FreeSWITCH.EventBinding.Bind("FSClient", switch_event_types_t.SWITCH_EVENT_ALL, null, event_handler, true);
789-
freeswitch.switch_core_init_and_modload(flags, switch_bool_t.SWITCH_FALSE, ref err);
803+
freeswitch.switch_core_init_and_modload(flags, switch_bool_t.SWITCH_FALSE, out err);
790804
reload_audio_devices(true, true);
791805
}
792806

Conference.cs

Lines changed: 80 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,35 @@
44
using System.Linq;
55
using System.Windows;
66
using System.Windows.Controls;
7+
using System.Xml;
8+
using System.Xml.Serialization;
79
using FreeSWITCH.Native;
810

911
namespace FSClient {
12+
[XmlRoot("settingsConference")]
13+
public class SettingsConference {
14+
public SettingsField[] fields { get; set; }
15+
public Conference GetConference() {
16+
var socket = Conference.instance;
17+
foreach (SettingsField field in fields) {
18+
FieldValue val = FieldValue.GetByName(socket.values, field.name);
19+
if (val != null)
20+
val.value = field.value;
21+
}
22+
return socket;
23+
}
24+
public SettingsConference() {
25+
}
26+
public SettingsConference(Conference socket) {
27+
fields = (from fv in socket.values select new SettingsField(fv)).ToArray();
28+
}
29+
}
30+
1031
public class ConferenceUser : ObservableClass {
11-
32+
1233
[Flags]
13-
public enum USER_STATE{
14-
TALK=1, FLOOR=2, MUTE=4, DEAF=8
34+
public enum USER_STATE {
35+
TALK = 1, FLOOR = 2, MUTE = 4, DEAF = 8
1536
};
1637

1738
public static bool StateTest(USER_STATE state, USER_STATE test) {
@@ -185,7 +206,52 @@ public void Split() {
185206
}
186207

187208
}
188-
class Conference : ObservableClass {
209+
210+
public class Conference : ObservableClass {
211+
public static Field[] fields = {
212+
new Field(Field.FIELD_TYPE.String, "Enter Sound","enter-sound","enter-sound","tone_stream://%(200,0,500,600,700)",""),
213+
new Field(Field.FIELD_TYPE.String, "Exit Sound","exit-sound","exit-sound","tone_stream://%(500,0,300,200,100,50,25)",""),
214+
new Field(Field.FIELD_TYPE.Int,"Min Energy Level","energy-level","energy-level","300",""),
215+
new Field(Field.FIELD_TYPE.Bool,"Comfort Noise","comfort-noise","comfort-noise","true",""),
216+
new Field(Field.FIELD_TYPE.Combo,"Audio Sample Rate","rate","rate","16000","",new Field.FieldOption{display_value="8000", value="8000"},new Field.FieldOption{display_value="12000", value="12000"},new Field.FieldOption{display_value="16000", value="16000"},new Field.FieldOption{display_value="24000", value="24000"},new Field.FieldOption{display_value="32000", value="32000"},new Field.FieldOption{display_value="44100", value="44100"},new Field.FieldOption{display_value="48000", value="48000"},new Field.FieldOption{display_value="First Member Rate(auto)", value="auto"}),
217+
new Field(Field.FIELD_TYPE.Combo,"Audio Frame Interval","interval","interval","20","",new Field.FieldOption{display_value="10", value="10"},new Field.FieldOption{display_value="20", value="20"},new Field.FieldOption{display_value="30", value="30"},new Field.FieldOption{display_value="40", value="40"},new Field.FieldOption{display_value="50", value="50"},new Field.FieldOption{display_value="60", value="60"},new Field.FieldOption{display_value="70", value="70"},new Field.FieldOption{display_value="80", value="80"},new Field.FieldOption{display_value="90", value="90"},new Field.FieldOption{display_value="110", value="110"},new Field.FieldOption{display_value="120", value="120"},new Field.FieldOption{display_value="First Member Rate(auto)", value="auto"}),
218+
new Field(Field.FIELD_TYPE.MultiItemSort,"Default Member Flags","member-flags","member-flags","dist-dtmf","","dist-dtmf","mute","deaf","mute-detect","moderator","nomoh","endconf","mintwo","ghost"),
219+
220+
};
221+
private static string[] AllowedEmptyFields = new[] { "enter-sound", "exit-sound" };
222+
public FieldValue[] values = FieldValue.FieldValues(fields);
223+
public void gen_config(XmlNode config_node) {
224+
var controls = XmlUtils.AddNodeNode(config_node, "caller-controls");
225+
var control_group = XmlUtils.AddNodeNode(controls, "group");
226+
XmlUtils.AddNodeAttrib(control_group, "name", "default");
227+
var profiles = XmlUtils.AddNodeNode(config_node, "profiles");
228+
var profile = XmlUtils.AddNodeNode(profiles, "profile");
229+
XmlUtils.AddNodeAttrib(profile, "name", "default");
230+
foreach (FieldValue value in values) {
231+
if (String.IsNullOrEmpty(value.field.xml_name))
232+
continue;
233+
if (String.IsNullOrWhiteSpace(value.value) && !AllowedEmptyFields.Contains(value.field.name))
234+
continue;
235+
Utils.add_xml_param(profile, value.field.xml_name, value.value);
236+
}
237+
File.WriteAllText(@"c:\temp\conf.xml",config_node.OuterXml);
238+
}
239+
public void reload_config() {
240+
Utils.bgapi_exec("reload", "mod_conference");
241+
242+
}
243+
public void edit() {
244+
GenericEditor editor = new GenericEditor();
245+
editor.Init("Editing Conference Settings", values);
246+
editor.ShowDialog();
247+
if (editor.DialogResult == true) {
248+
MessageBoxResult mres = MessageBox.Show("Do you want to reload the conference settings now, if there is an active conference this will do nothing?", "Reload Module Warning", MessageBoxButton.YesNo);
249+
if (mres != MessageBoxResult.Yes)
250+
return;
251+
reload_config();
252+
}
253+
}
254+
189255
private System.Threading.Timer duration_timer;
190256

191257

@@ -201,11 +267,11 @@ public Call our_conference_call {
201267
}
202268

203269
void _our_conference_call_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e) {
204-
if (! our_conference_call.call_ended && our_conference_call.state == Call.CALL_STATE.Answered)
270+
if (!our_conference_call.call_ended && our_conference_call.state == Call.CALL_STATE.Answered)
205271
conf_color = "#FF4EFF00";
206272
else
207273
conf_color = "#FFF1FF00";
208-
274+
209275
}
210276
private Call _our_conference_call;
211277

@@ -230,11 +296,11 @@ private Conference() {
230296
void users_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e) {
231297
conf_visible = users.Count > 0 ? Visibility.Visible : Visibility.Hidden;
232298
if (am_recording_file != null && users.Count == 0)
233-
am_recording_file=null;
234-
DelayedFunction.DelayedCall("ConferenceOnlyUsLeft", only_us_left_check, 2000);
299+
am_recording_file = null;
300+
DelayedFunction.DelayedCall("ConferenceOnlyUsLeft", only_us_left_check, 2000);
235301
}
236302

237-
private void only_us_left_check(){
303+
private void only_us_left_check() {
238304
if (users.Count != 1)
239305
return;
240306
var first_user = users.FirstOrDefault();
@@ -303,7 +369,7 @@ private MenuItem UserMenu(ConferenceUser user) {
303369
main.Items.Add(CreateMenuItem("UnDeaf", () => user.Deaf(true)));
304370
else
305371
main.Items.Add(CreateMenuItem("Deaf", () => user.Deaf()));
306-
if (! user.is_us)
372+
if (!user.is_us)
307373
main.Items.Add(CreateMenuItem("Split Out", user.Split));
308374
main.Items.Add(CreateMenuItem("Drop From Conference", user.Drop));
309375
return main;
@@ -386,7 +452,7 @@ public void NewFSEvent(object sender, FSEvent evt) {
386452
String source = evt.get_header("Caller-Source");
387453
String direction = evt.get_header("Call-Direction");
388454
user = new ConferenceUser { id = member_id, uuid = uuid, party_name = evt.get_header("Caller-Caller-ID-Name"), party_number = evt.get_header("Caller-Caller-ID-Number") };
389-
if (source == "mod_portaudio" && direction == "inbound"){
455+
if (source == "mod_portaudio" && direction == "inbound") {
390456
user.party_number = user.party_name = "You";
391457
user.is_us = true;
392458
}
@@ -422,12 +488,11 @@ public void NewFSEvent(object sender, FSEvent evt) {
422488
}
423489
}
424490

425-
public void join_conference(){
426-
if (our_conference_call != null && our_conference_call.call_ended == false){
491+
public void join_conference() {
492+
if (our_conference_call != null && our_conference_call.call_ended == false) {
427493
if (our_conference_call.state != Call.CALL_STATE.Answered)
428494
our_conference_call.switch_to();
429-
}
430-
else
495+
} else
431496
broker.DialString("fsc_conference");
432497
}
433498
}

External Items/conf/freeswitch.xml

Lines changed: 1 addition & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
<X-PRE-PROCESS cmd="set" data="hold_music=local_stream://moh"/>
44
<X-PRE-PROCESS cmd="set" data="console_loglevel=info"/>
55
<X-PRE-PROCESS cmd="set" data="us-ring=v=0;%(2000,4000,440.0,480.0)"/>
6+
<X-PRE-PROCESS cmd="set" data="media_mix_inbound_outbound_codecs=true"/>
67

78
<section name="configuration" description="Various Configuration">
89
<configuration name="console.conf" description="Console Logger">
@@ -48,10 +49,8 @@
4849
<load module="mod_spandsp"/>
4950
<load module="mod_ilbc"/>
5051
<load module="mod_isac"/>
51-
<load module="mod_speex"/>
5252
<load module="mod_siren"/>
5353
<load module="mod_bv"/>
54-
<load module="mod_celt"/>
5554
<load module="mod_siren"/>
5655
<load module="mod_silk"/>
5756
<load module="mod_sndfile"/>
@@ -62,23 +61,6 @@
6261
<load module="mod_conference"/>
6362
</modules>
6463
</configuration>
65-
<configuration name="conference.conf" description="Audio Conference">
66-
<caller-controls>
67-
<group name="default" />
68-
</caller-controls>
69-
<profiles>
70-
<profile name="default">
71-
<param name="member-flags" value="dist-dtmf"/>
72-
<param name="rate" value="16000"/>
73-
<param name="interval" value="20"/>
74-
<param name="energy-level" value="300"/>
75-
<param name="enter-sound" value="tone_stream://%(200,0,500,600,700)"/>
76-
<param name="exit-sound" value="tone_stream://%(500,0,300,200,100,50,25)"/>
77-
<param name="comfort-noise" value="true"/>
78-
</profile>
79-
</profiles>
80-
81-
</configuration>
8264

8365
<configuration name="portaudio.conf" description="Soundcard Endpoint">
8466
<settings>

FSClient.csproj

Lines changed: 26 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<?xml version="1.0" encoding="utf-8"?>
2-
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
2+
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
33
<PropertyGroup>
44
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
55
<Platform Condition=" '$(Platform)' == '' ">x86</Platform>
@@ -10,17 +10,23 @@
1010
<AppDesignerFolder>Properties</AppDesignerFolder>
1111
<RootNamespace>FSClient</RootNamespace>
1212
<AssemblyName>FSClient</AssemblyName>
13-
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
14-
<TargetFrameworkProfile>Client</TargetFrameworkProfile>
13+
<TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>
14+
<TargetFrameworkProfile>
15+
</TargetFrameworkProfile>
1516
<FileAlignment>512</FileAlignment>
1617
<ProjectTypeGuids>{60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
1718
<WarningLevel>4</WarningLevel>
1819
<Utf8Output>true</Utf8Output>
1920
<ExpressionBlendVersion>4.0.20421.0</ExpressionBlendVersion>
20-
<SccProjectName>SAK</SccProjectName>
21-
<SccLocalPath>SAK</SccLocalPath>
22-
<SccAuxPath>SAK</SccAuxPath>
23-
<SccProvider>SAK</SccProvider>
21+
<SccProjectName>
22+
</SccProjectName>
23+
<SccLocalPath>
24+
</SccLocalPath>
25+
<SccAuxPath>
26+
</SccAuxPath>
27+
<SccProvider>
28+
</SccProvider>
29+
<IsWebBootstrapper>false</IsWebBootstrapper>
2430
<PublishUrl>publish\</PublishUrl>
2531
<Install>true</Install>
2632
<InstallFrom>Disk</InstallFrom>
@@ -33,7 +39,6 @@
3339
<MapFileExtensions>true</MapFileExtensions>
3440
<ApplicationRevision>0</ApplicationRevision>
3541
<ApplicationVersion>1.0.0.%2a</ApplicationVersion>
36-
<IsWebBootstrapper>false</IsWebBootstrapper>
3742
<UseApplicationTrust>false</UseApplicationTrust>
3843
<BootstrapperEnabled>true</BootstrapperEnabled>
3944
</PropertyGroup>
@@ -46,6 +51,7 @@
4651
<DefineConstants>TRACE;DEBUG</DefineConstants>
4752
<ErrorReport>prompt</ErrorReport>
4853
<WarningLevel>4</WarningLevel>
54+
<Prefer32Bit>false</Prefer32Bit>
4955
</PropertyGroup>
5056
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
5157
<PlatformTarget>x86</PlatformTarget>
@@ -55,6 +61,7 @@
5561
<DefineConstants>TRACE</DefineConstants>
5662
<ErrorReport>prompt</ErrorReport>
5763
<WarningLevel>4</WarningLevel>
64+
<Prefer32Bit>false</Prefer32Bit>
5865
</PropertyGroup>
5966
<PropertyGroup>
6067
<ApplicationIcon>phone.ico</ApplicationIcon>
@@ -69,8 +76,12 @@
6976
<Reference Include="System.Data" />
7077
<Reference Include="System.Drawing" />
7178
<Reference Include="System.Windows.Controls.Input.Toolkit, Version=3.5.40128.1, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
72-
<SpecificVersion>False</SpecificVersion>
73-
<HintPath>C:\Program Files (x86)\WPF Toolkit\v3.5.50211.1\System.Windows.Controls.Input.Toolkit.dll</HintPath>
79+
<HintPath>packages\WPFToolkit.3.5.50211.1\lib\System.Windows.Controls.Input.Toolkit.dll</HintPath>
80+
<Private>True</Private>
81+
</Reference>
82+
<Reference Include="System.Windows.Controls.Layout.Toolkit, Version=3.5.40128.1, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
83+
<HintPath>packages\WPFToolkit.3.5.50211.1\lib\System.Windows.Controls.Layout.Toolkit.dll</HintPath>
84+
<Private>True</Private>
7485
</Reference>
7586
<Reference Include="System.Windows.Forms" />
7687
<Reference Include="System.Xaml" />
@@ -85,7 +96,10 @@
8596
<Reference Include="WindowsBase" />
8697
<Reference Include="PresentationCore" />
8798
<Reference Include="PresentationFramework" />
88-
<Reference Include="WPFToolkit, Version=3.5.40128.1, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
99+
<Reference Include="WPFToolkit, Version=3.5.40128.1, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
100+
<HintPath>packages\WPFToolkit.3.5.50211.1\lib\WPFToolkit.dll</HintPath>
101+
<Private>True</Private>
102+
</Reference>
89103
</ItemGroup>
90104
<ItemGroup>
91105
<ApplicationDefinition Include="App.xaml">
@@ -208,6 +222,7 @@
208222
<SubType>Designer</SubType>
209223
</EmbeddedResource>
210224
<None Include="app.config" />
225+
<None Include="packages.config" />
211226
<None Include="Properties\Settings.settings">
212227
<Generator>SettingsSingleFileGenerator</Generator>
213228
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
@@ -264,7 +279,6 @@ if exist "%25FREESWITCH_SRC_LOCATION%25" copy "%25FREESWITCH_SRC_LOCATION%25\"Wi
264279
if not exist ".\mod" md mod
265280
if exist "%25FREESWITCH_SRC_LOCATION%25" copy "%25FREESWITCH_SRC_LOCATION%25\"Win32\$(ConfigurationName)\mod\mod_managed.dll .
266281
if exist "%25FREESWITCH_SRC_LOCATION%25" copy "%25FREESWITCH_SRC_LOCATION%25\"Win32\$(ConfigurationName)\mod\mod_spandsp.dll .\mod
267-
if exist "%25FREESWITCH_SRC_LOCATION%25" copy "%25FREESWITCH_SRC_LOCATION%25\"Win32\$(ConfigurationName)\mod\mod_celt.dll .\mod
268282
if exist "%25FREESWITCH_SRC_LOCATION%25" copy "%25FREESWITCH_SRC_LOCATION%25\"Win32\$(ConfigurationName)\mod\mod_commands.dll .\mod
269283
if exist "%25FREESWITCH_SRC_LOCATION%25" copy "%25FREESWITCH_SRC_LOCATION%25\"Win32\$(ConfigurationName)\mod\mod_console.dll .\mod
270284
if exist "%25FREESWITCH_SRC_LOCATION%25" copy "%25FREESWITCH_SRC_LOCATION%25\"Win32\$(ConfigurationName)\mod\mod_dialplan_xml.dll .\mod
@@ -278,7 +292,6 @@ if exist "%25FREESWITCH_SRC_LOCATION%25" copy "%25FREESWITCH_SRC_LOCATION%25\"Wi
278292
if exist "%25FREESWITCH_SRC_LOCATION%25" copy "%25FREESWITCH_SRC_LOCATION%25\"Win32\$(ConfigurationName)\mod\mod_siren.dll .\mod
279293
if exist "%25FREESWITCH_SRC_LOCATION%25" copy "%25FREESWITCH_SRC_LOCATION%25\"Win32\$(ConfigurationName)\mod\mod_sndfile.dll .\mod
280294
if exist "%25FREESWITCH_SRC_LOCATION%25" copy "%25FREESWITCH_SRC_LOCATION%25\"Win32\$(ConfigurationName)\mod\mod_sofia.dll .\mod
281-
if exist "%25FREESWITCH_SRC_LOCATION%25" copy "%25FREESWITCH_SRC_LOCATION%25\"Win32\$(ConfigurationName)\mod\mod_speex.dll .\mod
282295
if exist "%25FREESWITCH_SRC_LOCATION%25" copy "%25FREESWITCH_SRC_LOCATION%25\"Win32\$(ConfigurationName)\mod\mod_tone_stream.dll .\mod
283296
if exist "%25FREESWITCH_SRC_LOCATION%25" copy "%25FREESWITCH_SRC_LOCATION%25\"Win32\$(ConfigurationName)\mod\mod_silk.dll .\mod
284297
if exist "%25FREESWITCH_SRC_LOCATION%25" copy "%25FREESWITCH_SRC_LOCATION%25\"Win32\$(ConfigurationName)\mod\mod_bv.dll .\mod

0 commit comments

Comments
 (0)