dolphin King
asked on
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
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;
ASKER
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
on VCL i do
and it sended normal
on android when i comment out the sendbuffer the app is not freezing
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);
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;
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;
and it sended normal
on android when i comment out the sendbuffer the app is not freezing
ASKER
also i suspend the rawtobyte converter i am not sure whats going on
Don't know too... Seem that Indy works different on android... Maybe some properties will help... hard to say...
ASKER
i even changed the Gstream : TJavaArray<Byte>; To smallint still the same
ASKER
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
ASKER
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
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
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;
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
As example - here is my old answer to similar question....
Try change to:
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;
ASKER
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
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;
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
...
ASKER
new count variable did not compiled
ASKER
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;
try to comment line: ClientThread.SendBuffer(Mi cstream.Da ta, NewCount).... still crash?
you may try my source for SendBuffer
you may try my source for SendBuffer
ASKER
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
how you define MICBUFFSIZE?
ASKER
same as you showed
when removing *10 send 714 for one time and the app freeze
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);
when removing *10 send 714 for one time and the app freeze
ASKER
can you help me on how to use the recorder in worker thread ?
Sorry, I'm back on Monday here...
ASKER
its ok i will be waiting
ASKER
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;
ASKER
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
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...
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...
ASKER
the problem is the Fmx client does not send the buffer contentiously like the vcl , its send all of them after disconnected
ASKER
thats seems global indy problem i read too many topics around that
ASKER
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
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....
Some issues could be due to incorrect string/char handling.... You could try to disable zero indexing too....
ASKER
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 ?
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Then again ... it is better to use separate thread to send data....