.NET Core: Read /dev/ file - c#

Connecting my RFID reader to my Linux machine it get installed automatically. I can see its output using hexdump /dev/hidraw0.
I want to read that input using C# .NET Core. I works fine using Pinvoke. Here the opening part (details over here):
[DllImport("libc")]
public static extern int open(string pathname, OpenFlags flags);
int fd = open("/dev/hidraw0", OpenFlags.O_RDONLY);
Is it possible to do the opening and reading using .NET Core methods? /dev/hidraw0 is just a (device) file, right? Wouldn't it be possible to use FileStream or BinaryReader? The problem I am facing: I only find methods which read available data, but I need a blocking read method which wait until data is available and then return it. Or maybe there is a DataAvailable event or alike?
Basically my question boils down to: Am a stuck with libc's read() and open() methods or is there a .NET Core way for reading /dev/ files?

I think this could help you: Linux & Dotnet – Read from a device file
public void ReadDeviceStream(CancellationToken stoppingToken)
{
// Use the device file
var targetFile = new FileInfo("/dev/inputs/event1");
// Open a stream
using (FileStream fs = targetFile.Open(FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
stoppingToken.Register(() => fs?.Close());
int blockId = 1;
// A big buffer, for simplicity purpose and to receive the entire touch report. We should use
// the proper buffer size based on the event size. Note that we could also
// use the binary reader
var buffer = new byte[1024];
// Read until the token gets cancelled
while (!stoppingToken.IsCancellationRequested && fs.Read(buffer) > 0)
{
ShowBinaryContent(blockId, buffer);
blockId++;
}
}
}
public void ShowBinaryContent(int blockId, byte[] buffer)
{
Console.WriteLine($"Block #{blockId}");
Console.WriteLine(BitConverter.ToString(bytes)); // Hex format: AB-1D...
Console.WriteLine(string.Empty);
}

Related

C# Getting Runtime error : The process cannot access the file because it is being used by another process

Here is my code:
enter image description here
using System.IO;
namespace Randoms
{
public class Program
{
public static void Main()
{
byte[] buffer = new byte[10240]; // buffer size
string path = #"C:\Users\RAHUL\Desktop\file.txt";
using (FileStream source = new FileStream(path, FileMode.Open, FileAccess.Read))
{
long fileLength = source.Length;
using (FileStream dest = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.Read))
{
long totalBytes = 0;
int currentBlockSize = 0;
while ((currentBlockSize = source.Read(buffer, 0, buffer.Length)) > 0)
{
totalBytes += currentBlockSize;
double percentage = (double)totalBytes * 100.0 / fileLength;
dest.Write(buffer, 0, currentBlockSize);
}
}
}
}
}
}
Please check the image which shows the error which I am getting.I have tried to change the FileAccess multiple times but not getting any luck.
This post explains how to both read and write to a file using a single stream:
How to both read and write a file in C#
Consider you may have the file still open from a previous erroneous run. Use a tool like Sysinternals Process Monitor or Unlocker to verify it isn't open by another instance.
How to use Process Monitor:
http://www.manuelmeyer.net/2013/09/tooltips-unlocking-files-with-sysinternals-process-monitor/
Both source and dest are referencing the same file. In the first instance (source) you open it exclusively (ie not shared).
In the second instance (dest) you now want to create the file which you opened in the first instance, but allow it to be shared.
Since the source is already open an in use you cannot write over the top of it using dest.
I think what you may be really want is to have the path parameter for the dest to be different to path parameter for the source, since you are essentially trying to re-write the same data into the same file at the same location right now.

Playing ohLibSpotify pcm data stream in C# with NAudio

I'm trying to play raw pcm data delivered from ohLibSpotify c# library (https://github.com/openhome/ohLibSpotify).
I get the data in the following callback:
public void MusicDeliveryCallback(SpotifySession session, AudioFormat format, IntPtr frames, int num_frames)
{
//EXAMPLE DATA
//format.channels = 2, format.samplerate = 44100, format.sample_type = Int16NativeEndian
//frames = ?
//num_frames = 2048
}
Now i want to directly play the received data with NAudio (http://naudio.codeplex.com/). With the following code snippet i can play a mp3 file from disk. Is it possible to directly pass the data received from spotify to NAudio and play it in realtime?
using (var ms = File.OpenRead("test.pcm"))
using (var rdr = new Mp3FileReader(ms))
using (var wavStream = WaveFormatConversionStream.CreatePcmStream(rdr))
using (var baStream = new BlockAlignReductionStream(wavStream))
using (var waveOut = new WaveOut(WaveCallbackInfo.FunctionCallback()))
{
waveOut.Init(baStream);
waveOut.Play();
while (waveOut.PlaybackState == PlaybackState.Playing)
{
Thread.Sleep(100);
}
}
EDIT:
I updated my code. The program doesn't throw any errors, but i also can't hear music. Is anything wrong in my code?
This is the music delivery callback:
public void MusicDeliveryCallback(SpotifySession session, AudioFormat format, IntPtr frames, int num_frames)
{
//format.channels = 2, format.samplerate = 44100, format.sample_type = Int16NativeEndian
//frames = ?
//num_frames = 2048
byte[] frames_copy = new byte[num_frames];
Marshal.Copy(frames, frames_copy, 0, num_frames);
bufferedWaveProvider = new BufferedWaveProvider(new WaveFormat(format.sample_rate, format.channels));
bufferedWaveProvider.BufferDuration = TimeSpan.FromSeconds(40);
bufferedWaveProvider.AddSamples(frames_copy, 0, num_frames);
bufferedWaveProvider.Read(frames_copy, 0, num_frames);
if (_waveOutDeviceInitialized == false)
{
IWavePlayer waveOutDevice = new WaveOut();
waveOutDevice.Init(bufferedWaveProvider);
waveOutDevice.Play();
_waveOutDeviceInitialized = true;
}
}
And these are the overwritten callbacks in the SessionListener:
public override int MusicDelivery(SpotifySession session, AudioFormat format, IntPtr frames, int num_frames)
{
_sessionManager.MusicDeliveryCallback(session, format, frames, num_frames);
return base.MusicDelivery(session, format, frames, num_frames);
}
public override void GetAudioBufferStats(SpotifySession session, out AudioBufferStats stats)
{
stats.samples = 2048 / 2; //???
stats.stutter = 0; //???
}
I think you can do this:
Create a BufferedWaveProvider.
Pass this to waveOut.Init.
In your MusicDeliveryCallback, use Marshal.Copy to copy from the native buffer into a managed byte array.
Pass this managed byte array to AddSamples on your BufferedWaveProvider.
In your GetAudioBufferStats callback, use bufferedWaveProvider.BufferedBytes / 2 for "samples" and leave "stutters" as 0.
I think that will work. It involves some unnecessary copying and doesn't accurately keep track of stutters, but it's a good starting point. I think it might be a better (more efficient and reliable) solution to implement IWaveProvider and manage the buffering yourself.
I wrote the ohLibSpotify wrapper-library, but I don't work for the same company anymore, so I'm not involved in its development anymore. You might be able to get more help from someone on this forum: http://forum.openhome.org/forumdisplay.php?fid=6 So far as music delivery goes, ohLibSpotify aims to have as little overhead as possible. It doesn't copy the music data at all, it just passes you the same native pointer that the libspotify library itself provided, so that you can copy it yourself to its final destination and avoid an unnecessary layer of copying. It does make it a bit clunky for simple usage, though.
Good luck!
First, your code snippet shown above is more complicated than it needs to be. You only need five, instead of two using statments. Mp3FileReader decodes to PCM for you. Second, use WaveOutEvent in preference to WaveOut with function callbacks. It is much more reliable.
using (var rdr = new Mp3FileReader("test.pcm"))
using (var waveOut = new WaveOutEvent())
{
//...
}
To answer you actual question, you need to use a BufferedWaveProvider. You create one of these and pass it to your output device in the Init method. Now, as you receive audio, decompress it to PCM (if it is compressed) and put it into the BufferedWaveProvider. The NAudioDemo application includes examples of how to do this, so look at the NAudio source code to see how its done.

Why Tape Backup dimension change for every program i use?

i'm writing a little tape writer application in C#, using class contained in this article:
http://www.codeproject.com/Articles/15487/Magnetic-Tape-Data-Storage-Part-1-Tape-Drive-IO-Co
this works very well, but writes a lot more data on tape than the original file data.
Pratical example:
my test file is 160mb.
writing in a tape results in about 300mb space occupation.
enabling hardware compression it takes about 250mb.
if i read the just wrote raw data from tape i get an about 170mb file (witch is acceptable) and the backupped file always works well.
I tried with other programs, Microsoft NTBackup uses just 170mb (!!) with compression enabled, other commercial and free program uses from 200 to 300mb
But ALL the programs can read correctly the backup (same md5 and sha1 on recovered file!)
whats going on? how can i improve my application? i really can't understand this.
i add my "write" function, who uses a modded write in the class (this works only if you write a single file):
private void Write(string path)
{
int BlockCounter = 0;
int BytesRead = 0;
Byte[] Temp = new Byte[BUFFER_SIZE];
using (System.IO.FileStream InputStream = System.IO.File.OpenRead(path))
{
TapeOperator TapeOp = new TapeOperator();
TapeOp.Load("\\\\.\\Tape0", 0);
TapeOp.SetTapePosition(0);
BytesRead = InputStream.Read(Temp, 0, BUFFER_SIZE);
while (BytesRead > 0)
{
TapeOp.Write(BlockCounter, Temp);
BlockCounter++;
BytesRead = InputStream.Read(Temp, 0, BUFFER_SIZE);
}
TapeOp.TapeMark(1, 1, 1); //TapeMark is a custom function to write a FileMark
BlockCounter++;
TapeOp.Close();
}
}
Modded write from class:
public void Write(long startPos, byte[] stream)
{
m_stream.Write(stream, 0, stream.Length);
m_stream.Flush();
}
My take on it would be the block size of the tape is greater than your BUFFER_SIZE. You are not filling the tape blocks all the way.

Redirect STDERR output from COM object wrapper in .NET

I'm trying to make use of the ImageMagick COM object (ImageMagickObject) in a .NET library. This library is intended to be called from IronRuby, but that isn't all that important. I want to take this approach because it will fit with my existing calls, which currently call the ImageMagick binaries as external processes. The COM object will take the same arguments as the binaries, but will save the process creation and are about 5x faster overall.
My only hurdle is that the "Compare" method for the COM object returns its result to STDERR. This is also a problem with the binary, but it's easy to pipe that back into STDOUT, where I was expecting it. With the COM object, I'm getting my results from function return values.
How can I redirect the result from "Compare" to a string buffer or even a file instead of STDERR?
I have tried the following, which does stop the output from reaching STDERR, but it doesn't write to the file as expected:
using ImageMagickObject;
...
public class ImageMagickCOM
{
[DllImport("Kernel32.dll", SetLastError = true)]
public static extern int SetStdHandle(int device, IntPtr handle);
private const int STDOUT_HANDLE = -11;
private const int STDERR_HANDLE = -12;
private ImageMagickObject.MagickImage magickImage = null;
private FileStream filestream = null;
private StreamWriter streamwriter = null;
public ImageMagickCOM()
{
IntPtr handle;
int status;
filestream = new FileStream("output.txt", FileMode.Create);
streamwriter = new StreamWriter(filestream);
streamwriter.AutoFlush = true;
//handle = filestream.Handle; // deprecated
handle = filestream.SafeFileHandle.DangerousGetHandle(); // replaces filestream.handle
status = SetStdHandle(STDOUT_HANDLE, handle);
status = SetStdHandle(STDERR_HANDLE, handle);
Console.SetOut(streamwriter);
Console.SetError(streamwriter);
magickImage = new ImageMagickObject.MagickImage();
}
public string Compare()
{
object[] args = new object[] { "-metric", "AE", "-fuzz", "10%", "imageA.jpg", "imageB.jpg", "diff.png" };
return (string)this.magickImage.Compare(ref args);
}
public void Close()
{
if (this.magickImage != null)
{
Marshal.ReleaseComObject(magickImage);
this.magickImage = null;
}
if (this.streamwriter != null)
{
this.streamwriter.Flush();
this.streamwriter.Close();
this.streamwriter = null;
this.filestream = null;
}
}
}
Only the "Compare" action seems to use STDERR to send a result (it uses the return value as a success indicator). All of the other methods (Identify, Convert, Mogrify, etc) work as you would expect.
For reference, it gets called something like this (from IronRuby):
require 'ImagingLib.dll'
im = ImagingLib::ImageMagickCOM.new
im.compare # returns nil
im.close
And output.txt is created, but empty. Nothing gets printed to STDOUT or STDERR.
EDITS: For clarity regarding streamwriter flush/close and how the sample is used from IronRuby.
Did you try Disposing the(or flushing) writer and stream? It could have died stuck in the buffer. A using block might help there.
using(filestream = new FileStream("output.txt", FileMode.Create))
using(streamwriter = new StreamWriter(filestream))
{
...
}
After adding the debug option I finally got some text in the file.
Is that the result you are expecting? If so, see debug option of the compare command-line tool.
Please note that setting the Console.Error or Console.Out to streamwriter will cause an exception if you try to log anything directly or indirectly using the aforementioned properties.
If you really need to set those properties, set them to another instance of StreamWriter. If you do not need them, omit the calls to Console.SetOut and Console.SetError.
I have also noticed that once ImageMagickObject.MagickImage instance is created, it is not possible to redirect the standard error. If the standard error redirection needs to be undone, or performed multiple times, try executing the code in another application domain.
It looks like .Handle is deprecated, have you tried .SafeFileHandle.DangerousGetHandle() instead?
Ref: http://msdn.microsoft.com/en-us/library/system.runtime.interopservices.safehandle.dangerousgethandle.aspx
(Additionally: can you confirm you close the StreamWriter after the data has been written? Like, if you move it to just before the app closes, to see if the data makes its way out?)
According to the documentation "FileShare.Read is the default for those FileStream constructors without a FileShare parameter"... Perhaps it could help to have FileAccess.Read, FileAccess.Write, FileShare.Read and FileShare.Write set on in the FileStream c-tor?
I don't have ImageMagick exe to play with... if you can post the link, it would be great.

Modifying XMP data with C#

I'm using C# in ASP.NET version 2. I'm trying to open an image file, read (and change) the XMP header, and close it back up again. I can't upgrade ASP, so WIC is out, and I just can't figure out how to get this working.
Here's what I have so far:
Bitmap bmp = new Bitmap(Server.MapPath(imageFile));
MemoryStream ms = new MemoryStream();
StreamReader sr = new StreamReader(Server.MapPath(imageFile));
*[stuff with find and replace here]*
byte[] data = ToByteArray(sr.ReadToEnd());
ms = new MemoryStream(data);
originalImage = System.Drawing.Image.FromStream(ms);
Any suggestions?
How about this kinda thing?
byte[] data = File.ReadAllBytes(path);
... find & replace bit here ...
File.WriteAllBytes(path, data);
Also, i really recommend against using System.Bitmap in an asp.net process, as it leaks memory and will crash/randomly fail every now and again (even MS admit this)
Here's the bit from MS about why System.Drawing.Bitmap isn't stable:
http://msdn.microsoft.com/en-us/library/system.drawing.aspx
"Caution:
Classes within the System.Drawing namespace are not supported for use within a Windows or ASP.NET service. Attempting to use these classes from within one of these application types may produce unexpected problems, such as diminished service performance and run-time exceptions."
Part 1 of the XMP spec 2012, page 10 specifically talks about how to edit a file in place without needing to understand the surrounding format (although they do suggest this as a last resort). The embedded XMP packet looks like this:
<?xpacket begin="■" id="W5M0MpCehiHzreSzNTczkc9d"?>
... the serialized XMP as described above: ...
<x:xmpmeta xmlns:x="adobe:ns:meta/">
<rdf:RDF xmlns:rdf= ...>
...
</rdf:RDF>
</x:xmpmeta>
... XML whitespace as padding ...
<?xpacket end="w"?>
In this example, ‘■’ represents the
Unicode “zero width non-breaking space
character” (U+FEFF) used as a
byte-order marker.
The (XMP Spec 2010, Part 3, Page 12) also gives specific byte patterns (UTF-8, UTF16, big/little endian) to look for when scanning the bytes. This would complement Chris' answer about reading the file in as a giant byte stream.
You can use the following functions to read/write the binary data:
public byte[] GetBinaryData(string path, int bufferSize)
{
MemoryStream ms = new MemoryStream();
using (FileStream fs = File.Open(path, FileMode.Open, FileAccess.Read))
{
int bytesRead;
byte[] buffer = new byte[bufferSize];
while((bytesRead = fs.Read(buffer,0,bufferSize))>0)
{
ms.Write(buffer,0,bytesRead);
}
}
return(ms.ToArray());
}
public void SaveBinaryData(string path, byte[] data, int bufferSize)
{
using (FileStream fs = File.Open(path, FileMode.Create, FileAccess.Write))
{
int totalBytesSaved = 0;
while (totalBytesSaved<data.Length)
{
int remainingBytes = Math.Min(bufferSize, data.Length - totalBytesSaved);
fs.Write(data, totalBytesSaved, remainingBytes);
totalBytesSaved += remainingBytes;
}
}
}
However, loading entire images to memory would use quite a bit of RAM. I don't know much about XMP headers, but if possible you should:
Load only the headers in memory
Manipulate the headers in memory
Write the headers to a new file
Copy the remaining data from the original file

Categories