PerDomain_st *Binder_InitDomain(DomainMgr_st *dm_st, dcb_ro_t *rop, dcb_rw_t *rwp, StretchAllocator_clp salloc) { Client_t *bcl; Server_t *bsv; PerDomain_st *bst; IDCStubs_Info stubinfo; /* Allocate bsv, bcl and bst */ bst = ROP_TO_PDS(rop); memset(bst, 0, sizeof(*bst)); bsv = &bst->s; bcl = (Client_t *)&(rwp->binder_rw); TRC (eprintf("Binder_NewDomain: state at %x\n", bst)); #if 0 /* Block until the boot domains are ready */ /* XXX XXX see comment in DomainMgr.c about Intel and ARM */ TRC(eprintf("Dom ID = %qx, boot_regs = %qx\n", rop->id, EC_READ(dm_st->boot_regs))); #ifdef SRCIT #undef DOM_USER #define DOM_USER DOM_SERIAL #endif #ifndef __ALPHA__ EC_AWAIT (dm_st->boot_regs, ((rop->id < DOM_USER) ? rop->id : DOM_USER)&0xffffffff); #else EC_AWAIT (dm_st->boot_regs, (rop->id < DOM_USER) ? rop->id : DOM_USER); #endif #endif /* 0 */ /* Create IDC buffers for the new domain's channel to the binder */ bst->args = STR_NEW_SALLOC(dm_st->sysalloc, FRAME_SIZE); bst->results = STR_NEW_SALLOC(dm_st->sysalloc, FRAME_SIZE); /* Map the stretches. */ SALLOC_SETPROT(dm_st->sysalloc, bst->results, rop->pdid, SET_ELEM(Stretch_Right_Read) ); SALLOC_SETPROT(dm_st->sysalloc, bst->args, rop->pdid, SET_ELEM(Stretch_Right_Read)| SET_ELEM(Stretch_Right_Write)); /* * Next, initialise as much of the Client structure as we can at * this stage, given that we're in the Binder's domain and the * client won't have a threads package anyway. The rest of this * state will be initialised when the client domain calls Bind on * the Binder offer. Compare with lib/nemesis/IDC/ShmTransport.c: * notice that we have to init the state to what the methods in * Shm[Client|Server]Binding_op are expecting. */ stubinfo = NAME_FIND (IDC_CONTEXT">Binder", IDCStubs_Info); TRC(eprintf("Binder_NewDomain: creating Binder client IDC state.\n")); { Binder_clp client_cl = NARROW ((Type_Any *)(&stubinfo->surr), Binder_clp); CL_INIT(bcl->client_cl, (addr_t) client_cl->op, bcl); CL_INIT(bcl->binding_cl, &BinderClientBinding_op, bcl); } ANY_INIT (&bcl->cs.srgt, Binder_clp, &bcl->client_cl); bcl->cs.binding = &bcl->binding_cl; bcl->cs.marshal = dm_st->shmidc; /* The client ShmConnection_t immediately follows the Client_t (aka bcl) in the binder_rw. */ bcl->conn = (ShmConnection_t *)(bcl+1); if(stubinfo->clnt) { /* Let the stubs set up any required run-time state */ IDCClientStubs$InitState(stubinfo->clnt, &bcl->cs); } /* Now setup the client side ShmConnection */ /* XXX Leave mu_init to user */ /* Transmit buffer rec */ bcl->conn->txbuf.base = STR_RANGE(bst->args, &bcl->conn->txsize); bcl->conn->txbuf.ptr = bcl->conn->txbuf.base; bcl->conn->txbuf.space = bcl->conn->txsize; bcl->conn->txbuf.heap = NULL; /* Receive buffer rec */ bcl->conn->rxbuf.base = STR_RANGE(bst->results, &bcl->conn->rxsize); bcl->conn->rxbuf.ptr = bcl->conn->rxbuf.base; bcl->conn->rxbuf.space = bcl->conn->rxsize; bcl->conn->rxbuf.heap = NULL; /* Event counts will be filled in by the domain */ bcl->conn->evs.tx = NULL_EVENT; bcl->conn->evs.rx = NULL_EVENT; /* We can call the new domain's VP interface to get end-points */ bcl->conn->eps.tx = VP$AllocChannel (&rop->vp_cl); bcl->conn->eps.rx = VP$AllocChannel (&rop->vp_cl); bcl->conn->call = 0; bcl->conn->dom = dm_st->dm_dom->id; /* XXX SMH: for some reason we don't know our own pdom. Hoho. */ bcl->conn->pdid = NULL_PDID; /* bcl->offer is not used normally; in BINDER_MUX it is inited below */ /* * Initialise the server idc state. */ /* First we setup the server connection state */ MU_INIT (&bst->sconn.mu); /* XXX - unused; entry SYNC on server */ bst->sconn.txbuf = bcl->conn->rxbuf; bst->sconn.txsize = bst->sconn.txbuf.space; bst->sconn.rxbuf = bcl->conn->txbuf; bst->sconn.rxbuf.heap = Pvs(heap); /* XXX */ bst->sconn.rxsize = bst->sconn.rxbuf.space; bst->sconn.call = 0; bst->sconn.eps.tx = Events$AllocChannel(Pvs(evs)); bst->sconn.eps.rx = Events$AllocChannel(Pvs(evs)); bst->sconn.evs.tx = EC_NEW(); bst->sconn.evs.rx = NULL_EVENT; /* we use "Entry" synch. on server */ bst->sconn.dom = rop->id; bst->sconn.pdid = rop->pdid; #ifdef CONFIG_BINDER_MUX /* Initialise the (de)muxing server. */ TRC(eprintf("Binder_NewDomain: creating Binder MuxIDC server state.\n")); CL_INIT (bst->mux.cntrl_cl, &MuxStubs_ms, &bst->mux); CL_INIT (bst->mux.cntrl_cl, &MuxStubs_ms, &bst->mux); /* We use the connection state we setup above */ bst->mux.conn = &bst->sconn; bst->mux.ss.service = NULL; /* There's no specific service */ bst->mux.ss.binding = &bsv->binding_cl; #endif TRC(eprintf("Binder_NewDomain: creating Binder IDC server state.\n")); bsv->ss.service = &bst->binder; bsv->ss.binding = &bsv->binding_cl; bsv->ss.marshal = dm_st->shmidc; CL_INIT (bsv->cntrl_cl, stubinfo->stub->op, bsv); CL_INIT (bsv->binding_cl, &ShmServerBinding_op, bsv); /* We use (or share!) the connection state we setup above */ bsv->conn = &bst->sconn; /* Hijack offer field for PerDomain_st */ bsv->offer = (Offer_t *) bst; /* XXX PRB Moved this before the Plumber_Connect since otherwise Events$Attach does an ntsc_send causing the new domain to be woken up! */ Events$Attach (Pvs(evs), bsv->conn->evs.tx, bsv->conn->eps.tx, Channel_EPType_TX); /* Connect the event channels */ Plumber$Connect (Plumber, dm_st->dm_dom, rop, bsv->conn->eps.tx, bcl->conn->eps.rx); Plumber$Connect (Plumber, rop, dm_st->dm_dom, bcl->conn->eps.tx, bsv->conn->eps.rx); #ifdef CONFIG_BINDER_MUX /* Register the binder server with the demuxing server */ bcl->offer = (Offer_t *)RegisterServer(&bst->mux, &bsv->cntrl_cl); if(bcl->offer == (Offer_t *)-1) { eprintf("Binder_NewDomain: addition of binder to mux svr failed!\n"); ntsc_halt(); } #endif /* Initialise the rest of the per-domain state */ TRC(eprintf("Binder_NewDomain: creating Binder per-domain state.\n")); bst->rop = rop; bst->rwp = rwp; bst->dm_st = dm_st; /* refCount starts at 1, to allow for the following references to the rop/rwp to be held (update as necessary): 1: the server binding (possibly muxed) */ bst->refCount = 1; bst->callback = NULL; CL_INIT (bst->binder, &binder_ops, bst); /* The offer closure is a special hand crafted one */ CL_INIT (bst->offer_cl, &offer_ops, bcl); rop->binder_offer = &bst->offer_cl; #define panic(format, args...) \ do { eprintf(format, ## args); ntsc_halt(); } while(0) TRC(eprintf("Binder_NewDomain: registering entry.\n")); TRY { #ifdef CONFIG_BINDER_MUX Entry$Bind (Pvs(entry), bst->mux.conn->eps.rx, &(bst->mux.cntrl_cl)); #else Entry$Bind (Pvs(entry), bsv->conn->eps.rx, &bsv->cntrl_cl ); #endif } CATCH_Entry$TooManyChannels() { eprintf("Too many channels registering Binder\n"); } ENDTRY; TRC(eprintf("Binder_NewDomain: done.\n")); return bst; }
nsresult MediaEngineWebRTCMicrophoneSource::UpdateSingleSource( const AllocationHandle* aHandle, const NormalizedConstraints& aNetConstraints, const MediaEnginePrefs& aPrefs, const nsString& aDeviceId, const char** aOutBadConstraint) { FlattenedConstraints c(aNetConstraints); MediaEnginePrefs prefs = aPrefs; prefs.mAecOn = c.mEchoCancellation.Get(prefs.mAecOn); prefs.mAgcOn = c.mAutoGainControl.Get(prefs.mAgcOn); prefs.mNoiseOn = c.mNoiseSuppression.Get(prefs.mNoiseOn); uint32_t maxChannels = 1; if (mAudioInput->GetMaxAvailableChannels(maxChannels) != 0) { return NS_ERROR_FAILURE; } // Check channelCount violation if (static_cast<int32_t>(maxChannels) < c.mChannelCount.mMin || static_cast<int32_t>(maxChannels) > c.mChannelCount.mMax) { *aOutBadConstraint = "channelCount"; return NS_ERROR_FAILURE; } // Clamp channelCount to a valid value if (prefs.mChannels <= 0) { prefs.mChannels = static_cast<int32_t>(maxChannels); } prefs.mChannels = c.mChannelCount.Get(std::min(prefs.mChannels, static_cast<int32_t>(maxChannels))); // Clamp channelCount to a valid value prefs.mChannels = std::max(1, std::min(prefs.mChannels, static_cast<int32_t>(maxChannels))); LOG(("Audio config: aec: %d, agc: %d, noise: %d, delay: %d, channels: %d", prefs.mAecOn ? prefs.mAec : -1, prefs.mAgcOn ? prefs.mAgc : -1, prefs.mNoiseOn ? prefs.mNoise : -1, prefs.mPlayoutDelay, prefs.mChannels)); mPlayoutDelay = prefs.mPlayoutDelay; switch (mState) { case kReleased: MOZ_ASSERT(aHandle); if (sChannelsOpen == 0) { if (!InitEngine()) { LOG(("Audio engine is not initalized")); return NS_ERROR_FAILURE; } } else { // Until we fix (or wallpaper) support for multiple mic input // (Bug 1238038) fail allocation for a second device return NS_ERROR_FAILURE; } if (mAudioInput->SetRecordingDevice(mCapIndex)) { return NS_ERROR_FAILURE; } mAudioInput->SetUserChannelCount(prefs.mChannels); if (!AllocChannel()) { FreeChannel(); LOG(("Audio device is not initalized")); return NS_ERROR_FAILURE; } LOG(("Audio device %d allocated", mCapIndex)); { // Update with the actual applied channelCount in order // to store it in settings. uint32_t channelCount = 0; mAudioInput->GetChannelCount(channelCount); MOZ_ASSERT(channelCount > 0); prefs.mChannels = channelCount; } break; case kStarted: if (prefs == mLastPrefs) { return NS_OK; } if (prefs.mChannels != mLastPrefs.mChannels) { MOZ_ASSERT(mSources.Length() > 0); auto& source = mSources.LastElement(); mAudioInput->SetUserChannelCount(prefs.mChannels); // Get validated number of channel uint32_t channelCount = 0; mAudioInput->GetChannelCount(channelCount); MOZ_ASSERT(channelCount > 0 && mLastPrefs.mChannels > 0); // Check if new validated channels is the same as previous if (static_cast<uint32_t>(mLastPrefs.mChannels) != channelCount && !source->OpenNewAudioCallbackDriver(mListener)) { return NS_ERROR_FAILURE; } // Update settings prefs.mChannels = channelCount; } if (MOZ_LOG_TEST(GetMediaManagerLog(), LogLevel::Debug)) { MonitorAutoLock lock(mMonitor); if (mSources.IsEmpty()) { LOG(("Audio device %d reallocated", mCapIndex)); } else { LOG(("Audio device %d allocated shared", mCapIndex)); } } break; default: LOG(("Audio device %d in ignored state %d", mCapIndex, mState)); break; } if (sChannelsOpen > 0) { int error; error = mVoEProcessing->SetEcStatus(prefs.mAecOn, (webrtc::EcModes)prefs.mAec); if (error) { LOG(("%s Error setting Echo Status: %d ",__FUNCTION__, error)); // Overhead of capturing all the time is very low (<0.1% of an audio only call) if (prefs.mAecOn) { error = mVoEProcessing->SetEcMetricsStatus(true); if (error) { LOG(("%s Error setting Echo Metrics: %d ",__FUNCTION__, error)); } } } error = mVoEProcessing->SetAgcStatus(prefs.mAgcOn, (webrtc::AgcModes)prefs.mAgc); if (error) { LOG(("%s Error setting AGC Status: %d ",__FUNCTION__, error)); } error = mVoEProcessing->SetNsStatus(prefs.mNoiseOn, (webrtc::NsModes)prefs.mNoise); if (error) { LOG(("%s Error setting NoiseSuppression Status: %d ",__FUNCTION__, error)); } } mSkipProcessing = !(prefs.mAecOn || prefs.mAgcOn || prefs.mNoiseOn); if (mSkipProcessing) { mSampleFrequency = MediaEngine::USE_GRAPH_RATE; mAudioOutputObserver = nullptr; } else { // make sure we route a copy of the mixed audio output of this MSG to the // AEC mAudioOutputObserver = new AudioOutputObserver(); } SetLastPrefs(prefs); return NS_OK; }
/* ** The Nemesis domain is special - it gets passed ** only half a comment ** and its Pvs are special. */ void Go(Activation_cl *self, VP_clp vp /* IN */, Activation_Reason ar /* IN */ ) { kernel_st *kst = (kernel_st *)self->st; dcb_rw_t *rwp = vp->st; dcb_ro_t *rop = DCB_RW2RO(rwp); ActivationF_cl *actf; TRY { #ifdef __IX86__ ntsc_entkern(); /* There is an NTSC hack that prevents this from being undone. */ #endif /* __IX86__ */ /* Direct all output from Nemesis domain through NTSC (or, on Alpha, direct to the hardware) */ Pvs(err)=Pvs(out)=Pvs(console)=&triv_wr_cl; TRC(printf("Nemesis domain entered.\n")); TRC(printf(" + DCBRO at %p\n", rop)); TRC(printf(" psmask=%qx\n", rop->psmask)); #ifdef __ALPHA__ TRC(printf(" ps=%qx\n", ntsc_rdps())); #endif TRC(printf(" + DCBRW at %p\n", rwp)); TRC(printf(" + Activation clp at %p\n", self)); TRC(printf(" + VP clp at %p\n", vp)); TRC(printf(" + activationsOn=%d\n", VP$ActivationMode(vp))); TRC(printf(" + Activation Reason %d\n", ar)); TRC(printf(" + PVS = %p\n", PVS())); TRC(DUMP_PVS()); { StretchAllocator_clp salloc; StretchAllocator_SizeSeq *sizes; StretchAllocator_StretchSeq *stretches; ThreadsPackage_Stack protoStack; Stretch_clp userStretch; BootDomain_Info *nem_info; ThreadsPackage_clp tp; ThreadF_clp thdf; #ifdef CONFIG_MEMSYS_EXPT SDriverMod_cl *sdmod; StretchTbl_cl *strtab; #define MAX_DESCS 5 Mem_PMemDesc pmem[MAX_DESCS + 1]; Type_Any fany; flink_t *lk; flist_t *cur; int i = 0; /* Create a new stretch driver (physical one for now) */ TRC(printf("Creating initial stretch driver and stretch tab.\n")); sdmod = NAME_FIND("modules>SDriverMod", SDriverMod_clp); strtab = NAME_FIND("sys>StretchTable", StretchTbl_clp); /* Grab the pmem which has been allocated for us by dmgr */ for(lk = rop->finfo.next; lk != &rop->finfo; lk = lk->next) { cur = (flist_t *)lk; pmem[i].start_addr = cur->base; pmem[i].frame_width = cur->fwidth; pmem[i].nframes = cur->npf >> (cur->fwidth - FRAME_WIDTH); pmem[i].attr = 0; if(++i == MAX_DESCS) break; } pmem[i].nframes = 0; /* terminate array */ ANY_INIT(&fany, Frames_clp, rop->frames); Pvs(sdriver) = SDriverMod$NewPhysical(sdmod, vp, Pvs(heap), strtab, pmem, &fany); #endif /* Add our personal frames closure into the sys context */ /* XXX SDE: I'm not convinced that this is a good idea; the Nemesis domain (and all other domains) should have a bit of private namespace for this. I was bitten once by a domain using the Nemesis domain's Frames closure directly because its own hadn't overridden it in the namespace. */ CX_ADD("sys>Frames", rop->frames, Frames_clp); TRC(eprintf (" + Finding Nemesis StretchAllocator\n")); salloc = NAME_FIND("sys>StretchAllocator", StretchAllocator_clp); TRC(eprintf (" + StretchAlloc = %p\n", salloc)); TRC(eprintf (" + Finding parameters\n")); nem_info= NAME_FIND("progs>Nemesis", BootDomain_InfoP); sizes = SEQ_NEW(StretchAllocator_SizeSeq, 3, Pvs(heap)); SEQ_ELEM(sizes, 0) = FRAME_SIZE; /* for guard page */ SEQ_ELEM(sizes, 1) = nem_info->stackWords*sizeof(word_t); SEQ_ELEM(sizes, 2) = nem_info->pHeapWords*sizeof(word_t); TRC(eprintf (" + Allocating Stretches\n")); stretches = STR_NEWLIST_SALLOC(salloc, sizes); protoStack.guard = SEQ_ELEM(stretches, 0); protoStack.stretch = SEQ_ELEM(stretches, 1); userStretch = SEQ_ELEM(stretches, 2); TRC(eprintf (" + Freeing SEQs\n")); SEQ_FREE(sizes); SEQ_FREE(stretches); #ifdef CONFIG_MEMSYS_EXPT /* Bind and map the stack */ { Stretch_Size sz; addr_t stackva; int npages; TRC(printf("+ Binding and mapping stack.\n")); stackva = STR_RANGE(protoStack.stretch, &sz); npages = sz >> PAGE_WIDTH; while(npages--) { StretchDriver$Map(Pvs(sdriver), protoStack.stretch, stackva); stackva += PAGE_SIZE; } } #endif TRC(printf(" + Setting protection\n")); SALLOC_SETGLOBAL(salloc, protoStack.guard, 0); /* XXX PRB Global write is a bit dodgy to say the least! */ SALLOC_SETGLOBAL(salloc, protoStack.stretch, SET_ELEM(Stretch_Right_Read) | SET_ELEM(Stretch_Right_Write) ); SALLOC_SETGLOBAL(salloc, userStretch, SET_ELEM(Stretch_Right_Read) | SET_ELEM(Stretch_Right_Write) ); TRC(printf(" + Finding ThreadsPackage\n")); tp = NAME_FIND("modules>NonPreemptiveThreads",ThreadsPackage_clp); TRC(printf(" + ThreadsPackage = %p\n", tp)); if(!(thdf = ThreadsPackage$New(tp, (addr_t)&NemesisMainThread, (addr_t)kst, &protoStack, userStretch, nem_info->stackWords*sizeof(word_t), (Pervasives_Init *)PVS(), &actf))) { TRC(printf("Nemesis: can't get threads.\n")); ntsc_halt(); } /* Set ourselves up to handle memory faults */ /* first get/set an event channel for fault notification */ rwp->mm_ep = VP$AllocChannel(Pvs(vp)); #if defined(CONFIG_MEMSYS_STD) || defined(CONFIG_MEMSYS_EXPT) { MMNotifyMod_cl *mmnmod; MMNotify_cl *mmnfy; StretchTbl_clp strtable; #ifdef CONFIG_MEMSYS_EXPT /* get the stretch table */ TRC(eprintf (" + Finding StretchTable\n")); strtable = NAME_FIND("sys>StretchTable", StretchTbl_clp); #else strtable = (StretchTbl_cl *)NULL; #endif mmnmod = NAME_FIND("modules>MMNotifyMod", MMNotifyMod_clp); mmnfy = MMNotifyMod$New(mmnmod, vp, Pvs(heap), strtable); CX_ADD("sys>MMNotify", mmnfy, MMNotify_clp); ActivationF$Attach(actf, (ChannelNotify_cl *)mmnfy, rwp->mm_ep); } #endif /* for non expt, we do all this with a mmentry in main thd */ } TRC(printf(" + yielding to main thread.\n")); VP$ActivationsOn(Pvs(vp)); VP$Yield(Pvs(vp)); } CATCH_Context$NotFound(name) { printf("Caught execption Context$NotFound(%s)\n", name); } CATCH_ALL { printf("Caught exception %s\n", exn_ctx.cur_exception); } ENDTRY; /* XXX we are not happy here; for now, just halt. */ printf("\nNemesis: Much bogosity!!! halting.\n"); ntsc_dbgstop(); }
ALERROR CSoundMgr::LoadWaveFile (HMMIO hFile, int *retiChannel) // LoadWaveFile // // Creates a sound buffer from an open MMIO file { ASSERT(m_pDS); MMCKINFO parent, child; ::ZeroMemory(&parent, sizeof(parent)); ::ZeroMemory(&child, sizeof(child)); // Descend into the RIFF parent.fccType = mmioFOURCC('W', 'A', 'V', 'E'); if (mmioDescend(hFile, &parent, NULL, MMIO_FINDRIFF)) { mmioClose(hFile, 0); return ERR_FAIL; } // Descend to the wave format child.ckid = mmioFOURCC('f', 'm', 't', ' '); if (mmioDescend(hFile, &child, &parent, 0)) { mmioClose(hFile, 0); return ERR_FAIL; } // Allocate a block large enough to hold the format size DWORD dwFmtSize = child.cksize; DWORD dwAllocSize = max(dwFmtSize, sizeof(WAVEFORMATEX)); WAVEFORMATEX *pFormat = (WAVEFORMATEX *)new char [dwAllocSize]; ::ZeroMemory(pFormat, dwAllocSize); if (mmioRead(hFile, (char *)pFormat, dwFmtSize) != (LONG)dwFmtSize) { delete [] (char *)pFormat; mmioClose(hFile, 0); return ERR_FAIL; } // Now descend to the data if (mmioAscend(hFile, &child, 0)) { delete [] (char *)pFormat; mmioClose(hFile, 0); return ERR_FAIL; } child.ckid = mmioFOURCC('d', 'a', 't', 'a'); if (mmioDescend(hFile, &child, &parent, MMIO_FINDCHUNK)) { delete [] (char *)pFormat; mmioClose(hFile, 0); return ERR_FAIL; } DWORD dwDataSize = child.cksize; // Create the DirectSound buffer DSBUFFERDESC dsbdesc; LPDIRECTSOUNDBUFFER pBuffer; ::ZeroMemory(&dsbdesc, sizeof(dsbdesc)); dsbdesc.dwSize = sizeof(dsbdesc); dsbdesc.dwFlags = DSBCAPS_CTRLVOLUME | DSBCAPS_CTRLPAN; dsbdesc.dwBufferBytes = dwDataSize; dsbdesc.lpwfxFormat = pFormat; if (FAILED(m_pDS->CreateSoundBuffer(&dsbdesc, &pBuffer, NULL))) { // If we can't create the sound buffer, try creating the same buffer // but with no volume or pan controls. dsbdesc.dwFlags = 0; if (FAILED(m_pDS->CreateSoundBuffer(&dsbdesc, &pBuffer, NULL))) { delete [] (char *)pFormat; return ERR_FAIL; } } delete [] (char *)pFormat; // Now read into the buffer LPVOID pDest; DWORD dwDestSize; if (FAILED(pBuffer->Lock(0, 0, &pDest, &dwDestSize, NULL, NULL, DSBLOCK_ENTIREBUFFER))) { pBuffer->Release(); mmioClose(hFile, 0); return ERR_FAIL; } if (mmioRead(hFile, (char *)pDest, dwDestSize) != (LONG)dwDataSize) { pBuffer->Release(); mmioClose(hFile, 0); return ERR_FAIL; } // Done with the wave file mmioClose(hFile, 0); // Add to the channel int iChannel = AllocChannel(); SChannel *pChannel = GetChannel(iChannel); pChannel->pBuffer = pBuffer; pChannel->pNext = NULL; // Done if (retiChannel) *retiChannel = iChannel; return NOERROR; }
nsresult MediaEngineWebRTCMicrophoneSource::UpdateSingleSource( const AllocationHandle* aHandle, const NormalizedConstraints& aNetConstraints, const MediaEnginePrefs& aPrefs, const nsString& aDeviceId, const char** aOutBadConstraint) { FlattenedConstraints c(aNetConstraints); MediaEnginePrefs prefs = aPrefs; prefs.mAecOn = c.mEchoCancellation.Get(prefs.mAecOn); prefs.mAgcOn = c.mAutoGainControl.Get(prefs.mAgcOn); prefs.mNoiseOn = c.mNoiseSuppression.Get(prefs.mNoiseOn); LOG(("Audio config: aec: %d, agc: %d, noise: %d, delay: %d", prefs.mAecOn ? prefs.mAec : -1, prefs.mAgcOn ? prefs.mAgc : -1, prefs.mNoiseOn ? prefs.mNoise : -1, prefs.mPlayoutDelay)); mPlayoutDelay = prefs.mPlayoutDelay; switch (mState) { case kReleased: MOZ_ASSERT(aHandle); if (sChannelsOpen == 0) { if (!InitEngine()) { LOG(("Audio engine is not initalized")); return NS_ERROR_FAILURE; } } else { // Until we fix (or wallpaper) support for multiple mic input // (Bug 1238038) fail allocation for a second device return NS_ERROR_FAILURE; } if (!AllocChannel()) { LOG(("Audio device is not initalized")); return NS_ERROR_FAILURE; } if (mAudioInput->SetRecordingDevice(mCapIndex)) { FreeChannel(); return NS_ERROR_FAILURE; } LOG(("Audio device %d allocated", mCapIndex)); break; case kStarted: if (prefs == mLastPrefs) { return NS_OK; } if (MOZ_LOG_TEST(GetMediaManagerLog(), LogLevel::Debug)) { MonitorAutoLock lock(mMonitor); if (mSources.IsEmpty()) { LOG(("Audio device %d reallocated", mCapIndex)); } else { LOG(("Audio device %d allocated shared", mCapIndex)); } } break; default: LOG(("Audio device %d in ignored state %d", mCapIndex, mState)); break; } if (sChannelsOpen > 0) { int error; error = mVoEProcessing->SetEcStatus(prefs.mAecOn, (webrtc::EcModes)prefs.mAec); if (error) { LOG(("%s Error setting Echo Status: %d ",__FUNCTION__, error)); // Overhead of capturing all the time is very low (<0.1% of an audio only call) if (prefs.mAecOn) { error = mVoEProcessing->SetEcMetricsStatus(true); if (error) { LOG(("%s Error setting Echo Metrics: %d ",__FUNCTION__, error)); } } } error = mVoEProcessing->SetAgcStatus(prefs.mAgcOn, (webrtc::AgcModes)prefs.mAgc); if (error) { LOG(("%s Error setting AGC Status: %d ",__FUNCTION__, error)); } error = mVoEProcessing->SetNsStatus(prefs.mNoiseOn, (webrtc::NsModes)prefs.mNoise); if (error) { LOG(("%s Error setting NoiseSuppression Status: %d ",__FUNCTION__, error)); } } mSkipProcessing = !(prefs.mAecOn || prefs.mAgcOn || prefs.mNoiseOn); if (mSkipProcessing) { mSampleFrequency = MediaEngine::USE_GRAPH_RATE; } SetLastPrefs(prefs); return NS_OK; }