Delphi - Record and stream audio Android -
i'm trying record audio 1 android device (server) , send android device (client) play live, using indy http server, send stream client, calling android api record audio, using audiorecord , play on other side using audiotrack. both of codes bellow.
i'm receiving audio recorder , playing, problem is, audio played not continuous, he's breaking every buffer played, half of time, example, if send 1 second sample, seems half played. checked buffer size, same buffer size read audiorecord same size played in audiotrack. not know if delay time indy server/client. i've tried lot of combination of buffer size, sample rates, audio formats , on, audio still breaking.
any appreciated.
here server code
unit serveraudio5; interface uses system.sysutils, system.types, system.uitypes, system.classes, system.variants, fmx.types, fmx.controls, fmx.forms, fmx.graphics, fmx.dialogs, system.ioutils, system.diagnostics, fmx.platform.android, androidapi.jni.net, androidapi.jnibridge, androidapi.jni.javatypes, androidapi.jni.graphicscontentviewtext, androidapi.jni.media, idcontext, idcustomhttpserver, idbasecomponent, idcomponent, idcustomtcpserver, idhttpserver, fmx.stdctrls, fmx.controls.presentation, fmx.scrollbox, fmx.memo; type tform1 = class(tform) memo1: tmemo; btnconnect: tbutton; btndisconnect: tbutton; idhttpserver1: tidhttpserver; timer1: ttimer; timer2: ttimer; procedure formcreate(sender: tobject); procedure idhttpserver1commandget(acontext: tidcontext; arequestinfo: tidhttprequestinfo; aresponseinfo: tidhttpresponseinfo); procedure idhttpserver1connect(acontext: tidcontext); procedure idhttpserver1disconnect(acontext: tidcontext); procedure timer1timer(sender: tobject); procedure btnconnectclick(sender: tobject); procedure btndisconnectclick(sender: tobject); procedure timer2timer(sender: tobject); private { private declarations } enable_server: boolean; enable_audio: boolean; audiorecorder: jaudiorecord; samplerate: integer; channelconfig: integer; audioformat: integer; minbufsize: integer; audiomem: tmemorystream; audiostr: tjavaarray<smallint>; public { public declarations } end; var form1: tform1; implementation {$r *.fmx} {$r *.nmxhdpiph.fmx android} procedure tform1.btnconnectclick(sender: tobject); begin // start server if enable_server = false begin enable_server:= true; idhttpserver1.active := true; memo1.lines.add('server started'); end; end; procedure tform1.btndisconnectclick(sender: tobject); begin if enable_server = true begin enable_server:= false; idhttpserver1.active := false; memo1.lines.add('server finished'); end; end; procedure tform1.formcreate(sender: tobject); begin enable_server:= false; enable_audio:= false; timer1.enabled:= false; samplerate:= 11025; channelconfig:= tjaudioformat.javaclass.channel_in_mono; audioformat:= tjaudioformat.javaclass.encoding_pcm_16bit; // minbufsize = 1024 bytes minbufsize:= tjaudiorecord.javaclass.getminbuffersize(samplerate, channelconfig, audioformat); // audiorecover = 1024*4 = 4096 audiostr:= tjavaarray<smallint>.create(minbufsize*4); audiomem:= tmemorystream.create; audiorecorder:= tjaudiorecord.javaclass.init(tjmediarecorder_audiosource.javaclass.mic, samplerate, channelconfig, audioformat, minbufsize*4); end; procedure tform1.idhttpserver1commandget(acontext: tidcontext; arequestinfo: tidhttprequestinfo; aresponseinfo: tidhttpresponseinfo); begin if arequestinfo.document = '/audiorecover' begin aresponseinfo.responseno := 200; aresponseinfo.contenttype := 'audiorecover'; aresponseinfo.closeconnection := false; aresponseinfo.writeheader; // enable audio enable_audio:= true; end; end; procedure tform1.idhttpserver1connect(acontext: tidcontext); begin memo1.lines.add('connection make with: '+acontext.connection.socket.binding.peerip); timer1.enabled:= true; end; procedure tform1.idhttpserver1disconnect(acontext: tidcontext); begin memo1.lines.add('disconnection make with: '+acontext.connection.socket.binding.peerip); enable_audio:= false; end; procedure tform1.timer1timer(sender: tobject); var index: integer; begin if enable_audio begin memo1.lines.add('start recording'); timer1.enabled:= false; (audiorecorder jaudiorecord).startrecording; timer2.enabled:= true; end; end; procedure tform1.timer2timer(sender: tobject); var index: integer; newcount: integer; begin while true begin if enable_audio begin // read audiorecover newcount:= (audiorecorder jaudiorecord).read(audiostr, 0,audiostr.length); // read command not read 4096, 2048 audiomem.write(audiostr.data^, newcount); // newcount = 2048 bytes audiomem.position:= 0; //send stream using socket idhttpserver1.contexts.locklist try index := 0 count-1 begin tidcontext( items[index] ).connection.iohandler.writeln('audiorecover'); tidcontext( items[index] ).connection.iohandler.writeln(inttostr(audiomem.size)); tidcontext( items[index] ).connection.iohandler.write(audiomem); end; idhttpserver1.contexts.unlocklist; end; audiomem.clear; end; end; end end.
here client code
unit clientaudio4; interface uses system.sysutils, system.types, system.uitypes, system.classes, system.variants, fmx.types, fmx.controls, fmx.forms, fmx.graphics, fmx.dialogs, system.diagnostics, fmx.platform.android, androidapi.jni.net, androidapi.jnibridge, androidapi.jni.javatypes, androidapi.jni.graphicscontentviewtext, androidapi.jni.media, fmx.edit, idbasecomponent, idcomponent, idtcpconnection, idtcpclient, fmx.scrollbox, fmx.memo, fmx.controls.presentation, fmx.stdctrls; type tform1 = class(tform) connect: tbutton; disconnect: tbutton; memo1: tmemo; idtcpclient1: tidtcpclient; timer1: ttimer; host: tedit; timer2: ttimer; procedure connectclick(sender: tobject); procedure disconnectclick(sender: tobject); procedure formcreate(sender: tobject); procedure idtcpclient1connected(sender: tobject); procedure idtcpclient1disconnected(sender: tobject); procedure timer1timer(sender: tobject); procedure timer2timer(sender: tobject); private { private declarations } enable_play: boolean; audioplay: jaudiotrack; audiostream: tjavaarray<smallint>; trackmin: integer; public { public declarations } end; var form1: tform1; implementation {$r *.fmx} {$r *.nmxhdpiph.fmx android} procedure tform1.connectclick(sender: tobject); begin idtcpclient1.host:= host.text; idtcpclient1.connect; end; procedure tform1.disconnectclick(sender: tobject); begin idtcpclient1.disconnect; end; procedure tform1.formcreate(sender: tobject); begin host.text:= '192.168.0.100'; trackmin:= tjaudiotrack.javaclass.getminbuffersize(11025, tjaudioformat.javaclass.channel_out_mono, tjaudioformat.javaclass.encoding_pcm_16bit); audiostream:= tjavaarray<smallint>.create(trackmin); audioplay:= tjaudiotrack.javaclass.init(tjaudiomanager.javaclass.stream_music, 11025, tjaudioformat.javaclass.channel_out_mono, tjaudioformat.javaclass.encoding_pcm_16bit, trackmin, tjaudiotrack.javaclass.mode_stream); end; procedure tform1.idtcpclient1connected(sender: tobject); begin memo1.lines.add('connection to: '+idtcpclient1.host); timer1.enabled:= true; end; procedure tform1.idtcpclient1disconnected(sender: tobject); begin memo1.lines.add('disconnect to: '+idtcpclient1.host); enable_play:= false; end; procedure tform1.timer1timer(sender: tobject); var trackmin: integer; begin timer1.enabled:= false; idtcpclient1.iohandler.writeln('get '+'/audiorecover'+' http/1.0'); idtcpclient1.iohandler.writeln; enable_play:= true; // start play (audioplay jaudiotrack).play(); timer2.enabled:= true; end; procedure tform1.timer2timer(sender: tobject); var s3: string; s4: string; clength: integer; audiorec: tmemorystream; begin while true begin if enable_play begin try // try header s3:= trim(lowercase(idtcpclient1.iohandler.readln)); if s3 = 'audiorecover' begin audiorec:= tmemorystream.create; // read length of memorystream s4:= lowercase(idtcpclient1.iohandler.readln); clength:= strtoint(s4); // read stream idtcpclient1.iohandler.readstream(audiorec, clength); audiorec.position:= 0; // set array audiorec.read(audiostream.data^, clength); // write audiotrack play video (audioplay jaudiotrack).write(audiostream, 0, clength); audiorec.clear; audiorec.free; end; end; end; end; end; end.
AResponseInfo.CharSet:='idcsUTF_16';
ReplyDeleteAResponseInfo.ContentType := 'audio/ogg';
Those two lines should be the right format to use.
should have added that it uses IdCharsets which has (TIdCharSet)
ReplyDeleteor else it sends : Content-Type: text/html; charset=utf-8
ReplyDelete