Hello Francois, I've checked several times and I don't believe that I'm calling anything I shouldn't but I could be wrong of course. Yes, I know ICS can handle fast large scale communications.
Pardon the long text reply but below is the full code for the Socket's client thread's Execute method. If you or anyone else sees anything wrong, please let me know. Note, because of the problems I've been having, my override of the Send method posts the data to be sent to the background thread via a PostMessage() operation. I know that the TWSocket.Send() method is thread-safe and is protected by a critical section, but I was desperate and wanted to remove any chance of a bad inter-thread access causing a problem. The BgSend() call you will see in the thread's Execute method is just a call to the inherited send method (TWSocket). TWSocketClientDeluxe is my sub-class of TWSocket: procedure TClientThread.Execute; procedure validateSocketParameters(theReason: string); begin if WSocket.Addr = '' then raise Exception.Create('(TClientThread.Execute) ' + theReason + ' requested without the Addr parameter having a valid value.'); if WSocket.Port = '' then raise Exception.Create('(TClientThread.Execute) ' + theReason + ' requested without the Port parameter having a valid value.'); if WSocket.Proto = '' then raise Exception.Create('(TClientThread.Execute) ' + theReason + ' requested without the Proto parameter having a valid value.'); end; // --------------------------------------------------------------- procedure checkPublishStatistics(theSocket: TWSocketClientDeluxe; bShuttingDown: boolean); var intfSocketStatistics: IClientSocketDeluxeStatistics; bPublish: boolean; begin intfSocketStatistics := nil; bPublish := false; // Do we have anyone waiting for statistics? if WSocket is TWSocketClientDeluxe then begin with WSocket as TWSocketClientDeluxe do begin if notifyStatisticsHandle > 0 then begin if bShuttingDown then begin // We're shutting down. Just publish a "blank" // statistics record. intfSocketStatistics := TClientSocketDeluxeStatistics.Create(Name, ID); end else // Calculate the statistics and publish them. intfSocketStatistics := TClientSocketDeluxeStatistics.Create(WSocket as TWSocketClientDeluxe); // Are we shutting down? if bShuttingDown then begin // Publish an empty statistics record to let // the notifyee we are done. // intfSocketStatistics.statistics := newClientSocketDeluxeStatistics; bPublish := true end // Has one second elapsed since we last published // statistics or are we shutting down? (Need // to else if diffMilliseconds(FLastStatisticsPublished_dt) > 1000 then begin // Publish statistics. bPublish := true; end; if bPublish then begin // Post it to the notification handle. if notifyStatisticsHandle = 0 then raise Exception.Create('(TClientThread.Execute::checkPublishStatistics) The handle for statistics update notifications is zero.'); PostMessageWithUserDataIntf(notifyStatisticsHandle, WM_CLIENT_SOCKET_DELUXE_STATISTICS, POSTMESSAGEUSERDATA_LPARAM_IS_INTF, intfSocketStatistics); // Update the time statistics were last published. FLastStatisticsPublished_dt := Now; end; // if bPublish then end; // if notifyStatisticsHandle > 0 then end; // with WSocket as TWSocketClientDeluxe do end; // if WSocket is TWSocketClientDeluxe then end; var errMsg: string; MsgRec : TMsg; theSockCliDeluxe: TWSocketClientDeluxe; theSocketName: string; intfSocketStatistics: IClientSocketDeluxeStatistics; intf: IPostMessageUserData; intfCliSockSendDataReq: IClientSocketSendDataRequest; P: Pointer; S: string; begin intfSocketStatistics := nil; intfCliSockSendDataReq := nil; try theSocketName := '(unassigned)'; if not Assigned(WSocket) then // exit; raise Exception.Create('(TClientThread.Execute) The client socket is unassigned.'); theSocketName := WSocket.Name; // 1-24-2012: Added empty component name check. if theSocketName = '' then raise Exception.Create('(TClientThread.Execute) The client socket is nameless.'); // Set our thread name. setThreadName_delphi(theSocketName + '_clientthread'); { Attach client socket to this thread } WSocket.ThreadAttach; // I assume that if multithreading is being used than we want // higher than normal priority. // SetThreadPriority(ThreadID, THREAD_PRIORITY_ABOVE_NORMAL); { Signal main thread that we've attached socket to this thread } ThreadAttached := TRUE; { Now let the main thread continue starting the connection. } { This little Sleep avoids race condition. } Sleep(0); // Check for auto-connect flag being set to TRUE. if FAutoConnect then begin // Validate the Addr/Port/Proto parameters. validateSocketParameters('Auto-connect'); OutputDebugString(PChar( '(TClientThread.Execute) Calling CONNECT for the socket named: ' + theSocketName )); // Connect. WSocket.Connect; end; // if FAutoConnect then { Then process messages until WM_QUIT message is posted. } { TWSocket is event-driven. So even when used within a thread, we } { have to have a "message pump". Any message pump will do and there } { is one built in TWSocket, so use it ! } // WSocket.MessageLoop; { We need our own message loop to catch WM_BG_CUSTOM_REQUEST messages. The code below is identical to WSocket.MessageLoop with the additional handling we require. } FLastStatisticsPublished_dt := Now; { If GetMessage retrieves the WM_QUIT, the return value is FALSE and } { the message loop is broken. } while GetMessage(MsgRec, 0, 0, 0) do begin if MsgRec.hwnd = 0 then {<== ** VERY IMPORTANT ** } begin // --------------- PostThreadMessage() --------------------- // The window handle field is 0 indicating this is one of // our messages posted to this thread using // PostThreadMessage(). Handle it. // Is it a request to execute a custom background thread request? if MsgRec.message = WM_BG_CUSTOM_SOCKET_REQUEST then begin // ATI: 1-10-2012: Custom background thread request. // // If our owner socket is a TWSocketClientDeluxe instance and // we have a custom background request event handler, then // call it now. if WSocket is TWSocketClientDeluxe then begin theSockCliDeluxe := TWSocketClientDeluxe(WSocket); if Assigned(theSockCliDeluxe.OnBgCustomRequestProc) then theSockCliDeluxe.OnBgCustomRequestProc(MsgRec); end; // if WSocket is TWSocketClientDeluxe then end // Is it a request to reconnect with the same settings as the // last connect (current settings)? else if MsgRec.message = WM_BG_SOCKET_RECONNECT then begin // If we are not "closed" then this is an error. if not (WSocket.State = wsClosed) then raise Exception.Create('(TClientThread.Execute) A reconnect request was received when our socket was not in the "closed" state. Socket name: ' + WSocket.Name); // --------------- RECONNECT --------------- // Validate the Addr/Port/Proto parameters. validateSocketParameters('Reconnect'); // Here! Kludge. { For some reason, despite the Addr/Port/Proto assignments being valid, the F*Assigned (e.g. - FPortAssigned) values are FALSE. There is a bug somewhere that we should fix, but for now we are redoing the assignments simply to get those flags set to TRUE. } WSocket.Addr := WSocket.Addr; WSocket.Port := WSocket.Port; WSocket.Proto := WSocket.Proto; // Re-connect. WSocket.Connect; end // if (GAUNTLET) then else if MsgRec.message = WM_BG_SOCKET_SEND_REQUEST then begin // -------------- SEND DATA REQUEST ------------------ // Recover the send data request interface. intf := nil; P := Pointer(MsgRec.lParam); if not Assigned(P) then raise Exception.Create('(TClientThread.Execute) Long parameter was not assigned, received pointer invalid while recovering the IPostBufferToCollection interface.'); Move(P, intf, sizeof(intf)); if not Assigned(intf) then raise Exception.Create('(TClientThread.Execute) Received an unassigned interface object.'); if not Supports(intf, IClientSocketSendDataRequest, intfCliSockSendDataReq) then raise Exception.Create('(TClientThread.Execute) Interface object received is not a IClientSocketSendDataRequest interface.'); if not Assigned(intfCliSockSendDataReq.data) then raise Exception.Create('(TClientThread.Execute) The send data request has an unassigned data pointer.'); if intfCliSockSendDataReq.dataLen <= 0 then raise Exception.Create('(TClientThread.Execute) The send data request''s buffer length is less than or equal to 0.'); // Send the data now but use the background send method or we // will create a recursive self-posting situation. with WSocket as TWSocketClientDeluxe do begin // S := intfCliSockSendDataReq.dataAsStr; BgSend(intfCliSockSendDataReq.data, intfCliSockSendDataReq.dataLen); end; // with WSocket as TWSocketClientDeluxe do // Release the interface variables we used. intf := nil; intfCliSockSendDataReq := nil; end; // else - if (GAUNTLET) then // See if it's time to publish a statistics update. checkPublishStatistics(WSocket as TWSocketClientDeluxe, false); end else begin // --------------- TWSocket WndProc() --------------------- // Message is meant for TWSocket component. TranslateMessage(MsgRec); // Pass it on. DispatchMessage(MsgRec); end; // else - // ------------ SOCKET STATISTICS UPDATE --------------------- end; // while() { Be sure to have main thread waiting for termination before terminating} Sleep(0); // Final publish (empty statistics record). checkPublishStatistics(WSocket as TWSocketClientDeluxe, true); { Detach the hidden window from within the thread } WSocket.ThreadDetach; // Unblock the main thread if it is waiting on us to exit and it gave us // an Event to signal. if Assigned(FThreadTerminate_event) then begin if not FThreadTerminate_event.SetEvent then begin errMsg := 'Terminate thread event was unable to be signaled during the exiting of this client thread. Socket name: ' + FWSocket.Name; postComponentLogMessage_error(errMsg, FWSocket.Name); OutputDebugString(PChar(errMsg)); end; end; // if Assigned(FThreadTerminate_event) then except On E: Exception do begin // Post a message to the component log. postComponentLogMessage_error('ERROR in client thread for socket(' + theSocketName +'). Details: ' + E.Message, Self.ClassName); // Continue raising the Exception. raise; end; end; // try end; // --------------------------------------------------------------- Thanks, Robert --- On Mon, 2/6/12, François Piette <francois.pie...@skynet.be> wrote: > From: François Piette <francois.pie...@skynet.be> > Subject: Re: [twsocket] Problems with TWSocket and Skype > To: "'ICS support mailing'" <twsocket@elists.org> > Date: Monday, February 6, 2012, 10:01 PM > It is likely that your problem comes > from the different programming paradigm > between the two libraries. ICS is non-blocking > (asynchronous) while the > other is blocking. It is possible that you don't follow the > rules for > asynchronous programming and get problems... There are two > very important > rules: 1) Never call directly or indirectly the message pump > from one of the > component event and 2) never forget that all calls to > methods - such as Send > - are merely requests and that you get control back > immediately while your > request execute in the background. > > If you follow the rules, everything will be OK. You can > verify by yourself > that ICS components are capable of high speed communication > with a huge > number of simultaneous connections, both client or server > side. See the HTTP > and FTP client and server to convince yourself. > > -- > francois.pie...@overbyte.be > The author of the freeware multi-tier middleware MidWare > The author of the freeware Internet Component Suite (ICS) > http://www.overbyte.be > > > > > -----Message d'origine----- > De : twsocket-boun...@elists.org > [mailto:twsocket-boun...@elists.org] > De la > part de robertoschler > Envoyé : mardi 7 février 2012 05:07 > À : TWSOCKET > Objet : [twsocket] Problems with TWSocket and Skype > > Hello, > > A couple of years ago I tried using TWSocket with Skype to > send audio back > and forth between my Delphi 6 application and the Skype > client. I never > could get it to work until I switched to the Indy > components. > > Since then I've used ICS in several applications they have > always worked > great. Now I have another application that interfaces > with Skype and again > I am having trouble trying to get TWSocket to work with > Skype. > > My application acts as a middleman between an external WiFi > webcam device > relaying audio from its microphone to Skype's input audio > port and relaying > audio from Skype's output audio port to the webcam device's > speaker. I am > using ICS on both sides now. TWSocket works just fine > with the external > WiFi webcam, however, I can't make it work with Skype. > The audio going to > Skype is frequently "jamming up" whereby the buffered byte > count rises > quickly for short durations, enough to make the audio stream > going to Skype > unusable (calling TWSocket.Send). The socket receiving > audio from Skype > receives about 11 to 20 data deliveries successfully and > then just dies > (OnDataAvailable stops firing). The connection stays > open, but Skype stops > sending audio permanently. > > > Both sockets for the pair of connections are spawned by a > listening socket. > The way you tell the Skype client to receive audio from your > application is > to open a socket on a port number of your choice and > Listen. You then tell > Skype the port number you are using and Skype connects to > you on that port. > The same goes for the socket you use send audio to > Skype. In both cases you > Listen and Skype connects to you on the given port. > The difference of > course being that you repeatedly handle OnDataAvailable() > events on the > socket that is receiving audio from Skype, and repeatedly > call Send() on the > socket that is sending audio to Skype. > > I'd rather keep things ICS all around but I'm close to > switching to Indy on > the Skype side. I recently found out that Skype uses > Indy for its Windows > clients. I'm also aware that Indy uses a thread that > blocks to do its work > as opposed to TWSocket which uses a message loop. > > Can anyone speculate as to what about Indy's sockets are > more compatible > with Skype than (at least for me) TWSocket sockets? > What could I try to > quickly fix this situation, perhaps by more closely > emulating Indy's > behavior? > > Thanks, > Robert > -- > To unsubscribe or change your settings for TWSocket mailing > list please goto > http://lists.elists.org/cgi-bin/mailman/listinfo/twsocket > Visit our website at http://www.overbyte.be > > -- > To unsubscribe or change your settings for TWSocket mailing > list > please goto http://lists.elists.org/cgi-bin/mailman/listinfo/twsocket > Visit our website at http://www.overbyte.be > -- To unsubscribe or change your settings for TWSocket mailing list please goto http://lists.elists.org/cgi-bin/mailman/listinfo/twsocket Visit our website at http://www.overbyte.be