Bug 1037754: Query GMPService to determine if H.264 is available r=cpearce
☠☠ backed out by d5be9f365771 ☠ ☠
authorRandell Jesup <rjesup@jesup.org>
Wed, 16 Jul 2014 22:59:17 -0400
changeset 216457 6d976c67e9265b85a9975c762bf01aefc7430712
parent 216456 c752c9ef9596a614ad78dcc337b276d04c7b9cbb
child 216458 20ea2bb7e90db109e4a809bbf111f474e61d4658
push id515
push userraliiev@mozilla.com
push dateMon, 06 Oct 2014 12:51:51 +0000
treeherdermozilla-release@267c7a481bef [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerscpearce
bugs1037754
milestone33.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1037754: Query GMPService to determine if H.264 is available r=cpearce
content/media/gmp/GMPService.cpp
content/media/gmp/GMPService.h
content/media/gmp/mozIGeckoMediaPluginService.idl
media/webrtc/signaling/src/media-conduit/WebrtcGmpVideoCodec.cpp
media/webrtc/signaling/src/media/VcmSIPCCBinding.cpp
media/webrtc/signaling/src/media/VcmSIPCCBinding.h
--- a/content/media/gmp/GMPService.cpp
+++ b/content/media/gmp/GMPService.cpp
@@ -9,16 +9,17 @@
 #include "nsIObserverService.h"
 #include "GeckoChildProcessHost.h"
 #include "mozilla/ClearOnShutdown.h"
 #include "mozilla/SyncRunnable.h"
 #include "nsXPCOMPrivate.h"
 #include "mozilla/Services.h"
 #include "nsNativeCharsetUtils.h"
 #include "nsIConsoleService.h"
+#include "mozilla/unused.h"
 
 namespace mozilla {
 namespace gmp {
 
 static StaticRefPtr<GeckoMediaPluginService> sSingletonService;
 
 class GMPServiceCreateHelper MOZ_FINAL : public nsRunnable
 {
@@ -108,16 +109,20 @@ void
 GeckoMediaPluginService::Init()
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   nsCOMPtr<nsIObserverService> obsService = mozilla::services::GetObserverService();
   MOZ_ASSERT(obsService);
   MOZ_ALWAYS_TRUE(NS_SUCCEEDED(obsService->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false)));
   MOZ_ALWAYS_TRUE(NS_SUCCEEDED(obsService->AddObserver(this, NS_XPCOM_SHUTDOWN_THREADS_OBSERVER_ID, false)));
+
+  // Kick off scanning for plugins
+  nsCOMPtr<nsIThread> thread;
+  unused << GetThread(getter_AddRefs(thread));
 }
 
 NS_IMETHODIMP
 GeckoMediaPluginService::Observe(nsISupports* aSubject,
                                  const char* aTopic,
                                  const char16_t* aSomeData)
 {
   if (!strcmp(NS_XPCOM_SHUTDOWN_OBSERVER_ID, aTopic)) {
@@ -250,16 +255,17 @@ GeckoMediaPluginService::GetGMPVideoEnco
 void
 GeckoMediaPluginService::UnloadPlugins()
 {
   MOZ_ASSERT(NS_GetCurrentThread() == mGMPThread);
 
   MOZ_ASSERT(!mShuttingDownOnGMPThread);
   mShuttingDownOnGMPThread = true;
 
+  MutexAutoLock lock(mMutex);
   for (uint32_t i = 0; i < mPlugins.Length(); i++) {
     mPlugins[i]->UnloadProcess();
   }
   mPlugins.Clear();
 }
 
 void
 GeckoMediaPluginService::LoadFromEnvironment()
@@ -325,23 +331,38 @@ GeckoMediaPluginService::RemovePluginDir
   if (NS_FAILED(rv)) {
     return rv;
   }
   nsCOMPtr<nsIRunnable> r = new PathRunnable(this, aDirectory, false);
   thread->Dispatch(r, NS_DISPATCH_NORMAL);
   return NS_OK;
 }
 
+NS_IMETHODIMP
+GeckoMediaPluginService::HasPluginForAPI(const nsAString& aOrigin,
+                                         const nsACString& aAPI,
+                                         nsTArray<nsCString>* aTags,
+                                         bool* aResult)
+{
+  NS_ENSURE_ARG(aTags && aTags->Length() > 0);
+  NS_ENSURE_ARG(aResult);
+
+  nsCString temp(aAPI);
+  GMPParent *parent = SelectPluginForAPI(aOrigin, temp, *aTags);
+  *aResult = !!parent;
+
+  return NS_OK;
+}
+
 GMPParent*
 GeckoMediaPluginService::SelectPluginForAPI(const nsAString& aOrigin,
                                             const nsCString& aAPI,
                                             const nsTArray<nsCString>& aTags)
 {
-  MOZ_ASSERT(NS_GetCurrentThread() == mGMPThread);
-
+  MutexAutoLock lock(mMutex);
   for (uint32_t i = 0; i < mPlugins.Length(); i++) {
     GMPParent* gmp = mPlugins[i];
     bool supportsAllTags = true;
     for (uint32_t t = 0; t < aTags.Length(); t++) {
       const nsCString& tag = aTags[t];
       if (!gmp->SupportsAPI(aAPI, tag)) {
         supportsAllTags = false;
         break;
@@ -397,30 +418,32 @@ GeckoMediaPluginService::AddOnGMPThread(
   mozilla::SyncRunnable::DispatchToThread(mainThread, task);
   nsRefPtr<GMPParent> gmp = task->GetParent();
   rv = gmp->Init(directory);
   if (NS_FAILED(rv)) {
     NS_WARNING("Can't Create GMPParent");
     return;
   }
 
+  MutexAutoLock lock(mMutex);
   mPlugins.AppendElement(gmp);
 }
 
 void
 GeckoMediaPluginService::RemoveOnGMPThread(const nsAString& aDirectory)
 {
   MOZ_ASSERT(NS_GetCurrentThread() == mGMPThread);
 
   nsCOMPtr<nsIFile> directory;
   nsresult rv = NS_NewLocalFile(aDirectory, false, getter_AddRefs(directory));
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return;
   }
 
+  MutexAutoLock lock(mMutex);
   for (uint32_t i = 0; i < mPlugins.Length(); ++i) {
     nsCOMPtr<nsIFile> pluginpath = mPlugins[i]->GetDirectory();
     bool equals;
     if (NS_SUCCEEDED(directory->Equals(pluginpath, &equals)) && equals) {
       mPlugins[i]->UnloadProcess();
       mPlugins.RemoveElementAt(i);
       return;
     }
--- a/content/media/gmp/GMPService.h
+++ b/content/media/gmp/GMPService.h
@@ -64,18 +64,18 @@ private:
     NS_DECL_NSIRUNNABLE
 
   private:
     nsRefPtr<GeckoMediaPluginService> mService;
     nsString mPath;
     bool mAdd;
   };
 
+  Mutex mMutex; // Protects mGMPThread and mShuttingDown and mPlugins
   nsTArray<nsRefPtr<GMPParent>> mPlugins;
-  Mutex mMutex; // Protects mGMPThread and mShuttingDown
   nsCOMPtr<nsIThread> mGMPThread;
   bool mShuttingDown;
   bool mShuttingDownOnGMPThread;
 };
 
 } // namespace gmp
 } // namespace mozilla
 
--- a/content/media/gmp/mozIGeckoMediaPluginService.idl
+++ b/content/media/gmp/mozIGeckoMediaPluginService.idl
@@ -16,25 +16,34 @@ class GMPVideoHost;
 %}
 
 [ptr] native GMPVideoDecoderProxy(GMPVideoDecoderProxy);
 [ptr] native GMPVideoEncoderProxy(GMPVideoEncoderProxy);
 [ptr] native GMPVideoHost(GMPVideoHost);
 [ptr] native MessageLoop(MessageLoop);
 [ptr] native TagArray(nsTArray<nsCString>);
 
-[scriptable, uuid(7cef50ca-7a0f-41f2-9560-47abf709f0d7)]
+[scriptable, uuid(a9b826da-725a-4b81-814f-b715445188f2)]
 interface mozIGeckoMediaPluginService : nsISupports
 {
   /**
    * The GMP thread. Callable from any thread.
    */
   readonly attribute nsIThread thread;
 
   /**
+   * Get a plugin that supports the specified tags.
+   * Callable on any thread
+   */
+  [noscript]
+  boolean hasPluginForAPI([optional] in AString origin,
+                          in ACString api,
+                          in TagArray tags);
+
+  /**
    * Get a video decoder that supports the specified tags.
    * The array of tags should at least contain a codec tag, and optionally
    * other tags such as for EME keysystem.
    * Callable only on GMP thread.
    */
   [noscript]
   GMPVideoDecoderProxy getGMPVideoDecoder(in TagArray tags,
                                           [optional] in AString origin,
--- a/media/webrtc/signaling/src/media-conduit/WebrtcGmpVideoCodec.cpp
+++ b/media/webrtc/signaling/src/media-conduit/WebrtcGmpVideoCodec.cpp
@@ -141,17 +141,17 @@ int32_t
 WebrtcGmpVideoEncoder::InitEncode_g(const webrtc::VideoCodec* aCodecSettings,
                                     int32_t aNumberOfCores,
                                     uint32_t aMaxPayloadSize)
 {
   GMPVideoHost* host = nullptr;
   GMPVideoEncoderProxy* gmp = nullptr;
 
   nsTArray<nsCString> tags;
-  tags.AppendElement(NS_LITERAL_CSTRING("vp8"));
+  tags.AppendElement(NS_LITERAL_CSTRING("h264"));
   nsresult rv = mMPS->GetGMPVideoEncoder(&tags,
                                          NS_LITERAL_STRING(""),
                                          &host,
                                          &gmp);
   if (NS_FAILED(rv)) {
     return WEBRTC_VIDEO_CODEC_ERROR;
   }
 
@@ -173,17 +173,17 @@ WebrtcGmpVideoEncoder::InitEncode_g(cons
   codec.mMinBitrate = aCodecSettings->minBitrate;
   codec.mMaxBitrate = aCodecSettings->maxBitrate;
   codec.mMaxFramerate = aCodecSettings->maxFramerate;
 
   // Pass dummy codecSpecific data for now...
   nsTArray<uint8_t> codecSpecific;
  
   // H.264 mode 1 only supported so far
-  GMPErr err = mGMP->InitEncode(codec, codecSpecific, this, 1, 256000 /*aMaxPayloadSize*/);
+  GMPErr err = mGMP->InitEncode(codec, codecSpecific, this, 1, 1024*1024 /*aMaxPayloadSize*/);
   if (err != GMPNoErr) {
     return WEBRTC_VIDEO_CODEC_ERROR;
   }
 
   return WEBRTC_VIDEO_CODEC_OK;
 }
 
 
@@ -413,17 +413,17 @@ WebrtcGmpVideoDecoder::InitDecode(const 
 int32_t
 WebrtcGmpVideoDecoder::InitDecode_g(const webrtc::VideoCodec* aCodecSettings,
                                     int32_t aNumberOfCores)
 {
   GMPVideoHost* host = nullptr;
   GMPVideoDecoderProxy* gmp = nullptr;
 
   nsTArray<nsCString> tags;
-  tags.AppendElement(NS_LITERAL_CSTRING("vp8"));
+  tags.AppendElement(NS_LITERAL_CSTRING("h264"));
   if (NS_WARN_IF(NS_FAILED(mMPS->GetGMPVideoDecoder(&tags,
                                                     NS_LITERAL_STRING(""),
                                                     &host,
                                                     &gmp)))) {
     return WEBRTC_VIDEO_CODEC_ERROR;
   }
 
   mGMP = gmp;
--- a/media/webrtc/signaling/src/media/VcmSIPCCBinding.cpp
+++ b/media/webrtc/signaling/src/media/VcmSIPCCBinding.cpp
@@ -84,16 +84,17 @@ typedef enum {
 #define SIPSDP_ILBC_MODE20 20
 
 /* static */
 
 using namespace mozilla;
 using namespace CSF;
 
 VcmSIPCCBinding * VcmSIPCCBinding::gSelf = nullptr;
+bool VcmSIPCCBinding::gInitGmpCodecs = false;
 int VcmSIPCCBinding::gAudioCodecMask = 0;
 int VcmSIPCCBinding::gVideoCodecMask = 0;
 int VcmSIPCCBinding::gVideoCodecGmpMask = 0;
 nsIThread *VcmSIPCCBinding::gMainThread = nullptr;
 nsIEventTarget *VcmSIPCCBinding::gSTSThread = nullptr;
 nsCOMPtr<nsIPrefBranch> VcmSIPCCBinding::gBranch = nullptr;
 
 static mozilla::RefPtr<TransportFlow> vcmCreateTransportFlow(
@@ -223,35 +224,96 @@ void VcmSIPCCBinding::setAudioCodecs(int
 }
 
 void VcmSIPCCBinding::setVideoCodecs(int codecMask)
 {
   CSFLogDebug(logTag, "SETTING VIDEO: %d", codecMask);
   VcmSIPCCBinding::gVideoCodecMask = codecMask;
 }
 
-void VcmSIPCCBinding::addVideoCodecsGmp(int codecMask)
-{
-  CSFLogDebug(logTag, "ADDING VIDEO: %d", codecMask);
-  VcmSIPCCBinding::gVideoCodecGmpMask |= codecMask;
-}
-
 int VcmSIPCCBinding::getAudioCodecs()
 {
   return VcmSIPCCBinding::gAudioCodecMask;
 }
 
 int VcmSIPCCBinding::getVideoCodecs()
 {
   return VcmSIPCCBinding::gVideoCodecMask;
 }
 
+static void GMPDummy() {};
+
+bool VcmSIPCCBinding::scanForGmpCodecs()
+{
+  if (!gSelf) {
+    return false;
+  }
+  if (!gSelf->mGMPService) {
+    gSelf->mGMPService = do_GetService("@mozilla.org/gecko-media-plugin-service;1");
+    if (!gSelf->mGMPService) {
+      return false;
+    }
+  }
+
+  // XXX find a way to a) do this earlier, b) not block mainthread
+  // Perhaps fire on first RTCPeerconnection creation, and block
+  // processing (async) CreateOffer or CreateAnswer's until it has returned.
+  // Since they're already async, it's easy to avoid starting them there.
+  // However, we might like to do it even earlier, perhaps.
+
+  // XXX We shouldn't be blocking MainThread on the GMP thread!
+  // This initiates the scan for codecs
+  nsIThread *thread;
+  nsresult rv = gSelf->mGMPService->GetThread(&thread);
+  if (NS_FAILED(rv)) {
+    return false;
+  }
+  // presumes that all GMP dir scans have been queued for the GMPThread
+  RUN_ON_THREAD(thread,
+                WrapRunnableNM(&GMPDummy),
+                NS_DISPATCH_SYNC);
+  return true;
+}
+
 int VcmSIPCCBinding::getVideoCodecsGmp()
 {
-  return VcmSIPCCBinding::gVideoCodecGmpMask;
+  if (!gInitGmpCodecs) {
+    if (scanForGmpCodecs()) {
+      gInitGmpCodecs = true;
+    }
+  }
+  if (gInitGmpCodecs) {
+    if (!gSelf->mGMPService) {
+     gSelf->mGMPService = do_GetService("@mozilla.org/gecko-media-plugin-service;1");
+    }
+    if (gSelf->mGMPService) {
+      // XXX I'd prefer if this was all known ahead of time...
+
+      nsTArray<nsCString> tags;
+      tags.AppendElement(NS_LITERAL_CSTRING("h264"));
+
+      // H.264 only for now
+      bool has_gmp;
+      nsresult rv;
+      rv = gSelf->mGMPService->HasPluginForAPI(NS_LITERAL_STRING(""),
+                                               NS_LITERAL_CSTRING("encode-video"),
+                                               &tags,
+                                               &has_gmp);
+      if (NS_SUCCEEDED(rv) && has_gmp) {
+        rv = gSelf->mGMPService->HasPluginForAPI(NS_LITERAL_STRING(""),
+                                                 NS_LITERAL_CSTRING("decode-video"),
+                                                 &tags,
+                                                 &has_gmp);
+        if (NS_SUCCEEDED(rv) && has_gmp) {
+          return VCM_CODEC_RESOURCE_H264;
+        }
+      }
+    }
+  }
+  return 0;
 }
 
 int VcmSIPCCBinding::getVideoCodecsHw()
 {
   // Check to see if what HW codecs are available (not in use) at this moment.
   // Note that streaming video decode can reserve a decoder
 
   // XXX See bug 1018791 Implement W3 codec reservation policy
--- a/media/webrtc/signaling/src/media/VcmSIPCCBinding.h
+++ b/media/webrtc/signaling/src/media/VcmSIPCCBinding.h
@@ -6,16 +6,17 @@
 #define _CSF_VCM_SIPCC_BINDING_H_
 
 extern "C"
 {
 #include "ccapi_types.h"
 }
 
 #include "sigslot.h"
+#include "mozIGeckoMediaPluginService.h"
 
 class nsIThread;
 class nsIEventTarget;
 class nsIPrefBranch;
 
 namespace mozilla {
     class NrIceMediaStream;
 };
@@ -27,21 +28,22 @@ namespace CSF
     class AudioControl;
     class VideoControl;
     class MediaProvider;
     class MediaProviderObserver;
 
     class StreamObserver
     {
     public:
-    	virtual void registerStream(cc_call_handle_t call, int streamId, bool isVideo) = 0;
-    	virtual void deregisterStream(cc_call_handle_t call, int streamId) = 0;
-    	virtual void dtmfBurst(int digit, int direction, int duration) = 0;
-    	virtual void sendIFrame(cc_call_handle_t call) = 0;
+    	  virtual void registerStream(cc_call_handle_t call, int streamId, bool isVideo) = 0;
+    	  virtual void deregisterStream(cc_call_handle_t call, int streamId) = 0;
+    	  virtual void dtmfBurst(int digit, int direction, int duration) = 0;
+    	  virtual void sendIFrame(cc_call_handle_t call) = 0;
     };
+
     class VcmSIPCCBinding : public sigslot::has_slots<>
     {
     public:
         VcmSIPCCBinding ();
         virtual ~VcmSIPCCBinding();
 
         // The getter is only for use by the vcm_* impl functions.
         void setStreamObserver(StreamObserver*);
@@ -53,44 +55,46 @@ namespace CSF
         static AudioControl * getAudioControl();
         static VideoControl * getVideoControl();
 
         void setMediaProviderObserver(MediaProviderObserver* obs);
         static MediaProviderObserver * getMediaProviderObserver();
 
         static void setAudioCodecs(int codecMask);
         static void setVideoCodecs(int codecMask);
-        static void addVideoCodecsGmp(int codecMask);
 
         static int getAudioCodecs();
         static int getVideoCodecs();
         static int getVideoCodecsGmp();
         static int getVideoCodecsHw();
 
-	static void setMainThread(nsIThread *thread);
-	static nsIThread *getMainThread();
-	static nsIEventTarget *getSTSThread();
+        static void setMainThread(nsIThread *thread);
+        static nsIThread *getMainThread();
+        static nsIEventTarget *getSTSThread();
 
-	static void setSTSThread(nsIEventTarget *thread);
+        static void setSTSThread(nsIEventTarget *thread);
 
-	static void connectCandidateSignal(mozilla::NrIceMediaStream* stream);
+        static void connectCandidateSignal(mozilla::NrIceMediaStream* stream);
 
         static nsCOMPtr<nsIPrefBranch> getPrefBranch();
 
+        static int gVideoCodecGmpMask;
     private:
-	void CandidateReady(mozilla::NrIceMediaStream* stream,
-			    const std::string& candidate);
+        static bool scanForGmpCodecs();
+        void CandidateReady(mozilla::NrIceMediaStream* stream,
+                            const std::string& candidate);
 
+        nsCOMPtr<mozIGeckoMediaPluginService> mGMPService;
         static VcmSIPCCBinding * gSelf;
         StreamObserver* streamObserver;
         MediaProviderObserver *mediaProviderObserver;
+        static bool gInitGmpCodecs;
         static int gAudioCodecMask;
         static int gVideoCodecMask;
-        static int gVideoCodecGmpMask;
-	static nsIThread *gMainThread;
-	static nsIEventTarget *gSTSThread;
+        static nsIThread *gMainThread;
+        static nsIEventTarget *gSTSThread;
         static nsCOMPtr<nsIPrefBranch> gBranch;
     };
 }
 
 #endif