зеркало из https://github.com/mozilla/gecko-dev.git
Bug 991037 - Part 0: Stop sync waiting until GMP is ready, since this happens on main now and will deadlock. r=mt
This commit is contained in:
Родитель
b6553fb9e5
Коммит
f038acb4d1
|
@ -239,75 +239,43 @@ 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
|
||||
nsCOMPtr<nsIThread> thread;
|
||||
nsresult rv = gSelf->mGMPService->GetThread(getter_AddRefs(thread));
|
||||
if (NS_FAILED(rv)) {
|
||||
return false;
|
||||
}
|
||||
// presumes that all GMP dir scans have been queued for the GMPThread
|
||||
mozilla::SyncRunnable::DispatchToThread(thread,
|
||||
WrapRunnableNM(&GMPDummy));
|
||||
return true;
|
||||
}
|
||||
|
||||
int VcmSIPCCBinding::getVideoCodecsGmp()
|
||||
{
|
||||
if (!gInitGmpCodecs) {
|
||||
if (scanForGmpCodecs()) {
|
||||
gInitGmpCodecs = true;
|
||||
}
|
||||
// This code assumes that GMP has been initted, specifically
|
||||
// by PeerConnectionCtx::initGMP()
|
||||
if (!gSelf->mGMPService) {
|
||||
gSelf->mGMPService = do_GetService("@mozilla.org/gecko-media-plugin-service;1");
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!gSelf->mGMPService) {
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
|
||||
// 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_FAILED(rv) || !has_gmp) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
rv = gSelf->mGMPService->HasPluginForAPI(NS_LITERAL_STRING(""),
|
||||
NS_LITERAL_CSTRING("decode-video"),
|
||||
&tags,
|
||||
&has_gmp);
|
||||
if (NS_FAILED(rv) || !has_gmp) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return VCM_CODEC_RESOURCE_H264;
|
||||
}
|
||||
|
||||
int VcmSIPCCBinding::getVideoCodecsHw()
|
||||
|
|
|
@ -78,7 +78,6 @@ namespace CSF
|
|||
|
||||
static int gVideoCodecGmpMask;
|
||||
private:
|
||||
static bool scanForGmpCodecs();
|
||||
void CandidateReady(mozilla::NrIceMediaStream* stream,
|
||||
const std::string& candidate);
|
||||
|
||||
|
|
|
@ -280,7 +280,7 @@ FreeOnMain_m(nsAutoPtr<RTCStatsQueries> aQueryList) {
|
|||
static void
|
||||
EverySecondTelemetryCallback_s(nsAutoPtr<RTCStatsQueries> aQueryList) {
|
||||
using namespace Telemetry;
|
||||
|
||||
|
||||
if(!PeerConnectionCtx::isActive()) {
|
||||
return;
|
||||
}
|
||||
|
@ -391,6 +391,8 @@ PeerConnectionCtx::EverySecondTelemetryCallback_m(nsITimer* timer, void *closure
|
|||
#endif
|
||||
|
||||
nsresult PeerConnectionCtx::Initialize() {
|
||||
initGMP();
|
||||
|
||||
mCCM = CSF::CallControlManager::create();
|
||||
|
||||
NS_ENSURE_TRUE(mCCM.get(), NS_ERROR_FAILURE);
|
||||
|
@ -465,9 +467,49 @@ nsresult PeerConnectionCtx::Initialize() {
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
static void GMPReady_m() {
|
||||
if (PeerConnectionCtx::isActive()) {
|
||||
PeerConnectionCtx::GetInstance()->onGMPReady();
|
||||
}
|
||||
};
|
||||
|
||||
static void GMPReady() {
|
||||
PeerConnectionCtx::gMainThread->Dispatch(WrapRunnableNM(&GMPReady_m),
|
||||
NS_DISPATCH_NORMAL);
|
||||
};
|
||||
|
||||
void PeerConnectionCtx::initGMP()
|
||||
{
|
||||
mGMPService = do_GetService("@mozilla.org/gecko-media-plugin-service;1");
|
||||
|
||||
if (!mGMPService) {
|
||||
CSFLogError(logTag, "%s failed to get the gecko-media-plugin-service",
|
||||
__FUNCTION__);
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIThread> thread;
|
||||
nsresult rv = mGMPService->GetThread(getter_AddRefs(thread));
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
mGMPService = nullptr;
|
||||
CSFLogError(logTag,
|
||||
"%s failed to get the gecko-media-plugin thread, err=%u",
|
||||
__FUNCTION__,
|
||||
static_cast<unsigned>(rv));
|
||||
return;
|
||||
}
|
||||
|
||||
// presumes that all GMP dir scans have been queued for the GMPThread
|
||||
thread->Dispatch(WrapRunnableNM(&GMPReady), NS_DISPATCH_NORMAL);
|
||||
}
|
||||
|
||||
nsresult PeerConnectionCtx::Cleanup() {
|
||||
CSFLogDebug(logTag, "%s", __FUNCTION__);
|
||||
|
||||
mQueuedJSEPOperations.Clear();
|
||||
mGMPService = nullptr;
|
||||
|
||||
mCCM->destroy();
|
||||
mCCM->removeCCObserver(this);
|
||||
return NS_OK;
|
||||
|
@ -487,6 +529,18 @@ CSF::CC_CallPtr PeerConnectionCtx::createCall() {
|
|||
return mDevice->createCall();
|
||||
}
|
||||
|
||||
void PeerConnectionCtx::queueJSEPOperation(nsRefPtr<nsIRunnable> aOperation) {
|
||||
mQueuedJSEPOperations.AppendElement(aOperation);
|
||||
}
|
||||
|
||||
void PeerConnectionCtx::onGMPReady() {
|
||||
mGMPReady = true;
|
||||
for (size_t i = 0; i < mQueuedJSEPOperations.Length(); ++i) {
|
||||
mQueuedJSEPOperations[i]->Run();
|
||||
}
|
||||
mQueuedJSEPOperations.Clear();
|
||||
}
|
||||
|
||||
void PeerConnectionCtx::onDeviceEvent(ccapi_device_event_e aDeviceEvent,
|
||||
CSF::CC_DevicePtr aDevice,
|
||||
CSF::CC_DeviceInfoPtr aInfo ) {
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
|
||||
#include "StaticPtr.h"
|
||||
#include "PeerConnectionImpl.h"
|
||||
#include "mozIGeckoMediaPluginService.h"
|
||||
|
||||
namespace mozilla {
|
||||
class PeerConnectionCtxShutdown;
|
||||
|
@ -75,6 +76,17 @@ class PeerConnectionCtx : public CSF::CC_Observer {
|
|||
|
||||
mozilla::dom::PCImplSipccState sipcc_state() { return mSipccState; }
|
||||
|
||||
bool isReady() {
|
||||
// If mGMPService is not set, we aren't using GMP.
|
||||
if (mGMPService) {
|
||||
return mGMPReady;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void queueJSEPOperation(nsRefPtr<nsIRunnable> aJSEPOperation);
|
||||
void onGMPReady();
|
||||
|
||||
// Make these classes friend so that they can access mPeerconnections.
|
||||
friend class PeerConnectionImpl;
|
||||
friend class PeerConnectionWrapper;
|
||||
|
@ -92,7 +104,7 @@ class PeerConnectionCtx : public CSF::CC_Observer {
|
|||
std::map<const std::string, PeerConnectionImpl *> mPeerConnections;
|
||||
|
||||
PeerConnectionCtx() : mSipccState(mozilla::dom::PCImplSipccState::Idle),
|
||||
mCCM(nullptr), mDevice(nullptr) {}
|
||||
mCCM(nullptr), mDevice(nullptr), mGMPReady(false) {}
|
||||
// This is a singleton, so don't copy construct it, etc.
|
||||
PeerConnectionCtx(const PeerConnectionCtx& other) MOZ_DELETE;
|
||||
void operator=(const PeerConnectionCtx& other) MOZ_DELETE;
|
||||
|
@ -105,6 +117,8 @@ class PeerConnectionCtx : public CSF::CC_Observer {
|
|||
mSipccState = aState;
|
||||
}
|
||||
|
||||
void initGMP();
|
||||
|
||||
static void
|
||||
EverySecondTelemetryCallback_m(nsITimer* timer, void *);
|
||||
|
||||
|
@ -113,6 +127,7 @@ class PeerConnectionCtx : public CSF::CC_Observer {
|
|||
int mConnectionCounter;
|
||||
|
||||
nsCOMPtr<nsITimer> mTelemetryTimer;
|
||||
|
||||
public:
|
||||
// TODO(jib): If we ever enable move semantics on std::map...
|
||||
//std::map<nsString,nsAutoPtr<mozilla::dom::RTCStatsReportInternal>> mLastReports;
|
||||
|
@ -125,6 +140,15 @@ private:
|
|||
CSF::CallControlManagerPtr mCCM;
|
||||
CSF::CC_DevicePtr mDevice;
|
||||
|
||||
// We cannot form offers/answers properly until the Gecko Media Plugin stuff
|
||||
// has been initted, which is a complicated mess of thread dispatches,
|
||||
// including sync dispatches to main. So, we need to be able to queue up
|
||||
// offer creation (or SetRemote, when we're the answerer) until all of this is
|
||||
// ready to go, since blocking on this init is just begging for deadlock.
|
||||
nsCOMPtr<mozIGeckoMediaPluginService> mGMPService;
|
||||
bool mGMPReady;
|
||||
nsTArray<nsRefPtr<nsIRunnable>> mQueuedJSEPOperations;
|
||||
|
||||
static PeerConnectionCtx *gInstance;
|
||||
public:
|
||||
static nsIThread *gMainThread;
|
||||
|
|
|
@ -1218,7 +1218,18 @@ PeerConnectionImpl::CreateOffer(const SipccOfferOptions& aOptions)
|
|||
|
||||
cc_media_options_t* cc_options = aOptions.build();
|
||||
NS_ENSURE_TRUE(cc_options, NS_ERROR_UNEXPECTED);
|
||||
mInternal->mCall->createOffer(cc_options, tc);
|
||||
|
||||
if (!PeerConnectionCtx::GetInstance()->isReady()) {
|
||||
// Uh oh. We're not ready yet. Enqueue this operation.
|
||||
PeerConnectionCtx::GetInstance()->queueJSEPOperation(
|
||||
WrapRunnable(mInternal->mCall,
|
||||
&CSF::CC_Call::createOffer,
|
||||
cc_options,
|
||||
tc));
|
||||
} else {
|
||||
mInternal->mCall->createOffer(cc_options, tc);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -1275,8 +1286,21 @@ PeerConnectionImpl::SetRemoteDescription(int32_t action, const char* aSDP)
|
|||
STAMP_TIMECARD(tc, "Set Remote Description");
|
||||
|
||||
mRemoteRequestedSDP = aSDP;
|
||||
mInternal->mCall->setRemoteDescription((cc_jsep_action_t)action,
|
||||
mRemoteRequestedSDP, tc);
|
||||
|
||||
if (!PeerConnectionCtx::GetInstance()->isReady()) {
|
||||
// Uh oh. We're not ready yet. Enqueue this operation. (This must be a
|
||||
// remote offer, or else we would not have gotten this far)
|
||||
PeerConnectionCtx::GetInstance()->queueJSEPOperation(
|
||||
WrapRunnable(mInternal->mCall,
|
||||
&CSF::CC_Call::setRemoteDescription,
|
||||
(cc_jsep_action_t)action,
|
||||
mRemoteRequestedSDP,
|
||||
tc));
|
||||
} else {
|
||||
mInternal->mCall->setRemoteDescription((cc_jsep_action_t)action,
|
||||
mRemoteRequestedSDP, tc);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче