Solved

Streaming a buffer while it is being written

Posted on 2004-09-08
12
249 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
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 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
Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
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

Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

Question has a verified solution.

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

Suggested Solutions

Title # Comments Views Activity
Making delphi communicate with a c# service 16 138
Reconfigure Delphi Install? 2 78
Adoquery sql  left join does not work 25 121
How to Get Images From Server using App Tethering 11 53
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…
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…
Exchange organizations may use the Journaling Agent of the Transport Service to archive messages going through Exchange. However, if the Transport Service is integrated with some email content management application (such as an antispam), the admini…
Finding and deleting duplicate (picture) files can be a time consuming task. My wife and I, our three kids and their families all share one dilemma: Managing our pictures. Between desktops, laptops, phones, tablets, and cameras; over the last decade…

759 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