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

Reply via email to