Beispiel #1
0
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;
}
Beispiel #3
0
/*
** 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();
}
Beispiel #4
0
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;
}