Merge m-c to inbound.
authorRyan VanderMeulen <ryanvm@gmail.com>
Thu, 25 Oct 2012 21:57:47 -0400
changeset 111608 3137b9aec214b7ea3c9579848a0bcfec65616656
parent 111607 c312620c97f221d2970cf95a48d55022e7920a82 (current diff)
parent 111585 5ecff3e46ed55a485c15ee12809f08e04b0f6114 (diff)
child 111609 02647d980da2fa2e8c7d4a156d22b51e7f25696f
push id93
push usernmatsakis@mozilla.com
push dateWed, 31 Oct 2012 21:26:57 +0000
milestone19.0a1
Merge m-c to inbound.
--- a/browser/modules/webrtcUI.jsm
+++ b/browser/modules/webrtcUI.jsm
@@ -85,26 +85,28 @@ function prompt(aBrowser, aCallID, aAudi
     }
   };
 
   let secondaryActions = [];
   let selectableDevices = videoDevices.length ? videoDevices : audioDevices;
   if (selectableDevices.length > 1) {
     let selectableDeviceNumber = 0;
     for (let device of selectableDevices) {
+      // See bug 449811 for why we do this
+      let actual_device = device;
       selectableDeviceNumber++;
       secondaryActions.push({
         label: stringBundle.getFormattedString(
                  device.type == "audio" ?
                    "getUserMedia.shareSpecificMicrophone.label" :
                    "getUserMedia.shareSpecificCamera.label",
                  [ device.name ]),
         accessKey: selectableDeviceNumber,
         callback: function () {
-          Services.obs.notifyObservers(device, "getUserMedia:response:allow", aCallID);
+          Services.obs.notifyObservers(actual_device, "getUserMedia:response:allow", aCallID);
         }
       });
     }
   }
   secondaryActions.push({
     label: stringBundle.getString("getUserMedia.denyRequest.label"),
     accessKey: stringBundle.getString("getUserMedia.denyRequest.accesskey"),
     callback: function () {
--- a/content/media/webrtc/MediaEngineDefault.cpp
+++ b/content/media/webrtc/MediaEngineDefault.cpp
@@ -12,17 +12,18 @@
 #include "ImageTypes.h"
 
 #ifdef MOZ_WIDGET_ANDROID
 #include "AndroidBridge.h"
 #include "nsISupportsUtils.h"
 #endif
 
 #define CHANNELS 1
-#define RATE USECS_PER_S
+#define VIDEO_RATE USECS_PER_S
+#define AUDIO_RATE 16000
 
 namespace mozilla {
 
 NS_IMPL_THREADSAFE_ISUPPORTS1(MediaEngineDefaultVideoSource, nsITimerCallback)
 /**
  * Default video source.
  */
 
@@ -127,17 +128,17 @@ MediaEngineDefaultVideoSource::Start(Sou
 
   // SetData copies data, so we can free the frame
   mImage->SetData(data);
   PR_Free(frame);
 
   // AddTrack takes ownership of segment
   VideoSegment *segment = new VideoSegment();
   segment->AppendFrame(image.forget(), USECS_PER_S / DEFAULT_FPS, gfxIntSize(DEFAULT_WIDTH, DEFAULT_HEIGHT));
-  mSource->AddTrack(aID, RATE, 0, segment);
+  mSource->AddTrack(aID, VIDEO_RATE, 0, segment);
 
   // We aren't going to add any more tracks
   mSource->AdvanceKnownTracksTime(STREAM_TIME_MAX);
 
   // Remember TrackID so we can end it later
   mTrackID = aID;
 
   // Start timer for subsequent frames
@@ -279,17 +280,17 @@ MediaEngineDefaultAudioSource::Start(Sou
     return NS_ERROR_FAILURE;
   }
 
   mSource = aStream;
 
   // AddTrack will take ownership of segment
   AudioSegment* segment = new AudioSegment();
   segment->Init(CHANNELS);
-  mSource->AddTrack(aID, RATE, 0, segment);
+  mSource->AddTrack(aID, AUDIO_RATE, 0, segment);
 
   // We aren't going to add any more tracks
   mSource->AdvanceKnownTracksTime(STREAM_TIME_MAX);
 
   // Remember TrackID so we can finish later
   mTrackID = aID;
 
   // 1 Audio frame per Video frame
@@ -325,17 +326,17 @@ MediaEngineDefaultAudioSource::Snapshot(
    return NS_ERROR_NOT_IMPLEMENTED;
 }
 
 NS_IMETHODIMP
 MediaEngineDefaultAudioSource::Notify(nsITimer* aTimer)
 {
   AudioSegment segment;
   segment.Init(CHANNELS);
-  segment.InsertNullDataAtStart(1);
+  segment.InsertNullDataAtStart(AUDIO_RATE/100); // 10ms of fake data
 
   mSource->AppendToTrack(mTrackID, &segment);
 
   return NS_OK;
 }
 
 void
 MediaEngineDefault::EnumerateVideoDevices(nsTArray<nsRefPtr<MediaEngineVideoSource> >* aVSources) {
--- a/dom/media/MediaManager.cpp
+++ b/dom/media/MediaManager.cpp
@@ -57,23 +57,22 @@ public:
   Run()
   {
     // Only run if the window is still active.
     NS_ASSERTION(NS_IsMainThread(), "Only call on main thread");
 
     nsCOMPtr<nsIDOMGetUserMediaSuccessCallback> success(mSuccess);
     nsCOMPtr<nsIDOMGetUserMediaErrorCallback> error(mError);
 
-    {
-      MutexAutoLock lock(MediaManager::Get()->GetMutex());
-      WindowTable* activeWindows = MediaManager::Get()->GetActiveWindows();
-      if (activeWindows->Get(mWindowID)) {
-        error->OnError(mErrorMsg);
-      }
+    if (!(MediaManager::Get()->IsWindowStillActive(mWindowID))) {
+      return NS_OK;
     }
+    // This is safe since we're on main-thread, and the windowlist can only
+    // be invalidated from the main-thread (see OnNavigation)
+    error->OnError(mErrorMsg);
     return NS_OK;
   }
 
 private:
   already_AddRefed<nsIDOMGetUserMediaSuccessCallback> mSuccess;
   already_AddRefed<nsIDOMGetUserMediaErrorCallback> mError;
   const nsString mErrorMsg;
   uint64_t mWindowID;
@@ -101,24 +100,22 @@ public:
   Run()
   {
     // Only run if the window is still active.
     NS_ASSERTION(NS_IsMainThread(), "Only call on main thread");
 
     nsCOMPtr<nsIDOMGetUserMediaSuccessCallback> success(mSuccess);
     nsCOMPtr<nsIDOMGetUserMediaErrorCallback> error(mError);
 
-    {
-      MutexAutoLock lock(MediaManager::Get()->GetMutex());
-      WindowTable* activeWindows = MediaManager::Get()->GetActiveWindows();
-      if (activeWindows->Get(mWindowID)) {
-        // XPConnect is a magical unicorn.
-        success->OnSuccess(mFile);
-      }
+    if (!(MediaManager::Get()->IsWindowStillActive(mWindowID))) {
+      return NS_OK;
     }
+    // This is safe since we're on main-thread, and the windowlist can only
+    // be invalidated from the main-thread (see OnNavigation)
+    success->OnSuccess(mFile);
     return NS_OK;
   }
 
 private:
   already_AddRefed<nsIDOMGetUserMediaSuccessCallback> mSuccess;
   already_AddRefed<nsIDOMGetUserMediaErrorCallback> mError;
   nsCOMPtr<nsIDOMFile> mFile;
   uint64_t mWindowID;
@@ -247,29 +244,30 @@ public:
     nsRefPtr<nsDOMLocalMediaStream> stream;
     uint32_t hints = (mAudioSource ? nsDOMMediaStream::HINT_CONTENTS_AUDIO : 0);
     hints |= (mVideoSource ? nsDOMMediaStream::HINT_CONTENTS_VIDEO : 0);
 
     stream = nsDOMLocalMediaStream::CreateInputStream(hints);
 
     nsPIDOMWindow *window = static_cast<nsPIDOMWindow*>
       (nsGlobalWindow::GetInnerWindowWithId(mWindowID));
-    WindowTable* activeWindows = MediaManager::Get()->GetActiveWindows();
     {
-      MutexAutoLock lock(MediaManager::Get()->GetMutex());
-
       if (!stream) {
-        if (activeWindows->Get(mWindowID)) {
-          nsCOMPtr<nsIDOMGetUserMediaErrorCallback> error(mError);
-          LOG(("Returning error for getUserMedia() - no stream"));
-          error->OnError(NS_LITERAL_STRING("NO_STREAM"));
+        if (!(MediaManager::Get()->IsWindowStillActive(mWindowID))) {
+          return NS_OK;
         }
+        // This is safe since we're on main-thread, and the windowlist can only
+        // be invalidated from the main-thread (see OnNavigation)
+        nsCOMPtr<nsIDOMGetUserMediaErrorCallback> error(mError);
+        LOG(("Returning error for getUserMedia() - no stream"));
+        error->OnError(NS_LITERAL_STRING("NO_STREAM"));
         return NS_OK;
       }
     }
+
     if (window && window->GetExtantDoc()) {
       stream->CombineWithPrincipal(window->GetExtantDoc()->NodePrincipal());
     }
 
     // Ensure there's a thread for gum to proxy to off main thread
     nsIThread *mediaThread = MediaManager::GetThread();
 
     // Add our listener. We'll call Start() on the source when get a callback
@@ -290,23 +288,23 @@ public:
       new MediaOperationRunnable(MEDIA_START, stream,
                                  mAudioSource, mVideoSource));
     mediaThread->Dispatch(runnable, NS_DISPATCH_NORMAL);
 
     // We're in the main thread, so no worries here either.
     nsCOMPtr<nsIDOMGetUserMediaSuccessCallback> success(mSuccess);
     nsCOMPtr<nsIDOMGetUserMediaErrorCallback> error(mError);
 
-    {
-      MutexAutoLock lock(MediaManager::Get()->GetMutex());
-      if (activeWindows->Get(mWindowID)) {
-        LOG(("Returning success for getUserMedia()"));
-        success->OnSuccess(static_cast<nsIDOMLocalMediaStream*>(stream));
-      }
+    if (!(MediaManager::Get()->IsWindowStillActive(mWindowID))) {
+      return NS_OK;
     }
+    // This is safe since we're on main-thread, and the windowlist can only
+    // be invalidated from the main-thread (see OnNavigation)
+    LOG(("Returning success for getUserMedia()"));
+    success->OnSuccess(static_cast<nsIDOMLocalMediaStream*>(stream));
 
     return NS_OK;
   }
 
 private:
   already_AddRefed<nsIDOMGetUserMediaSuccessCallback> mSuccess;
   already_AddRefed<nsIDOMGetUserMediaErrorCallback> mError;
   nsRefPtr<MediaEngineSource> mAudioSource;
@@ -430,19 +428,22 @@ public:
                         mVideo ? mVideoDevice->GetSource() : nullptr);
     return NS_OK;
   }
 
   nsresult
   Denied()
   {
     if (NS_IsMainThread()) {
+      // This is safe since we're on main-thread, and the window can only
+      // be invalidated from the main-thread (see OnNavigation)
       nsCOMPtr<nsIDOMGetUserMediaErrorCallback> error(mError);
       error->OnError(NS_LITERAL_STRING("PERMISSION_DENIED"));
     } else {
+      // This will re-check the window being alive on main-thread
       NS_DispatchToMainThread(new ErrorCallbackRunnable(
         mSuccess, mError, NS_LITERAL_STRING("PERMISSION_DENIED"), mWindowID
       ));
     }
 
     return NS_OK;
   }
 
@@ -784,72 +785,69 @@ MediaManager::GetUserMedia(bool aPrivile
     // Hack: should init singleton earlier unless it's expensive (mem or CPU)
     (void) MediaManager::Get();
   }
 
   // Store the WindowID in a hash table and mark as active. The entry is removed
   // when this window is closed or navigated away from.
   uint64_t windowID = aWindow->WindowID();
   nsRefPtr<GetUserMediaRunnable> gUMRunnable;
-  {
-    MutexAutoLock lock(mMutex);
-    StreamListeners* listeners = mActiveWindows.Get(windowID);
-    if (!listeners) {
-      listeners = new StreamListeners;
-      mActiveWindows.Put(windowID, listeners);
-    }
-
-    // Developer preference for turning off permission check.
-    if (Preferences::GetBool("media.navigator.permission.disabled", false)) {
-      aPrivileged = true;
-    }
+  // This is safe since we're on main-thread, and the windowlist can only
+  // be invalidated from the main-thread (see OnNavigation)
+  StreamListeners* listeners = GetActiveWindows()->Get(windowID);
+  if (!listeners) {
+    listeners = new StreamListeners;
+    GetActiveWindows()->Put(windowID, listeners);
+  }
 
-    /**
-     * Pass runnables along to GetUserMediaRunnable so it can add the
-     * MediaStreamListener to the runnable list. The last argument can
-     * optionally be a MediaDevice object, which should provided if one was
-     * selected by the user via the UI, or was provided by privileged code
-     * via the device: attribute via nsIMediaStreamOptions.
-     *
-     * If a fake stream was requested, we force the use of the default backend.
-     */
-    if (fake) {
-      // Fake stream from default backend.
-      gUMRunnable = new GetUserMediaRunnable(
-        audio, video, onSuccess.forget(), onError.forget(), listeners,
-        windowID, new MediaEngineDefault()
-                                             );
-    } else if (audiodevice || videodevice) {
-      // Stream from provided device.
-      gUMRunnable = new GetUserMediaRunnable(
-        audio, video, picture, onSuccess.forget(), onError.forget(), listeners,
-        windowID,
-        static_cast<MediaDevice*>(audiodevice.get()),
-        static_cast<MediaDevice*>(videodevice.get())
-                                             );
-    } else {
-      // Stream from default device from WebRTC backend.
-      gUMRunnable = new GetUserMediaRunnable(
-        audio, video, picture, onSuccess.forget(), onError.forget(), listeners,
-        windowID
-                                             );
-    }
+  // Developer preference for turning off permission check.
+  if (Preferences::GetBool("media.navigator.permission.disabled", false)) {
+    aPrivileged = true;
   }
 
+  /**
+   * Pass runnables along to GetUserMediaRunnable so it can add the
+   * MediaStreamListener to the runnable list. The last argument can
+   * optionally be a MediaDevice object, which should provided if one was
+   * selected by the user via the UI, or was provided by privileged code
+   * via the device: attribute via nsIMediaStreamOptions.
+   *
+   * If a fake stream was requested, we force the use of the default backend.
+   */
+  if (fake) {
+    // Fake stream from default backend.
+    gUMRunnable = new GetUserMediaRunnable(
+      audio, video, onSuccess.forget(), onError.forget(), listeners,
+      windowID, new MediaEngineDefault()
+                                           );
+  } else if (audiodevice || videodevice) {
+    // Stream from provided device.
+    gUMRunnable = new GetUserMediaRunnable(
+      audio, video, picture, onSuccess.forget(), onError.forget(), listeners,
+      windowID,
+      static_cast<MediaDevice*>(audiodevice.get()),
+      static_cast<MediaDevice*>(videodevice.get())
+                                           );
+  } else {
+    // Stream from default device from WebRTC backend.
+    gUMRunnable = new GetUserMediaRunnable(
+      audio, video, picture, onSuccess.forget(), onError.forget(), listeners,
+      windowID
+                                           );
+  }
 
 #ifdef ANDROID
   if (picture) {
     // ShowFilePickerForMimeType() must run on the Main Thread! (on Android)
     NS_DispatchToMainThread(gUMRunnable);
   }
   // XXX No support for Audio or Video in Android yet
 #else
   // XXX No full support for picture in Desktop yet (needs proper UI)
   if (aPrivileged || fake) {
-    (void) MediaManager::GetThread();
     mMediaThread->Dispatch(gUMRunnable, NS_DISPATCH_NORMAL);
   } else {
     // Ask for user permission, and dispatch runnable (or not) when a response
     // is received via an observer notification. Each call is paired with its
     // runnable by a GUID.
     nsresult rv;
     nsCOMPtr<nsIUUIDGenerator> uuidgen =
       do_GetService("@mozilla.org/uuid-generator;1", &rv);
@@ -860,20 +858,17 @@ MediaManager::GetUserMedia(bool aPrivile
     rv = uuidgen->GenerateUUIDInPlace(&id);
     NS_ENSURE_SUCCESS(rv, rv);
 
     char buffer[NSID_LENGTH];
     id.ToProvidedString(buffer);
     NS_ConvertUTF8toUTF16 callID(buffer);
 
     // Store the current callback.
-    {
-      MutexAutoLock lock(mMutex);
-      mActiveCallbacks.Put(callID, gUMRunnable);
-    }
+    mActiveCallbacks.Put(callID, gUMRunnable);
 
     // Construct JSON structure with both the windowID and the callID.
     nsAutoString data;
     data.Append(NS_LITERAL_STRING("{\"windowID\":"));
 
     // Convert window ID to string.
     char windowBuffer[32];
     PR_snprintf(windowBuffer, 32, "%llu", aWindow->GetOuterWindow()->WindowID());
@@ -917,56 +912,52 @@ MediaManager::GetUserMediaDevices(nsPIDO
   return NS_OK;
 }
 
 MediaEngine*
 MediaManager::GetBackend()
 {
   // Plugin backends as appropriate. The default engine also currently
   // includes picture support for Android.
+  // This IS called off main-thread.
+  MutexAutoLock lock(mMutex);
   if (!mBackend) {
 #if defined(MOZ_WEBRTC)
     mBackend = new MediaEngineWebRTC();
 #else
     mBackend = new MediaEngineDefault();
 #endif
   }
-
   return mBackend;
 }
 
-WindowTable*
-MediaManager::GetActiveWindows()
-{
-  return &mActiveWindows;
-}
-
 void
 MediaManager::OnNavigation(uint64_t aWindowID)
 {
+  NS_ASSERTION(NS_IsMainThread(), "OnNavigation called off main thread");
+
   // Invalidate this window. The runnables check this value before making
   // a call to content.
-  {
-    MutexAutoLock lock(mMutex);
-    StreamListeners* listeners = mActiveWindows.Get(aWindowID);
-    if (!listeners) {
-      return;
-    }
+
+  // This is safe since we're on main-thread, and the windowlist can only
+  // be added to from the main-thread (see OnNavigation)
+  StreamListeners* listeners = GetActiveWindows()->Get(aWindowID);
+  if (!listeners) {
+    return;
+  }
 
-    uint32_t length = listeners->Length();
-    for (uint32_t i = 0; i < length; i++) {
-      nsRefPtr<GetUserMediaCallbackMediaStreamListener> listener =
-        listeners->ElementAt(i);
-      listener->Invalidate();
-      listener = nullptr;
-    }
-    listeners->Clear();
+  uint32_t length = listeners->Length();
+  for (uint32_t i = 0; i < length; i++) {
+    nsRefPtr<GetUserMediaCallbackMediaStreamListener> listener =
+      listeners->ElementAt(i);
+    listener->Invalidate();
+  }
+  listeners->Clear();
 
-    mActiveWindows.Remove(aWindowID);
-  }
+  GetActiveWindows()->Remove(aWindowID);
 }
 
 nsresult
 MediaManager::Observe(nsISupports* aSubject, const char* aTopic,
   const PRUnichar* aData)
 {
   NS_ASSERTION(NS_IsMainThread(), "Observer invoked off the main thread");
   nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
@@ -974,36 +965,31 @@ MediaManager::Observe(nsISupports* aSubj
   if (!strcmp(aTopic, "xpcom-shutdown")) {
     obs->RemoveObserver(this, "xpcom-shutdown");
     obs->RemoveObserver(this, "getUserMedia:response:allow");
     obs->RemoveObserver(this, "getUserMedia:response:deny");
 
     // Close off any remaining active windows.
     {
       MutexAutoLock lock(mMutex);
-      mActiveWindows.Clear();
+      GetActiveWindows()->Clear();
       mActiveCallbacks.Clear();
       sSingleton = nullptr;
     }
 
     return NS_OK;
   }
 
   if (!strcmp(aTopic, "getUserMedia:response:allow")) {
     nsString key(aData);
     nsRefPtr<nsRunnable> runnable;
-    {
-      MutexAutoLock lock(mMutex);
-      if (!mActiveCallbacks.Get(key, getter_AddRefs(runnable))) {
-        return NS_OK;
-      }
+    if (!mActiveCallbacks.Get(key, getter_AddRefs(runnable))) {
+      return NS_OK;
     }
-
-    // Reuse the same thread to save memory.
-    (void) MediaManager::GetThread();
+    mActiveCallbacks.Remove(key);
 
     if (aSubject) {
       // A particular device was chosen by the user.
       // NOTE: does not allow setting a device to null; assumes nullptr
       nsCOMPtr<nsIMediaDevice> device = do_QueryInterface(aSubject);
       if (device) {
         GetUserMediaRunnable* gUMRunnable =
           static_cast<GetUserMediaRunnable*>(runnable.get());
@@ -1014,35 +1000,31 @@ MediaManager::Observe(nsISupports* aSubj
         } else if (type.EqualsLiteral("audio")) {
           gUMRunnable->SetAudioDevice(static_cast<MediaDevice*>(device.get()));
         } else {
           NS_WARNING("Unknown device type in getUserMedia");
         }
       }
     }
 
+    // Reuse the same thread to save memory.
     mMediaThread->Dispatch(runnable, NS_DISPATCH_NORMAL);
-    {
-      MutexAutoLock lock(mMutex);
-      mActiveCallbacks.Remove(key);
-    }
     return NS_OK;
   }
 
   if (!strcmp(aTopic, "getUserMedia:response:deny")) {
     nsString key(aData);
     nsRefPtr<nsRunnable> runnable;
-    {
-      MutexAutoLock lock(mMutex);
-      if (mActiveCallbacks.Get(key, getter_AddRefs(runnable))) {
-        GetUserMediaRunnable* gUMRunnable =
-          static_cast<GetUserMediaRunnable*>(runnable.get());
-        gUMRunnable->Denied();
-        mActiveCallbacks.Remove(key);
-      }
+    if (!mActiveCallbacks.Get(key, getter_AddRefs(runnable))) {
+      return NS_OK;
     }
+    mActiveCallbacks.Remove(key);
+
+    GetUserMediaRunnable* gUMRunnable =
+      static_cast<GetUserMediaRunnable*>(runnable.get());
+    gUMRunnable->Denied();
     return NS_OK;
   }
 
   return NS_OK;
 }
 
 } // namespace mozilla
--- a/dom/media/MediaManager.h
+++ b/dom/media/MediaManager.h
@@ -270,68 +270,75 @@ private:
 
 class MediaManager MOZ_FINAL : public nsIObserver
 {
 public:
   static MediaManager* Get() {
     if (!sSingleton) {
       sSingleton = new MediaManager();
 
+      NS_NewThread(getter_AddRefs(sSingleton->mMediaThread));
+      MM_LOG(("New Media thread for gum"));
+
       NS_ASSERTION(NS_IsMainThread(), "Only create MediaManager on main thread");
       nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
       obs->AddObserver(sSingleton, "xpcom-shutdown", false);
       obs->AddObserver(sSingleton, "getUserMedia:response:allow", false);
       obs->AddObserver(sSingleton, "getUserMedia:response:deny", false);
     }
     return sSingleton;
   }
-  static Mutex& GetMutex() {
-    return Get()->mMutex;
-  }
   static nsIThread* GetThread() {
-    MutexAutoLock lock(Get()->mMutex); // only need to call Get() once
-    if (!sSingleton->mMediaThread) {
-      NS_NewThread(getter_AddRefs(sSingleton->mMediaThread));
-      MM_LOG(("New Media thread for gum"));
-    }
-    return sSingleton->mMediaThread;
+    return Get()->mMediaThread;
   }
 
   NS_DECL_ISUPPORTS
   NS_DECL_NSIOBSERVER
 
   MediaEngine* GetBackend();
-  WindowTable* GetActiveWindows();
+  bool IsWindowStillActive(uint64_t aWindowId) {
+    NS_ASSERTION(NS_IsMainThread(), "Only access windowlist on main thread");
+
+    return !!mActiveWindows.Get(aWindowId);
+  }
 
   nsresult GetUserMedia(bool aPrivileged, nsPIDOMWindow* aWindow,
     nsIMediaStreamOptions* aParams,
     nsIDOMGetUserMediaSuccessCallback* onSuccess,
     nsIDOMGetUserMediaErrorCallback* onError);
   nsresult GetUserMediaDevices(nsPIDOMWindow* aWindow,
     nsIGetUserMediaDevicesSuccessCallback* onSuccess,
     nsIDOMGetUserMediaErrorCallback* onError);
   void OnNavigation(uint64_t aWindowID);
 
 private:
+  WindowTable *GetActiveWindows() {
+    NS_ASSERTION(NS_IsMainThread(), "Only access windowlist on main thread");
+    return &mActiveWindows;
+  };
+
   // Make private because we want only one instance of this class
   MediaManager()
-  : mMutex("mozilla::MediaManager")
-  , mBackend(nullptr)
-  , mMediaThread(nullptr) {
+  : mMediaThread(nullptr)
+  , mMutex("mozilla::MediaManager")
+  , mBackend(nullptr) {
     mActiveWindows.Init();
     mActiveCallbacks.Init();
   };
 
   ~MediaManager() {
     delete mBackend;
   };
 
+  // ONLY access from MainThread so we don't need to lock
+  WindowTable mActiveWindows;
+  nsRefPtrHashtable<nsStringHashKey, nsRunnable> mActiveCallbacks;
+  // Always exists
+  nsCOMPtr<nsIThread> mMediaThread;
+
   Mutex mMutex;
   // protected with mMutex:
   MediaEngine* mBackend;
-  nsCOMPtr<nsIThread> mMediaThread;
-  WindowTable mActiveWindows;
-  nsRefPtrHashtable<nsStringHashKey, nsRunnable> mActiveCallbacks;
 
   static nsRefPtr<MediaManager> sSingleton;
 };
 
 } // namespace mozilla
--- a/media/webrtc/trunk/src/system_wrappers/source/trace_impl.cc
+++ b/media/webrtc/trunk/src/system_wrappers/source/trace_impl.cc
@@ -462,24 +462,24 @@ void TraceImpl::AddMessageToList(
 
     WebRtc_UWord16 idx = _nextFreeIdx[_activeQueue];
     _nextFreeIdx[_activeQueue]++;
 
     _level[_activeQueue][idx] = level;
     _length[_activeQueue][idx] = length;
     memcpy(_messageQueue[_activeQueue][idx], traceMessage, length);
 
-    if(_nextFreeIdx[_activeQueue] == WEBRTC_TRACE_MAX_QUEUE-1)
+    if(_nextFreeIdx[_activeQueue] >= WEBRTC_TRACE_MAX_QUEUE-1)
     {
         // Logging more messages than can be worked off. Log a warning.
         const char warning_msg[] = "WARNING MISSING TRACE MESSAGES\n";
-        _level[_activeQueue][_nextFreeIdx[_activeQueue]] = kTraceWarning;
-        _length[_activeQueue][_nextFreeIdx[_activeQueue]] = strlen(warning_msg);
-        memcpy(_messageQueue[_activeQueue][_nextFreeIdx[_activeQueue]],
-               warning_msg, _length[_activeQueue][idx]);
+        _level[_activeQueue][WEBRTC_TRACE_MAX_QUEUE-1] = kTraceWarning;
+        _length[_activeQueue][WEBRTC_TRACE_MAX_QUEUE-1] = strlen(warning_msg);
+        memcpy(_messageQueue[_activeQueue][WEBRTC_TRACE_MAX_QUEUE-1],
+               warning_msg, _length[_activeQueue][WEBRTC_TRACE_MAX_QUEUE-1]);
         _nextFreeIdx[_activeQueue]++;
     }
 }
 
 bool TraceImpl::Run(void* obj)
 {
     return static_cast<TraceImpl*>(obj)->Process();
 }