/* Sound Dialog plugin - DMS2 - April 00 - by Sébastien DENEUX*/ /* to do : - passage en son 3D - editeur */ typeof class = S;; typeof SDname = S;; var NbPluginInstance = 0;; /*used to limit the number of instances of the plugin*/ typeof configFile = S;; /*used to keep speaker state*/ defcom Csound=sound I S S;;/*id name audio*/ defcom CignoreOut=ignoreOut I I ;; /*use to advice a client that you ignore him so that he does not send you voice messages*/ /*params = our id + ignore flag (1=we ignore)*/ var defperiod=500;; /*default refresh period*/ var defd_max_sphere=1000;; /*default sphere radius*/ typeof period=I;; typeof d_max_sphere=I;; typeof timer=Timer;; typeof chatList=[[I I Ob] r1];; /*id + distance + ob -> list of the users that are in the sphere around user*/ typeof clisRegistered = [[I S] r1];; /*id + udp -> list of the clients that have registered (that have their speaker on)*/ typeof myChannel=Chn;; /*save the channel in current environment (in newOb, we are in the C3D environment), so we need to save it in the iniPlug and then use it when we create the UDP channel*/ typeof udp=Chn;; /*udp channel*/ typeof udpport=I;; /*client udp port*/ var silent=1;;/*1 when speaker off*/ /*2D interface*/ typeof bmpon=ObjBitmap;; typeof bmpoff=ObjBitmap;; typeof bmppon=ObjBitmap;; typeof bmppoff=ObjBitmap;; typeof bmppmute=ObjBitmap;; var recOnDef="Dms/3d/plugins/SoundDialog/recon.bmp";; var recOffDef="Dms/3d/plugins/SoundDialog/recoff.bmp";; var playonDef="Dms/3d/plugins/SoundDialog/playon.bmp";; var playoffDef="Dms/3d/plugins/SoundDialog/playoff.bmp";; var playmute="Dms/3d/plugins/SoundDialog/playmute.bmp";; typeof win=ObjWin;; typeof win2=ObjWin;; typeof info=ObjText;; /*ignore lists*/ typeof ignoreListIn=[I r1];; /*id of the clients to ignore for input*/ typeof ignoreListOut=[I r1];; /*id of the clients to ignore for output (you ignore them)*/ typeof ignoreListOut2=[I r1];; /*id of the clients to ignore for output (they ignore you)*/ typeof winInterface=ObjWin;; typeof usersList=ObjList;; typeof currentConItem=ObjMenuItem;; var conSpeedConfigFile="locked/conf/sounddialog/conspeed.conf";; typeof maxClients=I;; /*-------------------*/ /*create an udp channel (find a free port)*/ fun getUdp(i,j)= if i>=j then nil else let _setUDP _envchannel myChannel i "" -> c in if c==nil then getUdp i+1 j else [c i];; /*-------------*/ fun cliById(a,id)=let a->[currentId _] in currentId==id;; /*-------------*/ fun cliById2(a,b)=a==b;; /*-------------*/ fun getUdpFromIdInClisRegistered(id)= let search_in_list clisRegistered @cliById id -> [_ udp] in udp;; /*-------------*/ /*returns 1 if the id is in the limiter list else 0*/ fun isInChatZone(list,id)= if list==nil then nil else let list -> [[current_id dist _] nlist] in if current_id==id then dist else isInChatZone nlist id;; /*-------------------*/ /*send voice message to client by udp (p = id + name + audio)*/ fun broad(udp,p)=_sendUDP udp p;; /*-------------------*/ /*apply on list only for the clients that are not in the ignore out lists*/ fun apply_on_chatList(l,f,x,nb)= if l==nil then 0 else let l -> [[id dist ob] nxt] in ( if (search_in_list ignoreListOut @cliById2 id)!=nil then nil else if (search_in_list ignoreListOut2 @cliById2 id)!=nil then nil else let getUdpFromIdInClisRegistered id -> udp in if udp==nil then nil else /*cli has not registered*/ ( /*_fooS strcat strcat strcat strcat strcat "### send sound to id = " itoa id ", udp = " udp ",dist = " itoa dist;*/ _ADDlist usersList 0 ObName ob; set nb=nb+1; exec f with [udp x] ); if nb<=maxClients then apply_on_chatList nxt f x nb else nil /*if nxt!=nil then (_fooS "### sending limited";0) else 0*/ );; /*-------------------*/ /*sends voice messages*/ fun speak(audio)= if winInterface!=nil then _RSTlist usersList else nil; apply_on_chatList chatList @broad Csound [DMSid DMSlogin audio] 1; 0;; /*-------------------*/ fun cbcomm(ui,action,param)= if !strcmp action "addClientInRegisteredList" then let lineextr param -> [id[udp _]] in /* _fooS "### CLIENT cbcomm addClientInRegisteredList"; _fooS strcat "#### udp = " udp; _fooS strcat "#### id = " id;*/ let strcat strcat _hostIP ":" itoa udpport -> myUDP in if !strcmp myUDP udp then /*do not had myself*/ nil else ( /*add the new client to the list*/ set clisRegistered=[(atoi id) udp]::clisRegistered; 0 ) else if !strcmp action "removeClientfromRegisteredList" then ( /*_fooS "### CLIENT cbcomm removeClientfromRegisteredList"; _fooS strcat "### id = " param;*/ /*remove client from list*/ let search_in_list clisRegistered @cliById atoi param -> elt in /*param = id*/ if elt==nil then nil else set clisRegistered=remove_from_list clisRegistered elt; _paintE nil nil; 0 ) else 0;; /*-------------*/ fun testChatZone(current_ob)= let ObGetMain owner -> ownH3D in if ownH3D==nil then /*at beginning when H3D not loaded*/ nil else let M3distance session ownH3D ObGetMain current_ob -> d in if(d [current_ob noblist] in if current_ob!=nil then if current_ob!=owner && (ObAvatar current_ob)==1 then if d_max_sphere==0 then nil /*if this case occures, the soundDialog is not supposed to work*/ else let testChatZone current_ob -> cm in if cm!=nil then cm::(createChatList noblist) else (createChatList noblist) else (createChatList noblist) else nil else nil;; /*-------------*/ fun chatListSort(a,b)= let a -> [_ d1 _] in let b -> [_ d2 _] in if d2>=d1 then 1 else -1;; /*-------------*/ /*update chat list*/ /*sor the list by distance from user*/ fun updateChatList(t,b)= set chatList = rquicksort @chatListSort (createChatList ObList);; /*-------------------*/ fun updateMaxClients(a,b)= if currentConItem==a then nil else let b -> [msg nb no] in ( set maxClients=nb; _SETtext msg strcatn "With your connection speed, you can speak to "::(itoa maxClients)::" person(s)"::nil; _CHKmenu a 1; _CHKmenu currentConItem 0; set currentConItem = a; _storepack strbuild ("conType"::no::nil)::nil conSpeedConfigFile; 0 );; /*-------------------*/ fun _destroyWinInterface(a,b)= set winInterface=nil; 0;; /*-------------------*/ fun _resizeWinInterface(wn,b,w,h)= let b -> [msg speakingTxt] in let _GETlistPositionSize usersList -> [x y _ _] in let _GETtextPositionSize speakingTxt -> [x2 _ _ h2] in let _GETtextPositionSize msg -> [x3 _ _ h3] in ( _SIZElist usersList w-50 h-110 x y; _SIZEtext speakingTxt w-30 h2 x2 h-80; _SIZEtext msg w-20 h3 x3 h-50; 0 );; /*-------------------*/ fun showInterface()= if winInterface!=nil then nil else let _GETcursorPos DMSwin -> [x y] in ( set winInterface = _CRwindow _channel DMSwin x y 150 300 WN_MENU|WN_SIZEBOX|WN_MINBOX "Sound Dialog"; _CBwinDestroy winInterface @_destroyWinInterface nil; set usersList = _CRlist _channel winInterface 25 30 100 190 LB_DOWN|LB_NOSELECTION; let _CRtext _channel winInterface 15 220 120 30 ET_ALIGN_CENTER "You are speaking to" -> speakingTxt in let _CRtext _channel winInterface 10 250 130 50 ET_ALIGN_CENTER "" -> msg in let _CRmenu _channel winInterface -> menu in let _APPpopup _channel menu "&Connection Speed" -> menuConSpeed in let _APPitem _channel menuConSpeed ME_ENABLED "14.4 Modem" -> a1 in let _APPitem _channel menuConSpeed ME_ENABLED "28.8 Modem" -> a2 in let _APPitem _channel menuConSpeed ME_ENABLED "33.6 Modem" -> a3 in let _APPitem _channel menuConSpeed ME_ENABLED "56K Modem/ISDN" -> a4 in let _APPitem _channel menuConSpeed ME_ENABLED "112K Dual ISDN" -> a5 in let _APPitem _channel menuConSpeed ME_ENABLED "256K DSL/cable" -> a6 in let _APPitem _channel menuConSpeed ME_ENABLED "Higher Speed" -> a7 in /*let _APPitem _channel menuConSpeed ME_ENABLED "I do not know" -> a8 in*/ let strextr _getpack _checkpack conSpeedConfigFile -> l in let getInfo l "conType" -> no in ( _CBwinSize winInterface @_resizeWinInterface [msg speakingTxt]; _CBmenu a1 @updateMaxClients [msg 1 "1"]; _CBmenu a2 @updateMaxClients [msg 2 "2"]; _CBmenu a3 @updateMaxClients [msg 3 "3"]; _CBmenu a4 @updateMaxClients [msg 4 "4"]; _CBmenu a5 @updateMaxClients [msg 8 "5"]; _CBmenu a6 @updateMaxClients [msg 16 "6"]; _CBmenu a7 @updateMaxClients [msg 32 "7"]; /*_CBmenu a8 @updateMaxClients [msg 3 "8"];*/ /*do not know*/ if !strcmp no "1" then updateMaxClients a1 [msg 1 "1"] else if !strcmp no "2" then updateMaxClients a2 [msg 2 "2"] else if !strcmp no "3" then updateMaxClients a3 [msg 3 "3"] else if !strcmp no "4" then updateMaxClients a4 [msg 4 "4"] else if !strcmp no "5" then updateMaxClients a5 [msg 8 "5"] else if !strcmp no "6" then updateMaxClients a6 [msg 16 "6"] else if !strcmp no "7" then updateMaxClients a7 [msg 32 "7"] else /*if !strcmp no "8" then updateMaxClients a8 [msg 3 "8"] else*/ /*do not know*/ updateMaxClients a2 [msg 2 "2"] /*default if no cookie*/ ) );; /*-------------------*/ fun hideInterface()= _DSwindow winInterface; set winInterface=nil; 0;; /*-------------------*/ fun _paintE(a,b)= _BLTbitmap win if recording then bmpon else bmpoff 0 0; _BLTbitmap win2 if silent then bmppmute else if playing then bmppon else bmppoff 0 0; if playing then nil else _SETtext info ""; 0;; /*-------------------*/ /*click record button*/ fun _clickE(a,m,x,y,button)= if silent then nil /*we cannot speak if the sound dialog is not activated*/ else if !playing then /*we can speak only if nobody is speaking*/ if recording then nil else (showInterface; startrecsnd; _paintE nil nil) else nil;; /*-------------------*/ /*unclick record button*/ fun _unclickE(a,m,x,y,button)= stoprecsnd; set recording=0; /*should already be done in interaudio.pkg*/ _RSTlist usersList; _paintE nil nil;; /*-------------*/ /*activate the sound Dialog*/ fun soundDialogOn(o)= _deltimer timer; _rfltimer _starttimer _channel period @updateChatList 0; UsendSrv this (ObUi o) "register" (itoa udpport); /*register on the server (all clients will be informed)*/ set clisRegistered=nil; /*init registered list*/ set silent=0; /*speaker is on now*/ _paintE nil nil; _storepack strbuild ("speakerState"::"1"::nil)::nil configFile;/*save speaker state in config file*/ 0;; /*-------------*/ /*desactivate the sound Dialog*/ fun soundDialogOff(o)= if recording then _unclickE nil nil nil nil nil else nil; /*we stop recording if we were recording*/ _deltimer timer; UsendSrv this (ObUi o) "silent" nil; /*unregister on the server (all clients will be informed)*/ set clisRegistered=nil; /*reset registered list*/ set silent=1; /*speaker is off now*/ _paintE nil nil; _storepack strbuild ("speakerState"::"0"::nil)::nil configFile;/*save speaker state in config file*/ 0;; /*-------------------*/ /*click button sound on off*/ fun _clickE2(a,o,x,y,button)= set silent= if silent then (soundDialogOn o; _DMSevent this (strcatn (ObName o)::".clickOn"::nil) nil nil;0) else (soundDialogOff o; hideInterface; _DMSevent this (strcatn (ObName o)::".clickOff"::nil) nil nil;1); _paintE nil nil;; /*-------------------*/ fun _end(b)= _DMSdelete this;; /*-------------------*/ fun _resize2(x,s)= let x->[_ x y w h] in _SIZEwindow win2 w h x y; 0;; /*-------------------*/ fun _resize(x,s)= let x->[_ x y w h] in _SIZEwindow win w h x y; 0;; /*-------------------*/ fun _moveE(a,b,x,y,c)= _SETwinCursor win HandCursor;; /*-------------------*/ fun _resizeT(x,s)= let x->[_ x y w h] in _SIZEtext info w h x y; 0;; /*-------------------*/ /*CB called when bitmaps are downloaded*/ fun bitmapfile1loaded(f)= let _LDjpeg _channel _checkpack f -> x in let if x==nil then _LDbitmap _channel _checkpack f else x -> xx in set bmpon=if xx==nil then nil else xx; _paintE nil nil;/*repaint*/ 0;; /*-------------------*/ fun bitmapfile2loaded(f)= let _LDjpeg _channel _checkpack f -> x in let if x==nil then _LDbitmap _channel _checkpack f else x -> xx in set bmpoff=if xx==nil then nil else xx; _paintE nil nil; 0;; /*-------------------*/ fun bitmapfile3loaded(f)= let _LDjpeg _channel _checkpack f -> x in let if x==nil then _LDbitmap _channel _checkpack f else x -> xx in set bmppon=if xx==nil then nil else xx; _paintE nil nil; 0;; /*-------------------*/ fun bitmapfile4loaded(f)= let _LDjpeg _channel _checkpack f -> x in let if x==nil then _LDbitmap _channel _checkpack f else x -> xx in set bmppoff=if xx==nil then nil else xx; _paintE nil nil; 0;; /*-------------------*/ fun bitmapfile5loaded(f)= let _LDjpeg _channel _checkpack f -> x in let if x==nil then _LDbitmap _channel _checkpack f else x -> xx in set bmppmute=if xx==nil then nil else xx; _paintE nil nil; 0;; /*-------------------*/ /*ignore or receive the message voice of a client*/ fun __sound (id,name,audio)= if (silent) then 0 /*if client has his speaker off (silent==1) */ else if (search_in_list ignoreListIn @cliById2 id)!=nil then nil /*if client is in ignore list*/ else (_SETtext info (GetAudio name audio);0);; /*-------------*/ /*when a client ignores you, you do not send him voice messages*/ fun __ignoreOut(id,state)= if (state==1) then (set ignoreListOut2=id::(removef_from_list ignoreListOut2 @cliById2 id);0) /*add name to the ignore list out 2*/ else /*state==0*/ (set ignoreListOut2=removef_from_list ignoreListOut2 @cliById2 id;0);; /*remove name from ignore list out 2*/ /*-------------*/ /*update Ignore Flag*/ fun updateIgnoreFlag(type,id,state)= if !strcmp type "SpeakIn" then if atoi state then ( _sendUDP (getUdpFromIdInClisRegistered id) CignoreOut [DMSid 1]; set ignoreListIn=id::(removef_from_list ignoreListIn @cliById2 id); /*add id to the ignore list in*/ 0 ) else /*state==0*/ ( _sendUDP (getUdpFromIdInClisRegistered id) CignoreOut [DMSid 0]; set ignoreListIn=removef_from_list ignoreListIn @cliById2 id; /*remove id from ignore list in*/ 0 ) else if !strcmp type "SpeakOut" then if atoi state then (set ignoreListOut=id::(removef_from_list ignoreListOut @cliById2 id);0) /*add id to the ignore list out*/ else /*state==0*/ (set ignoreListOut=removef_from_list ignoreListOut @cliById2 id;0) /*remove id from ignore list out*/ else nil;; /*-------------*/ fun ChangeNameIgnList (oldname, newname, IgnList)= if IgnList == nil then 0 else let IgnList -> [currentname NIgnList] in if !strcmp oldname currentname then (mutate IgnList <- [newname _];1) else ChangeNameIgnList oldname newname NIgnList;; /*-------------*/ /*client has logged out, delete his name from the ignore lists*/ fun deleteIdFromIgnoreLists(id)= set ignoreListIn=removef_from_list ignoreListIn @cliById2 id; /*remove id from ignore list in*/ set ignoreListOut=removef_from_list ignoreListOut @cliById2 id; /*remove id from ignore list out*/ set ignoreListOut2=removef_from_list ignoreListOut2 @cliById2 id; /*remove id from ignore list out 2*/ 0;; /*-------------*/ fun activate(o,from,action,param,reply)= if !strcmp action (strcat SDname ".IgnLogout") then let lineextr param -> [id[name _]] in deleteIdFromIgnoreLists atoi id else if !strcmp action (strcat SDname ".IgnoreFlag") then let lineextr param -> [type[id[name[state _]]]] in updateIgnoreFlag type atoi id state else if !strcmp action (strcat SDname ".enableRec") then _clickE nil nil nil nil nil else if !strcmp action (strcat SDname ".disableRec") then _unclickE nil nil nil nil nil else if !strcmp action (strcat SDname ".on") then (soundDialogOn o;0) else if !strcmp action (strcat SDname ".off") then (soundDialogOff o;0) else nil;; /*-------------*/ fun destroySD(o)= UsendSrv this (ObUi o) "silent" nil; /*unregister on the server (all clients will be informed)*/ _deltimer timer; _killchannel udp; _DSbitmap bmpon; _DSbitmap bmpoff; _DSbitmap bmppon; _DSbitmap bmppoff; _DSbitmap bmppmute; 0;; /*-------------*/ fun newOb(o)= if (NbPluginInstance == 0) then ( set SDname = (ObName o); let hd UgetParam ObUi o "Period" -> tmp in set period = if tmp==nil then defperiod else atoi tmp; let hd UgetParam ObUi o "DMsphere" -> tmp in set d_max_sphere = if tmp==nil then defd_max_sphere else atoi tmp; ObRegisterAction o (strcat SDname ".on") @activate; ObRegisterAction o (strcat SDname ".off") @activate; ObRegisterAction o (strcat SDname ".IgnoreFlag") @activate; /*these actions are used to activate rec with directly with actions == click and unclik on rec button*/ ObRegisterAction o (strcatn SDname::".enableRec"::nil) @activate; ObRegisterAction o (strcatn SDname::".disableRec"::nil) @activate; UcbComm this (ObUi o) @cbcomm; /*get 2D interface bitmaps*/ let hd UgetParam ObUi o "bmpon" -> bmponFileName in if bmponFileName == nil then /*download default bitmap*/ _RSCdownload this recOnDef recOnDef @bitmapfile1loaded 1 else _RSCdownload this bmponFileName bmponFileName @bitmapfile1loaded 1; let hd UgetParam ObUi o "bmpoff" -> bmpoffFileName in if bmpoffFileName == nil then /*download default bitmap*/ _RSCdownload this recOffDef recOffDef @bitmapfile2loaded 1 else _RSCdownload this bmpoffFileName bmpoffFileName @bitmapfile2loaded 1; let hd UgetParam ObUi o "bmppon" -> bmpponFileName in if bmpponFileName == nil then /*download default bitmap*/ _RSCdownload this playonDef playonDef @bitmapfile3loaded 1 else _RSCdownload this bmpponFileName bmpponFileName @bitmapfile3loaded 1; let hd UgetParam ObUi o "bmppoff" -> bmppoffFileName in if bmppoffFileName == nil then /*download default bitmap*/ _RSCdownload this playoffDef playoffDef @bitmapfile4loaded 1 else _RSCdownload this bmppoffFileName bmppoffFileName @bitmapfile4loaded 1; let hd UgetParam ObUi o "bmppmute" -> bmppmuteFileName in if bmppmuteFileName == nil then /*download default bitmap*/ _RSCdownload this playmute playmute @bitmapfile5loaded 1 else _RSCdownload this bmppmuteFileName bmppmuteFileName @bitmapfile5loaded 1; /*create an udp channel*/ let getUdp 3000 4000->[c i] in (set udpport=i; set udp=c); /*2D interface*/ /*rec button*/ let _DMSgetZone this (strcatn SDname::".ButtonRec"::nil) @_end @_resize @_end ->[wn x y w h] in if wn==nil then nil else (set win=_CRwindow _channel wn x y w h WN_CHILDINSIDE|WN_NOCAPTION|WN_NOBORDER "speaker"; _CBwinPaint win @_paintE 0; _paintE nil nil; _CBcursorMove win @_moveE 0; _CBwinClick win @_clickE 0; _CBwinUnclick win @_unclickE 0); /*play button*/ let _DMSgetZone this (strcatn SDname::".ButtonPlay"::nil) @_end @_resize2 @_end ->[wn x y w h] in if wn==nil then nil else ( set win2=_CRwindow _channel wn x y w h WN_CHILDINSIDE|WN_NOCAPTION|WN_NOBORDER "speaker"; _CBwinPaint win2 @_paintE 0; _paintE nil nil; _CBcursorMove win2 @_moveE 0; _CBwinClick win2 @_clickE2 o); /*info zone*/ let _DMSgetZone this (strcatn SDname::".Info"::nil) nil @_resizeT @_end ->[win x y w h] in if win==nil then nil else set info=_CRtext _channel win x y w h ET_ALIGN_CENTER|ET_DOWN ""; iniAudio; /*initialize audio*/ set cbrec=@speak; /*CB sound recorded by client*/ set configFile = strcatn "locked/conf/soundDialog/"::DMSname::".conf"::nil; /*set the config file name (name of the site in locked/conf/soundDialog)*/ let strextr _getpack _checkpack configFile -> l in let getInfo l "speakerState" -> state in if !strcmp state "1" then soundDialogOn o /*if no config file, we use the autostart parameter*/ else let hd UgetParam ObUi o "autoStart" -> speakerState in /*speaker is on or off when starting*/ if !strcmp speakerState "1" then soundDialogOn o /*activate sound dialog*/ else nil; set NbPluginInstance = NbPluginInstance + 1; ObCbDestroy o @destroySD; 0 ) else ( set NbPluginInstance = NbPluginInstance + 1; nil );; /*-------------*/ fun IniPlug(file)= set myChannel = _channel; /*save current channel*/ set class=getInfo strextr _getpack _checkpack file "name"; PlugRegister class @newOb nil; 0;;