This discussion is archived
1 2 Previous Next 21 Replies Latest reply: Sep 8, 2012 3:55 AM by 898586 RSS

Multiplicity

898586 Newbie
Currently Being Moderated
If I had an issue - which I do - with my Java voip application, (I mean mine, not something I am using) but do not know if I am looking at a networking issue or a sound.sampled issue (or combination of both), where ought I post? Thanks.
  • 1. Re: Multiplicity
    jtahlborn Expert
    Currently Being Moderated
    895583 wrote:
    If I had an issue - which I do - with my Java voip application, (I mean mine, not something I am using) but do not know if I am looking at a networking issue or a sound.sampled issue (or combination of both), where ought I post? Thanks.
    pick a likely location and post. nobody's going to get bent out of shape if you thought it was a networking error but it turned out to be something else (and an admin can always move it to the correct forum at a later point in time). now, if you go posting it in the database forum, people there might be a little put out...
  • 2. Re: Multiplicity
    898586 Newbie
    Currently Being Moderated
    That's a good start. (And I'll try to avoid the db thread). Grin.

    'Be warned' however, this could be a long haul. I don't know whether the issue(s) is / are in .sound.sampled (by which I mean what lash-up I might have made out of that), or in the fundamental logic, after a re-modelling, bringing on my snow-blindness, or elsewhere. It would almost be better if someone could ask this question for me.

    There is a fair bit of code; no problem about posting any of it, but it's where to start that's the problem. The meta issue is, nevertheless : what am I doing 'wrong' (in any of the above areas I mentioned) when going from a reasonable 1 2 1 voip connection to 3 to 2? Something is falling over badly, apart from me.
  • 3. Re: Multiplicity
    DrClap Expert
    Currently Being Moderated
    Try to reduce the code you post so that it's the smallest possible code which exhibits the problem. (See SSCCE for more about that.) That way you might have some faint hope that somebody else will consider answering your question.
  • 4. Re: Multiplicity
    898586 Newbie
    Currently Being Moderated
    DrClap wrote:
    Try to reduce the code you post so that it's the smallest possible code which exhibits the problem. (See SSCCE for more about that.) That way you might have some faint hope that somebody else will consider answering your question.
    I will do that, thanks. I see from the logger that the next peer to join the conversation after the initial two, causes the logger to report that packets are being sent only to the newcomer* - so I've done something probably elementarily daft in my routine - I can't see that because I'm too close to it after a major re-write of the model, so maybe someone can spot something there. The question could however then still be perhaps only half-answered, since I am not sure whether a datagramsocket per corresponding peer is best, or whether one socket would suffice, and that the dataline won't be somehow suffering.

    * = actually it goes like this : Calling peer, plus the first to say 'yes' to the invitation, communicate fine. The logger shows the calling peer sending to the respondent's IP, and the respondent sending to the caller's correct IP. The speaker output for both also works ok. But when the third peer accepts the call invitation (which at the moment is just a simple OK on a dialog box), the third peer sends only to the first (the calling peer), the calling (first) peer starts sending instead to the new (third) peer, and the second starts likewise sending to the new third peer.

    'PlaceCall' is the delta for calling and called peers - they all implement it. PlaceCall sets up one set of speakers (SourceDataLine), and then continues by staying resident via a loop instantiating 'VoipLine' threads. These VoipLine threads launch a new Mic-per-peer, the peer's IP and key being obtained from a separately-distributed ConcurrentHashMap called conversationGroup. (The CCHM is actually further compared against yet another ephemeral CCHM to see whether a Mic thread has already been launched). So PlaceCall calls VoipLine, and VoipLine makes the Mics. (Convoluted, probably, and perhaps Mic and VoipLine ought to be one entity - but this can happen after the algo glitch is identified I think).

    conversationGroup is the CCHM disributed to all peers. conversing is the scratchpad CCHM to check if someone already has a Mic operating. And there may be the odd boolean or String declared that is not in use - the re-write has left some rubble around.

    I know this is a tough call, but I appreciate any help you guys can offer.
    >
    >
    class PlaceCall implements Runnable{
    
               protected SourceDataLine mySpeakersLine;
    
                   public void run() {
                             
                        
                              try{                         
                             liveconversation = true;
                             inacall = true;
                             listening_PORT = (new Integer(30314));
                             audioSocket_In = new DatagramSocket(listening_PORT.intValue());
                             conversing = new ConcurrentHashMap<String,InetAddress>();
                   
                              } catch (Exception exptsock) {exptsock.printStackTrace();}
                             
                                  mySpeakersLine = retrieveMySpeakers();
                                  try{                    
                             Thread MySpeakers = new Thread(new MySpeakers(mySpeakersLine,audioSocket_In));
                                        MySpeakers.setName("MySpeakers");
                                        MySpeakers.start();
                                  }catch(LineUnavailableException lunavex){lunavex.printStackTrace();}
                              do{
    try{
                             Set<Map.Entry<String, InetAddress>> entries = PersephonePc.this.conversationGroup.entrySet();
                             for (Map.Entry<String, InetAddress> e : entries) {
                                              
                                  if(!(conversing.containsKey(e.getKey()))){
                                         
                                       conversing.put(e.getKey(),e.getValue());
                                       if(!(e.getKey().equals(mynickname))){
                                            new Thread(new VoipLine(e.getKey(),e.getValue())).start();
                                       }
                                  }
                                    }
                             
                             Set<Map.Entry<String, InetAddress>> entriess = conversing.entrySet();
                             for (Map.Entry<String, InetAddress> ee : entriess) {
                                  System.out.println(ee.getKey());
                             }
    
    }catch(Exception fatality){fatality.printStackTrace();try{Thread.sleep(40000);}catch(InterruptedException cxception){}}
                             try{Thread.sleep(10000);}catch(InterruptedException conversationGroupexception){conversationGroupexception.printStackTrace();}               
                             
                              }while(inacall);
    
                   }
    
    
    
                   protected SourceDataLine retrieveMySpeakers() {
    
                        SourceDataLine srcDL = null;
    
                        ArrayList<Mixer.Info> mixInfos = new ArrayList<Mixer.Info>(Arrays.asList(AudioSystem.getMixerInfo()));
    
                        Line.Info sourceDLInfor = new Line.Info(SourceDataLine.class);
                                  
                        try{
                   
                           for (Mixer.Info mixInfo: mixInfos) {
                             Mixer mixer = AudioSystem.getMixer(mixInfo);
                                                 
                             if (mixer.isLineSupported(sourceDLInfor)){srcDL = (SourceDataLine) mixer.getLine(sourceDLInfor);mixerSouDL=mixer;break;}
                           }
    
                        }catch (LineUnavailableException lux){}
    
                        return(srcDL);
    
                    }
    
    
         }//eoc PlaceCall
    >
    >
    class VoipLine implements Runnable{
    
            private InetAddress peerInet;
            private String peerName;
            private int sendPORT;
            protected DatagramSocket audioSocket_Outt;
            private Thread myMic;
            private TargetDataLine myMicLine;
           
            
    
                   public VoipLine(String voiperName, InetAddress pINET){
    
                             try{     
    
                             this.peerInet = pINET;     
                             this.peerName = voiperName;
                             audioSocket_Outt = new DatagramSocket();
                             sendPORT = new Integer(audioSocket_Outt.getLocalPort());
                             audioSocket_Outt.setTrafficClass(0x08 | 0x10);
                             
                              } catch (Exception exptsock) {exptsock.printStackTrace();}
                        
                   }
    
    
    
                   public void run() {
                             
                              try{
                                   myMicLine = retrieveMyMic();
    
                                   liveconversation = true;
    
                                   Thread MyMic = new Thread(new MyMic(myMicLine,peerName,peerInet,this));
                                   MyMic.setName("MyMic");
                                   MyMic.start();     
                           
                               }catch(LineUnavailableException linux){System.out.println("Mic or Speakers unavailable");}
    
                   while(liveconversation){
                        Thread.yield();
                   }
    
                   }//run
    
                   
    
                   private TargetDataLine retrieveMyMic() {
    
                        TargetDataLine tdaline=null;
                        
                        ArrayList<Mixer.Info> mixInfos = new ArrayList<Mixer.Info>(Arrays.asList(AudioSystem.getMixerInfo()));
    
                        Line.Info targetDLInfor = new Line.Info(TargetDataLine.class);
    
              
                        try{
    
                             for (Mixer.Info mixInfo: mixInfos) {
                             Mixer mixer = AudioSystem.getMixer(mixInfo);
                                  
                             if (mixer.isLineSupported(targetDLInfor)){tdaline = (TargetDataLine) mixer.getLine(targetDLInfor);mixerTarDL=mixer;break;}
                             }
    
                        }catch (LineUnavailableException lux){}
    
                        return(tdaline);
    
                    }
    
    
         }//eoc VoipLine
    >
    >
    class MyMic implements Runnable{
              
              private Logger logMyMic = LoggerFactory.getLogger(MyMic.class.getName());
              
                   boolean donelog=false;
                   InetAddress tInet;
                   String tKey;
                   String quy;
                   String peerImHandling;
                   TargetDataLine microphone;
                   AudioFormat audform;
                   protected VoipLine vl;
                             
                   MyMic(TargetDataLine td, String mypeer, InetAddress myprinet,VoipLine v) throws LineUnavailableException{
                        
                        try{  
                        this.microphone = td;
                        this.peerImHandling = mypeer;
                        this.tKey = mypeer;
                        this.tInet = myprinet;
                        this.vl = v;
    
                        this.audform = getAudioFormat();
                        microphone.open(audform,BUFFSIZE);
                        
                           microphone.start();
                        
                        }catch(LineUnavailableException luxxxx){System.out.println("No targetdataline");log.error("", luxxxx);}
    
                   }
    
    
                   public void run(){
              
                        byte[] dgByteBufMIC =new byte[BUFFSIZE];
    
                             dgPacketMIC = new DatagramPacket(dgByteBufMIC, BUFFSIZE);
    
                             dgPacketMIC.setPort(DESTINATION_PORT_INSIDE_DATAGRAM);
    
                             dgPacketMIC.setAddress(tInet);
    
                        inacall=true;
                        keepspeaking = true;
                                int bytesread;
                        
         
                           while (inacall&&presentlyconnected&&keepspeaking){
                                                      
                             bytesread = microphone.read(dgByteBufMIC,0,BUFFSIZE);
                             
                             dgPacketMIC.setData(dgByteBufMIC,0,bytesread);     
    
                             try{
                             vl.audioSocket_Outt.send(dgPacketMIC);
                             }catch(IOException micoutexception){micoutexception.printStackTrace();}
    
                             if (logMyMic.isDebugEnabled()&&donelog==false) {
    
                                  logMyMic.debug(UdpUtils.packetToString(dgPacketMIC)); 
                                      
                                             }
    
                            }
                        
                   }
    
                       }//eoc MyMic
    
    >
    >
    Edited by: 895583 on 30-Aug-2012 04:27

    Edited by: 895583 on 30-Aug-2012 05:33
  • 5. Re: Multiplicity
    898586 Newbie
    Currently Being Moderated
    For the record, I've taken another tack on this one. I now have the "third" client participating, infrastructurally. (Not that it matters, but I scrapped the above classes mostly, and melded principles into new routines. This meant I implemented a ConcurrentLinkedQueue, letting the local peer-handler group feed from it. The voip packet feeder thread taking care of the datagram queue itself).

    The voip QOS isn't as good as the previously-working model (even with only 2 peers running), but that may be down to the way I'm polling and peeking the ConcurrentLinkedQueue - or not - - TBD. The session member cognizance is however evidently now established, and so with that infrastructure seemingly in place, it would be interesting to hear any ideas anyone may like to express about how the actual 'gram devolution and consumption could possibly be smoothed to improve the sound quality.
  • 6. Re: Multiplicity
    EJP Guru
    Currently Being Moderated
    I can't make much out of that but I'll give you one tip: when you catch an exception, don't just make up your own message. Always print the actual exception message, and until you have it working also the stack trace. Often the nested exception is most revealing.
  • 7. Re: Multiplicity
    898586 Newbie
    Currently Being Moderated
    Thanks. That is a tip I will indeed heed.

    I am not surprised that you did not make much out of it - I can't see the code picture from 'the outside', but I can imagine that no end of narrative could perhaps clearly ever explain what is going on in it - if that was your drift.

    Having said that, the entire project boils down I suppose to one idea having reached this stage of development : using a ConcurrentLinkedQueue to hold the ('voip') DatagramPackets, whch are added to the Queue by a single microphone-reading thread. These packets are then peek()-ed from the Queue by other-class, individual threads, who each send the same packet to their ward remote interlocutors over a DatagramSocket of course. (So, if there are 3 people talking, each machine has 2 of these Queue-reading threads running, one per remote interlocutor, sending the packets from the Queue).

    The Queue stack gets decapitated by the microphone thread - via poll() - each time a packet in it has been read by all N clients. So in the 3 peer scenario, the microphone thread removes the top packet after the other two have read, i.e. peek()-ed, it. The control mech for the poll() removal is simply a volatile app-scope boolean.

    Whilst the voice is there, but unacceptable at the moment, the mystery is that sysouts of the Queue access occasions, (kept by increment of a global int),instead of printing 0,1,2,0,1,2,0,1,2 ... 0,1,2,0, see the apparent number of peek()s as reaching the millions! At the moment, it looks like the Queue feed outstrips the reads and the int decrement to zero, and this is where I am right now. Thanks again, EJP.
  • 8. Re: Multiplicity
    EJP Guru
    Currently Being Moderated
    I would simplify the queuing part. Have each consumer register its own queue with the producer, and then just block in the take() method. No reference-counting required.
  • 9. Re: Multiplicity
    898586 Newbie
    Currently Being Moderated
    EJP, thanks.

    Just before implement your suggestion, I'd like to check what you mean by 'register'. Am I right to think you are using the term generically, and that if I make a Queue per consumer and make them visible to the producer for a put() - (most likely by having the consumer Queues in a ConcurrentHashMap let's say), would that fulfil your above criterion?

    (With 'register', you see, I picked up the notion of a listener of some sort).
  • 10. Re: Multiplicity
    EJP Guru
    Currently Being Moderated
    I can't make head or tail of all that verbiage, but:
        producer.register(queue);
  • 11. Re: Multiplicity
    898586 Newbie
    Currently Being Moderated
    Sorry to be dense, but of which class is register(...) a method?
  • 12. Re: Multiplicity
    EJP Guru
    Currently Being Moderated
    Err, the producer class?

    Is this such a mystery? Each consumer has its own queue, it has to tell the producer to queue to that queue, so it has to call a method that does so. The details are up to you, I don't need to write all your code for you.
  • 13. Re: Multiplicity
    898586 Newbie
    Currently Being Moderated
    Is this such a mystery?
    Well, it is for me, as I am not an expert of your level. I am not asking you to write code; all I wish to be sure of concerning your suggestion is that it is 'ok' to make those Queues visible to the producer (who puts them in the queues) by using a Map or other container, and that "register()" was a shorthand for that, rather than referring to an actual method . . .?

    My producer is a Thread, and neither Thread, nor the custom Runnable I concocted which is passed to a Thread constructor, have any method resembling "register()".That's all I am trying to be clear on. Thanks EJP.
  • 14. Re: Multiplicity
    EJP Guru
    Currently Being Moderated
    neither Thread, nor the custom Runnable I concocted which is passed to a Thread constructor, have any method resembling "register()".
    I agree. You have to write it.
1 2 Previous Next

Legend

  • Correct Answers - 10 points
  • Helpful Answers - 5 points