control vlc process in c# - c#

I'm running a c# program and I need to play a video on vlc on another process and feed it with commands.
I'm not looking for something like axVLCPlugin21
I only need basic play/pause/volume commands.
What is the easiest way to achieve this?
I tried this, but the stdin writing failed
Process p = Process.Start(#"C:\...\a.mp4");
p.StandardInput.Write("comand");

I also found the console Std In redirection didn't work to the VLC process. The only way I could get the VLC console interface to work is with SendKeys, which isn't a very nice way of doing it.
VLC also supports socket connections for the same interface though, and this seems to work quite well. Here's an example of how to connect and send/receive commands and responses.
static void Main()
{
IPEndPoint socketAddress = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 54165);
var vlcServerProcess = Process.Start(#"C:\Program Files (x86)\VideoLAN\VLC\vlc.exe", "-I rc --rc-host " + socketAddress.ToString());
try
{
Socket vlcRcSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
vlcRcSocket.Connect(socketAddress);
// start another thread to look for responses and display them
Task listener = Task.Factory.StartNew(() => Receive(vlcRcSocket));
Console.WriteLine("Connected. Enter VLC commands.");
while(true)
{
string command = Console.ReadLine();
if (command.Equals("quit")) break;
Send(vlcRcSocket, command);
}
Send(vlcRcSocket, "quit"); // close vlc rc interface and disconnect
vlcRcSocket.Disconnect(false);
}
finally
{
vlcServerProcess.Kill();
}
}
private static void Send(Socket socket, string command)
{
// send command to vlc socket, note \n is important
byte[] commandData = UTF8Encoding.UTF8.GetBytes(String.Format("{0}\n", command));
int sent = socket.Send(commandData);
}
private static void Receive(Socket socket)
{
do
{
if (socket.Connected == false)
break;
// check if there is any data
bool haveData = socket.Poll(1000000, SelectMode.SelectRead);
if (haveData == false) continue;
byte[] buffer = new byte[socket.ReceiveBufferSize];
using (MemoryStream mem = new MemoryStream())
{
while (haveData)
{
int received = socket.Receive(buffer);
mem.Write(buffer, 0, received);
haveData = socket.Poll(1000000, SelectMode.SelectRead);
}
Console.WriteLine(Encoding.UTF8.GetString(mem.ToArray()));
}
} while (true);
}

You have to redirect the standard input of the process you are creating. See the sample on this page for details.

Related

How to Timeout an Async UdpClient Receive AND Get a Response?

That title is a little weird, but I have a UdpClient and it uses ReceiveAsync to listen for response from the remote endpoint after a SendAsync. The problem is that the remote endpoint is a very flimsy IoT device that will either close the connection, or never reply.
I want to timeout the ReceiveAsync so the socket can be released when the device decides to do nothing. I saw a genius comment by AJ Richardson here that suggests doing this:
Task.WhenAny(
client.ReceiveAsync(),
Task.Delay(5000)
);
I'm sure that works great, but if the ReceiveAsync is successful, I need to read the response, but because it's wrapped in Task.WhenAny, I have no idea how to do that.
Could anyone give me any suggestions? Thanks in advance!
Clarification
To clarify, here's my scenario. I have a Hangfire background job. It receives a data model and based on it sends a message to an IoT device using UDP. The problem is that the devices are flimsy and will not respond, which means the client will be awaiting forever.
If that happens then the client will be holding onto the port, and depending on how many times the job is queued I can eventually run out of ports since their clients are just stuck awaiting.
To avoid that, I want to timeout after a 5 second period and release the client's port and other resources. That is where Task.WhenAny comes in. Either the ReceiveAsync or Task.Delay calls will complete first and end the process.
However, if ReceiveAsync completes first, I need to capture the response from it and do further processing with it. How do I do that?
Here is a more complete code sample of what I'm working with.
var iotAddress = new IPAddress(iot.Ip);
var iotEndpoint = new IPEndPoint(iotAddress, iot.Port);
try {
using (var client = new UdpClient(0, AddressFamily.InterNetwork)) {
client.Connect(iotEndpoint);
await client.SendAsync(bytes, bytes.Length);
if (!iot.WaitForResponse) {
return;
}
// await the response of the IoT device
var response = await client.ReceiveAsync();
// OR
//
// await either the response of the IoT device,
// or the delay to complete, effectively creating
// a timeout.
var timeoutOrComplete = await Task.WhenAny(
client.ReceiveAsync(),
Task.Delay(5000)
);
// If a response was received before the "timeout"
// was triggered, how do I get it?
var response = timeoutOrComplete.???
}
} catch {
// Ignore
}
Try following :
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
namespace ConsoleApplication1
{
class Program
{
public class UdpState
{
public UdpClient u;
public IPEndPoint e;
public string receivedMessage;
// Size of receive buffer.
public const int BufferSize = 256;
// Receive buffer.
public byte[] buffer = new byte[BufferSize];
}
public static ManualResetEvent receiveDone = new ManualResetEvent(false);
public static void Main()
{
string ip = "172.0.0.1";
int port = 11111;
IPAddress iotAddress = IPAddress.Parse(ip);
IPEndPoint iotEndpoint = new IPEndPoint(iotAddress, port);
byte[] bytes = Encoding.UTF8.GetBytes("Hello World");
UdpState state = new UdpState();
try {
using (UdpClient client = new UdpClient(0, AddressFamily.InterNetwork)) {
client.Connect(iotEndpoint);
state.e = iotEndpoint;
state.u = client;
// await the response of the IoT device
client.BeginReceive(new AsyncCallback(ReceiveCallback), state);
client.BeginSend(bytes, bytes.Length, iotEndpoint, new AsyncCallback(SendCallback), client);
receiveDone.WaitOne();
var response = state.receivedMessage;
}
} catch {
// Ignore
}
}
public static void ReceiveCallback(IAsyncResult ar)
{
UdpState state = ar.AsyncState as UdpState;
UdpClient u = state.u;
IPEndPoint e = state.e;
state.buffer = u.EndReceive(ar, ref e);
state.receivedMessage = Encoding.ASCII.GetString(state.buffer);
receiveDone.Set();
}
private static void SendCallback(IAsyncResult ar)
{
try
{
// Retrieve the socket from the state object.
UdpClient client = ar.AsyncState as UdpClient ;
// Complete sending the data to the remote device.
int bytesSent = client.EndSend(ar);
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
}
}

C# client socket multiple send and receive

I am using sockets for TCP-IP connection and I would like to establish simple system send-receive from the client side.
Socket sck;
sck = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
IPEndPoint localEndpt = new IPEndPoint(IPAddress.Parse("123.123.123.1"), 12345);
try
{
sck.Connect(localEndpt);
}
catch
{
Console.Write("Unable to Connect");
}
while (true)
{
Console.WriteLine("Enter Text");
string sendtext = Console.ReadLine();
byte[] Data = Encoding.ASCII.GetBytes(sendtext);
sck.Send(Data);
Console.WriteLine("Data Sent!");
byte[] bytesReceived = new byte[sck.ReceiveBufferSize];
int bytes = 0;
String strReceived = "";
int dataAvailable = 0;
while (dataAvailable == 0 || dataAvailable != sck.Available)
{
dataAvailable = sck.Available;
Thread.Sleep(100); // if no new data after 100ms assume transmission finished
}
if (sck.Available > 0)
{
bytes = sck.Receive(bytesReceived, bytesReceived.Length, 0);
strReceived+=Encoding.ASCII.GetString(bytesReceived, 0, bytes);
}
Console.WriteLine("Received from server: " + strReceived);
}
Console.Read();
The problem is that first requests goes throught but the second does not, because socket is not available anymore (socket "Availabe" attribute value is 0). What am I doing wrong? What would be the easiest way to establish multiple send-recieve requests (in order)?
This code works fine for me
private List<Socket> _clients = new List<Socket>();
private Thread _dataReceiveThread;
private bool _isConnected;
private void DataReceive()
{
while (_isConnected)
{
List<Socket> clients = new List<Socket>(_clients);
foreach (Socket client in clients)
{
try
{
if (!client.Connected) continue;
string txt = "";
while (client.Available > 0)
{
byte[] bytes = new byte[client.ReceiveBufferSize];
int byteRec = client.Receive(bytes);
if (byteRec > 0)
txt += Encoding.UTF8.GetString(bytes, 0, byteRec);
}
if (!string.IsNullOrEmpty(txt))
/* TODO: access the text received with "txt" */
}
catch (Exception e)
{
Exception_Handler(e);
}
}
}
}
Just run this code to get started
_isConnected = true;
_dataReceiveThread = new Thread(DataReceive);
_dataReceiveThread.Start();
Update list box in Cross thread:
This code can be placed in the comment section.
myListBox1.Invoke((Action)(() => { myListBox1.Items.Add(txt) }));
Socket. Available does NOT indicate whether the socket is available, but incoming data is available for reading:
https://msdn.microsoft.com/en-us/library/ee425135.aspx
Your program quits because it checks for a reply (incoming data) immediately after sending a message out. Use a Thread.Sleep before checking for data.
Maybe the message has not even been sent, because Socket.Send just places it in the network interface card's output buffer. When the socket finally sends the message, it will upare the connection state. If it got no reply (on a TCP connection), it will tell you that it is disconnected when you query the state. On UDP it will tell you nothing, because UDP is connectionless.

c# udp broadcast package not receiving

I got into UDP and decided to make a small chat just for practice.
I ran into a problem and I can't figure it out myself.
I created two c# console Programs which are exactly the same (Just Port is different)
I send a UDP broadcast package and then want to receive it on the second console program. What happens tho is that the program I send the broadcast from receives it and the other program doesn't. Same happens at the other way round.
I already switched off my firewall --> doesn't change anything.
I post you the whole code, I hope you guys can help me I would really love to keep going! Thank you so much!
class Program
{
const int PORT = 10101;
private static readonly UdpClient udpclient = new UdpClient(PORT);
static void Main(string[] args)
{
Console.ForegroundColor = ConsoleColor.Red;
udpclient.EnableBroadcast = true;
//bool for calling async receiver just once
bool receiving = false;
Console.WriteLine("Chat 2");
//to keep while loop running --> change later
bool keepchatting = true;
#region keepchating loop
while (keepchatting)
{
if (!receiving)
{
startlistening();
}
receiving = true;
newmessage();
}
}
#endregion
//new message --> call sendmessage to broadcast text via UDP
public static void newmessage()
{
string msg;
msg = Console.ReadLine();
byte[] message = Encoding.ASCII.GetBytes(msg);
sendmessage(message);
}
//Broadcast text via UDP
public static void sendmessage(byte[] tosend)
{
UdpClient client = new UdpClient();
client.EnableBroadcast = true;
IPEndPoint ip = new IPEndPoint(IPAddress.Parse("255.255.255.255"), PORT);
client.Send(tosend, tosend.Length, ip);
client.Close();
Console.WriteLine("Sent!");
}
static IAsyncResult ar = null;
//Setup Async Receive Method
public static void startlistening()
{
ar = udpclient.BeginReceive(RecievedMessage, new object());
}
//Message
public static void RecievedMessage(IAsyncResult ar)
{
IPEndPoint ip = new IPEndPoint(IPAddress.Any, PORT);
byte[] bytes = udpclient.EndReceive(ar, ref ip);
string msg = Encoding.ASCII.GetString(bytes);
Console.WriteLine("Received: " + msg);
startlistening();
}
}
I have changed only two parts to your code, on each client set the remote port number of the other client, try this:
On one client:
const int PORT = 10101;
const int PORT_Remote = 10102;
IPEndPoint ip = new IPEndPoint(IPAddress.Parse("255.255.255.255"), PORT_Remote);
On the other client:
const int PORT = 10102;
const int PORT_Remote = 10101;
IPEndPoint ip = new IPEndPoint(IPAddress.Parse("255.255.255.255"), PORT_Remote);
I've wrote an application recently where I was sending socket messages back and forth between two applications on my laptop. I used 127.0.0.1 (default IP address for local host) for the IP address. Could you try that?

Communicating with a Bluetooth OBDII dongle (I think it's an ELM327)

I have a Bluetooth OBDII dongle for my car (the brand is Veepeak), and I'm trying to write a Windows app that can communicate with it. So far it seems that I'm able to connect to the device from my laptop, send commands, and receive some sort of response, but the responses I receive are not what I expect. I am using the 32feet communication library to handle the Bluetooth stuff.
Here is the code I am using to connect and also the functions I am using to send messages:
BluetoothClient client;
Stream stream;
client = new BluetoothClient();
Guid uuid = new Guid("00001101-0000-1000-8000-00805f9b34fb");
client.BeginConnect(SelectedDevice.DeviceAddress, uuid, bluetoothClientConnectCallback, client);
private void bluetoothClientConnectCallback(IAsyncResult result)
{
client = (BluetoothClient)result.AsyncState;
client.EndConnect(result);
clientConnected = true;
stream = client.GetStream();
UIWriteLine("Client connected");
}
private string sendMessage(string message)
{
byte[] encodedMessage = Encoding.ASCII.GetBytes(message);
stream.Write(encodedMessage, 0, encodedMessage.Length);
Thread.Sleep(100);
int count = 0;
byte[] buffer = new byte[1024];
string retVal = string.Empty;
count = stream.Read(buffer, 0, buffer.Length);
retVal += Encoding.ASCII.GetString(buffer, 0, count);
return retVal.Replace("\n", "");
}
private string getValue(string pid)
{
byte[] encodedMessage = Encoding.ASCII.GetBytes(pid + "\r");
stream.Write(encodedMessage, 0, encodedMessage.Length);
Thread.Sleep(100);
bool cont = true;
int count = 0;
byte[] buffer = new byte[1024];
string retVal = string.Empty;
while (cont)
{
count = stream.Read(buffer, 0, buffer.Length);
retVal += Encoding.ASCII.GetString(buffer, 0, count);
if (retVal.Contains(">"))
{
cont = false;
}
}
return retVal.Replace("\n", "");
}
I use the sendMessage method to send AT commands, and the getValue method to get a specific PID (these methods are borrowing code from an OBDII library I found here).
When I send AT commands, I seem to only get an echo of whatever I send, and when I send PIDs, I get a response of a single question mark, which to my understanding means the command is invalid.
Is it possible that my dongle does not have an ELM327? Am I doing something wrong with my Bluetooth communication or is my UUID wrong? Thanks.
I also have a Veepeak. It comes quite highly recommended in the relevant reviews and works very well with the available trial apps and my android phone. I'm struggling with initialization in my own python app, however.
On the python based application that I'm developing on the raspi, I have to open a 'virtual' serial port that is mapped to the previously paired device by it's mac address. The pairing and noting of the mac address is done at the operating system level with generic bluetooth tools.

TcpClient.Close() works only with Thread.Sleep()

I have simple server that gets string from client and prints it on screen.
I also have simple client, sending data and closing:
static void Main()
{
var client = new TcpClient("localhost", 26140);
var stream = client.GetStream();
Byte[] data = System.Text.Encoding.UTF8.GetBytes("CALC qwer");
stream.Write(data, 0, data.Length);
stream.Close();
client.Close();
//Thread.Sleep(100);
}
And with uncommented string 'Thread.Sleep(100)' it works ok.
But when commenting, sometimes ( 1 of 5-10 runs ) client doesn't send the string.
Watching wireshark and netstat I've noticed that client sends SYN,ACK package, establishes connection and exits without sending anything and without closing the socket.
Could anyone explain this behaivor? Why sleep helps? What am I doing wrong?
UPD:
With this sample code adding flush() before closing really works, thanks Fox32.
But after it I returned to my initial code:
var client = new TcpClient("localhost", 26140);
client.NoDelay = true;
var stream = client.GetStream();
var writer = new StreamWriter(stream);
writer.WriteLine("CALC qwer");
writer.Flush();
stream.Flush();
stream.Close();
client.Close();
And it isn't working, even with NoDelay. It's bad - using StreamWriter over network stream?
UPD:
Here is server code:
static void Main(string[] args)
{
(new Server(26140)).Run();
}
In Server class:
public void Run()
{
var listener = new TcpListener(IPAddress.Any, port);
listener.Start();
while (true)
{
try
{
var client = listener.AcceptTcpClient();
Console.WriteLine("Client accepted: " + client.Client.RemoteEndPoint);
var stream = client.GetStream();
stream.ReadTimeout = 2000;
byte[] buffer = new byte[1000];
stream.Read(buffer, 0, 1000);
var s = Encoding.UTF8.GetString(buffer);
Console.WriteLine(s);
}
catch (Exception ex)
{
Console.WriteLine("ERROR! " + ex.Message);
}
}
}
UPD:
Adding even Sleep(1) makes crashes happen in 1 of 30-50 clients running at the same time.
And adding Sleep(10) seems to be solving it totally, I can't catch any crash.
Don't understand, why socket needs this several milliseconds to close correctly.
The TcpClient is using the Nagle's algorithm and waits for more data before sending it over the wire. If you close the socket to fast, no data is trasmitted.
You have multiple ways to solve this problem:
The NetworkStream has a Flush method for flushing the stream content (I'm not sure if this method does anything from the comment on MSDN)
Disable Nagle's algorithm: Set NoDelay of the TcpCLient to true.
The last option is to set the LingerState of the TcpClient. The Close method documentation states, that the LingerState is used while calling Close
In almost all cases you are supposed to call Shutdown on a Socket or TcpClient before disposing it. Disposing rudely kills the connection.
Your code basically contains a race condition with the TCP stack.
Setting NoDelay is also a fix for this but hurts performance. Calling Flush IMHO still results an an disorderly shutdown. Don't do it because they are just hacks which paint over the problem by hiding the symptoms. Call Shutdown.
I want to stress that Shutdown being called on the Socket is the only valid solution that I know of. Even Flush just forces the data onto the network. It can still be lost due to a network hickup. It will not be retransmitted after Close has been called because Close is a rude kill on the socket.
Unfortunately TcpClient has a bug which forces you to go to the underlying Socket to shut it down:
tcpClient.Client.Shutdown();
tcpClient.Close();
According to Reflector, if you have ever accessed GetStream this problem arises and Close does not close the underlying socket. In my estimation this bug was produced because the developer did not really know about the importance of Shutdown. Few people know and many apps are buggy because of it. A related question.
In your server side code you are only calling Read() once, but you can't assume the data will be available when you call read. You have to continue reading in a loop until no more data is available. See the full example below.
I have tried to reproduce your issue with the minimal amount of code and was not able to. The server prints out the clients message everytime. No special settings such as NoDelay and no explicit Close() or Flush(), just Using statements which ensures all resources are properly disposed.
class Program
{
static int port = 123;
static string ip = "1.1.1.1";
static AutoResetEvent waitHandle = new AutoResetEvent(false);
static void Main(string[] args)
{
StartServer();
waitHandle.WaitOne();
for (int x=0; x<1000; x++)
{
StartClient(x);
}
Console.WriteLine("Done starting clients");
Console.ReadLine();
}
static void StartClient(int count)
{
Task.Factory.StartNew((paramCount) =>
{
int myCount = (int)paramCount;
using (TcpClient client = new TcpClient(ip, port))
{
using (NetworkStream networkStream = client.GetStream())
{
using (StreamWriter writer = new StreamWriter(networkStream))
{
writer.WriteLine("hello, tcp world #" + myCount);
}
}
}
}, count);
}
static void StartServer()
{
Task.Factory.StartNew(() =>
{
try
{
TcpListener listener = new TcpListener(port);
listener.Start();
Console.WriteLine("Listening...");
waitHandle.Set();
while (true)
{
TcpClient theClient = listener.AcceptTcpClient();
Task.Factory.StartNew((paramClient) => {
TcpClient client = (TcpClient)paramClient;
byte[] buffer = new byte[32768];
MemoryStream memory = new MemoryStream();
using (NetworkStream networkStream = client.GetStream())
{
do
{
int read = networkStream.Read(buffer, 0, buffer.Length);
memory.Write(buffer, 0, read);
}
while (networkStream.DataAvailable);
}
string text = Encoding.UTF8.GetString(memory.ToArray());
Console.WriteLine("from client: " + text);
}, theClient);
}
}
catch (Exception e)
{
Console.WriteLine(e);
}
}, TaskCreationOptions.LongRunning);
}
}
UPD:
I've tested this bug on several computers and nothing crashed. Seems like it is a local bug on my computer.
ENDOFUPD
So, what I've found about reproducing this bug.
#Despertar - your code works well. But it isn't reproduce conditions of this bug. On client you need to send data and quit after it. And in your code many clients are sending data and after all application is closing.
This is how I'm testing this on my computer:
I have server ( just accepting connection and print incoming data ), client ( just sends data once end exits ) and running utility ( runs client exe several times ).
So, I starts server, copies running utility to the clients folder and runs it.
Running ulility starts 150 clients connecting to server and 5-10 of them dies ( I see error in the server console ). And uncommenting Thread.Sleep() on client works well, no errors.
Can anyone try to reproduce this version of code?
Client code:
private static void Main(string[] args)
{
try
{
using (TcpClient client = new TcpClient(ip, port))
{
using (NetworkStream networkStream = client.GetStream())
{
using (StreamWriter writer = new StreamWriter(networkStream))
{
writer.WriteLine("# hello, tcp world #");
writer.Flush();
}
networkStream.Flush();
networkStream.Close();
}
client.Close();
//Thread.Sleep(10);
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
Code, running client several times ( compile it in exe file and put near client's exe - this code will run many clients one by one ):
static void Main(string[] args)
{
string path = "YOU_CLIENT_PROJECT_NAME.exe";
for (int i = 0; i < 150; i++ )
{
Console.WriteLine(i);
Process.Start(path);
Thread.Sleep(50);
}
Console.WriteLine("Done");
Console.ReadLine();
}
( don't forget to change path to corrent exe filename )
Server code:
class Program
{
static int port = 26140;
static AutoResetEvent waitHandle = new AutoResetEvent(false);
static void Main(string[] args)
{
StartServer();
waitHandle.WaitOne();
Console.ReadLine();
}
static void StartServer()
{
Task.Factory.StartNew(() =>
{
try
{
TcpListener listener = new TcpListener(port);
listener.Start();
Console.WriteLine("Listening...");
waitHandle.Set();
while (true)
{
TcpClient theClient = listener.AcceptTcpClient();
Task.Factory.StartNew(paramClient =>
{
try
{
TcpClient client = (TcpClient) paramClient;
byte[] buffer = new byte[32768];
MemoryStream memory = new MemoryStream();
using (NetworkStream networkStream = client.GetStream())
{
networkStream.ReadTimeout = 2000;
do
{
int read = networkStream.Read(buffer, 0, buffer.Length);
memory.Write(buffer, 0, read);
} while (networkStream.DataAvailable);
string text = Encoding.UTF8.GetString(memory.ToArray());
}
}
catch (Exception e)
{
Console.WriteLine("ERROR: " + e.Message);
}
}, theClient);
}
}
catch (Exception e)
{
Console.WriteLine(e);
}
}, TaskCreationOptions.LongRunning);
}
}
I've tried code, reproducing this bug on several computers. No one crashes. Seems like it's my local computer bug.
Thanks for everybody for trying to help me.
Anyway, it's so strange. If I'll found out why this bug exists on my computer, I'll write about it.

Categories