cocobom 0 Posted March 23, 2022 In Win32 mode, we can specify a stream and give it to the sndplaysound function to play the sound, but on Android platform, it seems that we can only specify a sound file through TMediaPlayer class for playing. Is there a better way? Share this post Link to post
Dave Nottage 557 Posted March 23, 2022 This suggests it can be done using TMediaPlayer: https://github.com/Embarcadero/RADStudio11Demos/tree/main/Object Pascal/Multi-Device Samples/Media/StreamingMedia Share this post Link to post
Remy Lebeau 1398 Posted March 23, 2022 (edited) Internally, that is downloading an audio file from a URL, and then playing it. That is not the same as playing audio samples from memory or a resource. AFAIK, FireMonkey simply does not implement that kind of functionality natively, so you will have to implement it manually. See this StackOverflow post if you want to implement custom handling of other audio sources. Edited March 23, 2022 by Remy Lebeau Share this post Link to post
Guest Posted March 23, 2022 (edited) It's a test I made at the time, if you make it better please share it with us, like I did. is both client and server. unit Unit2; interface uses System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants, FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs, FMX.Controls.Presentation, FMX.StdCtrls, FMX.ScrollBox, FMX.Memo, FMX.Edit, IdContext, IdTCPConnection, IdTCPClient, IdBaseComponent, IdComponent, IdCustomTCPServer, IdTCPServer, IdIOHandler, IdIOHandlerStream, IdIOHandlerSocket, IdIOHandlerStack, IdServerIOHandler, IdServerIOHandlerSocket, IdServerIOHandlerStack, FMX.ListBox; type TMain = class(TForm) Button_ServerListen: TButton; Panel1: TPanel; Label1: TLabel; Memo_Debug: TMemo; Label_RunControl: TLabel; Timer_RunControl: TTimer; IdTCPServer: TIdTCPServer; IdTCPClient: TIdTCPClient; cTimerRecorder: TTimer; Button_ClientConnect: TButton; Timer_Connect: TTimer; Edit_RemoteIP: TEdit; ComboBox_SelectIP: TComboBox; procedure FormCreate(Sender: TObject); procedure Timer_RunControlTimer(Sender: TObject); procedure IdTCPServerExecute(AContext: TIdContext); procedure IdTCPServerConnect(AContext: TIdContext); procedure IdTCPServerDisconnect(AContext: TIdContext); procedure IdTCPClientConnected(Sender: TObject); procedure cTimerRecorderTimer(Sender: TObject); procedure IdTCPClientDisconnected(Sender: TObject); procedure Timer_ConnectTimer(Sender: TObject); procedure Button_ClientConnectClick(Sender: TObject); procedure ComboBox_SelectIPChange(Sender: TObject); private { Private declarations } public { Public declarations } Procedure Debug(From, Msg:String); end; var Main: TMain; implementation Uses System.IOUtils, System.Diagnostics, // TickCount Androidapi.JNI, Androidapi.JNIBridge, Androidapi.JNI.JavaTypes, Androidapi.JNI.Media, Androidapi.JNI.Net, Androidapi.Helpers, Androidapi.JNI.GraphicsContentViewText; // Wifi {$R *.fmx} Var // Server sAudioTrack: JAudioTrack; sMemory:TMemoryStream; sBuffer:TJavaArray<Byte>; Var // Client cMemory:TMemoryStream; cBuffer:TJavaArray<Byte>; cAudioRecord:JAudioRecord; cBufferSize:Integer; Var SampleRate:Integer; AudioFormat:Integer; tCountdown:Byte=2; InternalTimer:Integer=0; // ------------------------------ function GetWifiIpAddress: String; var WifiManagerObj: JObject; WifiManager: JWifiManager; WifiInfo: JWifiInfo; ip: Integer; begin WifiManagerObj := SharedActivityContext.getSystemService(TJContext.JavaClass.WIFI_SERVICE); WifiManager := TJWifiManager.Wrap((WifiManagerObj as ILocalObject).GetObjectID); WifiInfo := WifiManager.getConnectionInfo(); ip := WifiInfo.getIpAddress and $FFFFFFFF; result := Format('%d.%d.%d.%d', [(IP) and $FF, (IP shr 8) and $FF, (IP shr 16) and $FF, (IP shr 24) and $FF]); end; procedure TMain.Timer_RunControlTimer(Sender: TObject); begin Label_RunControl.Text:=IntToStr(Random(65535)); end; function MemoryStreamToString(M: TMemoryStream): string; begin SetString(Result, PChar(M.Memory), M.Size div SizeOf(Char)); end; procedure TMain.ComboBox_SelectIPChange(Sender: TObject); begin Edit_RemoteIP.Text:=Trim(ComboBox_SelectIP.Items.Strings[ComboBox_SelectIP.ItemIndex]); end; Procedure TMain.Debug(From, Msg:String); Begin Msg:=From+'> '+Trim(Msg); Memo_Debug.Lines.Add(Msg); Memo_Debug.SelStart := Length(Memo_Debug.Text); Memo_Debug.SelLength := 0; Memo_Debug.ScrollBy(0, Memo_Debug.Lines.Count); Sleep(1); End; procedure TMain.Button_ClientConnectClick(Sender: TObject); begin IdTCPClient.Host:=Edit_RemoteIP.Text; IdTCPClient.Port:=5555; IdTCPClient.ConnectTimeout:=3000; IdTCPClient.Connect; end; procedure TMain.Timer_ConnectTimer(Sender: TObject); begin tCountdown:=tCountdown-1; Button_ClientConnect.Text:='Bağlan ('+tCountDown.ToString+')'; if tCountdown<1 then Begin Timer_Connect.Enabled:=False; // -------------------------- TThread.CreateAnonymousThread( procedure() begin TThread.Synchronize(TThread.CurrentThread, procedure begin Button_ClientConnectClick(Sender); end); end).Start; End; end; procedure TMain.FormCreate(Sender: TObject); begin Edit_RemoteIP.Text:=GetWifiIpAddress; //SAMPLE_RATE 16000 - 22050 - 44100 SampleRate:=44100; AudioFormat:=TJAudioFormat.JavaClass.ENCODING_PCM_16BIT; // 3764, 8192 cbufferSize:=TJAudioRecord.JavaClass.getMinBufferSize(SampleRate, TJAudioFormat.JavaClass.CHANNEL_IN_MONO, AudioFormat); Debug('*','cBufferSize = '+cBufferSize.ToString()); if (cbufferSize=TJAudioRecord.JavaClass.ERROR_BAD_VALUE) then Debug('*','cbufferSize = ERROR_BAD_VALUE'); cAudioRecord:=TJAudioRecord.JavaClass.init(TJMediaRecorder_AudioSource.JavaClass.MIC, SampleRate, TJAudioFormat.JavaClass.CHANNEL_IN_MONO, AudioFormat, cBufferSize); sAudioTrack:=TJAudioTrack.JavaClass.init(TJAudioManager.JavaClass.STREAM_MUSIC, SampleRate, TJAudioFormat.JavaClass.CHANNEL_OUT_MONO, AudioFormat, cBufferSize, TJAudioTrack.JavaClass.MODE_STREAM); // MODE_STREAM - MODE_STATIC if (cAudioRecord.getState <> TJAudioRecord.JavaClass.STATE_INITIALIZED) then Debug('*','cAudioRecord.getState = '+cAudioRecord.getState.ToString()+'<>STATE_INITIALIZED'); cBuffer:=TJavaArray<Byte>.create(cBufferSize); sBuffer:=TJavaArray<Byte>.create(cBufferSize); sMemory:=TMemoryStream.Create; cMemory:=TMemoryStream.Create; Debug('*','# Server Start Event.'); IdTCPServer.DefaultPort:=5555; IdTCPServer.Bindings.Add.IP:=Edit_RemoteIP.Text; IdTCPServer.Active:=True; if IdTCPServer.Active then Begin Button_ServerListen.Enabled:=False; Button_ServerListen.Text:='Server Aktif'; Debug('*','Server ('+Edit_RemoteIP.Text+':'+IdTCPServer.DefaultPort.ToString+') Bekliyor.'); End; InternalTimer:=0; TThread.CreateAnonymousThread( procedure() begin Repeat Sleep(100); InternalTimer:=InternalTimer+1; Until (Application.Terminated); End).Start; // Timer_Connect.Enabled:=True; end; procedure TMain.IdTCPServerConnect(AContext: TIdContext); begin Debug('S', AContext.Connection.Socket.Binding.PeerIP+':'+AContext.Connection.Socket.Binding.PeerPort.ToString+' Bağlandı.'); Debug('S','sAudioTrack.Play'); sAudioTrack.Play; end; procedure TMain.IdTCPServerDisconnect(AContext: TIdContext); begin Debug('S', AContext.Connection.Socket.Binding.PeerIP+':'+AContext.Connection.Socket.Binding.PeerPort.ToString+' Koptu.'); Debug('S','sAudioTrack.Stop'); sAudioTrack.stop; end; procedure TMain.IdTCPServerExecute(AContext: TIdContext); Var rLen,x:Integer; begin if AContext.Connection.IOHandler.Readable then begin rLen:=0; Try rLen:=StrToIntdef(AContext.Connection.IOHandler.Readln,0); Except End; //Debug('S','rLen = '+rLen.ToString); if rLen>0 then Begin sMemory.Clear; Try AContext.Connection.IOHandler.ReadStream(sMemory, rLen, False); Except End; if sMemory.Size>0 then Begin // thread içinde yaz, bufferden sbuffer.size kadar okuyabilirsin, fazlası? sMemory.Position:=0; repeat x:=sMemory.Read(sBuffer.data^, sBuffer.Length); sAudioTrack.Write(sBuffer, 0, sBuffer.Length); until (x=0); End; End; End; End; procedure TMain.IdTCPClientConnected(Sender: TObject); begin Debug('C','TCPClient.Connected.'); Debug('C','cAudioRecord.Start'); cMemory.Clear; cAudioRecord.startRecording; cTimerRecorder.Enabled:=True; end; procedure TMain.IdTCPClientDisconnected(Sender: TObject); begin Debug('C','TCPClient.Disconnected.'); Debug('C','cAudioRecord.Stop'); cTimerRecorder.Enabled:=False; cAudioRecord.Stop; end; procedure TMain.cTimerRecorderTimer(Sender: TObject); Var rLen:Integer; begin cTimerRecorder.Enabled:=False; if IdTCPClient.Connected then Begin InternalTimer:=0; cMemory.Clear; Repeat Try rLen:=cAudioRecord.Read(cBuffer, 0, cBuffer.Length); cMemory.Write(cBuffer.Data^, rLen); Except End; Application.ProcessMessages; Until InternalTimer>9; rLen:=cMemory.Size; // buradan sonra thread ile yollasın. Debug('c',rLen.ToString()+'kb uploading.'); Try IdTCPClient.IOHandler.WriteLn(cMemory.Size.ToString); Except End; if rLen<>cMemory.Size then Debug('#','error on cmem size') else Begin cMemory.Position:=0; Try IdTCPClient.IOHandler.Write(cMemory, rLen, False); Except End; End; End; cTimerRecorder.Enabled:=True; end; // stream size 50kb dan büyükse upload et end. Sound Streamming - Remote Ses Buffering.rar Edited March 23, 2022 by Guest Share this post Link to post