Streaming a buffer while it is being written

Hello. I have an application that records audio (phone calls in a call center) from an external source to the hard drive. After the calls are recorded a user can then choose the call and play it back. My method for doing this is client/server. I load the audio via a TFileStream and stream it to the client application.

My question: I need to add the option for live playback. Meaning that while the audio is being recorded to disk, I need to also be able to stream it at the same time. A second or two of delay is ok. My problem is that since the file size will be changing while I am streaming, how can I accomplish this?
LVL 6
rbohacAsked:
Who is Participating?

Improve company productivity with a Business Account.Sign Up

x
 
Wim ten BrinkConnect With a Mentor Self-employed developerCommented:
Should it matter that the filesize is changing? All you have to do while reading is make sure you don't read past the end of the file. The bigger problem however will be reading from the file that you've opened for writing purposes.
A better solution might be to split the stream you're writing into two streams. One stream sends data to a file, the other stream sends data to the sound device.
0
 
rbohacAuthor Commented:
Unfortunately spliiting it is not an option.  Will a TFileStream allow me to keep reading while the file is being written?

Right now my code looks like:

FileStream := TFileStream.Create(FileName,fmOpenRead);
try
  FileStream.Seek(0,soFromBeginning);
  repeat
    begin
     Count:= FileStream.Read(buf,1024);
     Athread.Connection.WriteBuffer(buf,count,true);
     sleep(50);
     end;
  until count <> 1024;
finally
  FileStream.Free;
end;


Like that I would imaging that if the stream catches up to the end of the file, it would quit at that point.  What is the best way keep continuing? Maybe add some sort of a timeout that if count <> 1024 and it has been at least 3 seconds since the size changed, or something like that?
0
 
JaccoCommented:
Your code will not always work since Count<>1024 may mean the that the routine has caught up with the file writing and data is still being written. What might work is try writing as much as possible at once (no timeout needed) and when count <> 1024 try opening the file for writing/exclusive to check if the file is still being written to. If you can't open the file this way more data might come and you stay in the loop otherwise all data has been streamed.

Now you could use TFileStream.Create('....', fmOpenWrite) but this causes an exception if it fails. You could catch this in an exception handler but in the IDE you have to press F9 repeatedly to continue.

A better option might be to use the Windows.FileOpen function with the proper setting (WinHelp?) if you get an invalid handle you know the file is still being written to.

Regards Jacco
0
Free Tool: IP Lookup

Get more info about an IP address or domain name, such as organization, abuse contacts and geolocation.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

 
Wim ten BrinkConnect With a Mentor Self-employed developerCommented:
Well, you're writing to a stream so technically, splitting is an option! But not a very easy option.
What you would have to do is create a new TStream-based class and overwrite the Read/Write/Seek/Create method. The Create method would require two TStream classes as parameters. The Read-method and Seek-method could be just a dummy method. The Write method would write whatever is written to this stream to both the other streams, thus splitting the stream.
0
 
rbohacAuthor Commented:
No I'm not writing to the stream. The file is being written to by an external API (Actually a driver). I am just reading the data
0
 
JaccoCommented:
Hi,

I would go with the splitting option too. If you can change the code that writes the stream to the hard drive.

Regards Jacco
0
 
JaccoConnect With a Mentor Commented:
I researched a bit and the SysUtils the FileOpen is the easiest test. You can use the folowing code to see if the file can be opened exclusively:

function FileReady(const aFileName: string): Boolean;
var
  f: Integer;
begin
  f := FileOpen(FileNAme, 0);
  Result := f >= 0;
  if Result then
    FileClose(f);
end;

You might have to open the stream with fmShareDenyNone in the TFileStream you use to have this function work properly. Alternatively you could remember where you are in the stream, close it, test if you can open the file exclusively using the function above, and if you need to continue open the stream again.

I know thbis is not very clean and all, but if you want to access a file that is being written by a driver live...

Regards Jacco
0
 
Wim ten BrinkSelf-employed developerCommented:
> The file is being written to by an external API (Actually a driver).
That makes it a lot harder, actually. The driver might have opened that file in exclusive mode, thus blocking all other applications from accessing it. If you can open the file for reading purposes, Jacco provides an interesting option. Open the file for reading purposes and read everything until the end of file and write it to your second stream. Close the original file and check if the size is changing. If the size does change, you need to append a bit more data to the second stream. But you can't get around using a second stream.

You might try to get around this by using a different driver to record the sound of the phonecall. Some driver that does allow you to split the output into two streams. One for the filestream and one for playback.
0
 
rbohacAuthor Commented:
OK. I've been spinning my wheels on this one. As it is now, the file is locked, and I can not read from it while it is being written to. For one of the drivers, I was able to get source code for the API I am using.  The file is being opened with the following flags: O_BINARY | O_RDWR | O_CREAT

Does anybody know if this can be changed to allow read access from another application?

I also opened a question in the c++ Q about this: http://oldlook.experts-exchange.com:8080/Programming/Programming_Languages/Cplusplus/Q_21126464.html
0
 
JukiCommented:
you can inject a hook to external application which
wraps createfile, then replace CreateFile with
your own function, 3rd parameter should be
FILE_SHARE_READ which allows sharing for concurrent
reading;

if you can't inject, use virtual device and then read data
from 'backend'


Juhani Suhonen
0
 
JukiConnect With a Mentor Commented:
Also - even if you can not control file share flags, you can
open to file in another application (tfilestream) with the
following :

whateverstream := tfilestream.create('myfile',fmOpenRead or fmShareDenyNone);

that allows other programs to open the file for writing... except if the
program wants explicit access,
0
 
rbohacAuthor Commented:
Sorry, I forgot to close this out. All were good suggestions.

I ended up researching the API, and I am going to end up replacing the read/write functions and split the stream. (I found that it does have an option to replace the default read/write functions).
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.