diff --git a/src/controllers/atoms/RoomAvatar.js b/src/controllers/atoms/RoomAvatar.js
new file mode 100644
index 0000000000..481483949a
--- /dev/null
+++ b/src/controllers/atoms/RoomAvatar.js
@@ -0,0 +1,61 @@
+/*
+Copyright 2015 OpenMarket Ltd
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+'use strict';
+
+var MatrixClientPeg = require('../../MatrixClientPeg');
+
+module.exports = {
+    getDefaultProps: function() {
+        return {
+            width: 40,
+            height: 40,
+            resizeMethod: 'crop'
+        }
+    },
+
+    avatarUrlForRoom: function(room) {
+        var url = MatrixClientPeg.get().getAvatarUrlForRoom(
+            room,
+            this.props.width, this.props.height, this.props.resizeMethod,
+            false
+        );
+        if (url === null) {
+            url = this.defaultAvatarUrl(room);
+        }
+        return url;
+    },
+
+    defaultAvatarUrl: function(member) {
+        return "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAIAAAADnC86AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAADRJREFUeNrszQENADAIACB9QjNbxSKP4eagAFnTseHFErFYLBaLxWKxWCwWi8Vi8cX4CzAABSwCRWJw31gAAAAASUVORK5CYII=";
+    },
+
+    onError: function(ev) {
+        // don't tightloop if the browser can't load a data url
+        if (ev.target.src == this.defaultAvatarUrl(this.props.room)) {
+            return;
+        }
+        this.setState({
+            imageUrl: this.defaultAvatarUrl(this.props.room)
+        });
+    },
+
+    getInitialState: function() {
+        return {
+            imageUrl: this.avatarUrlForRoom(this.props.room)
+        };
+    }
+};
diff --git a/src/controllers/molecules/RoomHeader.js b/src/controllers/molecules/RoomHeader.js
index 8aa688b21e..2ef99953d0 100644
--- a/src/controllers/molecules/RoomHeader.js
+++ b/src/controllers/molecules/RoomHeader.js
@@ -16,6 +16,80 @@ limitations under the License.
 
 'use strict';
 
-module.exports = {
-};
+/*
+ * State vars:
+ * this.state.call_state = the UI state of the call (see CallHandler)
+ */
 
+var React = require('react');
+var dis = require("../../dispatcher");
+var CallHandler = require("../../CallHandler");
+
+module.exports = {
+    propTypes: {
+        room: React.PropTypes.object.isRequired,
+        editing: React.PropTypes.bool,
+        onSettingsClick: React.PropTypes.func,
+        onSaveClick: React.PropTypes.func,
+    },
+
+    getDefaultProps: function() {
+        return {
+            editing: false,
+            onSettingsClick: function() {},
+            onSaveClick: function() {},
+        };
+    },
+
+    componentDidMount: function() {
+        this.dispatcherRef = dis.register(this.onAction);
+        if (this.props.room) {
+            var call = CallHandler.getCall(this.props.room.roomId);
+            var callState = call ? call.call_state : "ended";
+            this.setState({
+                call_state: callState
+            });
+        }
+    },
+
+    componentWillUnmount: function() {
+        dis.unregister(this.dispatcherRef);
+    },
+
+    onAction: function(payload) {
+        // if we were given a room_id to track, don't handle anything else.
+        if (payload.room_id && this.props.room &&
+                this.props.room.roomId !== payload.room_id) {
+            return;
+        }
+        if (payload.action !== 'call_state') {
+            return;
+        }
+        var call = CallHandler.getCall(payload.room_id);
+        var callState = call ? call.call_state : "ended";
+        this.setState({
+            call_state: callState
+        });
+    },
+
+    onVideoClick: function() {
+        dis.dispatch({
+            action: 'place_call',
+            type: "video",
+            room_id: this.props.room.roomId
+        });
+    },
+    onVoiceClick: function() {
+        dis.dispatch({
+            action: 'place_call',
+            type: "voice",
+            room_id: this.props.room.roomId
+        });
+    },
+    onHangupClick: function() {
+        dis.dispatch({
+            action: 'hangup',
+            room_id: this.props.room.roomId
+        });
+    }
+};