source: svn/newcon3bcm2_21bu/nexus/modules/audio/7552/src/nexus_audio_input.c

Last change on this file was 76, checked in by megakiss, 10 years ago

1W 대기전력을 만족시키기 위하여 POWEROFF시 튜너를 Standby 상태로 함

  • Property svn:executable set to *
File size: 75.7 KB
Line 
1/***************************************************************************
2*     (c)2004-2011 Broadcom Corporation
3*
4*  This program is the proprietary software of Broadcom Corporation and/or its licensors,
5*  and may only be used, duplicated, modified or distributed pursuant to the terms and
6*  conditions of a separate, written license agreement executed between you and Broadcom
7*  (an "Authorized License").  Except as set forth in an Authorized License, Broadcom grants
8*  no license (express or implied), right to use, or waiver of any kind with respect to the
9*  Software, and Broadcom expressly reserves all rights in and to the Software and all
10*  intellectual property rights therein.  IF YOU HAVE NO AUTHORIZED LICENSE, THEN YOU
11*  HAVE NO RIGHT TO USE THIS SOFTWARE IN ANY WAY, AND SHOULD IMMEDIATELY
12*  NOTIFY BROADCOM AND DISCONTINUE ALL USE OF THE SOFTWARE.
13*
14*  Except as expressly set forth in the Authorized License,
15*
16*  1.     This program, including its structure, sequence and organization, constitutes the valuable trade
17*  secrets of Broadcom, and you shall use all reasonable efforts to protect the confidentiality thereof,
18*  and to use this information only in connection with your use of Broadcom integrated circuit products.
19*
20*  2.     TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS"
21*  AND WITH ALL FAULTS AND BROADCOM MAKES NO PROMISES, REPRESENTATIONS OR
22*  WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, WITH RESPECT TO
23*  THE SOFTWARE.  BROADCOM SPECIFICALLY DISCLAIMS ANY AND ALL IMPLIED WARRANTIES
24*  OF TITLE, MERCHANTABILITY, NONINFRINGEMENT, FITNESS FOR A PARTICULAR PURPOSE,
25*  LACK OF VIRUSES, ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET POSSESSION
26*  OR CORRESPONDENCE TO DESCRIPTION. YOU ASSUME THE ENTIRE RISK ARISING OUT OF
27*  USE OR PERFORMANCE OF THE SOFTWARE.
28*
29*  3.     TO THE MAXIMUM EXTENT PERMITTED BY LAW, IN NO EVENT SHALL BROADCOM OR ITS
30*  LICENSORS BE LIABLE FOR (i) CONSEQUENTIAL, INCIDENTAL, SPECIAL, INDIRECT, OR
31*  EXEMPLARY DAMAGES WHATSOEVER ARISING OUT OF OR IN ANY WAY RELATING TO YOUR
32*  USE OF OR INABILITY TO USE THE SOFTWARE EVEN IF BROADCOM HAS BEEN ADVISED OF
33*  THE POSSIBILITY OF SUCH DAMAGES; OR (ii) ANY AMOUNT IN EXCESS OF THE AMOUNT
34*  ACTUALLY PAID FOR THE SOFTWARE ITSELF OR U.S. $1, WHICHEVER IS GREATER. THESE
35*  LIMITATIONS SHALL APPLY NOTWITHSTANDING ANY FAILURE OF ESSENTIAL PURPOSE OF
36*  ANY LIMITED REMEDY.
37*
38* $brcm_Workfile: nexus_audio_input.c $
39* $brcm_Revision: 28 $
40* $brcm_Date: 10/14/11 3:36p $
41*
42* API Description:
43*   API name: AudioInput
44*   Generic API for audio filter graph management
45*
46* Revision History:
47*
48* $brcm_Log: /nexus/modules/audio/7422/src/nexus_audio_input.c $
49*
50* 28   10/14/11 3:36p jgarrett
51* SW7425-1388: Coverity CID 33925,33926,33927,33928
52*
53* 27   10/11/11 4:46p jgarrett
54* SW7425-1349: Adding AudioDummyOutput
55*
56* 26   9/16/11 11:44a jgarrett
57* SWDTV-8673: Adding input running check for AnalogAudioDecoder
58*
59* 25   9/15/11 3:26p jgarrett
60* SWDTV-8673: Not attempting to change mixers or equalizer stages if a
61*  node is already started
62*
63* 24   9/8/11 8:45a jgarrett
64* SWDTV-6627: Adding nexus EQ support
65*
66* 23   8/26/11 12:03p jgarrett
67* SW7425-742: Merge to main branch
68*
69* SW7425-724/1   8/24/11 11:55a jgarrett
70* SW7425-724: Adding RF Audio Encoder
71*
72* 22   8/18/11 5:51p jgarrett
73* SWDTV-6306: Merge DTV APE changes to main branch
74*
75* Nexus_APE_Integration/1   8/11/11 6:26p jgarrett
76* SWDTV-6306: Adding SPDIF Input
77*
78* 21   8/9/11 9:35a jgarrett
79* SWDTV-6761: Stubbing out studio sound for STB chips
80*
81* 20   8/8/11 5:38p jgarrett
82* SWDTV-6761: Adding StudioSound
83*
84* 19   6/28/11 10:33a jgarrett
85* SW7422-406: Adding input volume settings for DSP mixers
86*
87* 18   6/16/11 6:02p jgarrett
88* SW7425-437: Breaking downstream connections properly if source node is
89*  shutdown while connected
90*
91* 17   6/5/11 6:57p jgarrett
92* SW7425-406: Initial FW mixer implemenation on APE
93*
94* 16   5/25/11 5:16p jgarrett
95* SW7425-408: Adding BDBG_OBJECT to input/output types and MS11 features
96*
97* 15   5/16/11 5:19p jgarrett
98* SWDTV-6762: Adding Audyssey ADV/ABX
99*
100* 14   5/16/11 4:57p jgarrett
101* SWDTV-6763: Adding 3D Surround
102*
103* 13   5/13/11 6:32p jgarrett
104* SW7425-410: Adding AVL
105*
106* 12   5/13/11 3:46p jgarrett
107* SW7425-552: Additional sample rate master fix for post-processing
108*
109* 11   5/12/11 9:50a jgarrett
110* SW7422-410: Adding custom voice auto shutdown
111*
112* 10   5/9/11 10:41a jgarrett
113* SW7425-552: Fixing sample rate master when post-processing is used.
114*
115* 9   4/26/11 4:23p jgarrett
116* SW7425-437: Not allowing dead nodes in the filter graph
117*
118* 8   4/26/11 11:35a jgarrett
119* SW7425-437: Resolving kernel mode shutdown issues
120*
121* 7   3/24/11 9:47a jgarrett
122* SW7422-352: Removing warnings on systems without HDMI input
123*
124* 6   3/23/11 6:28p jgarrett
125* SW7422-352: adding HDMI input support to nexus
126*
127* 5   3/22/11 2:35p jgarrett
128* SW7422-356: Fixing crash on mux stop
129*
130* 4   3/21/11 7:05p jgarrett
131* SW7422-356: Adding MuxOutput support in APE/Nexus
132*
133* 3   2/28/11 2:58p jgarrett
134* SW7422-146: Added input capture to I2sInput
135*
136* 2   2/22/11 5:44p jgarrett
137* SW7422-146: Implemented type renaming based on filter graph review
138*  comments
139*
140* 1   12/17/10 3:56p jgarrett
141* SW7422-146: Adding initial nexus on APE for 7422
142*
143***************************************************************************/
144
145#include "nexus_audio_module.h"
146#include "blst_queue.h"
147#include "blst_slist.h"
148#include "priv/nexus_audio_decoder_priv.h"
149
150BDBG_MODULE(nexus_audio_input);
151
152#if NEXUS_NUM_HDMI_INPUTS > 0
153#if NEXUS_NUM_HDMI_INPUTS > 1
154#error TODO: Support more than one HDMI Input
155#endif
156static BAPE_MaiInputHandle g_maiInput;
157#endif
158
159typedef enum NEXUS_AudioOutputTiming
160{
161    NEXUS_AudioOutputTiming_eFlexible,
162    NEXUS_AudioOutputTiming_eDac,
163    NEXUS_AudioOutputTiming_ePll,
164    NEXUS_AudioOutputTiming_eMax
165} NEXUS_AudioOutputTiming;
166
167typedef struct NEXUS_AudioInputMixerNode
168{
169    BAPE_MixerHandle inputMixer, outputMixer, eqMixer;
170    BAPE_MixerSettings settings;
171    NEXUS_AudioEqualizerHandle nexusEq;
172    BAPE_EqualizerHandle apeEq;
173    unsigned usageCount;
174    unsigned mixerIndex;
175    NEXUS_AudioOutputTiming timing;
176    unsigned dacTimingCount;
177    unsigned pllTimingCount;
178    unsigned flexTimingCount;
179    BLST_Q_ENTRY(NEXUS_AudioInputMixerNode) mixerNode;
180} NEXUS_AudioInputMixerNode;
181
182typedef struct NEXUS_AudioOutputNode
183{
184    NEXUS_AudioOutputObject *pOutputConnector;
185    NEXUS_AudioInputMixerNode *pMixerNode;          /* Copy of mixer this was added to */
186    BLST_Q_ENTRY(NEXUS_AudioOutputNode) outputNode;
187} NEXUS_AudioOutputNode;
188
189typedef struct NEXUS_AudioDownstreamNode
190{
191    NEXUS_AudioInputObject *pDownstreamObject;
192    BLST_Q_ENTRY(NEXUS_AudioDownstreamNode) downstreamNode;
193} NEXUS_AudioDownstreamNode;
194
195typedef struct NEXUS_AudioUpstreamNode
196{
197    void *pConnectionData;
198    size_t connectionDataSize;
199    NEXUS_AudioInputObject *pUpstreamObject;
200    BLST_Q_ENTRY(NEXUS_AudioUpstreamNode) upstreamNode;
201} NEXUS_AudioUpstreamNode;
202
203BDBG_OBJECT_ID(NEXUS_AudioInputData);
204
205typedef struct NEXUS_AudioInputData
206{
207    BDBG_OBJECT(NEXUS_AudioInputData)
208    NEXUS_AudioInputObject *pConnector;
209    BLST_Q_HEAD(UpstreamList, NEXUS_AudioUpstreamNode) upstreamList;       /* List of inputs to this node.  NEXUS_AudioUpstreamNodes will be in this list */
210    BLST_Q_HEAD(DownstreamList, NEXUS_AudioDownstreamNode) downstreamList; /* List of downstream objects connected to this node.
211                                                                              AudioDownstreamNodes will be in this list */
212    BLST_Q_HEAD(OutputList, NEXUS_AudioOutputNode) outputList;             /* One input can contain one or more outputs */
213    BLST_Q_HEAD(MixerList, NEXUS_AudioInputMixerNode) mixerList;
214
215    BAPE_MixerInputVolume inputVolume;
216} NEXUS_AudioInputData;
217
218static void NEXUS_AudioInput_P_ForceStopUpstream(NEXUS_AudioInput input);
219static void NEXUS_AudioInput_P_ForceStopDownstream(NEXUS_AudioInput input);
220static bool NEXUS_AudioInput_P_IsRunningUpstream(NEXUS_AudioInput input);
221static bool NEXUS_AudioInput_P_IsRunningDownstream(NEXUS_AudioInput input);
222static void NEXUS_AudioInput_P_UnlinkOutputPort(NEXUS_AudioInput input, NEXUS_AudioOutputNode *pOutputNode);
223static NEXUS_Error NEXUS_AudioInput_P_CheckOutputMixer(NEXUS_AudioInput input, NEXUS_AudioOutputNode *pOutputNode);
224static NEXUS_Error NEXUS_AudioInput_P_CheckOutputMixers(NEXUS_AudioInput input);
225static NEXUS_AudioOutputTiming NEXUS_AudioInput_P_GetOutputTiming(NEXUS_AudioOutput output);
226
227static NEXUS_AudioOutputTiming NEXUS_AudioInput_P_GetOutputTiming(NEXUS_AudioOutput output)
228{
229    BDBG_OBJECT_ASSERT(output, NEXUS_AudioOutput);
230    switch ( output->objectType )
231    {
232    case NEXUS_AudioOutputType_eArc:
233    case NEXUS_AudioOutputType_eSpdif:
234    case NEXUS_AudioOutputType_eI2s:
235        return NEXUS_AudioOutputTiming_ePll;
236    case NEXUS_AudioOutputType_eHdmi:
237    case NEXUS_AudioOutputType_eCapture:
238    case NEXUS_AudioOutputType_eDummy:
239        return NEXUS_AudioOutputTiming_eFlexible;
240    case NEXUS_AudioOutputType_eDac:
241    case NEXUS_AudioOutputType_eRfm:
242        return NEXUS_AudioOutputTiming_eDac;
243    default:
244        BDBG_ASSERT(("Output timing not known for output type %u", output->objectType));
245        BDBG_ASSERT(0);
246        return NEXUS_AudioOutputTiming_eMax;
247    }
248}
249
250bool NEXUS_AudioInput_P_IsRunning(NEXUS_AudioInput input)
251{
252    BDBG_OBJECT_ASSERT(input, NEXUS_AudioInput);
253    if ( NEXUS_AudioInput_P_IsRunningUpstream(input) ||
254         NEXUS_AudioInput_P_IsRunningDownstream(input) )
255    {
256        return true;
257    }
258    return false;
259}
260
261static bool NEXUS_AudioInput_P_IsRunningUpstream(NEXUS_AudioInput input)
262{
263    NEXUS_AudioUpstreamNode *pNode;
264    NEXUS_AudioInputData *pData;
265    bool running = false;
266
267    BDBG_OBJECT_ASSERT(input, NEXUS_AudioInput);
268
269    BDBG_MSG(("NEXUS_AudioInput_P_IsRunning(%p)", input));
270
271    pData = input->pMixerData;
272
273    /* Can't be running if not connected */
274    if ( NULL == pData )
275    {
276        BDBG_MSG(("No data - not running"));
277        return false;
278    }
279    BDBG_OBJECT_ASSERT(pData, NEXUS_AudioInputData);
280
281    switch ( input->objectType )
282    {
283#if NEXUS_NUM_AUDIO_DECODERS
284    case NEXUS_AudioInputType_eDecoder:
285        BDBG_MSG(("Decoder type - checking run status"));
286        running = NEXUS_AudioDecoder_P_IsRunning(input->pObjectHandle);
287        break;
288#endif
289#if NEXUS_NUM_AUDIO_PLAYBACKS
290    case NEXUS_AudioInputType_ePlayback:
291        BDBG_MSG(("Playback type - checking run status"));
292        running = NEXUS_AudioPlayback_P_IsRunning(input->pObjectHandle);
293        break;
294#endif
295#if NEXUS_NUM_I2S_INPUTS
296    case NEXUS_AudioInputType_eI2s:
297        BDBG_MSG(("I2sInput type - checking run status"));
298        running = NEXUS_I2sInput_P_IsRunning(input->pObjectHandle);
299        break;
300#endif
301#if NEXUS_NUM_RF_AUDIO_DECODERS
302    case NEXUS_AudioInputType_eRfDecoder:
303        BDBG_MSG(("RF Audio Decoder type - checking run status"));
304        running = NEXUS_RfAudioDecoder_P_IsRunning(input->pObjectHandle);
305        break;
306#endif
307#if NEXUS_NUM_ANALOG_AUDIO_DECODERS
308    case NEXUS_AudioInputType_eAnalogDecoder:
309        BDBG_MSG(("Analog Decoder type - checking run status"));
310        running = NEXUS_AnalogAudioDecoder_P_IsRunning(input->pObjectHandle);
311        break;         
312#endif
313    default:
314        /* Recurse if not a decoder type, stop if any input is running - that means we are also */
315        BDBG_MSG(("other type - recursively checking run status"));
316        pNode = BLST_Q_FIRST(&pData->upstreamList);
317        while ( NULL != pNode && false == running )
318        {
319            running = running || NEXUS_AudioInput_P_IsRunningUpstream(pNode->pUpstreamObject);
320            pNode = BLST_Q_NEXT(pNode, upstreamNode);
321        }
322        break;
323    }
324
325    BDBG_MSG(("Returning running status %d", running));
326    return running;
327}
328
329static bool NEXUS_AudioInput_P_IsRunningDownstream(NEXUS_AudioInput input)
330{
331    NEXUS_AudioDownstreamNode *pNode;
332    NEXUS_AudioInputData *pData;
333    bool running = false;
334
335    BDBG_OBJECT_ASSERT(input, NEXUS_AudioInput);
336
337    BDBG_MSG(("NEXUS_AudioInput_P_IsRunning(%p)", input));
338
339    pData = input->pMixerData;
340
341    /* Can't be running if not connected */
342    if ( NULL == pData )
343    {
344        BDBG_MSG(("No data - not running"));
345        return false;
346    }
347    BDBG_OBJECT_ASSERT(pData, NEXUS_AudioInputData);
348
349    switch ( input->objectType )
350    {
351#if NEXUS_NUM_AUDIO_DECODERS
352    case NEXUS_AudioInputType_eDecoder:
353        BDBG_MSG(("Decoder type - checking run status"));
354        running = NEXUS_AudioDecoder_P_IsRunning(input->pObjectHandle);
355        break;
356#endif
357#if NEXUS_NUM_AUDIO_PLAYBACKS
358    case NEXUS_AudioInputType_ePlayback:
359        BDBG_MSG(("Playback type - checking run status"));
360        running = NEXUS_AudioPlayback_P_IsRunning(input->pObjectHandle);
361        break;
362#endif
363#if NEXUS_NUM_I2S_INPUTS
364    case NEXUS_AudioInputType_eI2s:
365        BDBG_MSG(("I2sInput type - checking run status"));
366        running = NEXUS_I2sInput_P_IsRunning(input->pObjectHandle);
367        break;
368#endif
369#if NEXUS_NUM_RF_AUDIO_DECODERS
370    case NEXUS_AudioInputType_eRfDecoder:
371        BDBG_MSG(("RF Audio Decoder type - checking run status"));
372        running = NEXUS_RfAudioDecoder_P_IsRunning(input->pObjectHandle);
373        break;
374#endif
375    default:
376        break;
377    }
378
379    if ( !running )
380    {
381        /* Recurse  */
382        BDBG_MSG(("recursively checking run status"));
383        pNode = BLST_Q_FIRST(&pData->downstreamList);
384        while ( NULL != pNode && false == running )
385        {
386            running = running || NEXUS_AudioInput_P_IsRunningDownstream(pNode->pDownstreamObject);
387            pNode = BLST_Q_NEXT(pNode, downstreamNode);
388        }
389    }
390
391    BDBG_MSG(("Returning running status %d", running));
392    return running;
393}
394
395NEXUS_AudioInputFormat NEXUS_AudioInput_P_GetFormat(NEXUS_AudioInput input)
396{
397    NEXUS_AudioUpstreamNode *pNode;
398    NEXUS_AudioInputFormat format;
399    NEXUS_AudioInputData *pData;
400
401    BDBG_OBJECT_ASSERT(input, NEXUS_AudioInput);
402
403    BDBG_MSG(("NEXUS_AudioInput_P_GetFormat(%p)", input));
404
405    /* If input format is set at this node, return it.  Otherwise, recurse up, taking the maximum number of channels. */
406    if ( input->format == NEXUS_AudioInputFormat_eNone )
407    {
408        pData = input->pMixerData;
409
410        /* Can't do anything if not connected */
411        if ( NULL == pData )
412        {
413            return NEXUS_AudioInputFormat_eNone;
414        }
415        BDBG_OBJECT_ASSERT(pData, NEXUS_AudioInputData);
416
417        format = NEXUS_AudioInputFormat_eNone;
418
419        pNode = BLST_Q_FIRST(&pData->upstreamList);
420        while ( NULL != pNode )
421        {
422            NEXUS_AudioInputFormat newFormat;
423
424            newFormat = NEXUS_AudioInput_P_GetFormat(pNode->pUpstreamObject);
425
426            if ( newFormat > format )
427            {
428                format = newFormat;
429            }
430
431            pNode = BLST_Q_NEXT(pNode, upstreamNode);
432        }
433    }
434    else
435    {
436        format = input->format;
437    }
438
439    return format;
440}
441
442static NEXUS_AudioInputData *NEXUS_AudioInput_P_CreateData(NEXUS_AudioInput input)
443{
444    NEXUS_AudioInputData *pData;
445
446    BDBG_OBJECT_ASSERT(input, NEXUS_AudioInput);
447
448    BDBG_MSG(("Creating connection data for input %p", input));
449
450    pData = BKNI_Malloc(sizeof(NEXUS_AudioInputData));
451    if ( NULL != pData )
452    {
453        int i, j;
454        BDBG_OBJECT_SET(pData, NEXUS_AudioInputData);
455        input->pMixerData = pData;
456        pData->pConnector = input;
457        BLST_Q_INIT(&pData->upstreamList);
458        BLST_Q_INIT(&pData->downstreamList);
459        BLST_Q_INIT(&pData->outputList);
460        BLST_Q_INIT(&pData->mixerList);
461
462        for ( i = 0; i < BAPE_Channel_eMax; i++ )
463        {
464            for ( j = 0; j < BAPE_Channel_eMax; j++ )
465            {
466                pData->inputVolume.coefficients[i][j] = (i==j)?BAPE_VOLUME_NORMAL:BAPE_VOLUME_MIN;
467            }
468        }
469        pData->inputVolume.muted = false;
470    }
471
472    return pData;
473}
474
475NEXUS_Error NEXUS_AudioInput_P_AddInput(NEXUS_AudioInput destination, NEXUS_AudioInput source)
476{
477    NEXUS_AudioInputData *pDestinationData, *pSourceData;
478    NEXUS_AudioDownstreamNode *pDownstream;
479    NEXUS_AudioUpstreamNode *pUpstream;
480    NEXUS_Error errCode;
481    BAPE_MixerAddInputSettings addInputSettings;
482
483    BDBG_OBJECT_ASSERT(destination, NEXUS_AudioInput);
484    BDBG_OBJECT_ASSERT(source, NEXUS_AudioInput);
485
486    BDBG_MSG(("NEXUS_AudioInput_P_AddInput(%p,%p)", destination, source));
487
488    BAPE_Mixer_GetDefaultAddInputSettings(&addInputSettings);
489
490    /* On 7440/3563/7405+ architectures, inputs must be stopped for this to proceed. */
491    if ( NEXUS_AudioInput_P_IsRunning(destination) )
492    {
493        BDBG_ERR(("Can not add inputs to a node while it's running."));
494        return BERR_TRACE(BERR_NOT_SUPPORTED);
495    }
496    if ( NEXUS_AudioInput_P_IsRunning(source) )
497    {
498        BDBG_ERR(("Can not add running inputs to a node."));
499        return BERR_TRACE(BERR_NOT_SUPPORTED);
500    }
501    if ( (source->objectType == NEXUS_AudioInputType_eHdmi ||
502          source->objectType == NEXUS_AudioInputType_eSpdif) &&
503         destination->objectType != NEXUS_AudioInputType_eDecoder )
504    {
505        BDBG_ERR(("Can only connect SPDIF or HDMI Input to a decoder"));
506        return BERR_TRACE(BERR_NOT_SUPPORTED);
507    }
508
509    /* Other sanity checks are done by caller, they differ per-type */
510    pDestinationData = destination->pMixerData;
511    if ( NULL == pDestinationData )
512    {
513        /* Must allocate data on the first connection */
514        pDestinationData = NEXUS_AudioInput_P_CreateData(destination);
515    }
516    BDBG_OBJECT_ASSERT(pDestinationData, NEXUS_AudioInputData);
517
518    pSourceData = source->pMixerData;
519    if ( NULL == pSourceData )
520    {
521        /* Must allocate data on the first connection */
522        pSourceData = NEXUS_AudioInput_P_CreateData(source);
523    }
524    BDBG_OBJECT_ASSERT(pSourceData, NEXUS_AudioInputData);
525
526    pDownstream = BKNI_Malloc(sizeof(NEXUS_AudioDownstreamNode));
527    if ( NULL == pDownstream )
528    {
529        return BERR_TRACE(NEXUS_OUT_OF_SYSTEM_MEMORY);
530    }
531
532    pUpstream = BKNI_Malloc(sizeof(NEXUS_AudioUpstreamNode));
533    if ( NULL == pUpstream )
534    {
535        BKNI_Free(pDownstream);
536        return BERR_TRACE(NEXUS_OUT_OF_SYSTEM_MEMORY);
537    }
538
539    pDownstream->pDownstreamObject = destination;
540    pUpstream->pUpstreamObject = source;
541    pUpstream->pConnectionData = NULL;
542    pUpstream->connectionDataSize = 0;
543
544    /* Link source -> APE mixer if required */
545    if ( destination->objectType == NEXUS_AudioInputType_eMixer )
546    {
547        NEXUS_AudioInputMixerNode *pMixerNode;
548        NEXUS_AudioMixerSettings mixerSettings;
549
550        NEXUS_AudioMixer_GetSettings(destination->pObjectHandle, &mixerSettings);
551
552        for ( pMixerNode = BLST_Q_FIRST(&pDestinationData->mixerList);
553              pMixerNode != NULL;
554              pMixerNode = BLST_Q_NEXT(pMixerNode, mixerNode) )
555        {
556            if ( NULL == mixerSettings.master )
557            {
558                addInputSettings.sampleRateMaster = (source->objectType == NEXUS_AudioInputType_ePlayback)?false:true;
559            }
560            else
561            {
562                addInputSettings.sampleRateMaster = (source == mixerSettings.master) ? true : false;
563            }
564            errCode = BAPE_Mixer_AddInput(pMixerNode->inputMixer, (BAPE_Connector)source->port, &addInputSettings);
565            if ( errCode )
566            {
567                BKNI_Free(pDownstream);
568                BKNI_Free(pUpstream);
569                return BERR_TRACE(errCode);
570            }
571        }
572    }
573
574    /* Create connection from source -> destination */
575    BLST_Q_INSERT_TAIL(&pSourceData->downstreamList, pDownstream, downstreamNode);
576    /* Create reverse-linkage for destination -> source */
577    BLST_Q_INSERT_TAIL(&pDestinationData->upstreamList, pUpstream, upstreamNode);
578
579    /* Done */
580    return BERR_SUCCESS;
581}
582
583NEXUS_Error NEXUS_AudioInput_P_RemoveAllInputs(NEXUS_AudioInput destination)
584{
585    NEXUS_Error errCode;
586    NEXUS_AudioUpstreamNode *pNode;
587    NEXUS_AudioInputData *pDestinationData;
588
589    BDBG_MSG(("NEXUS_AudioInput_P_RemoveAllInputs(%p)", destination));
590
591    pDestinationData = destination->pMixerData;
592
593    if ( NULL != pDestinationData )
594    {
595        BDBG_OBJECT_ASSERT(pDestinationData, NEXUS_AudioInputData);
596        while ( NULL != (pNode=BLST_Q_FIRST(&pDestinationData->upstreamList)) )
597        {
598            errCode = NEXUS_AudioInput_P_RemoveInput(destination, pNode->pUpstreamObject);
599            if ( errCode )
600            {
601                return BERR_TRACE(errCode);
602            }
603        }
604    }
605    return BERR_SUCCESS;
606}
607
608NEXUS_Error NEXUS_AudioInput_P_RemoveInput(NEXUS_AudioInput destination, NEXUS_AudioInput source)
609{
610    NEXUS_AudioUpstreamNode *pUpstreamNode;
611    NEXUS_AudioDownstreamNode *pDownstreamNode;
612    NEXUS_AudioInputData *pDestinationData;
613    NEXUS_AudioInputData *pSourceData;
614
615    BDBG_MSG(("NEXUS_AudioInput_P_RemoveInput(%p,%p)", destination, source));
616
617    pDestinationData = destination->pMixerData;
618    BDBG_OBJECT_ASSERT(pDestinationData, NEXUS_AudioInputData);    /* It's impossible for this to be NULL in a valid config. */
619
620    /* On 7440/3563/7405+ architectures, inputs must be stopped for this to proceed. */
621    if ( NEXUS_AudioInput_P_IsRunning(destination) )
622    {
623        BDBG_ERR(("Can not remove inputs from a node while it's running."));
624        return BERR_TRACE(BERR_NOT_SUPPORTED);
625    }
626
627    BDBG_MSG(("Unlink upstream link"));
628
629    if ( destination->objectType == NEXUS_AudioInputType_eMixer )
630    {
631        NEXUS_AudioInputMixerNode *pMixerNode;
632        for ( pMixerNode = BLST_Q_FIRST(&pDestinationData->mixerList);
633              pMixerNode != NULL;
634              pMixerNode = BLST_Q_NEXT(pMixerNode, mixerNode) )
635        {
636            BAPE_Mixer_RemoveInput(pMixerNode->inputMixer, (BAPE_Connector)source->port);
637        }
638    }
639
640    /* TODO: Unlink post-processing */
641
642    /* Unlink upstream link */
643    pUpstreamNode = BLST_Q_FIRST(&pDestinationData->upstreamList);
644    while ( NULL != pUpstreamNode && pUpstreamNode->pUpstreamObject != source )
645    {
646        pUpstreamNode = BLST_Q_NEXT(pUpstreamNode, upstreamNode);
647    }
648    /* We had better find a node or the list is broken */
649    if ( NULL == pUpstreamNode)
650    {
651        BDBG_ASSERT(NULL != pUpstreamNode);
652        return BERR_TRACE(NEXUS_UNKNOWN);
653    }
654    BDBG_ASSERT(pUpstreamNode->pUpstreamObject == source);
655    BLST_Q_REMOVE(&pDestinationData->upstreamList, pUpstreamNode, upstreamNode);
656    BDBG_MSG(("Free connection data"));
657    /* Free up connection-specific data if set */
658    if ( NULL != pUpstreamNode->pConnectionData )
659    {
660        BDBG_MSG(("Connection data exists -- freeing"));
661        BKNI_Free(pUpstreamNode->pConnectionData);
662        pUpstreamNode->pConnectionData = NULL;
663        pUpstreamNode->connectionDataSize = 0;
664    }
665    BDBG_MSG(("Freeing upstream node"));
666    BKNI_Free(pUpstreamNode);
667
668    pSourceData = source->pMixerData;
669    BDBG_OBJECT_ASSERT(pSourceData, NEXUS_AudioInputData);
670
671    BDBG_MSG(("Free downstream data"));
672    pDownstreamNode = BLST_Q_FIRST(&pSourceData->downstreamList);
673    while ( NULL != pDownstreamNode && pDownstreamNode->pDownstreamObject != destination )
674    {
675        pDownstreamNode = BLST_Q_NEXT(pDownstreamNode, downstreamNode);
676    }
677    /* We had better find a node or the list is broken */
678    if ( NULL == pDownstreamNode )
679    {
680        BDBG_ASSERT(NULL != pDownstreamNode);
681        return BERR_TRACE(NEXUS_UNKNOWN);
682    }
683    BDBG_ASSERT(pDownstreamNode->pDownstreamObject == destination);
684    BLST_Q_REMOVE(&pSourceData->downstreamList, pDownstreamNode, downstreamNode);
685    BKNI_Free(pDownstreamNode);
686
687    return BERR_SUCCESS;
688}
689
690bool NEXUS_AudioInput_P_IsConnected(NEXUS_AudioInput destination, NEXUS_AudioInput source)
691{
692    NEXUS_AudioUpstreamNode *pUpstreamNode;
693    NEXUS_AudioInputData *pDestinationData;
694    NEXUS_AudioInputData *pSourceData;
695
696    BDBG_OBJECT_ASSERT(destination, NEXUS_AudioInput);
697    BDBG_OBJECT_ASSERT(source, NEXUS_AudioInput);
698
699    BDBG_MSG(("NEXUS_AudioInput_P_IsConnected(%p,%p)", destination, source));
700
701    pDestinationData = destination->pMixerData;
702    pSourceData = source->pMixerData;
703
704    /* No possible connection if data is absent for either object */
705    if ( NULL == destination->pMixerData || NULL == source->pMixerData )
706    {
707        return false;
708    }
709    BDBG_OBJECT_ASSERT(pDestinationData, NEXUS_AudioInputData);
710    BDBG_OBJECT_ASSERT(pSourceData, NEXUS_AudioInputData);
711
712    /* Check for destination->source link */
713    pUpstreamNode = BLST_Q_FIRST(&pDestinationData->upstreamList);
714    while ( NULL != pUpstreamNode && pUpstreamNode->pUpstreamObject != source )
715    {
716        pUpstreamNode = BLST_Q_NEXT(pUpstreamNode, upstreamNode);
717    }
718
719    return (NULL == pUpstreamNode) ? false : true;
720}
721
722static NEXUS_Error NEXUS_AudioInput_P_IterateOutputs(NEXUS_AudioInput input, NEXUS_AudioOutputList *pOutputList, int *pIndex, bool scanMixers)
723{
724    int i;
725    NEXUS_AudioOutputNode *pOutputNode;
726    NEXUS_AudioDownstreamNode *pDownstreamNode;
727    NEXUS_AudioInputData *pData;
728    NEXUS_Error errCode = BERR_SUCCESS;
729
730    BDBG_OBJECT_ASSERT(input, NEXUS_AudioInput);
731    BDBG_ASSERT(NULL != pOutputList);
732    BDBG_ASSERT(NULL != pIndex);
733
734    BDBG_MSG(("NEXUS_AudioInput_P_IterateOutputs(%p)", input));
735
736    /* First, iterate through any outputs directly attached to this object */
737    i = *pIndex;
738    pData = input->pMixerData;
739    BDBG_MSG(("Scanning node %p for outputs", input));
740    if ( NULL == pData || i >= NEXUS_AUDIO_MAX_OUTPUTS )
741    {
742        if ( NULL == pData )
743        {
744            BDBG_MSG(("No connection data at node %p", input));
745        }
746        else
747        {
748            BDBG_MSG(("Output list full at node %p", input));
749        }
750        goto done;
751    }
752    pOutputNode = BLST_Q_FIRST(&pData->outputList);
753    while ( NULL != pOutputNode && i < NEXUS_AUDIO_MAX_OUTPUTS )
754    {
755        BDBG_ASSERT(NULL != pOutputNode->pOutputConnector);
756        pOutputList->outputs[i++] = pOutputNode->pOutputConnector;
757        BDBG_MSG(("Found output %p at node %p", pOutputNode->pOutputConnector, input));
758        pOutputNode = BLST_Q_NEXT(pOutputNode, outputNode);
759    }
760
761    /* Now recurse through all downstream connections */
762    pDownstreamNode = BLST_Q_FIRST(&pData->downstreamList);
763    while ( NULL != pDownstreamNode && i < NEXUS_AUDIO_MAX_OUTPUTS )
764    {
765        if ( (pDownstreamNode->pDownstreamObject->objectType != NEXUS_AudioInputType_eMixer) ||
766             true == scanMixers )
767        {
768            BDBG_MSG(("Recursing into downstream node %p", pDownstreamNode->pDownstreamObject));
769            errCode = NEXUS_AudioInput_P_IterateOutputs(pDownstreamNode->pDownstreamObject, pOutputList, &i, scanMixers);
770            if ( errCode )
771            {
772                errCode = BERR_TRACE(errCode);
773                goto done;
774            }
775        }
776        else
777        {
778            BDBG_MSG(("Skipping downstream mixer %p", pDownstreamNode->pDownstreamObject));
779        }
780        pDownstreamNode = BLST_Q_NEXT(pDownstreamNode, downstreamNode);
781    }
782
783done:
784    *pIndex = i;
785    return errCode;
786}
787
788NEXUS_Error NEXUS_AudioInput_P_GetOutputs(NEXUS_AudioInput input, NEXUS_AudioOutputList *pOutputList, bool directOnly)
789{
790    int i=0;
791
792    BDBG_OBJECT_ASSERT(input, NEXUS_AudioInput);
793    BDBG_ASSERT(NULL != pOutputList);
794
795    BDBG_MSG(("NEXUS_AudioInput_P_GetOutputs(%p)", input));
796
797    /* Invalidate list on first call */
798    BKNI_Memset(pOutputList, 0, sizeof(NEXUS_AudioOutputList));
799
800    return NEXUS_AudioInput_P_IterateOutputs(input, pOutputList, &i, !directOnly);
801}
802
803NEXUS_Error NEXUS_AudioInput_P_SetConnectionData(NEXUS_AudioInput destination, NEXUS_AudioInput source, const void *pData, size_t dataSize)
804{
805    NEXUS_AudioInputData *pInputData;
806    NEXUS_AudioUpstreamNode *pUpstreamNode;
807
808    BDBG_OBJECT_ASSERT(destination, NEXUS_AudioInput);
809    BDBG_OBJECT_ASSERT(source, NEXUS_AudioInput);
810    BDBG_ASSERT(NULL != pData);
811    BDBG_ASSERT(dataSize > 0);
812
813    pInputData = destination->pMixerData;
814    BDBG_OBJECT_ASSERT(pInputData, NEXUS_AudioInputData);
815
816    pUpstreamNode = BLST_Q_FIRST(&pInputData->upstreamList);
817    while ( NULL != pUpstreamNode && pUpstreamNode->pUpstreamObject != source )
818    {
819        pUpstreamNode = BLST_Q_NEXT(pUpstreamNode, upstreamNode);
820    }
821    if ( NULL == pUpstreamNode )
822    {
823        BDBG_ASSERT(NULL != pUpstreamNode);
824        return BERR_TRACE(NEXUS_UNKNOWN);
825    }
826
827    if ( NULL != pUpstreamNode->pConnectionData && dataSize != pUpstreamNode->connectionDataSize )
828    {
829        /* Odd request.  Size has changed?  Handle it anyway */
830        BKNI_Free(pUpstreamNode->pConnectionData);
831        pUpstreamNode->connectionDataSize = 0;
832        pUpstreamNode->pConnectionData = NULL;
833    }
834
835    if ( NULL == pUpstreamNode->pConnectionData )
836    {
837        /* Malloc the data */
838        pUpstreamNode->pConnectionData = BKNI_Malloc(dataSize);
839        if ( NULL == pUpstreamNode->pConnectionData )
840        {
841            return BERR_OUT_OF_SYSTEM_MEMORY;
842        }
843        pUpstreamNode->connectionDataSize = dataSize;
844    }
845
846    BDBG_ASSERT(NULL != pUpstreamNode->pConnectionData);
847
848    /* Copy data */
849    BKNI_Memcpy(pUpstreamNode->pConnectionData, pData, dataSize);
850
851    return BERR_SUCCESS;
852}
853
854const void *NEXUS_AudioInput_P_GetConnectionData(NEXUS_AudioInput destination, NEXUS_AudioInput source)
855{
856    NEXUS_AudioInputData *pInputData;
857    NEXUS_AudioUpstreamNode *pUpstreamNode;
858    NEXUS_Error rc=0;
859
860    BDBG_OBJECT_ASSERT(destination, NEXUS_AudioInput);
861    BDBG_OBJECT_ASSERT(source, NEXUS_AudioInput);
862
863    pInputData = destination->pMixerData;
864    BDBG_OBJECT_ASSERT(pInputData, NEXUS_AudioInputData);
865
866    pUpstreamNode = BLST_Q_FIRST(&pInputData->upstreamList);
867    while ( NULL != pUpstreamNode && pUpstreamNode->pUpstreamObject != source )
868    {
869        pUpstreamNode = BLST_Q_NEXT(pUpstreamNode, upstreamNode);
870    }
871    if ( NULL == pUpstreamNode )
872    {
873        BDBG_ASSERT(NULL != pUpstreamNode);
874        rc=BERR_TRACE(NEXUS_UNKNOWN);
875        return NULL;
876    }
877
878    return pUpstreamNode->pConnectionData;  /* Return connection data pointer - may be NULL if never set */
879}
880
881NEXUS_Error NEXUS_AudioInput_P_ConnectOutput(NEXUS_AudioInput input, NEXUS_AudioOutput output)
882{
883    NEXUS_AudioInputData *pInputData;
884    NEXUS_AudioOutputNode *pNode;
885    NEXUS_Error errCode;
886
887    BDBG_OBJECT_ASSERT(input, NEXUS_AudioInput);
888    BDBG_OBJECT_ASSERT(output, NEXUS_AudioOutput);
889
890    pInputData = input->pMixerData;
891
892    /* SPDIF and HDMI are special cases.  HDMI accepts no outputs, SPDIF
893       can be connected either to a decoder or a SPDIF output as bypass */
894    if ( input->objectType == NEXUS_AudioInputType_eHdmi || input->objectType == NEXUS_AudioInputType_eSpdif )
895    {
896        BDBG_ERR(("Can not directly connect outputs to SPDIF or HDMI Input.  Please connect to a decoder for use."));
897        return BERR_TRACE(BERR_NOT_SUPPORTED);
898    }
899
900    BDBG_MSG(("Connecting output %p to input %p", output, input));
901
902    if ( NULL == pInputData )
903    {
904        pInputData = NEXUS_AudioInput_P_CreateData(input);
905        if ( NULL == pInputData )
906        {
907            return BERR_TRACE(BERR_OUT_OF_SYSTEM_MEMORY);
908        }
909    }
910    BDBG_OBJECT_ASSERT(pInputData, NEXUS_AudioInputData);
911
912#if NEXUS_HAS_AUDIO_MUX_OUTPUT
913    if ( output->objectType == NEXUS_AudioOutputType_eMux )
914    {
915        errCode = NEXUS_AudioMuxOutput_P_AddInput(output->pObjectHandle, input);
916        if ( errCode )
917        {
918            return BERR_TRACE(errCode);
919        }
920    }
921#endif
922
923    pNode = BKNI_Malloc(sizeof(NEXUS_AudioOutputNode));
924    if ( NULL == pNode )
925    {
926        errCode = BERR_TRACE(BERR_OUT_OF_SYSTEM_MEMORY);
927        goto err_malloc;
928    }
929
930    pNode->pOutputConnector = output;
931    pNode->pMixerNode = NULL;
932    BLST_Q_INSERT_TAIL(&pInputData->outputList, pNode, outputNode);
933
934    return BERR_SUCCESS;
935
936err_malloc:
937#if NEXUS_HAS_AUDIO_MUX_OUTPUT
938    if ( output->objectType == NEXUS_AudioOutputType_eMux )
939    {
940        NEXUS_AudioMuxOutput_P_RemoveInput(output->pObjectHandle, input);
941    }   
942#endif
943    return errCode;
944}
945
946NEXUS_Error NEXUS_AudioInput_P_DisconnectOutput(NEXUS_AudioInput input, NEXUS_AudioOutput output)
947{
948    NEXUS_AudioInputData *pInputData;
949    NEXUS_AudioOutputNode *pNode;
950
951    BDBG_OBJECT_ASSERT(input, NEXUS_AudioInput);
952    BDBG_OBJECT_ASSERT(output, NEXUS_AudioOutput);
953
954    pInputData = input->pMixerData;
955    BDBG_OBJECT_ASSERT(pInputData, NEXUS_AudioInputData);    /* Illegal for this to be NULL with connections */
956
957    pNode = BLST_Q_FIRST(&pInputData->outputList);
958    while ( NULL != pNode && pNode->pOutputConnector != output )
959    {
960        pNode = BLST_Q_NEXT(pNode, outputNode);
961    }
962    if ( NULL == pNode)
963    {
964        return BERR_TRACE(NEXUS_UNKNOWN);
965    }
966
967    /* Clear DAC slave selection if required. */
968    if ( NEXUS_AudioOutput_P_IsDacSlave(pNode->pOutputConnector) ||
969         NEXUS_AudioOutput_P_IsSpdifSlave(pNode->pOutputConnector) )
970    {
971        NEXUS_AudioOutput_P_SetSlaveSource(pNode->pOutputConnector, NULL);
972    }
973
974    /*
975       If a DAC is removed, the slave source will be re-evaluated at next start call
976       (During CheckOutputMixer).  No need to check that here.
977    */
978
979#if NEXUS_HAS_AUDIO_MUX_OUTPUT
980    if ( output->objectType == NEXUS_AudioOutputType_eMux )
981    {
982        NEXUS_AudioMuxOutput_P_RemoveInput(output->pObjectHandle, input);
983    }   
984    else
985#endif
986    {
987        NEXUS_AudioInput_P_UnlinkOutputPort(input, pNode);
988    }
989
990    BLST_Q_REMOVE(&pInputData->outputList, pNode, outputNode);
991
992    BKNI_Memset(pNode, 0, sizeof(*pNode));
993    BKNI_Free(pNode);
994
995    return BERR_SUCCESS;
996}
997
998void NEXUS_AudioInput_Shutdown(
999    NEXUS_AudioInput input
1000    )
1001{
1002    NEXUS_AudioInputData *pInputData;
1003    NEXUS_AudioOutputNode *pNode;
1004    NEXUS_AudioDownstreamNode *pDownstreamNode;
1005    NEXUS_Error rc;
1006
1007    BDBG_OBJECT_ASSERT(input, NEXUS_AudioInput);
1008
1009    BDBG_MSG(("Shutting down connector %p", input));
1010
1011    pInputData = input->pMixerData;
1012
1013    if ( NEXUS_AudioInput_P_IsRunning(input) )
1014    {
1015        BDBG_WRN(("Forcibly stopping inputs to input %p on shutdown", input));
1016        NEXUS_AudioInput_P_ForceStop(input);
1017    }
1018
1019    if ( NULL != pInputData )
1020    {
1021        BDBG_OBJECT_ASSERT(pInputData, NEXUS_AudioInputData);
1022        /* Break object connections */
1023        switch ( input->objectType )
1024        {
1025        default:
1026            break;
1027#if NEXUS_CVOICE
1028        case NEXUS_AudioInputType_eCustomVoice:
1029            NEXUS_CustomVoice_RemoveAllInputs(input->pObjectHandle);
1030            break;
1031#endif
1032        case NEXUS_AudioInputType_eEncoder:
1033            NEXUS_AudioEncoder_RemoveAllInputs(input->pObjectHandle);
1034            break;
1035        case NEXUS_AudioInputType_eRfEncoder:
1036            NEXUS_RfAudioEncoder_RemoveAllInputs(input->pObjectHandle);
1037            break;
1038        case NEXUS_AudioInputType_eTruSurroundXt:
1039            NEXUS_TruSurroundXt_RemoveAllInputs(input->pObjectHandle);
1040            break;
1041        case NEXUS_AudioInputType_eTruSurroundHd:
1042            NEXUS_TruSurroundHd_RemoveAllInputs(input->pObjectHandle);
1043            break;
1044        case NEXUS_AudioInputType_eTruVolume:
1045            NEXUS_TruVolume_RemoveAllInputs(input->pObjectHandle);
1046            break;
1047        case NEXUS_AudioInputType_eDolbyDigitalReencode:
1048            NEXUS_DolbyDigitalReencode_RemoveAllInputs(input->pObjectHandle);
1049            break;
1050        case NEXUS_AudioInputType_eDolbyVolume:
1051            NEXUS_DolbyVolume_RemoveAllInputs(input->pObjectHandle);
1052            break;
1053        case NEXUS_AudioInputType_eDolbyVolume258:
1054            NEXUS_DolbyVolume258_RemoveAllInputs(input->pObjectHandle);
1055            break;
1056        case NEXUS_AudioInputType_eMixer:
1057        case NEXUS_AudioInputType_eDspMixer:
1058            NEXUS_AudioMixer_RemoveAllInputs(input->pObjectHandle);
1059            break;
1060        case NEXUS_AudioInputType_eAutoVolumeLevel:
1061            NEXUS_AutoVolumeLevel_RemoveAllInputs(input->pObjectHandle);
1062            break;
1063        case NEXUS_AudioInputType_e3dSurround:
1064            NEXUS_3dSurround_RemoveAllInputs(input->pObjectHandle);
1065            break;
1066        case NEXUS_AudioInputType_eAudysseyAbx:
1067            NEXUS_AudysseyAbx_RemoveAllInputs(input->pObjectHandle);
1068            break;
1069        case NEXUS_AudioInputType_eAudysseyAdv:
1070            NEXUS_AudysseyAdv_RemoveAllInputs(input->pObjectHandle);
1071            break;
1072        case NEXUS_AudioInputType_eStudioSound:
1073            NEXUS_StudioSound_RemoveAllInputs(input->pObjectHandle);
1074            break;
1075        /* Remaining types are not yet supported */
1076        }
1077        /* Remove all inputs */
1078        rc = NEXUS_AudioInput_P_RemoveAllInputs(input);
1079        if (rc) {rc = BERR_TRACE(rc);}
1080        /* Break all downstream connections */
1081        while ( (pDownstreamNode=BLST_Q_FIRST(&pInputData->downstreamList)) )
1082        {
1083            BDBG_WRN(("Forcibly breaking connection between input %p and %p on shutdown", pDownstreamNode->pDownstreamObject, input));
1084            switch ( pDownstreamNode->pDownstreamObject->objectType )
1085            {
1086            default:
1087                rc = BERR_TRACE(BERR_NOT_SUPPORTED);
1088                break;
1089    #if NEXUS_CVOICE
1090            case NEXUS_AudioInputType_eCustomVoice:
1091                rc = NEXUS_CustomVoice_RemoveInput(pDownstreamNode->pDownstreamObject->pObjectHandle, input);
1092                break;
1093    #endif
1094            case NEXUS_AudioInputType_eEncoder:
1095                rc = NEXUS_AudioEncoder_RemoveInput(pDownstreamNode->pDownstreamObject->pObjectHandle, input);
1096                break;
1097            case NEXUS_AudioInputType_eRfEncoder:
1098                NEXUS_RfAudioEncoder_RemoveInput(pDownstreamNode->pDownstreamObject->pObjectHandle, input);
1099                break;
1100            case NEXUS_AudioInputType_eTruSurroundXt:
1101                rc = NEXUS_TruSurroundXt_RemoveInput(pDownstreamNode->pDownstreamObject->pObjectHandle, input);
1102                break;
1103            case NEXUS_AudioInputType_eTruSurroundHd:
1104                rc = NEXUS_TruSurroundHd_RemoveInput(pDownstreamNode->pDownstreamObject->pObjectHandle, input);
1105                break;
1106            case NEXUS_AudioInputType_eTruVolume:
1107                rc = NEXUS_TruVolume_RemoveInput(pDownstreamNode->pDownstreamObject->pObjectHandle, input);
1108                break;
1109            case NEXUS_AudioInputType_eDolbyDigitalReencode:
1110                rc = NEXUS_DolbyDigitalReencode_RemoveInput(pDownstreamNode->pDownstreamObject->pObjectHandle, input);
1111                break;
1112            case NEXUS_AudioInputType_eDolbyVolume:
1113                rc = NEXUS_DolbyVolume_RemoveInput(pDownstreamNode->pDownstreamObject->pObjectHandle, input);
1114                break;
1115            case NEXUS_AudioInputType_eDolbyVolume258:
1116                rc = NEXUS_DolbyVolume258_RemoveInput(pDownstreamNode->pDownstreamObject->pObjectHandle, input);
1117                break;
1118            case NEXUS_AudioInputType_eMixer:
1119            case NEXUS_AudioInputType_eDspMixer:
1120                rc = NEXUS_AudioMixer_RemoveInput(pDownstreamNode->pDownstreamObject->pObjectHandle, input);
1121                break;
1122            case NEXUS_AudioInputType_eAutoVolumeLevel:
1123                rc = NEXUS_AutoVolumeLevel_RemoveInput(pDownstreamNode->pDownstreamObject->pObjectHandle, input);
1124                break;
1125            case NEXUS_AudioInputType_e3dSurround:
1126                rc = NEXUS_3dSurround_RemoveInput(pDownstreamNode->pDownstreamObject->pObjectHandle, input);
1127                break;
1128            case NEXUS_AudioInputType_eAudysseyAbx:
1129                rc = NEXUS_AudysseyAbx_RemoveInput(pDownstreamNode->pDownstreamObject->pObjectHandle, input);
1130                break;
1131            case NEXUS_AudioInputType_eAudysseyAdv:
1132                rc = NEXUS_AudysseyAdv_RemoveInput(pDownstreamNode->pDownstreamObject->pObjectHandle, input);
1133                break;
1134        case NEXUS_AudioInputType_eStudioSound:
1135            NEXUS_StudioSound_RemoveInput(pDownstreamNode->pDownstreamObject->pObjectHandle, input);
1136            break;
1137            /* Remaining types are not yet supported */
1138            }
1139            if (rc) {
1140                rc = BERR_TRACE(rc);
1141                break;
1142            }
1143        }
1144        /* Remove all outputs */
1145        while ( NULL != (pNode = BLST_Q_FIRST(&pInputData->outputList)) )
1146        {
1147            BDBG_WRN(("Forcibly removing output %p on shutdown (port=%d)", pNode->pOutputConnector, pNode->pOutputConnector->port));
1148            rc = NEXUS_AudioOutput_RemoveInput(pNode->pOutputConnector, input);
1149            if (rc) {
1150                rc = BERR_TRACE(rc);
1151                break;
1152            }
1153        }
1154
1155        /* Free connection data */
1156        BDBG_OBJECT_DESTROY(pInputData, NEXUS_AudioInputData);
1157        BKNI_Free(pInputData);
1158        input->pMixerData = NULL;
1159    }
1160
1161    return ;
1162}
1163
1164/***************************************************************************
1165Summary:
1166    Prepare the input chain to start.  May build and/or validate connections.
1167 ***************************************************************************/
1168NEXUS_Error NEXUS_AudioInput_P_PrepareToStart(
1169    NEXUS_AudioInput input
1170    )
1171{
1172    NEXUS_Error errCode;
1173    NEXUS_AudioInputData *pData;
1174
1175    BDBG_OBJECT_ASSERT(input, NEXUS_AudioInput);
1176
1177    BDBG_MSG(("NEXUS_AudioInput_P_PrepareToStart(%p)", input));
1178
1179    pData = input->pMixerData;
1180    if ( NULL == pData )
1181    {
1182        /* If no connections exist, there is nothing to do */
1183        return BERR_SUCCESS;
1184    }
1185    BDBG_OBJECT_ASSERT(pData, NEXUS_AudioInputData);
1186
1187    BDBG_ASSERT(input->objectType != NEXUS_AudioInputType_eHdmi);
1188    BDBG_ASSERT(input->objectType != NEXUS_AudioInputType_eSpdif);
1189    BDBG_ASSERT(input->objectType != NEXUS_AudioInputType_eMixer);
1190
1191    BDBG_MSG(("Checking output mixers"));
1192    errCode = NEXUS_AudioInput_P_CheckOutputMixers(input);
1193    if ( errCode )
1194    {
1195        return BERR_TRACE(errCode);
1196    }
1197
1198    return BERR_SUCCESS;
1199}
1200
1201void NEXUS_AudioInput_GetSyncSettings_priv( NEXUS_AudioInput audioInput, NEXUS_AudioInputSyncSettings *pSyncSettings )
1202{
1203    NEXUS_ASSERT_MODULE();
1204    switch (audioInput->objectType)
1205    {
1206    case NEXUS_AudioInputType_eDecoder:
1207        NEXUS_AudioDecoder_GetSyncSettings_priv((NEXUS_AudioDecoderHandle)audioInput->pObjectHandle, pSyncSettings);
1208        break;
1209    default:
1210        BDBG_WRN(("This audio input does not support SyncChannel"));
1211        break;
1212    }
1213}
1214
1215NEXUS_Error NEXUS_AudioInput_SetSyncSettings_priv( NEXUS_AudioInput audioInput, const NEXUS_AudioInputSyncSettings *pSyncSettings )
1216{
1217    NEXUS_Error rc = 0;
1218    NEXUS_ASSERT_MODULE();
1219    switch (audioInput->objectType)
1220    {
1221    case NEXUS_AudioInputType_eDecoder:
1222        rc = NEXUS_AudioDecoder_SetSyncSettings_priv((NEXUS_AudioDecoderHandle)audioInput->pObjectHandle, pSyncSettings);
1223        break;
1224    default:
1225        BDBG_WRN(("This audio input does not support SyncChannel"));
1226        break;
1227    }
1228    return rc;
1229}
1230
1231NEXUS_Error NEXUS_AudioInput_GetSyncStatus_isr( NEXUS_AudioInput audioInput, NEXUS_AudioInputSyncStatus *pSyncStatus )
1232{
1233    NEXUS_Error rc = 0;
1234    switch (audioInput->objectType)
1235    {
1236    case NEXUS_AudioInputType_eDecoder:
1237        rc = NEXUS_AudioDecoder_GetSyncStatus_isr((NEXUS_AudioDecoderHandle)audioInput->pObjectHandle, pSyncStatus);
1238        break;
1239    default:
1240        BDBG_WRN(("This audio input does not support SyncChannel"));
1241        break;
1242    }
1243    return rc;
1244}
1245
1246/***************************************************************************
1247Summary:
1248    Returns the first object downstream from the current object that matches
1249    the specified type.  This is a depth-first search, not breadth-first.
1250 ***************************************************************************/
1251NEXUS_AudioInput NEXUS_AudioInput_P_FindByType(
1252    NEXUS_AudioInput input,
1253    NEXUS_AudioInputType type
1254    )
1255{
1256    NEXUS_AudioInput obj=NULL;
1257    NEXUS_AudioInputData *pData;
1258    NEXUS_AudioDownstreamNode *pNode;
1259
1260    BDBG_OBJECT_ASSERT(input, NEXUS_AudioInput);
1261
1262    if ( NULL == input->pMixerData )
1263    {
1264        return NULL;
1265    }
1266
1267    pData = input->pMixerData;
1268    BDBG_OBJECT_ASSERT(pData, NEXUS_AudioInputData);
1269
1270    /* Recurse through all children */
1271    for ( pNode = BLST_Q_FIRST(&pData->downstreamList);
1272        NULL != pNode;
1273        pNode = BLST_Q_NEXT(pNode, downstreamNode) )
1274    {
1275        if ( pNode->pDownstreamObject != NULL )
1276        {
1277            if ( pNode->pDownstreamObject->objectType == type )
1278            {
1279                return pNode->pDownstreamObject;
1280            }
1281            else
1282            {
1283                obj = NEXUS_AudioInput_P_FindByType(pNode->pDownstreamObject, type);
1284                if ( obj )
1285                {
1286                    return obj;
1287                }
1288            }
1289        }
1290    }
1291
1292    /* Not found if we get here */
1293    return NULL;
1294}
1295
1296static void NEXUS_AudioInput_P_UnlinkOutputPort(NEXUS_AudioInput input, NEXUS_AudioOutputNode *pOutputNode)
1297{
1298    NEXUS_AudioInputData *pData;
1299    NEXUS_AudioInputMixerNode *pMixerNode;
1300    BDBG_OBJECT_ASSERT(input, NEXUS_AudioInput);
1301    BDBG_ASSERT(NULL != pOutputNode);
1302    pData = input->pMixerData;
1303    BDBG_OBJECT_ASSERT(pData, NEXUS_AudioInputData);
1304   
1305    pMixerNode = pOutputNode->pMixerNode;
1306    if ( pMixerNode )
1307    {
1308        BDBG_ASSERT(pMixerNode->usageCount > 0);
1309        pMixerNode->usageCount--;
1310        BAPE_Mixer_RemoveOutput(pMixerNode->outputMixer, (BAPE_OutputPort)pOutputNode->pOutputConnector->port);
1311        if ( pMixerNode->usageCount == 0 )
1312        {
1313            /* Destroy the mixer */
1314            if ( pMixerNode->eqMixer )
1315            {
1316                BAPE_Mixer_RemoveAllInputs(pMixerNode->eqMixer);
1317                BAPE_Mixer_Destroy(pMixerNode->eqMixer);
1318            }
1319            if ( pMixerNode->apeEq )
1320            {
1321                BAPE_Equalizer_RemoveAllInputs(pMixerNode->apeEq);
1322                BAPE_Equalizer_Destroy(pMixerNode->apeEq);
1323            }
1324            BAPE_Mixer_Destroy(pMixerNode->inputMixer);
1325            BLST_Q_REMOVE(&pData->mixerList, pMixerNode, mixerNode);
1326            BKNI_Memset(pMixerNode, 0, sizeof(NEXUS_AudioInputMixerNode));
1327            BKNI_Free(pMixerNode);
1328        }
1329        else
1330        {
1331            switch ( NEXUS_AudioInput_P_GetOutputTiming(pOutputNode->pOutputConnector) )
1332            {
1333            case NEXUS_AudioOutputTiming_eDac:
1334                BDBG_ASSERT(pMixerNode->dacTimingCount > 0);
1335                pMixerNode->dacTimingCount--;
1336                break;
1337            case NEXUS_AudioOutputTiming_ePll:
1338                BDBG_ASSERT(pMixerNode->pllTimingCount > 0);
1339                pMixerNode->pllTimingCount--;
1340                break;
1341            case NEXUS_AudioOutputTiming_eFlexible:
1342                BDBG_ASSERT(pMixerNode->flexTimingCount > 0);
1343                pMixerNode->flexTimingCount--;
1344                break;
1345            default:
1346                /* Should never get here */
1347                BDBG_ASSERT(0);
1348                break;
1349            }
1350
1351            if ( (pMixerNode->dacTimingCount == 0 && pMixerNode->timing == NEXUS_AudioOutputTiming_eDac) ||
1352                 (pMixerNode->pllTimingCount == 0 && pMixerNode->timing == NEXUS_AudioOutputTiming_ePll)  )
1353            {
1354                pMixerNode->timing = NEXUS_AudioOutputTiming_eFlexible;
1355            }
1356        }
1357        pOutputNode->pMixerNode = NULL;
1358    }
1359}
1360
1361NEXUS_Error NEXUS_AudioInput_P_OutputSettingsChanged(
1362    NEXUS_AudioInput input, 
1363    NEXUS_AudioOutput output
1364    )
1365{
1366    NEXUS_AudioInputData *pData;
1367    NEXUS_AudioOutputNode *pOutputNode;
1368
1369    BDBG_OBJECT_ASSERT(input, NEXUS_AudioInput);
1370    BDBG_OBJECT_ASSERT(output, NEXUS_AudioOutput);
1371    pData = input->pMixerData;
1372    if ( NULL == pData )
1373    {
1374        return NEXUS_SUCCESS;
1375    }
1376    BDBG_OBJECT_ASSERT(pData, NEXUS_AudioInputData);
1377
1378    /* If we are running, stop here */
1379    if ( NEXUS_AudioInput_P_IsRunningUpstream(input) )
1380    {
1381        return NEXUS_SUCCESS;
1382    }
1383
1384    /* Check my local outputs first */
1385    for ( pOutputNode = BLST_Q_FIRST(&pData->outputList);
1386          pOutputNode != NULL;
1387          pOutputNode = BLST_Q_NEXT(pOutputNode, outputNode) )
1388    {
1389        if ( pOutputNode->pOutputConnector == output )
1390        {
1391            return NEXUS_AudioInput_P_CheckOutputMixer(input, pOutputNode);
1392        }
1393    }
1394
1395    BDBG_ERR(("output %p is not connected to input %p", output, input));
1396    BDBG_ASSERT(0);
1397    return BERR_TRACE(BERR_INVALID_PARAMETER);
1398}
1399
1400static NEXUS_Error NEXUS_AudioInput_P_CheckOutputMixer(
1401    NEXUS_AudioInput input, 
1402    NEXUS_AudioOutputNode *pOutputNode
1403    )
1404{
1405    NEXUS_AudioInputMixerNode *pMixerNode;
1406    BAPE_MixerSettings mixerSettings;
1407    NEXUS_AudioInputData *pData;
1408    NEXUS_Error errCode=0;
1409    NEXUS_AudioOutputTiming timing;
1410    BAPE_MixerAddInputSettings addInputSettings;
1411
1412    BDBG_OBJECT_ASSERT(input, NEXUS_AudioInput);
1413    BDBG_ASSERT(NULL != pOutputNode);
1414    pData = input->pMixerData;
1415    BDBG_OBJECT_ASSERT(pData, NEXUS_AudioInputData);
1416
1417    if ( pOutputNode->pOutputConnector->objectType == NEXUS_AudioOutputType_eMux )
1418    {
1419        /* Mux outputs do nothing here - they don't attach to a mixer */
1420        return BERR_SUCCESS;
1421    }
1422
1423    timing = NEXUS_AudioInput_P_GetOutputTiming(pOutputNode->pOutputConnector);
1424
1425    if ( NEXUS_AudioOutput_P_IsDacSlave(pOutputNode->pOutputConnector) ||
1426         NEXUS_AudioOutput_P_IsSpdifSlave(pOutputNode->pOutputConnector) )
1427    {
1428        NEXUS_AudioOutputNode *pMasterNode;
1429        NEXUS_AudioOutputType masterType = (NEXUS_AudioOutput_P_IsDacSlave(pOutputNode->pOutputConnector))?
1430            NEXUS_AudioOutputType_eDac:NEXUS_AudioOutputType_eSpdif;
1431        /* Setup master/slave linkage to first available master */
1432        for ( pMasterNode = BLST_Q_FIRST(&pData->outputList);
1433              pMasterNode != NULL;
1434              pMasterNode = BLST_Q_NEXT(pOutputNode, outputNode) )
1435        {
1436            BDBG_ASSERT(NULL != pMasterNode->pOutputConnector);
1437            if ( pMasterNode->pOutputConnector->objectType == masterType )
1438            {
1439                break;
1440            }
1441        }
1442        if ( NULL == pMasterNode )
1443        {
1444            BDBG_WRN(("No master output available to drive output %p (type %u)", pOutputNode->pOutputConnector, pOutputNode->pOutputConnector->objectType));
1445        }
1446        return NEXUS_AudioOutput_P_SetSlaveSource(pOutputNode->pOutputConnector, pMasterNode?pMasterNode->pOutputConnector:NULL);
1447    }
1448
1449    BDBG_MSG(("Getting output mixer settings"));
1450    NEXUS_AudioOutput_P_GetMixerSettings(pOutputNode->pOutputConnector, &mixerSettings);
1451    BAPE_Mixer_GetDefaultAddInputSettings(&addInputSettings);
1452
1453    if ( pOutputNode->pMixerNode )
1454    {
1455        /* See if our settings have changed relative to the current node */
1456        if ( BKNI_Memcmp(&mixerSettings, &pOutputNode->pMixerNode->settings, sizeof(BAPE_MixerSettings)) ||
1457             NEXUS_AudioOutput_P_GetEqualizer(pOutputNode->pOutputConnector) != pOutputNode->pMixerNode->nexusEq )
1458        {
1459            BDBG_MSG(("Unlinking mixer output"));
1460            NEXUS_AudioInput_P_UnlinkOutputPort(input, pOutputNode);
1461        }
1462    }
1463
1464    if ( NULL == pOutputNode->pMixerNode )
1465    {
1466        /* Scan through all mixers to see if we match existing settings */
1467        for ( pMixerNode = BLST_Q_FIRST(&pData->mixerList);
1468              pMixerNode != NULL;
1469              pMixerNode = BLST_Q_NEXT(pMixerNode, mixerNode) )
1470        {
1471            BDBG_MSG(("Comparing against mixer node %p", pMixerNode));
1472            if ( !BKNI_Memcmp(&mixerSettings, &pMixerNode->settings, sizeof(BAPE_MixerSettings)) )
1473            {
1474                if ( (pMixerNode->timing == NEXUS_AudioOutputTiming_eDac && timing == NEXUS_AudioOutputTiming_ePll) ||
1475                     (pMixerNode->timing == NEXUS_AudioOutputTiming_ePll && timing == NEXUS_AudioOutputTiming_eDac))
1476                {
1477                    BDBG_MSG(("Can not add PLL and DAC outputs to the same mixer."));
1478                    continue;
1479                }
1480                if ( pMixerNode->nexusEq != NEXUS_AudioOutput_P_GetEqualizer(pOutputNode->pOutputConnector) )
1481                {
1482                    /* TODO: Handle creating EQ/second mixer, linking, and adding output to appropriate mixer */
1483                    BDBG_MSG(("Can not have different equalization with the same mixer."));
1484                    continue;
1485                }
1486                BDBG_MSG(("Comparing against mixer node %p - MATCH", pMixerNode));
1487                errCode = BAPE_Mixer_AddOutput(pMixerNode->outputMixer, (BAPE_OutputPort)pOutputNode->pOutputConnector->port);
1488                if ( errCode )
1489                {
1490                    return BERR_TRACE(errCode);
1491                }
1492                NEXUS_AudioOutput_P_SetOutputFormat(pOutputNode->pOutputConnector, NEXUS_AudioInput_P_GetFormat(input));
1493                pOutputNode->pMixerNode = pMixerNode;
1494                pMixerNode->usageCount++;
1495                switch ( timing )
1496                {
1497                case NEXUS_AudioOutputTiming_eFlexible:
1498                    pMixerNode->flexTimingCount++;
1499                    break;
1500                case NEXUS_AudioOutputTiming_ePll:
1501                    pMixerNode->pllTimingCount++;
1502                    if ( pMixerNode->timing == NEXUS_AudioOutputTiming_eFlexible )
1503                    {
1504                        BDBG_MSG(("Added PLL output to flex mixer.  Switching mixer timing to PLL."));
1505                        pMixerNode->timing = NEXUS_AudioOutputTiming_ePll;
1506                    }
1507                    break;
1508                case NEXUS_AudioOutputTiming_eDac:
1509                    pMixerNode->dacTimingCount++;
1510                    if ( pMixerNode->timing == NEXUS_AudioOutputTiming_eFlexible )
1511                    {
1512                        BDBG_MSG(("Added DAC output to flex mixer.  Switching mixer timing to DAC."));
1513                        pMixerNode->timing = NEXUS_AudioOutputTiming_eDac;
1514                    }
1515                default:
1516                    break;
1517                }
1518                return BERR_SUCCESS;
1519            }
1520        }
1521
1522        /* If we get here, we need to add a new mixer */
1523        pMixerNode = BKNI_Malloc(sizeof(NEXUS_AudioInputMixerNode));
1524        if ( NULL == pMixerNode )
1525        {
1526            errCode = BERR_TRACE(BERR_OUT_OF_SYSTEM_MEMORY);
1527            goto err_malloc;
1528        }
1529        BKNI_Memset(pMixerNode, 0, sizeof(NEXUS_AudioInputMixerNode));
1530        pMixerNode->usageCount = 1;
1531        switch ( timing )
1532        {
1533        case NEXUS_AudioOutputTiming_eFlexible:
1534            pMixerNode->flexTimingCount=1;
1535            break;
1536        case NEXUS_AudioOutputTiming_ePll:
1537            pMixerNode->pllTimingCount=1;
1538            break;
1539        case NEXUS_AudioOutputTiming_eDac:
1540            pMixerNode->dacTimingCount=1;
1541        default:
1542            break;
1543        }
1544        pMixerNode->timing = timing;
1545        pMixerNode->nexusEq = NEXUS_AudioOutput_P_GetEqualizer(pOutputNode->pOutputConnector);
1546        BDBG_MSG(("Allocating mixer"));
1547        errCode = BAPE_Mixer_Create(NEXUS_AUDIO_DEVICE_HANDLE, &mixerSettings, &pMixerNode->inputMixer);
1548        if ( errCode )
1549        {
1550            errCode = BERR_TRACE(errCode);
1551            goto err_mixer_open;
1552        }
1553        pMixerNode->settings = mixerSettings;
1554        if ( input->objectType == NEXUS_AudioInputType_eMixer )
1555        {
1556            NEXUS_AudioUpstreamNode *pUpstreamNode;
1557            NEXUS_AudioMixerSettings mixerSettings;
1558            NEXUS_AudioMixer_GetSettings(input->pObjectHandle, &mixerSettings);
1559            /* Mixers add all upstream objects as inputs */
1560            for ( pUpstreamNode = BLST_Q_FIRST(&pData->upstreamList);
1561                  pUpstreamNode != NULL;
1562                  pUpstreamNode = BLST_Q_NEXT(pUpstreamNode, upstreamNode) )
1563            {
1564                /* Check for the mixer's master option */               
1565                if ( NULL == mixerSettings.master )
1566                {
1567                    addInputSettings.sampleRateMaster = (pUpstreamNode->pUpstreamObject->objectType == NEXUS_AudioInputType_ePlayback)?false:true;
1568                }
1569                else
1570                {
1571                    addInputSettings.sampleRateMaster = (pUpstreamNode->pUpstreamObject == mixerSettings.master) ? true : false;
1572                }
1573                errCode = BAPE_Mixer_AddInput(pMixerNode->inputMixer, (BAPE_Connector)pUpstreamNode->pUpstreamObject->port, &addInputSettings);
1574                if ( errCode )
1575                {
1576                    errCode = BERR_TRACE(errCode);
1577                    goto err_add_input;
1578                }
1579            }
1580        }
1581        else
1582        {
1583            /* Non-mixers add themselves as inputs */
1584            addInputSettings.sampleRateMaster = (input->objectType == NEXUS_AudioInputType_ePlayback)?false:true;
1585            errCode = BAPE_Mixer_AddInput(pMixerNode->inputMixer, (BAPE_Connector)input->port, &addInputSettings);
1586            if ( errCode )
1587            {
1588                errCode = BERR_TRACE(errCode);
1589                goto err_add_input;
1590            }
1591        }
1592        /* Determine output mixer based on whether we are using an equalizer or not */
1593        if ( pMixerNode->nexusEq )
1594        {
1595            BAPE_EqualizerSettings eqSettings;
1596            BAPE_Connector apeConnector;
1597            BDBG_MSG(("Equalizer active.  Outputs connect to a mixer->eq->mixer cascade."));
1598            BAPE_Equalizer_GetDefaultSettings(&eqSettings);
1599            BDBG_MSG(("Creating EQ"));
1600            errCode = BAPE_Equalizer_Create(NEXUS_AUDIO_DEVICE_HANDLE, &eqSettings, &pMixerNode->apeEq);
1601            if ( errCode )
1602            {
1603                errCode = BERR_TRACE(errCode);
1604                goto err_eq_create;
1605            }
1606            BDBG_MSG(("Linking EQ to input mixer"));
1607            BAPE_Mixer_GetConnector(pMixerNode->inputMixer, &apeConnector);
1608            errCode = BAPE_Equalizer_AddInput(pMixerNode->apeEq, apeConnector);
1609            if ( errCode )
1610            {
1611                errCode = BERR_TRACE(errCode);
1612                goto err_eq_add_input;
1613            }
1614            BDBG_MSG(("Creating cascaded mixer for EQ"));
1615            errCode = BAPE_Mixer_Create(NEXUS_AUDIO_DEVICE_HANDLE, &pMixerNode->settings, &pMixerNode->eqMixer);
1616            if ( errCode )
1617            {
1618                errCode = BERR_TRACE(errCode);
1619                goto err_output_mixer_create;
1620            }
1621            BAPE_Equalizer_GetConnector(pMixerNode->apeEq, &apeConnector);
1622            BAPE_Mixer_GetDefaultAddInputSettings(&addInputSettings);
1623            addInputSettings.sampleRateMaster = true;   /* Output mixer should always follow EQ Sample Rate */
1624            errCode = BAPE_Mixer_AddInput(pMixerNode->eqMixer, apeConnector, &addInputSettings);
1625            if ( errCode )
1626            {
1627                errCode = BERR_TRACE(errCode);
1628                goto err_output_mixer_add_input;
1629            }
1630            pMixerNode->outputMixer = pMixerNode->eqMixer;
1631        }
1632        else
1633        {
1634            BDBG_MSG(("No Equalizer.  Outputs connect to a single mixer."));
1635            pMixerNode->outputMixer = pMixerNode->inputMixer;
1636        }
1637
1638        errCode = BAPE_Mixer_AddOutput(pMixerNode->outputMixer, (BAPE_OutputPort)pOutputNode->pOutputConnector->port);
1639        if ( errCode )
1640        {
1641            errCode = BERR_TRACE(errCode);
1642            goto err_add_output;
1643        }
1644        NEXUS_AudioOutput_P_SetOutputFormat(pOutputNode->pOutputConnector, NEXUS_AudioInput_P_GetFormat(input));
1645
1646        /* Add to the list */
1647        pOutputNode->pMixerNode = pMixerNode;
1648        BLST_Q_INSERT_TAIL(&pData->mixerList, pMixerNode, mixerNode);
1649    }
1650
1651    /* Refresh equalizer stages if required.  There may be a more optimal way to do this, but this will work. */
1652    pMixerNode = pOutputNode->pMixerNode;
1653    BDBG_ASSERT(NULL != pMixerNode);
1654    if ( pMixerNode->nexusEq )
1655    {
1656        BAPE_EqualizerStageHandle *pStages;
1657        unsigned numStages;
1658        NEXUS_AudioEqualizer_P_GetStages(pMixerNode->nexusEq, &pStages, &numStages);
1659        errCode = BAPE_Equalizer_SetStages(pMixerNode->apeEq, pStages, numStages);
1660        if ( errCode )
1661        {
1662            NEXUS_AudioInput_P_UnlinkOutputPort(input, pOutputNode);
1663            return BERR_TRACE(errCode);
1664        }
1665    }
1666
1667    return BERR_SUCCESS;
1668
1669err_add_output:
1670    if ( pMixerNode->eqMixer )
1671    {
1672        BAPE_Mixer_RemoveAllInputs(pMixerNode->eqMixer);
1673    }
1674err_output_mixer_add_input:
1675    if ( pMixerNode->eqMixer )
1676    {
1677        BAPE_Mixer_Destroy(pMixerNode->eqMixer);
1678    }
1679err_output_mixer_create:
1680    if ( pMixerNode->apeEq )
1681    {
1682        BAPE_Equalizer_RemoveAllInputs(pMixerNode->apeEq);
1683    }   
1684err_eq_add_input:
1685    if ( pMixerNode->apeEq )
1686    {
1687        BAPE_Equalizer_Destroy(pMixerNode->apeEq);
1688    }
1689err_eq_create:
1690    BAPE_Mixer_RemoveAllInputs(pMixerNode->inputMixer);
1691err_add_input:
1692    BAPE_Mixer_Destroy(pMixerNode->inputMixer);
1693err_mixer_open:
1694    BKNI_Free(pMixerNode);
1695err_malloc:
1696    return errCode;
1697}
1698
1699static NEXUS_Error NEXUS_AudioInput_P_CheckOutputMixers(NEXUS_AudioInput input)
1700{
1701    NEXUS_Error errCode;
1702    NEXUS_AudioInputData *pData;
1703    NEXUS_AudioDownstreamNode *pDownstreamNode;
1704    NEXUS_AudioOutputNode *pOutputNode;
1705    bool hasOutputs=false;
1706    bool hasChildren=false;
1707
1708    BDBG_OBJECT_ASSERT(input, NEXUS_AudioInput);
1709    pData = input->pMixerData;
1710    if ( NULL == pData )
1711    {
1712        return BERR_SUCCESS;
1713    }
1714    BDBG_OBJECT_ASSERT(pData, NEXUS_AudioInputData);
1715   
1716    /* Make sure we're not running if this node might have more than one input */
1717    if ( BLST_Q_FIRST(&pData->upstreamList) != BLST_Q_LAST(&pData->upstreamList) )
1718    {
1719        if ( NEXUS_AudioInput_P_IsRunningUpstream(input) )
1720        {
1721            BDBG_MSG(("Already running"));
1722            return BERR_SUCCESS;
1723        }
1724    }
1725
1726    /* Check my local outputs first */
1727    for ( pOutputNode = BLST_Q_FIRST(&pData->outputList);
1728          pOutputNode != NULL;
1729          pOutputNode = BLST_Q_NEXT(pOutputNode, outputNode) )
1730    {
1731        BDBG_MSG(("Checking Output Mixer for output %p (output type %d)", pOutputNode->pOutputConnector, pOutputNode->pOutputConnector->objectType));
1732        NEXUS_AudioInput_P_CheckOutputMixer(input, pOutputNode);
1733        hasOutputs = true;
1734    }
1735
1736    for ( pDownstreamNode = BLST_Q_FIRST(&pData->downstreamList);
1737          pDownstreamNode != NULL;
1738          pDownstreamNode = BLST_Q_NEXT(pDownstreamNode, downstreamNode) )
1739    {
1740        /* Recurse through children */
1741        BDBG_MSG(("Recursively Checking Output Mixers for input %p (input type %d)", pDownstreamNode->pDownstreamObject, pDownstreamNode->pDownstreamObject->objectType));
1742        errCode = NEXUS_AudioInput_P_CheckOutputMixers(pDownstreamNode->pDownstreamObject);
1743        if ( errCode )
1744        {
1745            return BERR_TRACE(errCode);
1746        }
1747        hasChildren = true;
1748    }
1749
1750    switch ( input->objectType )
1751    {
1752    case NEXUS_AudioInputType_eDecoder:
1753    case NEXUS_AudioInputType_eDolbyDigitalReencode:
1754        /* This is okay for these types - they have multiple paths */
1755        break;
1756    default:
1757        if ( hasOutputs == false && hasChildren == false )
1758        {
1759            BDBG_ERR(("AudioInput %#x (type=%u) is not connected to any other nodes or outputs.  This is currently not supported.", input, input->objectType));
1760            return BERR_TRACE(BERR_NOT_SUPPORTED);
1761        }
1762        break;
1763    }
1764
1765    return BERR_SUCCESS;
1766}
1767
1768void NEXUS_AudioInput_P_GetVolume(
1769    NEXUS_AudioInput input, 
1770    BAPE_MixerInputVolume *pInputVolume    /* [out] */
1771    )
1772{
1773    NEXUS_AudioInputData *pData;
1774
1775    BDBG_OBJECT_ASSERT(input, NEXUS_AudioInput);
1776    BDBG_ASSERT(NULL != pInputVolume);
1777    pData = input->pMixerData;
1778
1779    if ( NULL == pData )
1780    {
1781        pData = NEXUS_AudioInput_P_CreateData(input);
1782        if ( NULL == pData )
1783        {
1784            (void)BERR_TRACE(BERR_OUT_OF_SYSTEM_MEMORY);
1785            BKNI_Memset(pInputVolume, 0, sizeof(*pInputVolume));
1786            return;
1787        }
1788    }
1789    BDBG_OBJECT_ASSERT(pData, NEXUS_AudioInputData);
1790    *pInputVolume = pData->inputVolume;
1791}
1792
1793static NEXUS_Error NEXUS_AudioInput_P_SetVolumeDownstream(
1794    NEXUS_AudioInput previous, 
1795    NEXUS_AudioInput input,
1796    const BAPE_MixerInputVolume *pInputVolume
1797    )
1798{
1799    NEXUS_AudioDownstreamNode *pDownstreamNode;
1800    NEXUS_AudioInputMixerNode *pMixerNode;
1801    NEXUS_AudioInputData *pData;
1802    BERR_Code errCode;
1803
1804    BDBG_OBJECT_ASSERT(input, NEXUS_AudioInput);
1805    BDBG_ASSERT(NULL != pInputVolume);
1806
1807    pData = input->pMixerData;
1808    if ( NULL == pData )
1809    {
1810        pData = NEXUS_AudioInput_P_CreateData(input);
1811        if ( NULL == pData )
1812        {
1813            return BERR_TRACE(BERR_OUT_OF_SYSTEM_MEMORY);
1814        }
1815    }
1816   
1817    /* Store Volume */
1818    pData->inputVolume = *pInputVolume;
1819
1820    /* Don't apply volume past DSP mixers */
1821    if ( input->objectType != NEXUS_AudioInputType_eDspMixer )
1822    {
1823        /* Iterate through my mixers and apply the volume setting */
1824        for ( pMixerNode = BLST_Q_FIRST(&pData->mixerList);
1825              pMixerNode != NULL;
1826              pMixerNode = BLST_Q_NEXT(pMixerNode, mixerNode) )
1827        {
1828            if ( input->objectType == NEXUS_AudioInputType_eMixer )
1829            {
1830                errCode = BAPE_Mixer_SetInputVolume(pMixerNode->inputMixer, (BAPE_Connector)previous->port, pInputVolume);
1831            }
1832            else
1833            {
1834                errCode = BAPE_Mixer_SetInputVolume(pMixerNode->inputMixer, (BAPE_Connector)input->port, pInputVolume);
1835            }
1836            if ( errCode )
1837            {
1838                return BERR_TRACE(errCode);
1839            }
1840        }
1841    }
1842
1843    /* Stop recursing after a mixer is found */
1844    switch ( input->objectType )
1845    {
1846    case NEXUS_AudioInputType_eMixer:
1847    case NEXUS_AudioInputType_eDspMixer:
1848        /* Propagate volume to mixer if needed */
1849        errCode = NEXUS_AudioMixer_P_SetInputVolume(input->pObjectHandle, previous, pInputVolume);
1850        if ( errCode )
1851        {
1852            return BERR_TRACE(errCode);
1853        }
1854        break;
1855    default:
1856        /* Iterate through downstream nodes and apply mixer volume */
1857        for ( pDownstreamNode = BLST_Q_FIRST(&pData->downstreamList);
1858              pDownstreamNode != NULL;
1859              pDownstreamNode = BLST_Q_NEXT(pDownstreamNode, downstreamNode) )
1860        {
1861            errCode = NEXUS_AudioInput_P_SetVolumeDownstream(input, pDownstreamNode->pDownstreamObject, pInputVolume);
1862            if ( errCode )
1863            {
1864                return BERR_TRACE(errCode);
1865            }
1866        }
1867        break;
1868    }
1869
1870    /* Done */
1871    return BERR_SUCCESS;
1872}
1873
1874NEXUS_Error NEXUS_AudioInput_P_SetVolume(
1875    NEXUS_AudioInput input, 
1876    const BAPE_MixerInputVolume *pInputVolume
1877    )
1878{
1879    return NEXUS_AudioInput_P_SetVolumeDownstream(NULL, input, pInputVolume);
1880}
1881
1882/***************************************************************************
1883Summary:
1884    Get an external input port handle
1885 ***************************************************************************/
1886BAPE_InputPort NEXUS_AudioInput_P_GetInputPort(
1887    NEXUS_AudioInput input
1888    )
1889{
1890    BDBG_OBJECT_ASSERT(input, NEXUS_AudioInput);
1891    switch ( input->objectType )
1892    {
1893#if NEXUS_NUM_HDMI_INPUTS
1894    case NEXUS_AudioInputType_eHdmi:
1895        {
1896            BAPE_InputPort port;
1897            BAPE_MaiInput_GetInputPort(g_maiInput, &port);
1898            return port;
1899        }
1900#endif
1901    default:
1902        return (BAPE_InputPort)input->inputPort;
1903    }
1904}
1905
1906/***************************************************************************
1907Summary:
1908Determine if this input supports dynamic format changes
1909 ***************************************************************************/
1910bool NEXUS_AudioInput_P_SupportsFormatChanges(
1911    NEXUS_AudioInput input
1912    )
1913{
1914    BDBG_OBJECT_ASSERT(input, NEXUS_AudioInput);
1915    switch ( input->objectType )
1916    {
1917    case NEXUS_AudioInputType_eHdmi:
1918    case NEXUS_AudioInputType_eSpdif:
1919        return true;
1920    default:
1921        return false;
1922    }
1923}
1924
1925/***************************************************************************
1926Summary:
1927Enable/Disable interrupt for dynamic format changes
1928 ***************************************************************************/
1929NEXUS_Error NEXUS_AudioInput_P_SetFormatChangeInterrupt(
1930    NEXUS_AudioInput input,
1931    void (*pCallback_isr)(void *, int),
1932    void *pParam1,
1933    int param2
1934    )
1935{
1936    if ( false == NEXUS_AudioInput_P_SupportsFormatChanges(input) )
1937    {
1938        return BERR_TRACE(BERR_NOT_SUPPORTED);
1939    }
1940    switch ( input->objectType )
1941    {
1942#if NEXUS_NUM_HDMI_INPUTS
1943    case NEXUS_AudioInputType_eHdmi:
1944        {
1945            BERR_Code errCode;
1946            BAPE_MaiInputFormatDetectionSettings detectionSettings;
1947            BAPE_MaiInput_GetFormatDetectionSettings(g_maiInput, &detectionSettings);
1948            detectionSettings.enabled = (pCallback_isr != NULL) ? true : false;
1949            detectionSettings.formatChangeInterrupt.pCallback_isr = pCallback_isr;
1950            detectionSettings.formatChangeInterrupt.pParam1 = pParam1;
1951            detectionSettings.formatChangeInterrupt.param2 = param2;
1952            errCode = BAPE_MaiInput_SetFormatDetectionSettings(g_maiInput, &detectionSettings);
1953            if ( errCode )
1954            {
1955                return BERR_TRACE(errCode);
1956            }
1957        }
1958        return BERR_SUCCESS;
1959#endif
1960#if NEXUS_NUM_SPDIF_INPUTS
1961    case NEXUS_AudioInputType_eSpdif:
1962        return NEXUS_SpdifInput_P_SetFormatChangeInterrupt(input->pObjectHandle, pCallback_isr, pParam1, param2);
1963#endif
1964    default:
1965        BSTD_UNUSED(pCallback_isr);
1966        BSTD_UNUSED(pParam1);
1967        BSTD_UNUSED(param2);
1968        return BERR_TRACE(BERR_NOT_SUPPORTED);
1969    }
1970}
1971
1972NEXUS_Error NEXUS_AudioInput_P_Init(void)
1973{
1974#if NEXUS_NUM_HDMI_INPUTS
1975    {
1976        BAPE_MaiInputSettings settings;
1977        BERR_Code errCode;
1978        BAPE_MaiInput_GetDefaultSettings(&settings);
1979        errCode = BAPE_MaiInput_Open(NEXUS_AUDIO_DEVICE_HANDLE, 0, &settings, &g_maiInput);
1980        if ( errCode )
1981        {
1982            return BERR_TRACE(errCode);
1983        }
1984    }
1985#endif
1986    return BERR_SUCCESS;
1987}
1988
1989void NEXUS_AudioInput_P_Uninit(void)
1990{
1991#if NEXUS_NUM_HDMI_INPUTS
1992    BAPE_MaiInput_Close(g_maiInput);
1993    g_maiInput = NULL;
1994#endif
1995}
1996
1997NEXUS_Error NEXUS_AudioInput_P_GetInputPortStatus(
1998    NEXUS_AudioInput input,
1999    NEXUS_AudioInputPortStatus *pStatus     /* [out] */
2000    )
2001{
2002    BDBG_OBJECT_ASSERT(input, NEXUS_AudioInput);
2003    BDBG_ASSERT(NULL != pStatus);
2004
2005    switch ( input->objectType )
2006    {
2007#if NEXUS_NUM_HDMI_INPUTS
2008    case NEXUS_AudioInputType_eHdmi:
2009        {
2010            BAPE_MaiInputFormatDetectionStatus detectionStatus;
2011            BAPE_MaiInput_GetFormatDetectionStatus(g_maiInput, &detectionStatus);
2012            pStatus->signalPresent = detectionStatus.signalPresent;
2013            pStatus->compressed = detectionStatus.compressed;
2014            pStatus->codec = NEXUS_Audio_P_MagnumToCodec(detectionStatus.preambleC.codec);
2015            pStatus->sampleRate = detectionStatus.sampleRate;
2016            switch ( detectionStatus.format )
2017            {
2018            default:
2019                pStatus->numPcmChannels = 0;
2020                break;
2021            case BAPE_MaiInputFormat_eMono:
2022                pStatus->numPcmChannels = 1;
2023                break;
2024            case BAPE_MaiInputFormat_ePcmStereo:
2025            case BAPE_MaiInputFormat_eSpdifPcmStereo:
2026                pStatus->numPcmChannels = 2;
2027                break;
2028            case BAPE_MaiInputFormat_ePcm3Channel:
2029                pStatus->numPcmChannels = 3;
2030                break;
2031            case BAPE_MaiInputFormat_ePcm5_1:
2032            case BAPE_MaiInputFormat_eSpdifPcm6Channel:
2033                pStatus->numPcmChannels = 6;
2034                break;
2035            case BAPE_MaiInputFormat_eSpdifPcm8Channel:
2036                pStatus->numPcmChannels = 8;
2037                break;
2038            }
2039        }
2040        return BERR_SUCCESS;
2041#endif
2042#if NEXUS_NUM_SPDIF_INPUTS
2043    case NEXUS_AudioInputType_eSpdif:
2044        return NEXUS_SpdifInput_P_GetInputPortStatus(input->pObjectHandle, pStatus);
2045#endif       
2046    default:
2047        return BERR_TRACE(BERR_NOT_SUPPORTED);
2048    }
2049}
2050
2051void NEXUS_AudioInput_P_ForceStop(NEXUS_AudioInput input)
2052{
2053    NEXUS_AudioDownstreamNode *pNode;
2054    NEXUS_AudioInputData *pData;
2055
2056    pData = input->pMixerData;
2057
2058    /* Can't be running if not connected */
2059    if ( NULL == pData )
2060    {
2061        return;
2062    }
2063    BDBG_OBJECT_ASSERT(pData, NEXUS_AudioInputData);
2064
2065    NEXUS_AudioInput_P_ForceStopUpstream(input);
2066
2067    /* Recurse Downstream */
2068    for ( pNode = BLST_Q_FIRST(&pData->downstreamList);
2069          NULL != pNode;
2070          pNode = BLST_Q_NEXT(pNode, downstreamNode) )
2071    {
2072        NEXUS_AudioInput_P_ForceStopDownstream(pNode->pDownstreamObject);
2073    }
2074}
2075
2076static void NEXUS_AudioInput_P_ForceStopUpstream(NEXUS_AudioInput input)
2077{
2078    /* Stop any upstream components first */
2079    NEXUS_AudioUpstreamNode *pUpNode;
2080    NEXUS_AudioInputData *pData;
2081
2082    BDBG_OBJECT_ASSERT(input, NEXUS_AudioInput);
2083
2084    BDBG_MSG(("NEXUS_AudioInput_P_ForceStopUpstream(%p)", input));
2085
2086    pData = input->pMixerData;
2087
2088    /* Can't be running if not connected */
2089    if ( NULL == pData )
2090    {
2091        return;
2092    }
2093    BDBG_OBJECT_ASSERT(pData, NEXUS_AudioInputData);
2094
2095    switch ( input->objectType )
2096    {
2097#if NEXUS_NUM_AUDIO_DECODERS
2098    case NEXUS_AudioInputType_eDecoder:
2099        if ( NEXUS_AudioDecoder_P_IsRunning(input->pObjectHandle) )
2100        {
2101            NEXUS_AudioDecoder_Stop(input->pObjectHandle);
2102        }
2103        break;
2104#endif
2105#if NEXUS_NUM_AUDIO_PLAYBACKS
2106    case NEXUS_AudioInputType_ePlayback:
2107        if ( NEXUS_AudioPlayback_P_IsRunning(input->pObjectHandle) )
2108        {
2109            NEXUS_AudioPlayback_Stop(input->pObjectHandle);
2110        }
2111        break;
2112#endif
2113#if NEXUS_NUM_I2S_INPUTS
2114    case NEXUS_AudioInputType_eI2s:
2115        if ( NEXUS_I2sInput_P_IsRunning(input->pObjectHandle) )
2116        {
2117            NEXUS_I2sInput_Stop(input->pObjectHandle);
2118        }
2119        break;
2120#endif
2121#if NEXUS_NUM_RF_AUDIO_DECODERS
2122    case NEXUS_AudioInputType_eRfDecoder:
2123        if ( NEXUS_RfAudioDecoder_P_IsRunning(input->pObjectHandle) )
2124        {
2125            NEXUS_RfAudioDecoder_Stop(input->pObjectHandle);
2126        }
2127        break;
2128#endif
2129#if NEXUS_NUM_ANALOG_AUDIO_DECODERS
2130    case NEXUS_AudioInputType_eAnalogDecoder:
2131        if ( NEXUS_AnalogAudioDecoder_P_IsRunning(input->pObjectHandle) )
2132        {
2133            NEXUS_AnalogAudioDecoder_Stop(input->pObjectHandle);
2134        }
2135        break;
2136#endif
2137    default:
2138        break;
2139    }
2140    /* Recurse Upstream */
2141    for ( pUpNode = BLST_Q_FIRST(&pData->upstreamList);
2142          NULL != pUpNode;
2143          pUpNode = BLST_Q_NEXT(pUpNode, upstreamNode) )
2144    {
2145        NEXUS_AudioInput_P_ForceStopUpstream(pUpNode->pUpstreamObject);
2146    }
2147}
2148
2149static void NEXUS_AudioInput_P_ForceStopDownstream(NEXUS_AudioInput input)
2150{
2151    /* Stop any upstream components first */
2152    NEXUS_AudioUpstreamNode *pUpNode;
2153    NEXUS_AudioDownstreamNode *pDownNode;
2154    NEXUS_AudioInputData *pData;
2155
2156    BDBG_OBJECT_ASSERT(input, NEXUS_AudioInput);
2157
2158    BDBG_MSG(("NEXUS_AudioInput_P_ForceStopUpstream(%p)", input));
2159
2160    pData = input->pMixerData;
2161
2162    /* Can't be running if not connected */
2163    if ( NULL == pData )
2164    {
2165        return;
2166    }
2167    BDBG_OBJECT_ASSERT(pData, NEXUS_AudioInputData);
2168
2169    switch ( input->objectType )
2170    {
2171#if NEXUS_NUM_AUDIO_DECODERS
2172    case NEXUS_AudioInputType_eDecoder:
2173        if ( NEXUS_AudioDecoder_P_IsRunning(input->pObjectHandle) )
2174        {
2175            NEXUS_AudioDecoder_Stop(input->pObjectHandle);
2176        }
2177        break;
2178#endif
2179#if NEXUS_NUM_AUDIO_PLAYBACKS
2180    case NEXUS_AudioInputType_ePlayback:
2181        if ( NEXUS_AudioPlayback_P_IsRunning(input->pObjectHandle) )
2182        {
2183            NEXUS_AudioPlayback_Stop(input->pObjectHandle);
2184        }
2185        break;
2186#endif
2187#if NEXUS_NUM_I2S_INPUTS
2188    case NEXUS_AudioInputType_eI2s:
2189        if ( NEXUS_I2sInput_P_IsRunning(input->pObjectHandle) )
2190        {
2191            NEXUS_I2sInput_Stop(input->pObjectHandle);
2192        }
2193        break;
2194#endif
2195#if NEXUS_NUM_RF_AUDIO_DECODERS
2196    case NEXUS_AudioInputType_eRfDecoder:
2197        if ( NEXUS_RfAudioDecoder_P_IsRunning(input->pObjectHandle) )
2198        {
2199            NEXUS_RfAudioDecoder_Stop(input->pObjectHandle);
2200        }
2201        break;
2202#endif
2203#if NEXUS_NUM_ANALOG_AUDIO_DECODERS
2204    case NEXUS_AudioInputType_eAnalogDecoder:
2205        if ( NEXUS_AnalogAudioDecoder_P_IsRunning(input->pObjectHandle) )
2206        {
2207            NEXUS_AnalogAudioDecoder_Stop(input->pObjectHandle);
2208        }
2209        break;
2210#endif
2211    case NEXUS_AudioInputType_eMixer:
2212    case NEXUS_AudioInputType_eDspMixer:
2213        /* Mixers are a special case.  They can have multiple inputs, all of which must be stopped also. */
2214        /* Recurse Upstream */
2215        for ( pUpNode = BLST_Q_FIRST(&pData->upstreamList);
2216              NULL != pUpNode;
2217              pUpNode = BLST_Q_NEXT(pUpNode, upstreamNode) )
2218        {
2219            NEXUS_AudioInput_P_ForceStopUpstream(pUpNode->pUpstreamObject);
2220        }
2221        break;
2222        /* Fall Through */
2223    default:
2224        break;
2225    }
2226    /* Recurse Downstream */
2227    for ( pDownNode = BLST_Q_FIRST(&pData->downstreamList);
2228          NULL != pDownNode;
2229          pDownNode = BLST_Q_NEXT(pDownNode, downstreamNode) )
2230    {
2231        NEXUS_AudioInput_P_ForceStopDownstream(pDownNode->pDownstreamObject);
2232    }
2233}
2234
Note: See TracBrowser for help on using the repository browser.