Solved

Streaming a buffer while it is being written

Posted on 2004-09-08
12
246 Views
Last Modified: 2010-04-05
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?
0
Comment
Question by:rbohac
  • 4
  • 3
  • 3
  • +1
12 Comments
 
LVL 17

Accepted Solution

by:
Wim ten Brink earned 300 total points
ID: 12007345
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
 
LVL 6

Author Comment

by:rbohac
ID: 12007470
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
 
LVL 10

Expert Comment

by:Jacco
ID: 12009582
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
ScreenConnect 6.0 Free Trial

At ScreenConnect, partner feedback doesn't fall on deaf ears. We collected partner suggestions off of their virtual wish list and transformed them into one game-changing release: ScreenConnect 6.0. Explore all of the extras and enhancements for yourself!

 
LVL 17

Assisted Solution

by:Wim ten Brink
Wim ten Brink earned 300 total points
ID: 12009681
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
 
LVL 6

Author Comment

by:rbohac
ID: 12009728
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
 
LVL 10

Expert Comment

by:Jacco
ID: 12009750
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
 
LVL 10

Assisted Solution

by:Jacco
Jacco earned 150 total points
ID: 12009876
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
 
LVL 17

Expert Comment

by:Wim ten Brink
ID: 12011381
> 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
 
LVL 6

Author Comment

by:rbohac
ID: 12028686
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
 

Expert Comment

by:Juki
ID: 12029672
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
 

Assisted Solution

by:Juki
Juki earned 50 total points
ID: 12029701
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
 
LVL 6

Author Comment

by:rbohac
ID: 12519876
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

Featured Post

Master Your Team's Linux and Cloud Stack!

The average business loses $13.5M per year to ineffective training (per 1,000 employees). Keep ahead of the competition and combine in-person quality with online cost and flexibility by training with Linux Academy.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

Title # Comments Views Activity
Copy file in dll not working but working on exe ! 18 93
Delphi - replicating a form 8 76
LAN or WAN ? 11 92
Tembedded WB animatid gifs not animated on some pcs 2 80
Hello everybody This Article will show you how to validate number with TEdit control, What's the TEdit control? TEdit is a standard Windows edit control on a form, it allows to user to write, read and copy/paste single line of text. Usua…
Introduction Raise your hands if you were as upset with FireMonkey as I was when I discovered that there was no TListview.  I use TListView in almost all of my applications I've written, and I was not going to compromise by resorting to TStringGrid…
Two types of users will appreciate AOMEI Backupper Pro: 1 - Those with PCIe drives (and haven't found cloning software that works on them). 2 - Those who want a fast clone of their boot drive (no re-boots needed) and it can clone your drive wh…
With Secure Portal Encryption, the recipient is sent a link to their email address directing them to the email laundry delivery page. From there, the recipient will be required to enter a user name and password to enter the page. Once the recipient …

810 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question