Ongoing work on conversations and display issues

This commit is contained in:
Tom Moor 2013-02-24 18:31:30 -08:00
parent 18c5597ed9
commit f0eda65a63
7 changed files with 6 additions and 6 deletions

@ -1 +1 @@
package com.sqwiggle { import com.sqwiggle.Member; import com.sqwiggle.Self; import com.sqwiggle.GUID; import flash.utils.Dictionary; public class Conversation extends Object { public var id:String; private var length:Number; public var members:Object; public function Conversation() { this.members = new Object(); } public function addMember(member:Member, inConversation:Boolean=false):void { trace('Conversation:addMember', member.userId); members[member.userId] = member; member.audioOn(inConversation); length++; } public function removeMember(member:Member, inConversation:Boolean=false):void { trace('Conversation:removeMember', member.userId); delete members[member.userId]; member.audioOff(inConversation); length--; } public function hasMember(member:Member):Boolean { return !!members[member.userId]; } public function isEmpty():Boolean { return length == 1; } } }
package com.sqwiggle { import com.sqwiggle.Member; import com.sqwiggle.Self; import com.sqwiggle.GUID; import flash.utils.Dictionary; public class Conversation extends Object { public var id:String; private var length:Number; public var members:Object; public function Conversation() { this.members = new Object(); } public function removeAllMembers():void { for (var i in members) { removeMember(members[i], false); } } public function addMember(member:Member, inConversation:Boolean=false):void { trace('Conversation:addMember', member.userId); members[member.userId] = member; member.audioOn(inConversation); length++; } public function removeMember(member:Member, inConversation:Boolean=false):void { trace('Conversation:removeMember', member.userId); delete members[member.userId]; member.audioOff(inConversation); length--; } public function hasMember(member:Member):Boolean { return !!members[member.userId]; } public function isEmpty():Boolean { return length == 1; } } }

@ -1 +1 @@
package com.sqwiggle { import com.sqwiggle.Conversation; import com.sqwiggle.Self; import com.sqwiggle.events.ApiEvent; import flash.events.Event; import flash.net.URLLoader; import flash.events.EventDispatcher; public class Conversations extends EventDispatcher { private var ongoing:Object; private var colours:Array; private var self:Self; public var members:Object; public function Conversations(self:Self, members:Object) { this.ongoing = new Object(); this.members = members; this.self = self; // make an API request to get ongoing conversations var request = Api.getRequest('/conversations'); request.addEventListener(Event.COMPLETE, function(event:ApiEvent) { updateMembers(event.data.conversations); }); } public function updateMembers(conversations:Object):void { // first find if the current user is in any conversation var selfInConversation = false; for (var a in conversations) { for (var b in conversations[a].users) { if (conversations[a].users[b].id == self.userId) { selfInConversation = a; } } } for (var i in conversations) { trace('updating conversation', i); // we dont know about this conversation if (!ongoing[i]) { ongoing[i] = new Conversation(); ongoing[i].id = i; } var conversation = ongoing[i]; var existingMembers = conversation.members; var selfInCurrentConversation = selfInConversation == i; // find existing members that should leave the convo for (var j in existingMembers) { // check if this user is still in the convo var filter = conversations[i].users.filter(function(user){ return user.id == this.userId; }, existingMembers[j]); var inConversation = !!filter.length; if (!inConversation) { trace('removing member from conversation', member.userId, conversation.id); conversation.removeMember(member, selfInCurrentConversation); } } // for every user that should be in this conversation for (var k in conversations[i].users) { var user = conversations[i].users[k]; var member; if (user.id == self.userId) { member = self; } else { member = members[user.id]; } if (!member) { continue; } if (!conversation.hasMember(member)) { if (selfInCurrentConversation) { trace('member already in a conversation with you'); } else { trace('adding member to conversation', member.userId, conversation.id); } conversation.addMember(member, selfInCurrentConversation); } } } dispatchEvent(new Event("conversationsupdated")); } public function getConversationForMember(member:Member):Conversation { for (var i in ongoing) { if (ongoing[i].hasMember(member)) { return ongoing[i]; } } return null; } private function nextColour():void { } } }
package com.sqwiggle { import com.sqwiggle.Conversation; import com.sqwiggle.Self; import com.sqwiggle.events.ApiEvent; import flash.events.Event; import flash.net.URLLoader; import flash.events.EventDispatcher; public class Conversations extends EventDispatcher { private var ongoing:Object; private var colours:Array; private var self:Self; public var members:Object; public function Conversations(self:Self, members:Object) { this.ongoing = new Object(); this.members = members; this.self = self; // make an API request to get ongoing conversations var request = Api.getRequest('/conversations'); request.addEventListener(Event.COMPLETE, function(event:ApiEvent) { updateMembers(event.data.conversations); }); } public function updateMembers(conversations:Object):void { if (!conversations) { Sqwiggle.trace('No conversations left'); for (var o in ongoing) { ongoing[0].removeAllMembers(); } conversations = new Object(); return; } // first find if the current user is in any conversation var selfInConversation = false; for (var a in conversations) { for (var b in conversations[a].users) { if (conversations[a].users[b].id == self.userId) { selfInConversation = a; } } } for (var i in conversations) { trace('updating conversation', i); // we dont know about this conversation if (!ongoing[i]) { ongoing[i] = new Conversation(); ongoing[i].id = i; } var conversation = ongoing[i]; var existingMembers = conversation.members; var selfInCurrentConversation = selfInConversation == i; var member; // find existing members that should leave the convo for (var j in existingMembers) { // check if this user is still in the convo var filter = conversations[i].users.filter(function(user){ return user.id == this.userId; }, existingMembers[j]); var inConversation = !!filter.length; member = existingMembers[j]; if (!inConversation) { trace('removing member from conversation', member.userId, conversation.id); conversation.removeMember(member, selfInCurrentConversation); } } // for every user that should be in this conversation for (var k in conversations[i].users) { var user = conversations[i].users[k]; if (user.id == self.userId) { member = self; } else { member = members[user.id]; } if (!member) { continue; } if (!conversation.hasMember(member)) { if (selfInCurrentConversation) { trace('member already in a conversation with you'); } else { trace('adding member to conversation', member.userId, conversation.id); } conversation.addMember(member, selfInCurrentConversation); } } } dispatchEvent(new Event("conversationsupdated")); } public function getConversationForMember(member:Member):Conversation { for (var i in ongoing) { if (ongoing[i].hasMember(member)) { return ongoing[i]; } } return null; } private function nextColour():void { } } }

@ -1 +1 @@
package com.sqwiggle { import flash.display.Sprite; import flash.display.Shape; import flash.display.MovieClip; import flash.media.Video; import flash.net.NetConnection; import flash.net.NetStream; import flash.net.NetStreamInfo; import flash.events.Event; import flash.events.MouseEvent; import flash.events.NetStatusEvent; import flash.text.TextField; import flash.text.TextFormat; import fl.transitions.Tween; import fl.transitions.easing.*; public class Member extends Sprite { public static const MAX_WIDTH = 400; public static const MAX_HEIGHT = 300; public static const INFOBAR_HEIGHT = 35; public var connection :NetConnection; public var userId :String; public var peerId :String; public var userName :String; protected var stream :NetStream; protected var video :Video; protected var infoBar :Sprite; protected var activity :MovieClip; public function Member(userId:String, peerId:String, userName:String='Anonymous') { this.userId = userId; this.peerId = peerId; this.userName = userName; render(300, 225); addEventListener(MouseEvent.MOUSE_OVER, hoverOver); addEventListener(MouseEvent.MOUSE_OUT, hoverOut); addEventListener(Event.ENTER_FRAME, updateActivity); } public function render(w:Number, h:Number):void { w = Math.min(Member.MAX_WIDTH, w); h = Math.min(Member.MAX_HEIGHT, h); if (!video) { video = new Video(); addChild(video); } if (!activity) { activity = new ActivityIndicator(); addChild(activity); } activity.x = 0; activity.y = w; activity.visible = false; video.width = w; video.height = h; drawInfoBar(); } private function drawInfoBar():void { if (infoBar) removeChild(infoBar); infoBar = new Sprite(); infoBar.y = video.height-Member.INFOBAR_HEIGHT; infoBar.alpha = 0; addChild(infoBar); var opaqueBar = new Sprite(); opaqueBar.graphics.beginFill(0x000000, 0.3); opaqueBar.graphics.drawRect(0,0,video.width,Member.INFOBAR_HEIGHT); opaqueBar.graphics.endFill(); infoBar.addChild(opaqueBar); var textFormat:TextFormat = new TextFormat(); textFormat.font = "Arial"; textFormat.size = 20; var nameField = new TextField(); nameField.x = 10; nameField.y = 4; // padding nameField.width = video.width; nameField.height = infoBar.height; nameField.selectable = false; nameField.textColor = 0xFFFFFF; nameField.text = userName; nameField.setTextFormat(textFormat); nameField.alpha = 0.8; infoBar.addChild(nameField); } public function connectToVideo(connection:NetConnection):void { trace('Connecting to video of: ' + userId + ', stream: ' + peerId); stream = new NetStream(connection, peerId); stream.addEventListener(NetStatusEvent.NET_STATUS, onNetStatus); stream.receiveAudio(false); stream.play(userId); video.attachNetStream(stream); } public function disconnectFromVideo():void { removeChild(video); stream.close(); } public function updateActivity(event:Event):void { var bytes:Number = stream.info.audioBytesPerSecond; if (bytes) { var maxActivityLevel = 5500; var activityLevel = (Math.max(0, bytes-1000)/100) / (maxActivityLevel/100) trace('Mic Activity', Math.round(activityLevel)); activity.alpha = activityLevel; } } public function audioOn(conversationInProgress:Boolean=false):void { stream.receiveAudio(true); activity.visible = true; if (conversationInProgress) { new Tween(video, "alpha", Regular.easeIn, 1, alpha, 0.5, true); } } public function audioOff(conversationInProgress:Boolean=false):void { stream.receiveAudio(false); activity.visible = false; if (conversationInProgress) { new Tween(video, "alpha", Regular.easeIn, 1, alpha, 1, true); } } public function onNetStatus(event:NetStatusEvent):void { trace('Net status ' + peerId + ': ' + event.info.code); } private function hoverOver(event:MouseEvent):void { new Tween(infoBar, "alpha", Regular.easeIn, 0, 1, 0.3, true); } private function hoverOut(event:MouseEvent):void { new Tween(infoBar, "alpha", Regular.easeIn, 1, 0, 0.3, true); } } }
package com.sqwiggle { import flash.display.Sprite; import flash.display.Shape; import flash.display.MovieClip; import flash.media.Video; import flash.net.NetConnection; import flash.net.NetStream; import flash.net.NetStreamInfo; import flash.events.Event; import flash.events.MouseEvent; import flash.events.NetStatusEvent; import flash.text.TextField; import flash.text.TextFormat; import fl.transitions.Tween; import fl.transitions.easing.*; public class Member extends Sprite { public static const MAX_WIDTH = 400; public static const MAX_HEIGHT = 300; public static const INFOBAR_HEIGHT = 35; public var connection :NetConnection; public var userId :String; public var peerId :String; public var userName :String; protected var stream :NetStream; protected var video :Video; protected var infoBar :Sprite; protected var activity :MovieClip; public function Member(userId:String, peerId:String, userName:String='Anonymous') { this.userId = userId; this.peerId = peerId; this.userName = userName; render(300, 225); addEventListener(MouseEvent.MOUSE_OVER, hoverOver); addEventListener(MouseEvent.MOUSE_OUT, hoverOut); addEventListener(Event.ENTER_FRAME, updateActivity); } public function render(w:Number, h:Number):void { w = Math.min(Member.MAX_WIDTH, w); h = Math.min(Member.MAX_HEIGHT, h); if (!video) { video = new Video(); addChild(video); } video.width = w; video.height = h; if (!activity) { activity = new ActivityIndicator(); activity.visible = false; addChild(activity); } activity.x = w; activity.y = 0; drawInfoBar(); } private function drawInfoBar():void { if (infoBar) removeChild(infoBar); infoBar = new Sprite(); infoBar.y = video.height-Member.INFOBAR_HEIGHT; infoBar.alpha = 0; addChild(infoBar); var opaqueBar = new Sprite(); opaqueBar.graphics.beginFill(0x000000, 0.3); opaqueBar.graphics.drawRect(0,0,video.width,Member.INFOBAR_HEIGHT); opaqueBar.graphics.endFill(); infoBar.addChild(opaqueBar); var textFormat:TextFormat = new TextFormat(); textFormat.font = "Arial"; textFormat.size = 20; var nameField = new TextField(); nameField.x = 10; nameField.y = 4; // padding nameField.width = video.width; nameField.height = infoBar.height; nameField.selectable = false; nameField.textColor = 0xFFFFFF; nameField.text = userName; nameField.setTextFormat(textFormat); nameField.alpha = 0.8; infoBar.addChild(nameField); } public function connectToVideo(connection:NetConnection):void { Sqwiggle.trace('Connecting to video of: ' + userId + ', stream: ' + peerId); stream = new NetStream(connection, peerId); stream.addEventListener(NetStatusEvent.NET_STATUS, onNetStatus); stream.receiveAudio(false); stream.play(userId); video.attachNetStream(stream); } public function disconnectFromVideo():void { removeChild(video); stream.close(); } public function updateActivity(event:Event):void { var bytes:Number = stream.info.audioBytesPerSecond; if (bytes) { var maxActivityLevel = 5500; var activityLevel = (Math.max(0, bytes-1000)/100) / (maxActivityLevel/100) activity.alpha = activityLevel; } } public function audioOn(conversationInProgress:Boolean=false):void { stream.receiveAudio(true); activity.visible = true; if (conversationInProgress) { new Tween(video, "alpha", Regular.easeIn, 1, alpha, 0.5, true); } } public function audioOff(conversationInProgress:Boolean=false):void { stream.receiveAudio(false); activity.visible = false; if (conversationInProgress) { new Tween(video, "alpha", Regular.easeIn, 1, alpha, 1, true); } } public function onNetStatus(event:NetStatusEvent):void { Sqwiggle.trace('Net status ' + peerId + ': ' + event.info.code); } private function hoverOver(event:MouseEvent):void { new Tween(infoBar, "alpha", Regular.easeIn, 0, 1, 0.3, true); } private function hoverOut(event:MouseEvent):void { new Tween(infoBar, "alpha", Regular.easeIn, 1, 0, 0.3, true); } } }

@ -1 +1 @@
package com.sqwiggle { import flash.events.NetStatusEvent; import flash.media.Camera; import flash.net.NetConnection; import flash.net.NetStream; import flash.media.Microphone; import flash.media.SoundCodec; import flash.events.MouseEvent; import flash.events.Event; import fl.transitions.Tween; import fl.transitions.easing.*; import com.sqwiggle.Member; public class Self extends Member { var cam:Camera; var mic:Microphone; public function Self(userId:String) { super(userId, '', 'Me'); // TODO: check for camera cam = Camera.getCamera(); cam.setQuality(0, 100); // TODO: check for mic mic = Microphone.getMicrophone(); mic.enableVAD = true; mic.codec = SoundCodec.SPEEX; mic.encodeQuality = 10; mic.setSilenceLevel(100); mic.setUseEchoSuppression(true); } public function updatePeerId():void { var options = new Object(); options.peer_id = peerId; // make an API request to save the new peerID var request = Api.putRequest('/users/update', options); // dispatch an event once the peerID is updated request.addEventListener(Event.COMPLETE, function(event:Event) { dispatchEvent(new Event("Connected")); }); } public override function updateActivity(event:Event):void { if (mic) { activity.alpha = 80 + (mic.activityLevel/5); } } public override function connectToVideo(connection:NetConnection):void { peerId = connection.nearID; trace('Publishing video to: ' + userId + ', stream: ' + peerId); var stream = new NetStream(connection, NetStream.DIRECT_CONNECTIONS); stream.addEventListener(NetStatusEvent.NET_STATUS, onNetStatus); stream.attachCamera(this.cam); stream.attachAudio(this.mic); stream.publish(this.userId); var client:Object = new Object(); client.onPeerConnect = function(caller:NetStream):Boolean { trace('Member connecting to your video stream: ' + caller.farID); return true; }; stream.client = client; video.attachCamera(this.cam); video.smoothing = true; video.deblocking = 5; // ensure we update this users peerID on the server for // other clients to connect to. updatePeerId(); } public override function audioOn(conversationInProgress:Boolean=false):void { mic.setSilenceLevel(0); if (conversationInProgress) { new Tween(video, "alpha", Regular.easeIn, 1, alpha, 0.5, true); } trace('Your audio is on'); } public override function audioOff(conversationInProgress:Boolean=false):void { mic.setSilenceLevel(100); if (conversationInProgress) { new Tween(video, "alpha", Regular.easeIn, 1, alpha, 1, true); } trace('Your audio is off'); } } }
package com.sqwiggle { import flash.events.NetStatusEvent; import flash.media.Camera; import flash.net.NetConnection; import flash.net.NetStream; import flash.media.Microphone; import flash.media.SoundCodec; import flash.events.MouseEvent; import flash.events.Event; import fl.transitions.Tween; import fl.transitions.easing.*; import com.sqwiggle.Member; public class Self extends Member { var cam:Camera; var mic:Microphone; public function Self(userId:String) { super(userId, '', 'Me'); // TODO: check for camera cam = Camera.getCamera(); cam.setQuality(0, 100); // TODO: check for mic mic = Microphone.getMicrophone(); mic.enableVAD = true; mic.codec = SoundCodec.SPEEX; mic.encodeQuality = 10; mic.setSilenceLevel(100); mic.setUseEchoSuppression(true); } public function updatePeerId():void { var options = new Object(); options.peer_id = peerId; // make an API request to save the new peerID var request = Api.putRequest('/users/update', options); // dispatch an event once the peerID is updated request.addEventListener(Event.COMPLETE, function(event:Event) { dispatchEvent(new Event("Connected")); }); } public override function updateActivity(event:Event):void { if (mic) { activity.alpha = 80 + (mic.activityLevel/5); } } public override function connectToVideo(connection:NetConnection):void { peerId = connection.nearID; Sqwiggle.trace('Publishing video to: ' + userId + ', stream: ' + peerId); var stream = new NetStream(connection, NetStream.DIRECT_CONNECTIONS); stream.addEventListener(NetStatusEvent.NET_STATUS, onNetStatus); stream.attachCamera(this.cam); stream.attachAudio(this.mic); stream.publish(this.userId); var client:Object = new Object(); client.onPeerConnect = function(caller:NetStream):Boolean { Sqwiggle.trace('Member connecting to your video stream: ' + caller.farID); return true; }; stream.client = client; video.attachCamera(this.cam); video.smoothing = true; video.deblocking = 5; // ensure we update this users peerID on the server for // other clients to connect to. updatePeerId(); } public override function audioOn(conversationInProgress:Boolean=false):void { mic.setSilenceLevel(0); if (conversationInProgress) { new Tween(video, "alpha", Regular.easeIn, 1, alpha, 0.5, true); } Sqwiggle.trace('Your audio is on'); } public override function audioOff(conversationInProgress:Boolean=false):void { mic.setSilenceLevel(100); if (conversationInProgress) { new Tween(video, "alpha", Regular.easeIn, 1, alpha, 1, true); } Sqwiggle.trace('Your audio is off'); } } }

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

BIN
p2p.fla

Binary file not shown.