JAudiorecorder record freezing the app

i am trying to use jaudiorecorder to record sound to a stream from android but while recorder and start sending buffer the app is completley freeze any idea why ?

here is the current code

//audio recorder 
GBUFFSIZE := TJAudioRecord.JavaClass.getMinBufferSize(8000,
TJAudioFormat.JavaClass.CHANNEL_IN_MONO,
TJAudioFormat.JavaClass.ENCODING_PCM_16BIT);

Gstream := TJavaArray<Byte>.Create(GBUFFSIZE);

AudioRecorder:= TJAudioRecord.JavaClass.init(TJMediaRecorder_AudioSource.JavaClass.VOICE_COMMUNICATION,
8000,
TJAudioFormat.JavaClass.CHANNEL_IN_MONO,
TJAudioFormat.JavaClass.ENCODING_PCM_16BIT,
GBUFFSIZE);


//start recording

(AudioRecorder as JAudioRecord).startRecording;
papulaterecorder.Enabled := True;

//timer
procedure TForm1.papulaterecorderTimer(Sender: TObject);
var
  index: Integer;
  NewCount: Integer;
  Bytes: TIdBytes;
begin


// Read from the AudioRecover
NewCount:= (AudioRecorder as JAudioRecord).read(Gstream, 0, GBUFFSIZE);
if  (NewCount > 0) then
begin
Bytes := RawToBytes(Gstream.Data^, NewCount);
SendBuffer(Bytes, NewCount);
end;

end;


end;


procedure SendBuffer(Buffer: TIdBytes; BufferSize: Cardinal);
Var
Strm: TIdMemoryBufferStream;
begin

Strm := TIdMemoryBufferStream.Create(PByte(Buffer), BufferSize);
try
FTCP.Socket.WriteLn('stream');
FTCP.Socket.LargeStream := True;
FTCP.Socket.Write(Strm, 0, True);
finally
Strm.Free;
end;
end;

Open in new window

dolphin KingAsked:
Who is Participating?

[Product update] Infrastructure Analysis Tool is now available with Business Accounts.Learn More

x
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

Sinisa VukSoftware architectCommented:
App is freezing cause Indy is blocking (send with block until all is send) component. Maybe ICS (internet component suite) is the solution...
Then again ... it is better to use separate thread to send data....
dolphin KingAuthor Commented:
but ics is not supporting on android yet , also i send the same way from vcl and it works normal

i suspect those variable that causes the  freeze  do  i sent the right data ? also what you mean by use separate thread

var
Bytes: TIdBytes;
..
Bytes := RawToBytes(Gstream.Data^, NewCount);
SendBuffer(Bytes, NewCount);

Open in new window


procedure SendBuffer(Buffer: TIdBytes; BufferSize: Cardinal);
Var
Strm: TIdMemoryBufferStream;
begin

Strm := TIdMemoryBufferStream.Create(PByte(Buffer), BufferSize);
try
FTCP.Socket.WriteLn('stream');
FTCP.Socket.LargeStream := True;
FTCP.Socket.Write(Strm, 0, True);
finally
Strm.Free;
end;
end;

Open in new window


on VCL i do

procedure Tform1.recorderData(Sender: TObject; const Buffer: Pointer; BufferSize: Cardinal; var FreeIt: Boolean);
var
Bytes: TIdBytes;
begin
FreeIt := True;

if (Buffer <> nil) and (BufferSize > 0) then
begin
try
Bytes := RawToBytes(Buffer^, BufferSize);
except
exit;
end;
begin
SendBuffer(Bytes, BufferSize);
end;
end;
end;

Open in new window


and it sended normal

on android when i comment out the sendbuffer the app is not freezing
dolphin KingAuthor Commented:
also i suspend the rawtobyte converter i am not sure whats going on
Learn Ruby Fundamentals

This course will introduce you to Ruby, as well as teach you about classes, methods, variables, data structures, loops, enumerable methods, and finishing touches.

Sinisa VukSoftware architectCommented:
Don't know too... Seem that Indy works different on android... Maybe some properties will help... hard to say...
dolphin KingAuthor Commented:
i even changed the Gstream : TJavaArray<Byte>; To smallint still the same
dolphin KingAuthor Commented:
ok i want to test something different can you show me how to rung that audio recorder in a worker thread ? i want to send the stream in a worker thread instead of a timer but i dont know how
dolphin KingAuthor Commented:
also i see problem when some data sent it sent as 715 size it should be 1600 to allow the vcl player to playing it i am trying to look deeply

also i have changed the send buffer so now its looks like


procedure TForm1.timer1Timer(Sender: TObject);
var
  NewCount: Integer;
begin

NewCount:= (AudioRecorder as JAudioRecord).read(Gstream, 0, GBUFFSIZE);
if NewCount > 0 then
begin
try
ClientThread.SendBuffer(Gstream.Data, Gstream.Length);
except
end;

end;


end;


SendBuffer(Buffer: pointer; BufferSize: Cardinal);
Var
Strm: TIdMemoryBufferStream;
begin
ClientThread.Lock;
try

Strm := TIdMemoryBufferStream.Create(Buffer, BufferSize);
try
FTCP.Socket.WriteLn('Stream');
FTCP.Socket.LargeStream := True;
FTCP.Socket.Write(Strm, 0, True);
finally
Strm.Free;
end;
finally
ClientThread.Unlock;
end;
end;

Open in new window



now it does send the stream but audio cannot be played i have trace the size comes its very small 714 , it should be  1600 to allow the vcl player to playing it i use  Tliveaudioplayer from wave audio package
Sinisa VukSoftware architectCommented:
As example - here is my old answer to similar question....

Try change to:
procedure SendBuffer(Buffer: TIdBytes; BufferSize: Cardinal);
Var
Strm: TIdMemoryBufferStream;
begin

Strm := TIdMemoryBufferStream.Create(PByte(Buffer), BufferSize);
try
FTCP.IOHandler.WriteLn('stream');
FTCP.IOHandler.LargeStream := True;
FTCP.IOHandler.Write(Strm, 0, True);
finally
Strm.Free;
end;
end;

Open in new window

dolphin KingAuthor Commented:
the sending part is solved already see my updated code above i can send data to the vcl but no sound can be played ,  it does send the stream but audio cannot be played i have trace the size comes its very small 714 , it should be  1600 to allow the vcl player to playing it i use  Tliveaudioplayer from wave audio package


updated code again

procedure TForm1.timer1Timer(Sender: TObject);
var
  NewCount: Integer;
begin

NewCount:= (AudioRecorder as JAudioRecord).read(Gstream, 0, GBUFFSIZE);
if NewCount > 0 then
begin
try
ClientThread.SendBuffer(Gstream.Data, Gstream.Length);
except
end;

end;


end;


SendBuffer(Buffer: pointer; BufferSize: Cardinal);
Var
Strm: TIdMemoryBufferStream;
begin
ClientThread.Lock;
try

Strm := TIdMemoryBufferStream.Create(Buffer, BufferSize);
try
FTCP.Socket.WriteLn('Stream');
FTCP.Socket.LargeStream := True;
FTCP.Socket.Write(Strm, 0, True);
finally
Strm.Free;
end;
finally
ClientThread.Unlock;
end;
end;

Open in new window

Sinisa VukSoftware architectCommented:
try to wait to sending buffer fill up to 1600 bytes....

...
GBUFFSIZE := TJAudioRecord.JavaClass.getMinBufferSize(8000,
TJAudioFormat.JavaClass.CHANNEL_IN_MONO,
TJAudioFormat.JavaClass.ENCODING_PCM_16BIT);

Gstream := TJavaArray<Byte>.Create(GBUFFSIZE * 10);

AudioRecorder:= TJAudioRecord.JavaClass.init(TJMediaRecorder_AudioSource.JavaClass.VOICE_COMMUNICATION,
8000,
TJAudioFormat.JavaClass.CHANNEL_IN_MONO,
TJAudioFormat.JavaClass.ENCODING_PCM_16BIT,
GBUFFSIZE * 10);
...

procedure TForm1.timer1Timer(Sender: TObject);
var
  NewCount: Integer;
begin
  timer1.Enable := False;
  try
  //check for enough data....
NewCount:= (AudioRecorder as JAudioRecord).read(Gstream, 0, GBUFFSIZE * 10, 0);
{
[i]readMode 	int: one of READ_BLOCKING = 0, READ_NON_BLOCKING = 1.
With READ_BLOCKING, the read will block until all the requested data is read.
With READ_NON_BLOCKING, the read will return immediately after reading as much audio data as possible without blocking.[/i]
}
if NewCount > 0 then
begin
....

finally
  timer1.Enable := True;
end;
end; //timer1Timer
...

Open in new window

dolphin KingAuthor Commented:
new count variable did not compiled
dolphin KingAuthor Commented:
app force closed after starting to send current code

procedure TForm1.timer1Timer(Sender: TObject);
var
  NewCount: Integer;
begin


Timer1.Enabled := False;
 try

NewCount := 0;

NewCount:= (AudioRecorder as JAudioRecord).read(Micstream, 0, MICBUFFSIZE * 10);
if NewCount > 0 then
begin

ClientThread.SendBuffer(Micstream.Data, NewCount);


end;


finally
Timer1.Enabled := True;
end;



end;

Open in new window

Sinisa VukSoftware architectCommented:
try to comment line: ClientThread.SendBuffer(Micstream.Data, NewCount).... still crash?

you may try my source for SendBuffer
dolphin KingAuthor Commented:
your send buffer is similar to the one i do , when  MICBUFFSIZE * 10 the app is closed when its MICBUFFSIZE only its send one time and the app is freezed
Sinisa VukSoftware architectCommented:
how you define MICBUFFSIZE?
dolphin KingAuthor Commented:
same as you showed
MICBUFFSIZE := TJAudioRecord.JavaClass.getMinBufferSize(8000,
TJAudioFormat.JavaClass.CHANNEL_IN_MONO,
TJAudioFormat.JavaClass.ENCODING_PCM_16BIT);

Micstream := TJavaArray<Byte>.Create(MICBUFFSIZE * 10);

AudioRecorder:= TJAudioRecord.JavaClass.init(TJMediaRecorder_AudioSource.JavaClass.VOICE_COMMUNICATION,
8000,
TJAudioFormat.JavaClass.CHANNEL_IN_MONO,
TJAudioFormat.JavaClass.ENCODING_PCM_16BIT,
MICBUFFSIZE * 10);

Open in new window



when removing *10 send 714 for one time and the app freeze
dolphin KingAuthor Commented:
can you help me  on how to use the recorder in worker thread ?
Sinisa VukSoftware architectCommented:
Sorry, I'm back on Monday here...
dolphin KingAuthor Commented:
its ok i will be waiting
dolphin KingAuthor Commented:
i did that recording part in a thread , but still cannot send audio to the server something prevent me

type
    TAudiocallbackproc = procedure (Sender: TObject;  Sbuffer:pointer; SBufferSize: Cardinal) of object;

    TAudioStreamThread = class(TThread)
      private
        FonAudiocallbackproc : TAudiocallbackproc;
        FCs: TCriticalSection;
        Fbuffer : pointer;
        FBufferSize : Cardinal;
        //recorder
        AudioRecorder: JAudioRecord;
        MICBUFFSIZE: Integer;
        Micstream : TJavaArray<Byte>;
        procedure DoAudiocallbackproc;
        //
      protected
        procedure Execute; override;
      Public
      constructor Create(CreateSuspended: Boolean; AonAudiocallbackproc: TAudiocallbackproc); reintroduce;
      destructor Destroy; override;
      end;


{ TAudioStreamThread }

constructor TAudioStreamThread.Create(CreateSuspended: Boolean;
  AonAudiocallbackproc: TAudiocallbackproc);
begin
inherited Create(CreateSuspended);
FreeOnTerminate := True;
FCs := TCriticalSection.Create;
FonAudiocallbackproc := AonAudiocallbackproc;
end;

destructor TAudioStreamThread.Destroy;
begin
FreeAndNil(FCs);
  inherited;
end;

procedure TAudioStreamThread.DoAudiocallbackproc;
begin
if Assigned(FonAudiocallbackproc) then
begin
FonAudiocallbackproc(self, Fbuffer, FBufferSize);
end;
end;

procedure TAudioStreamThread.Execute;
var
NewCount : integer;
begin

// microphone

MICBUFFSIZE := TJAudioRecord.JavaClass.getMinBufferSize(8000,
TJAudioFormat.JavaClass.CHANNEL_IN_MONO,
TJAudioFormat.JavaClass.ENCODING_PCM_16BIT);
Micstream := TJavaArray<Byte>.Create(MICBUFFSIZE);
AudioRecorder:= TJAudioRecord.JavaClass.init(TJMediaRecorder_AudioSource.JavaClass.VOICE_COMMUNICATION,
8000,
TJAudioFormat.JavaClass.CHANNEL_IN_MONO,
TJAudioFormat.JavaClass.ENCODING_PCM_16BIT,
MICBUFFSIZE);

(AudioRecorder as JAudioRecord).startRecording;

NewCount := 0;
while not terminated  do
begin
NewCount:= (AudioRecorder as JAudioRecord).read(Micstream, 0, MICBUFFSIZE);
if NewCount > 0 then
begin
Fbuffer := Micstream.Data;
FBufferSize :=  Micstream.Length;
CThread.SendBuffer(Fbuffer, FBufferSize);
end;
end;

end;


procedure TCThread.SendBuffer(Buffer: pointer; BufferSize: Cardinal);
Var
Strm: TIdMemoryBufferStream;
begin
crit.Lock;
try
if not FTCP.Connected then
begin
exit;
end;

Strm := TIdMemoryBufferStream.Create(Buffer, BufferSize);
try
FTCP.Socket.WriteLn('Stream');
FTCP.Socket.LargeStream := True;
FTCP.Socket.Write(Strm, 0, True);
finally
Strm.Free;
end;
finally
crit.Unlock;
end;
end;

Open in new window

dolphin KingAuthor Commented:
more details when debugging the server when i send from vcl its alway send 1600 size , on android when i send its sends huge amount of numbers and they are not showing unless i got disconnected
Sinisa VukSoftware architectCommented:
Are these numbers readl data? (compare to vcl type)
Maybe there is a problem transforming from TJavaArray to TIDByteArray or similar type.... when sending using Indy.....
Try to make small project which will send predefined (known) set of data from android to server... and check if comes ok. Make this data smaller than 1600 and in second case larger...
dolphin KingAuthor Commented:
the  problem is the Fmx client does not send the buffer contentiously like the vcl , its send all of them after disconnected
Sinisa VukSoftware architectCommented:
Found that other users had same issue too...Like here... But Remy Lebeau (TeamB) did not post his resolution....
Do you check for Connected property on Client side? Seems that this could make problems...
dolphin KingAuthor Commented:
thats seems global indy problem i read too many topics around that
dolphin KingAuthor Commented:
i removed connected property check , still the same problem seems more likely indy bug , i really dont know what to do now , i wanted to broadcast audio from android device to vcl project
Sinisa VukSoftware architectCommented:
Try this TCPServerClient library ... It is build around Indy ..but maybe works better...This components simplified net transport - could be  asynchronous or synchronous transfer...
Some issues could be due to incorrect string/char handling.... You could try to disable zero indexing too....
dolphin KingAuthor Commented:
it does not compatible with xe8 :) i dont know if there is other way to send the stream ? as example send it as string then convert it back to a stream on server side or even on client side ?
Sinisa VukSoftware architectCommented:
Strings are array of bytes as your data too... Did you try if there is any difference if put: LargeStream := False

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Delphi

From novice to tech pro — start learning today.