I have a problem with my bot joining voice channel.
Code:
using Discord;
using Discord.Commands;
using Discord.Audio;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace DodoBot
{
class MyBot
{
DiscordClient discord;
CommandService commands;
Random rand;
string[] cats = new string[]
{
"cate.jpg",
"gut.jpg",
"meh.jpg",
"ugly.jpg",
"wow.jpg",
};
public MyBot()
{
rand = new Random();
discord = new DiscordClient(x =>
{
x.LogLevel = LogSeverity.Info;
x.LogHandler = Log;
});
discord.UsingCommands(x =>
{
x.PrefixChar = '!';
x.AllowMentionPrefix = true;
});
commands = discord.GetService<CommandService>();
RegisterHiCommand();
RegisterCatdCommand();
RegisterCatCommand();
OnJoin();
OnLeave();
discord.UsingAudio(x =>
{
x.Mode = AudioMode.Outgoing;
RegisterJoinVoiceCommand();
});
discord.ExecuteAndWait(async () =>
{
await discord.Connect("MyToken", TokenType.Bot);
});
}
private void RegisterJoinVoiceCommand()
{
commands.CreateCommand("summon")
.Do(async (e) =>
{
await e.Channel.SendMessage("```Joining masta!```");
await discord.GetService<AudioService>().Join(discord.FindServers("VoiceChannel").FirstOrDefault().VoiceChannels.FirstOrDefault());
});
}
private void RegisterCatdCommand()
{
commands.CreateCommand("catd")
.Do(async (e) =>
{
Message[] msg2Del;
msg2Del = await e.Channel.DownloadMessages(1);
await e.Channel.DeleteMessages(msg2Del);
int imgIndex = rand.Next(cats.Length);
await e.Channel.SendFile("Cats/"+cats[imgIndex]);
});
}
private void RegisterCatCommand()
{
commands.CreateCommand("cat")
.Do(async (e) =>
{
int imgIndex = rand.Next(cats.Length);
await e.Channel.SendFile("Cats/" + cats[imgIndex]);
});
}
private void RegisterHiCommand()
{
commands.CreateCommand("hi")
.Do(async (e) =>
{
await e.Channel.SendMessage("HelloWorld!");
});
}
private void OnJoin()
{
discord.UserJoined += async (s, e) =>
{
var channel = e.Server.FindChannels("general").FirstOrDefault();
var user = e.User.Name;
await channel.SendMessage(string.Format("#"+user + " has joined!"));
};
}
private void OnLeave()
{
discord.UserLeft += async (s, e) =>
{
var channel = e.Server.FindChannels("general").FirstOrDefault();
var user = e.User.Name;
await channel.SendMessage(string.Format("#"+user + " has left!"));
};
}
private void Log(object sender, LogMessageEventArgs e)
{
Console.WriteLine(e.Message);
}
}
}
I've done everything like it's written in the documentation here.
It executes the SendMessange command but it doesn't join the voice channel.
But Visual Studio says:
here.
Did I make a mistake?
Thank you for your answers.
Does your server called "VoiceChannel"?
If not, than by calling
discord.FindServers("VoiceChannel")
your client, most likely, founds nothing (null) instead of collection of servers, and tries to fetch voice channels from First() of them
for example, if your server named "My server" and has voice channel named "VoiceChannel" you can use this construction to get your voice channel:
discord.Servers.Single(s => s.Name == "My server").VoiceChannels.Single(v => v.Name == "VoiceChannel")
Call this right under your class myBot,
IVoiceChannel channel;
IAudioClient client;
Try using this in your music command, if you need more information, I can share my entire Music Module but this should do the trick.
IVoiceChannel channel = (Context.User as IVoiceState).VoiceChannel;
IAudioClient client = await channel.ConnectAsync();
Related
I'm trying to connect to Mosquitto using MQTTnet. I am able to receive messages but IsConnected property is false. Anyone know why?
Only property iStart is set to true.
The problem seems to be with the Mosquitto host.
mosquitto.conf is mostly defaults. I only have these parameters set:
allow_anonymous true
password_file C:\mosquitto\passwd
tls_version tlsv1.2
log_dest file C:\mosquitto\log\mosquitto.log
Log file is empty.
class Program
{
static async Task Main()
{
var mqttClientId = "MyClientId"; // Unique ClientId or pass a GUID as string for something random
var mqttBrokerAddress = "localhost"; // hostname or IP address of your MQTT broker
var mqttBrokerUsername = "guest"; // Broker Auth username if using auth
var mqttBrokerPassword = "guest"; // Broker Auth password if using auth
var topic = "topic"; // topic to subscribe to
var mqttClient = new MqttFactory().CreateManagedMqttClient();
var mqttClientOptions = new ManagedMqttClientOptionsBuilder()
.WithAutoReconnectDelay(TimeSpan.FromSeconds(5))
.WithClientOptions(new MqttClientOptionsBuilder()
.WithTcpServer(mqttBrokerAddress, 1883)
.WithCredentials(mqttBrokerUsername, mqttBrokerPassword) // Remove this line if no auth
.WithCleanSession().WithKeepAlivePeriod(new TimeSpan(1))//.WithTls(tlsOptions)
.Build()
)
.Build();
mqttClient.ApplicationMessageReceivedAsync += async e => MqttOnNewMessage(e);
mqttClient.ConnectedAsync += async e => MqttOnConnected(e);
mqttClient.DisconnectedAsync += async e => MqttOnDisconnected(e);
mqttClient.SynchronizingSubscriptionsFailedAsync += async e => test(e);
mqttClient.ConnectingFailedAsync += async e => test2(e);
var aaa = new List<MqttTopicFilter>();
var bbb = new MqttTopicFilterBuilder().WithTopic(topic).Build();
aaa.Add(bbb);
try
{
await mqttClient.SubscribeAsync(aaa);
await mqttClient.StartAsync(mqttClientOptions);
System.Console.WriteLine(mqttClient.IsConnected);
}
catch (Exception ex)
{
throw;
}
Console.ReadLine();
}
private static void test2(ConnectingFailedEventArgs e)
{
Console.WriteLine();
}
private static void test(ManagedProcessFailedEventArgs e)
{
Console.WriteLine();
}
private static void MqttOnNewMessage(MqttApplicationMessageReceivedEventArgs e)
{
// Do something with each incoming message from the topic
Console.WriteLine($"MQTT Client: OnNewMessage Topic: {e.ApplicationMessage.Topic} / Message: {e.ApplicationMessage.Payload}");
}
private static void MqttOnConnected(MqttClientConnectedEventArgs e) => Console.WriteLine($"MQTT Client: Connected with result: {e.ConnectResult.ResultCode}");
private static void MqttOnDisconnected(MqttClientDisconnectedEventArgs e) => Console.WriteLine($"MQTT Client: Broker connection lost with reason: {e.Reason}.");
}
I have to consume from a Kafka topic, get the message and do some json clean and filter job, then I need to produce the new message to another Kafka topic, my code is like this:
public static YamlMappingNode configs;
public static void Main(string[] args)
{
using (var reader = new StreamReader(Path.Combine(Directory.GetCurrentDirectory(), ".gitlab-ci.yml")))
{
var yaml = new YamlStream();
yaml.Load(reader);
//find variables
configs = (YamlMappingNode)yaml.Documents[0].RootNode;
configs = (YamlMappingNode)configs.Children.Where(k => k.Key.ToString() == "variables")?.FirstOrDefault().Value;
}
CancellationTokenSource cts = new CancellationTokenSource();
Console.CancelKeyPress += (_, e) => {
e.Cancel = true; // prevent the process from terminating.
cts.Cancel();
};
Run_ManualAssign(configs, cts.Token);
}
public static async void Run_ManualAssign(YamlMappingNode configs, CancellationToken cancellationToken)
{
var brokerList = configs.Where(k => k.Key.ToString() == "kfk_broker")?.FirstOrDefault().Value.ToString();
var topics = configs.Where(k => k.Key.ToString() == "input_kfk_topic")?.FirstOrDefault().Value.ToString();
var config = new ConsumerConfig
{
// the group.id property must be specified when creating a consumer, even
// if you do not intend to use any consumer group functionality.
GroupId = new Guid().ToString(),
BootstrapServers = brokerList,
// partition offsets can be committed to a group even by consumers not
// subscribed to the group. in this example, auto commit is disabled
// to prevent this from occurring.
EnableAutoCommit = true
};
using (var consumer =
new ConsumerBuilder<Ignore, string>(config)
.SetErrorHandler((_, e) => Console.WriteLine($"Error: {e.Reason}"))
.Build())
{
//consumer.Assign(topics.Select(topic => new TopicPartitionOffset(topic, 0, Offset.Beginning)).ToList());
consumer.Assign(new TopicPartitionOffset(topics, 0, Offset.End));
//var producer = new ProducerBuilder<Null, string>(config).Build();
try
{
while (true)
{
try
{
var consumeResult = consumer.Consume(cancellationToken);
/// Note: End of partition notification has not been enabled, so
/// it is guaranteed that the ConsumeResult instance corresponds
/// to a Message, and not a PartitionEOF event.
//filter message
var result = ReadMessage(configs, consumeResult.Message.Value);
//send to kafka topic
await Run_ProducerAsync(configs, result);
}
catch (ConsumeException e)
{
Console.WriteLine($"Consume error: {e.Error.Reason}");
}
}
}
catch (OperationCanceledException)
{
Console.WriteLine("Closing consumer.");
consumer.Close();
}
}
}
#endregion
#region Run_Producer
public static async Task Run_ProducerAsync(YamlMappingNode configs, string message)
{
var brokerList = configs.Where(k => k.Key.ToString() == "kfk_broker")?.FirstOrDefault().Value.ToString();
var topicName = configs.Where(k => k.Key.ToString() == "target_kafka_topic")?.FirstOrDefault().Value.ToString();
var config = new ProducerConfig {
BootstrapServers = brokerList,
};
using (var producer = new ProducerBuilder<Null, string>(config).Build())
{
try
{
/// Note: Awaiting the asynchronous produce request below prevents flow of execution
/// from proceeding until the acknowledgement from the broker is received (at the
/// expense of low throughput).
var deliveryReport = await producer.ProduceAsync(topicName, new Message<Null, string> { Value = message });
producer.Flush(TimeSpan.FromSeconds(10));
Console.WriteLine($"delivered to: {deliveryReport.TopicPartitionOffset}");
}
catch (ProduceException<string, string> e)
{
Console.WriteLine($"failed to deliver message: {e.Message} [{e.Error.Code}]");
}
}
}
#endregion
Am I doing something wrong here? The program existed immediately when executing var deliveryReport = await producer.ProduceAsync(topicName, new Message<Null, string> { Value = message });, no error message, no error code.
In the meanwhile I used Python and config the same for Producer, it works well.
Run_ManualAssign(configs, cts.Token);
For this line in the Main function, you are calling async without await in a sync function. Thus the program exit immediately after this invoke started (not finished as it is async)
You could have 2 options
Use async Main function and add await in front of this invoke.
https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/proposals/csharp-7.1/async-main
If you really want to call async function in sync function
Run_ManualAssign(configs, ts.Token).ConfigureAwait(false).GetAwaiter().GetResult();
I solved this problem but I don't know why actually. I opened an issue here.
There is a simple video editor, saving video to a file is implemented in the background, implementation of the documentation https://learn.microsoft.com/en-us/windows/uwp/audio-video-camera/process-media-files-in-the-Background . The program works, but there is a nuance - saving the video in the background occurs only when the main stream is inactive, that is, when the application is minimized to the taskbar or closed. If the application is deployed then the background video save task is suspended. Tell me how to implement the background task when the main application is active? Thank you!
Class background tasks:
using Windows.ApplicationModel.Background;
using Windows.Storage;
using Windows.UI.Notifications;
using Windows.Data.Xml.Dom;
using Windows.Media.MediaProperties;
using Windows.Media.Transcoding;
using System.Threading;
using System;
using System.Diagnostics;
using System.Threading.Tasks;
using Windows.Media.Editing;
using Windows.Foundation;
using Windows.UI.Core;
using Lumia.Imaging;
using Lumia.Imaging.Adjustments;
using Lumia.Imaging.Artistic;
using System.Collections.Generic;
using Windows.Foundation.Collections;
using VideoEffectComponent;
namespace MediaProcessingBackgroundTask
{
public sealed class MediaProcessingTask : IBackgroundTask
{
IBackgroundTaskInstance backgroundTaskInstance;
BackgroundTaskDeferral deferral;
CancellationTokenSource cancelTokenSource = new CancellationTokenSource();
MediaTranscoder transcoder;
MediaComposition composition;
MediaClip clip;
EffectList effList = new EffectList();
PropertySet configurationPropertySet = new PropertySet();
PropertySet DustPropertySet = new PropertySet();
PropertySet ScretcchPropertySet = new PropertySet();
Windows.Media.Effects.VideoEffectDefinition videoEffect;
BrightnessEffect brightnessEff = new BrightnessEffect();
ContrastEffect contrastEff = new ContrastEffect();
HueSaturationEffect saturationEff = new HueSaturationEffect();
public async void Run(IBackgroundTaskInstance taskInstance)
{
Debug.WriteLine("In background task Run method");
backgroundTaskInstance = taskInstance;
taskInstance.Canceled += new BackgroundTaskCanceledEventHandler(OnCanceled);
taskInstance.Progress = 0;
deferral = taskInstance.GetDeferral();
Debug.WriteLine("Background " + taskInstance.Task.Name + " is called # " + (DateTime.Now).ToString());
try
{
await TranscodeFileAsync();
ApplicationData.Current.LocalSettings.Values["TranscodingStatus"] = "Completed Successfully";
SendToastNotification("File transcoding complete.");
}
catch (Exception e)
{
Debug.WriteLine("Exception type: {0}", e.ToString());
ApplicationData.Current.LocalSettings.Values["TranscodingStatus"] = "Error ocurred: " + e.ToString();
}
deferral.Complete();
}
private async Task TranscodeFileAsync()
{
transcoder = new MediaTranscoder();
try
{
var settings = ApplicationData.Current.LocalSettings;
settings.Values["TranscodingStatus"] = "Started";
var inputFileName = ApplicationData.Current.LocalSettings.Values["InputFileName"] as string;
var outputFileName = ApplicationData.Current.LocalSettings.Values["OutputFileName"] as string;
var redCurve = ApplicationData.Current.LocalSettings.Values["CurvRed"] as Point[];
var greenCurve = ApplicationData.Current.LocalSettings.Values["CurvGreen"] as Point[];
var blueCurve = ApplicationData.Current.LocalSettings.Values["CurvBlue"] as Point[];
var sat = ApplicationData.Current.LocalSettings.Values["SatVal"];
var brid = ApplicationData.Current.LocalSettings.Values["BridVal"];
var con = ApplicationData.Current.LocalSettings.Values["ContrVal"];
var dust = ApplicationData.Current.LocalSettings.Values["dustCVal"];
var scetch = ApplicationData.Current.LocalSettings.Values["scetchCVal"];
saturationEff.Saturation = (double)sat;
brightnessEff.Level = (double)brid;
contrastEff.Level = (double)con;
CurvesEffect curves = new CurvesEffect();
Curve RedC = new Curve();
Curve GreenC = new Curve();
Curve BlueC = new Curve();
RedC.Points = redCurve;
GreenC.Points = greenCurve;
BlueC.Points = blueCurve;
curves.Blue = BlueC;
curves.Green = GreenC;
curves.Red = RedC;
if (inputFileName == null || outputFileName == null)
{
return;
}
var inputFile = await Windows.Storage.StorageFile.GetFileFromPathAsync(inputFileName);
var outputFile = await Windows.Storage.StorageFile.GetFileFromPathAsync(outputFileName);
composition = await MediaComposition.LoadAsync(inputFile);
clip = composition.Clips[0];
effList.Add(saturationEff);
effList.Add(brightnessEff);
effList.Add(contrastEff);
effList.Add(curves);
configurationPropertySet.Add(new KeyValuePair<string, object>("Effect", effList));
DustPropertySet = new PropertySet();
DustPropertySet["DustCount"] = dust;
ScretcchPropertySet = new PropertySet();
ScretcchPropertySet["ScetchAmount"] = scetch;
videoEffect = new Windows.Media.Effects.VideoEffectDefinition("Lumia.Imaging.VideoEffect", configurationPropertySet);
clip.VideoEffectDefinitions.Add(new Windows.Media.Effects.VideoEffectDefinition(typeof(Vignet).FullName, VignetPropertySet));
clip.VideoEffectDefinitions.Add(new Windows.Media.Effects.VideoEffectDefinition(typeof(ExampleVideoEffect).FullName, ScretcchPropertySet));
clip.VideoEffectDefinitions.Add(new Windows.Media.Effects.VideoEffectDefinition(typeof(Dust).FullName, DustPropertySet));
clip.VideoEffectDefinitions.Add(videoEffect);
MediaEncodingProfile mp = MediaEncodingProfile.CreateMp4(VideoEncodingQuality.HD1080p);
Debug.WriteLine("PrepareFileTranscodeAsync");
settings.Values["TranscodingStatus"] = "Preparing to transcode ";
var startTime = TimeSpan.FromMilliseconds(DateTime.Now.Millisecond);
Debug.WriteLine("Starting transcoding #" + startTime);
var progressT = new Progress<double>(TranscodeProgress);
settings.Values["TranscodingStatus"] = "Transcoding ";
settings.Values["ProcessingFileName"] = inputFileName;
var saveOperation = composition.RenderToFileAsync(outputFile, MediaTrimmingPreference.Precise, mp);// AsTask(cancelTokenSource.Token, progressT);
saveOperation.Completed = (info, status) =>
{
SendToastNotification("Video saved.");
clip.VideoEffectDefinitions.Clear();
composition = null;
deferral.Complete();
if (status != AsyncStatus.Completed)
{
// ShowErrorMessage("Error saving composition");
}
};
await saveOperation.AsTask(cancelTokenSource.Token, progressT);
Debug.WriteLine("Source content could not be transcoded.");
var endTime = TimeSpan.FromMilliseconds(DateTime.Now.Millisecond);
Debug.WriteLine("End time = " + endTime);
}
catch (Exception e)
{
Debug.WriteLine("Exception type: {0}", e.ToString());
throw;
}
}
void TranscodeProgress(double percent)
{
Debug.WriteLine("Transcoding progress: " + percent.ToString().Split('.')[0] + "%");
backgroundTaskInstance.Progress = (uint)percent;
}
private void SendToastNotification(string toastMessage)
{
ToastTemplateType toastTemplate = ToastTemplateType.ToastText01;
XmlDocument toastXml = ToastNotificationManager.GetTemplateContent(toastTemplate);
XmlNodeList toastTextElements = toastXml.GetElementsByTagName("text");
toastTextElements[0].AppendChild(toastXml.CreateTextNode(toastMessage));
ToastNotification toast = new ToastNotification(toastXml);
ToastNotificationManager.CreateToastNotifier().Show(toast);
}
private void OnCanceled(IBackgroundTaskInstance sender, BackgroundTaskCancellationReason reason)
{
Debug.WriteLine("Background " + sender.Task.Name + " Cancel Requested..." + reason.ToString());
}
}
}
Register and launch the background task
MediaProcessingTrigger mediaProcessingTrigger;
string backgroundTaskBuilderName = "TranscodingBackgroundTask";
BackgroundTaskRegistration taskRegistration;
private void RegisterBackgroundTask()
{
// New a MediaProcessingTrigger
mediaProcessingTrigger = new MediaProcessingTrigger();
var builder = new BackgroundTaskBuilder();
builder.Name = backgroundTaskBuilderName;
builder.TaskEntryPoint = "MediaProcessingBackgroundTask.MediaProcessingTask";
builder.SetTrigger(mediaProcessingTrigger);
// unregister old ones
foreach (var cur in BackgroundTaskRegistration.AllTasks)
{
if (cur.Value.Name == backgroundTaskBuilderName)
{
cur.Value.Unregister(true);
}
}
taskRegistration = builder.Register();
taskRegistration.Progress += new BackgroundTaskProgressEventHandler(OnProgress);
taskRegistration.Completed += new BackgroundTaskCompletedEventHandler(OnCompleted);
return;
}
private void OnProgress(IBackgroundTaskRegistration task, BackgroundTaskProgressEventArgs args)
{
string progress = "Progress: " + args.Progress + "%";
Debug.WriteLine(progress);
var ignored = Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
{
TextSave.Text = progress;
ProgressSave.Value = args.Progress;
});
}
private void OnCompleted(IBackgroundTaskRegistration task, BackgroundTaskCompletedEventArgs args)
{
Debug.WriteLine(" background task complete");
var ignored = Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
{
TasckCompleted();
});
}
private async void LaunchBackgroundTask()
{
var success = true;
if (mediaProcessingTrigger != null)
{
MediaProcessingTriggerResult activationResult;
activationResult = await mediaProcessingTrigger.RequestAsync();
switch (activationResult)
{
case MediaProcessingTriggerResult.Allowed:
// Task starting successfully
break;
case MediaProcessingTriggerResult.CurrentlyRunning:
// Already Triggered
case MediaProcessingTriggerResult.DisabledByPolicy:
// Disabled by system policy
case MediaProcessingTriggerResult.UnknownError:
// All other failures
success = false;
break;
}
if (!success)
{
// Unregister the media processing trigger background task
taskRegistration.Unregister(true);
}
}
}
saving the video in the background occurs only when the main stream is inactive , that is, when the application is minimized to the taskbar or closed.
In your above code snippet, the background task is triggered by LaunchBackgroundTask() method. When the background task occurred depends on where you invoke this method that you didn't show the relative code snippet. According to your description that background task only triggered when main stream is inactive, I think you invoke this method inside the event handle which is fired once app inactive, for example, you invoked the method inside EnteredBackground event. In that case, you may need to add LaunchBackgroundTask() method invoking foreground to meet your requirements, for example, just invoke it in a button click event.
private void btnlaunch_Click(object sender, RoutedEventArgs e)
{
LaunchBackgroundTask();
}
The MediaProcessingTask is out-of-process background task, once the background task is triggered, no matter the app is active or inactive it will continue running. But if you mean re-deployed, by testing on my side, this will uninstall the app firstly which will un-register the background task and force it stopped.
Before you judge me for posting ANOTHER NullReferenceException problem, please read my code. I've been googling NullReferenceException errors for a while now and, it doesn't explain why this specific section gives me an error.
if (e.After.VoiceChannel.Name != null)
I've also looked at the documentation for Discord.NET, however, that has also yielded nothing. Here is the whole file.
using Discord;
using Discord.Commands;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace DiscBot
{
class myBot
{
DiscordClient discord;
public myBot()
{
discord = new DiscordClient(x =>
{
x.LogLevel = LogSeverity.Info;
x.LogHandler = Log;
});
discord.UsingCommands(x =>
{
x.PrefixChar = '~';
x.AllowMentionPrefix = true;
x.HelpMode = HelpMode.Public;
});
var commands = discord.GetService<CommandService>();
commands.CreateCommand("greet")
.Description("Does a thing")
.Parameter("theGreeted", ParameterType.Unparsed)
.Do(async (e)=>
{
var msgtoRead = e.Channel.DownloadMessages(1);
await e.Channel.SendTTSMessage("Hello " + e.GetArg("theGreeted"));
});
discord.UserUpdated += async (s, e) => {
var channel = e.Server.FindChannels("general", ChannelType.Text).FirstOrDefault();
string usrnm = e.After.Name;
// This shouldn't get an error
// But when I run the code I
// get a Null Reference Exception
if (e.After.VoiceChannel.Name != null)
{
await channel.SendMessage(usrnm + " to " + e.After.VoiceChannel.Name);
}
else
{
await channel.SendMessage(usrnm + " exited");
}
};
discord.UserJoined += async (s, e) =>
{
var channel = e.Server.FindChannels("mainbois", ChannelType.Text).FirstOrDefault();
var user = e.User;
await channel.SendTTSMessage(string.Format("Another human has entered..."));
};
discord.ExecuteAndWait(async () =>
{
await discord.Connect("MYBOTTOKEN", TokenType.Bot);
});
}
private void Log(object sender, LogMessageEventArgs e)
{
Console.WriteLine(e.Message);
}
}
}
Any help is much appreciated. Thanks in advance!
P.S. Please chastise if I made a simple error somewhere. :P
Found out that I can't check
if (e.After.VoiceChannel.Name != null)
if VoiceChannel is null. In other words, I can't check a value based on a null (if that makes any sense). My new code looks like
if (e.After.VoiceChannel != null)
Thanks to anyone who took the time to look at my code. :D
i'm currently trying to create a very basic test app which should:
1) Broadcast "sometext" on port "1234"
2) Wait a second for answers
3) Return all answers
While the solution posted below works fine for the first time, every subsequent call blocks forever at:
stream = await socket.GetOutputStreamAsync(...)
Till now i tried every possible way of cleaning up (since thats where i suppose the failure), even wrapping everything in using(...) statements.
The problem occurs with the emulator as well as a hardware device using Windows Phone 8.1
Thanks in advance!
The code to start the "discovery":
private void Button_Click(object sender, RoutedEventArgs e)
{
PluginUDP pudp = new PluginUDP();
var task = pudp.scan("asf");
task.Wait();
foreach (string s in task.Result)
output.Text += s + "\r\n";
}
The code for the "discovery" itself:
using System;
using Windows.Networking;
using Windows.Networking.Sockets;
using Windows.Storage.Streams;
using System.Text;
using System.IO;
using System.Threading.Tasks;
using System.Collections.Concurrent;
using namespace whatever
{
public class PluginUDP
{
private static readonly HostName BroadcastAddress = new HostName("255.255.255.255");
private static readonly string BroadcastPort = "1234";
private static readonly byte[] data = Encoding.UTF8.GetBytes("00wlan-ping00");
ConcurrentBag<string> receivers;
public async System.Threading.Tasks.Task<string[]> scan(string options)
{
receivers = new ConcurrentBag<string>();
receivers.Add("ok");
DatagramSocket socket = null;
IOutputStream stream = null;
DataWriter writer = null;
try
{
socket = new DatagramSocket();
socket.MessageReceived += MessageReceived;
await socket.BindServiceNameAsync("");
stream = await socket.GetOutputStreamAsync(BroadcastAddress, BroadcastPort);
writer = new DataWriter(stream);
writer.WriteBytes(data);
await writer.StoreAsync();
Task.Delay(1000).Wait();
}
catch (Exception exception)
{
receivers.Add(exception.Message);
}
finally
{
if (writer != null)
{
writer.DetachStream();
writer.Dispose();
}
if(stream != null)
stream.Dispose();
if(socket != null)
socket.Dispose();
}
return receivers.ToArray(); ;
}
private async void MessageReceived(DatagramSocket socket, DatagramSocketMessageReceivedEventArgs args)
{
try
{
var result = args.GetDataStream();
var resultStream = result.AsStreamForRead(1024);
using (var reader = new StreamReader(resultStream))
{
var text = await reader.ReadToEndAsync();
if (text.Contains("pong"))
{
receivers.Add(args.RemoteAddress.ToString());
}
}
}
catch (Exception exception)
{
receivers.Add("ERRCV");
}
}
}
}
Your problem starts here:
task.Wait();
You're blocking on async code, which leads you to a deadlock.
You want:
private async void Button_Click(object sender, RoutedEventArgs e)
{
PluginUDP pudp = new PluginUDP();
string[] result = await pudp.scan("asf");
foreach (string s in result)
output.Text += s + "\r\n";
}
You also want to do:
await Task.Delay(1000);
Instead of:
Task.Delay(1000).Wait();