Solved

Streaming a buffer while it is being written

Posted on 2004-09-08
12
241 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
 
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
How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

 
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

How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

Join & Write a Comment

Introduction The parallel port is a very commonly known port, it was widely used to connect a printer to the PC, if you look at the back of your computer, for those who don't have newer computers, there will be a port with 25 pins and a small print…
In my programming career I have only very rarely run into situations where operator overloading would be of any use in my work.  Normally those situations involved math with either overly large numbers (hundreds of thousands of digits or accuracy re…
Illustrator's Shape Builder tool will let you combine shapes visually and interactively. This video shows the Mac version, but the tool works the same way in Windows. To follow along with this video, you can draw your own shapes or download the file…
This demo shows you how to set up the containerized NetScaler CPX with NetScaler Management and Analytics System in a non-routable Mesos/Marathon environment for use with Micro-Services applications.

760 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

Need Help in Real-Time?

Connect with top rated Experts

20 Experts available now in Live!

Get 1:1 Help Now