I'm currently searching for some way to extended SFML.Net to use MP3. Therefore ioctllr recommended NLayer, which I wanted to try. This is my approach:
namespace AudioCuesheetEditor.AudioBackend
{
public class SFMLMp3Stream : Stream
{
private static readonly Logfile log = Logfile.getLogfile(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
private MpegFile file;
public SFMLMp3Stream(String _filename)
{
//TODO:Check file existence
file = new MpegFile(_filename);
log.debug("file = " + file.ToString());
}
#region implemented abstract members of Stream
public override void Flush()
{
file.Position = 0;
}
public override long Seek(long offset, SeekOrigin origin)
{
switch (origin)
{
case SeekOrigin.Begin:
file.Position = offset;
break;
case SeekOrigin.Current:
file.Position = file.Position + offset;
break;
case SeekOrigin.End:
break;
}
return file.Position;
}
public override void SetLength(long value)
{
//TODO?
int i = 1;
}
public override int Read(byte[] buffer, int offset, int count)
{
return file.ReadSamples(buffer, offset, count);
}
public override void Write(byte[] buffer, int offset, int count)
{
throw new NotImplementedException();
}
public override bool CanRead
{
get
{
return true;
}
}
public override bool CanSeek
{
get
{
return file.CanSeek;
}
}
public override bool CanWrite
{
get
{
//Writing to stream is prohibited
return false;
}
}
public override long Length
{
get
{
return file.Length;
}
}
public override long Position
{
get
{
return file.Position;
}
set
{
file.Position = value;
}
}
#endregion
}
}
Used this way:
musicStream = new SFMLMp3Stream(this.objProgram.getObjCuesheet().getAudiofilePath(true));
try
{
music = new Music(musicStream);
}
catch(Exception ex)
{
log.fatal(ex.ToString());
}
I get the exception from SFML:
05.06.2014 10:34:28 AudioCuesheetEditor.AudioBackend.AudioManagerSFML: FATAL | SFML.LoadingFailedException: Failed to load music from memory
bei SFML.Audio.Music..ctor(Stream stream)
bei AudioCuesheetEditor.AudioBackend.AudioManagerSFML.setMusic() in d:\tmp\AudioCuesheetEditor\src\AudioCuesheetEditor\AudioBackend\AudioManagerSFML.cs:Zeile 50.
I read in SFML, that it needs PCM 16 Bit signed integers (http://en.sfml-dev.org/forums/index.php?topic=1406.0). Does NLayer support this? How do I need to change the code, that it works?
Thanks for your help.
Sven
Unhappiliy Music class doesn't offer reading an mp3 stream.
Related
Consider I have the following snippet:
public void Store(Stream s, object t)
{
var serializer = new DataContractSerializer(target.GetType(),
new DataContractSerializerSettings
{
PreserveObjectReferences = true
});
serializer.WriteObject(s, target);
}
where s is write-only and doesn't support seeking.
Is there any way to get bytes count that was written to stream by WriteObject? I know I can do it in the following way:
using (var memStream = new MemoryStream())
{
serializer.WriteObject(serializer, target);
Debug.WriteLine(memStream.Length);
memStream.CopyTo(s);
}
but I wonder wheter it is possible to avoid CopyTo - object is quite huge.
EDIT:
I've just came up with an idea: I can create a wrapper that counts bytes on write. It's the best solution so fat, but maybe there is another way.
DONE
I've implemented a wrapper: https://github.com/pwasiewicz/counted-stream - maybe it will be useful for someone.
Thanks!
Sample implementation of a wrapper I've made:
public class CountedStream : Stream
{
private readonly Stream stream;
public CountedStream(Stream stream)
{
if (stream == null) throw new ArgumentNullException("stream");
this.stream = stream;
}
public long WrittenBytes { get; private set; }
public override void Flush()
{
this.stream.Flush();
}
public override int Read(byte[] buffer, int offset, int count)
{
return this.stream.Read(buffer, offset, count);
}
public override long Seek(long offset, SeekOrigin origin)
{
return this.stream.Seek(offset, origin);
}
public override void SetLength(long value)
{
this.stream.SetLength(value);
}
public override void Write(byte[] buffer, int offset, int count)
{
if (buffer.Length >= offset + count)
throw new ArgumentException("Count exceeds buffer size");
this.stream.Write(buffer, offset, count);
this.WrittenBytes += count;
}
public override bool CanRead
{
get { return this.stream.CanRead; }
}
public override bool CanSeek
{
get { return this.stream.CanSeek; }
}
public override bool CanWrite
{
get { return this.stream.CanWrite; }
}
public override long Length
{
get { return this.stream.Length; }
}
public override bool CanTimeout
{
get { return this.stream.CanTimeout; }
}
public override long Position
{
get { return this.stream.Position; }
set { this.stream.Position = value; }
}
}
I want to put the contents of some files into the database to be read by a seperate process. This is a two step thing as the files will be uploaded to a java server but then processed by a seperate c# application that runs periodically.
I was planning on using a nvarchar(Max) column to represent the data but I can't see how to read from that sort of column in a sensible way. I don't want to use SqlDataReader.GetString as that will force me to hold all the data in memory at once. The files aren't massive but that just seems like a stupid thing to do - it'll give me it as a single string which will then need splitting up into lines, so the whole approach would be totally backwards.
I was assuming I'd just be able to use a normal stream reader but calling GetStream fails saying it doesn't work for this type of column.
Any ideas? Is it just going to be easier for the database to pretend this isn't really text and store it as bytes so I can stream it?
I wrote this extension method some time ago:
public static class DataExtensions
{
public static Stream GetStream(this IDataRecord record, int ordinal)
{
return new DbBinaryFieldStream(record, ordinal);
}
public static Stream GetStream(this IDataRecord record, string name)
{
int i = record.GetOrdinal(name);
return record.GetStream(i);
}
private class DbBinaryFieldStream : Stream
{
private readonly IDataRecord _record;
private readonly int _fieldIndex;
private long _position;
private long _length = -1;
public DbBinaryFieldStream(IDataRecord record, int fieldIndex)
{
_record = record;
_fieldIndex = fieldIndex;
}
public override bool CanRead
{
get { return true; }
}
public override bool CanSeek
{
get { return true; }
}
public override bool CanWrite
{
get { return false; }
}
public override void Flush()
{
throw new NotSupportedException();
}
public override long Length
{
get
{
if (_length < 0)
{
_length = _record.GetBytes(_fieldIndex, 0, null, 0, 0);
}
return _length;
}
}
public override long Position
{
get
{
return _position;
}
set
{
_position = value;
}
}
public override int Read(byte[] buffer, int offset, int count)
{
long nRead = _record.GetBytes(_fieldIndex, _position, buffer, offset, count);
_position += nRead;
return (int)nRead;
}
public override long Seek(long offset, SeekOrigin origin)
{
long newPosition = _position;
switch (origin)
{
case SeekOrigin.Begin:
newPosition = offset;
break;
case SeekOrigin.Current:
newPosition = _position + offset;
break;
case SeekOrigin.End:
newPosition = this.Length - offset;
break;
default:
break;
}
if (newPosition < 0)
throw new ArgumentOutOfRangeException("offset");
_position = newPosition;
return _position;
}
public override void SetLength(long value)
{
throw new NotSupportedException();
}
public override void Write(byte[] buffer, int offset, int count)
{
throw new NotSupportedException();
}
}
}
It's designed for a BLOB, but it works for a NVARCHAR(max) as well (at least on SQL Server).
You can use it like this:
using (var dataReader = command.ExecuteReader())
{
dataReader.Read();
using (var stream = dataReader.GetStream("Text"))
using (var streamReader = new StreamReader(stream))
{
// read the text using the StreamReader...
}
}
Im trying to read/write xml from/to a server using a tcp socket connection. It gives me the error Root element is missing. I know there are xmpp/jabber libraries out there but I am looking for an easy custom solution how to do this in general and how to fix the error in my code.
I would greatly appreciate if someone could help me out :)
private void WritePreauthStreamInit(XmlWriter writer, string domain)
{
this.socketStream = new NetworkStream(this._socket);
XmlWriter writer1 = XmlWriter.Create(this.socketStream);
writer1.WriteStartElement("stream", "stream", "http://etherx.jabber.org/streams");
writer1.WriteAttributeString("to", domain);
writer1.WriteAttributeString("version", "1.0");
writer1.WriteStartElement("start-ack");
writer1.WriteEndElement();
writer1.Flush();
XmlReader reader1 = XmlReader.Create(this.socketStream);
while (reader1.Read()) //Exception: Root element is missing
{
string xml = reader1.Read().ToString();
}
}
My guess is that either XmlReader has false assumptions regarding buffer size of received data (I.E.: it expects to read either 4096 bytes or hit the end of the stream before it starts processing data) or the server is not sending what would be a valid document.
Either way, you could check by implementing a logging stream wrapper which dumps network traffic to disk or by using Wireshark or similar.
public class LoggingStreamWrapper : Stream
{
private Stream baseStream;
private TextWriter twLog;
private Encoding baseEncoding;
public LoggingStreamWrapper(Stream baseStream, TextWriter twLog)
: this(baseStream, twLog, Encoding.UTF8)
{
}
public LoggingStreamWrapper(Stream baseStream, TextWriter twLog, Encoding encoding)
{
if (baseStream == null)
throw new ArgumentNullException("baseStream");
if (twLog == null)
throw new ArgumentNullException("twLog");
this.baseStream = baseStream;
this.twLog = twLog;
this.baseEncoding = encoding;
}
public override bool CanRead
{
get { return baseStream.CanRead; }
}
public override bool CanSeek
{
get { return baseStream.CanSeek; }
}
public override bool CanWrite
{
get { return baseStream.CanWrite; }
}
public override void Flush()
{
baseStream.Flush();
twLog.WriteLine("Flushed stream");
twLog.Flush();
}
public override long Length
{
get { return baseStream.Length; }
}
public override long Position
{
get { return baseStream.Position; }
set
{
baseStream.Position = value;
twLog.WriteLine(string.Format("Set position to {0}", value));
twLog.Flush();
}
}
public override int Read(byte[] buffer, int offset, int count)
{
var bRead = baseStream.Read(buffer, offset, count);
if (bRead > 1)
{
twLog.WriteLine(string.Format("Read {0} bytes from stream: {1}\r\n{2}", bRead,
getText(buffer, offset, bRead),
Convert.ToBase64String(buffer, offset, bRead, Base64FormattingOptions.InsertLineBreaks)));
twLog.Flush();
}
else
{
twLog.WriteLine(string.Format("Read {0} bytes from stream", bRead));
twLog.Flush();
}
return bRead;
}
private string getText(byte[] buffer, int offset, int bRead)
{
try
{
return baseEncoding.GetString(buffer, offset, bRead);
}
catch
{
return "{ERROR: Could not convert to text}";
}
}
public override long Seek(long offset, SeekOrigin origin)
{
var newpos = baseStream.Seek(offset, origin);
twLog.WriteLine(string.Format("Seeked to {0} relative to {1}. New offset {2}", offset, origin, newpos));
twLog.Flush();
return newpos;
}
public override void SetLength(long value)
{
baseStream.SetLength(value);
twLog.WriteLine(string.Format("Set length to {0}", value));
twLog.Flush();
}
public override void Write(byte[] buffer, int offset, int count)
{
baseStream.Write(buffer, offset, count);
twLog.WriteLine(string.Format("Wrote {0} bytes to stream: {1}\r\n{2}", count,
getText(buffer, offset, count),
Convert.ToBase64String(buffer, offset, count, Base64FormattingOptions.InsertLineBreaks)));
twLog.Flush();
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
if (disposing)
{
twLog.Dispose();
baseStream.Dispose();
}
}
}
i am using the following code to minify my css on the fly:
namespace MyCMS.Modules
{
public class CSSModule : IHttpModule
{
void IHttpModule.Dispose()
{
throw new NotImplementedException();
}
void IHttpModule.Init(HttpApplication context)
{
context.BeginRequest += new EventHandler(context_BeginRequest);
}
void context_BeginRequest(object sender, EventArgs e)
{
HttpApplication app = (HttpApplication)sender;
HttpContext context = app.Context;
if (app.Request.RawUrl.Contains(".css"))
{
context.Response.Filter = new CSSFilter(app.Response.Filter);
}
}
private class CSSFilter : Stream
{
public CSSFilter(Stream sink) { _sink = sink; }
private Stream _sink;
public override bool CanRead { get { return true; } }
public override bool CanSeek { get { return true; } }
public override bool CanWrite { get { return true; } }
public override void Flush() { _sink.Flush(); }
public override long Length { get { return 0; } }
private long _position;
public override long Position
{
get { return _position; }
set { _position = value; }
}
public override int Read(byte[] buffer, int offset, int count) { return _sink.Read(buffer, offset, count); }
public override long Seek(long offset, SeekOrigin origin) { return _sink.Seek(offset, origin); }
public override void SetLength(long value) { _sink.SetLength(value); }
public override void Close() { _sink.Close(); }
public override void Write(byte[] buffer, int offset, int count)
{
byte[] data = new byte[count];
Buffer.BlockCopy(buffer, offset, data, 0, count);
string html = System.Text.Encoding.Default.GetString(buffer);
html = Yahoo.Yui.Compressor.CssCompressor.Compress(html,0, Yahoo.Yui.Compressor.CssCompressionType.Hybrid, true);
byte[] outdata = System.Text.Encoding.Default.GetBytes(html);
_sink.Write(outdata, 0, outdata.GetLength(0));
}
}
}
}
The problem is, the CRC of the GZip ( which is enabled on the server ) fails.
I do understand why it fails, since the file content was X and now its Y (minified),
and the original CRC was calculated for X, not Y.
what can i do to fix this?
I have created a sample MVC Application with CSSModule ,
With out module Site.css size was ~6kb.
Using module Site.css size ~1kb.
May be it will help you.
Link: http://www.mediafire.com/?a86fqg1zqy44ssc
http://www.sendspace.com/file/exxrj5
I have a WCF service that streams large files (100MB+) from a remote FTP server.
[ServiceContract]
public interface IStreamService
{
[OperationContract]
Stream GetDataFromFtp();
}
public class StreamService : IStreamService
{
public Stream GetDataFromFtp()
{
Stream ftpStream = Retr(...);
return ftpStream;
}
}
As WCF streams the file to the client, I want to stream it into a local cache, so that future requests don't need to go all the way back to the remote FTP - I can just serve them off disk.
I'm having problems achieving this without buffering the entire 100MB file stream in memory before returning it.
I tried using a simple capturing stream wrapper that does a write for each read:
public class CapturingStreamWrapper : Stream
{
private readonly Stream stream;
private readonly Stream captureStream;
public override int Read(byte[] buffer, int offset, int count)
{
int readBytes = stream.Read(buffer, offset, count);
captureStream.Write(buffer, offset, readBytes);
return readBytes;
}
}
public class StreamService : IStreamService
{
public Stream GetDataFromFtp()
{
Stream ftpStream = Retr(...);
Stream cacheStream = File.OpenWrite(...);
return new CapturingStreamWrapper(ftpStream, cacheStream);
}
}
But this didn't seem to work.
Additionally this doesn't provide any error handling - I need a catch block for the cache to delete any half-written file if the client transfer fails (i.e. transactional cache). I'm not sure how this would work because I don't know when streams are called/cleaned up in the WCF lifecycle.
Any ideas how I can stream into a file as I stream back to the client?
I ended up writing a couple of interconnected stream classes - one that pipes to the other as it reads. Apologies for the large code paste:
/// <summary>
/// A stream that, as it reads, makes those bytes available on an ouput
/// stream. Thread safe.
/// </summary>
public class CacheStream : Stream
{
private readonly Stream stream;
public CacheStream(Stream stream)
{
if (stream == null) throw new ArgumentNullException("stream");
this.stream = stream;
OutputStream = new CacheOutputStream(this);
}
public event EventHandler<BytesReadEventArgs> BytesRead = delegate { };
public event EventHandler Closing = delegate { };
public Stream OutputStream { get; private set; }
public override void Flush()
{
stream.Flush();
}
public override long Seek(long offset, SeekOrigin origin)
{
throw new InvalidOperationException("Cannot seek in CachingStream.");
}
public override void SetLength(long value)
{
stream.SetLength(value);
}
public override int Read(byte[] buffer, int offset, int count)
{
int numberOfBytesRead = stream.Read(buffer, offset, count);
if (numberOfBytesRead > 0)
PipeToOutputStream(buffer, offset, numberOfBytesRead);
return numberOfBytesRead;
}
private void PipeToOutputStream(byte[] buffer, int offset, int numberOfBytesRead)
{
var tmp = new byte[numberOfBytesRead];
Array.Copy(buffer, offset, tmp, 0, numberOfBytesRead);
BytesRead(this, new BytesReadEventArgs(tmp));
}
public override void Write(byte[] buffer, int offset, int count)
{
throw new InvalidOperationException("Cannot write in CachingStream.");
}
public override bool CanRead
{
get { return stream.CanRead; }
}
public override bool CanSeek
{
get { return false; }
}
public override bool CanWrite
{
get { return false; }
}
public override long Length
{
get { return stream.Length; }
}
public override long Position
{
get { return stream.Position; }
set { throw new InvalidOperationException("Cannot set position in CachingStream."); }
}
public override void Close()
{
Closing(this, EventArgs.Empty);
base.Close();
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
OutputStream.Dispose();
}
}
And
/// <summary>
/// Output portion of CacheStream. Streams bytes from a queue of buffers.
/// Thread safe.
/// </summary>
public class CacheOutputStream : Stream
{
private volatile int position;
private volatile int length;
private volatile bool sourceIsClosed;
// No Deque<T> in the BCL yet, but LinkedList is more or less the same.
private readonly LinkedList<byte[]> buffers = new LinkedList<byte[]>();
public CacheOutputStream(CacheStream stream)
{
if (stream == null) throw new ArgumentNullException("stream");
stream.BytesRead += (o, e) => AddToQueue(e.Buffer);
stream.Closing += (o, e) => sourceIsClosed = true;
}
private void AddToQueue(byte[] buffer)
{
if (buffer.Length == 0)
return;
lock (buffers)
{
buffers.AddLast(buffer);
length += buffer.Length;
}
}
public override int Read(byte[] buffer, int offset, int count)
{
if (buffer == null) throw new ArgumentNullException("buffer");
bool noMoreBuffersAvailable = HasNoMoreBuffersAvailable();
// Guard clause - closed and nothing more to write.
if (noMoreBuffersAvailable && sourceIsClosed)
return 0;
if (noMoreBuffersAvailable)
{
// Not closed yet! Block infinitely until we get closed or have some data.
while (HasNoMoreBuffersAvailable())
{
if (sourceIsClosed)
return 0;
Thread.Sleep(TimeSpan.FromMilliseconds(50));
}
}
byte[] currentBuffer = GetCurrentBuffer();
int numberOfBytesRead = DoRead(buffer, count, currentBuffer, offset);
PutLeftoverBytesAtFrontOfQueue(currentBuffer, numberOfBytesRead);
return numberOfBytesRead;
}
// Check if caller didn't have enough space to fit the buffer.
// Put the remaining bytes at the front of the queue.
private void PutLeftoverBytesAtFrontOfQueue(byte[] currentBuffer, int numberOfBytesRead)
{
if (currentBuffer == null) throw new ArgumentNullException("currentBuffer");
if (numberOfBytesRead == currentBuffer.Length)
return; // Clean read!
var remainingBuffer = new byte[currentBuffer.Length - numberOfBytesRead];
Array.Copy(currentBuffer, numberOfBytesRead, remainingBuffer, 0, remainingBuffer.Length);
lock (buffers)
buffers.AddFirst(remainingBuffer);
}
private int DoRead(byte[] buffer, int count, byte[] currentBuffer, int offset)
{
int maxNumberOfBytesWeCanWrite = Math.Min(count, currentBuffer.Length);
Array.Copy(currentBuffer, 0, buffer, offset, maxNumberOfBytesWeCanWrite);
position += maxNumberOfBytesWeCanWrite;
return maxNumberOfBytesWeCanWrite;
}
private byte[] GetCurrentBuffer()
{
byte[] currentBuffer;
lock (buffers)
{
currentBuffer = buffers.First.Value;
buffers.RemoveFirst();
}
return currentBuffer;
}
private bool HasNoMoreBuffersAvailable()
{
lock (buffers)
return buffers.Count == 0;
}
public override void Flush() { }
public override long Seek(long offset, SeekOrigin origin)
{
throw new InvalidOperationException("Cannot seek in CachingStream.");
}
public override void SetLength(long value)
{
throw new InvalidOperationException("Cannot set length in CachingStream.");
}
public override void Write(byte[] buffer, int offset, int count)
{
throw new InvalidOperationException("Cannot write in a CachingStream.");
}
public override bool CanRead
{
get { return true; }
}
public override bool CanSeek
{
get { return false; }
}
public override bool CanWrite
{
get { return false; }
}
public override long Length
{
get { return length; }
}
public override long Position
{
get { return position; }
set { throw new InvalidOperationException("Cannot set position in CachingStream."); }
}
}