source: svn/newcon3bcm2_21bu/nexus/modules/astm/7552/src/nexus_astm.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: 91.4 KB
Line 
1/***************************************************************************
2 *     (c)2007-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_astm.c $
39 * $brcm_Revision: 51 $
40 * $brcm_Date: 12/15/11 2:49p $
41 *
42 * Module Description:
43 *
44 * Revision History:
45 *
46 * $brcm_Log: /nexus/modules/astm/7400/src/nexus_astm.c $
47 *
48 * 51   12/15/11 2:49p bandrews
49 * SW3548-1159: missing a module lock
50 *
51 * 50   12/7/11 2:56p bandrews
52 * SW7335-1330: must not use memset to init the settings; instead get them
53 *  from the decoder, preserving previous settings for callbacks and such
54 *
55 * 49   11/3/11 4:45p bandrews
56 * SW7231-391: fix warning
57 *
58 * 48   10/31/11 7:46p bandrews
59 * SW7231-391: merge to main
60 *
61 * SW7420-2078/1   10/25/11 5:22p bandrews
62 * SW7231-391: update parser band and timebase implementations to use
63 *  handles everywhere, even for legacy enum usage
64 *
65 * 47   9/2/11 10:21a dlwin
66 * SW7335-1330: Coverity: 35222, UNINIT
67 *
68 * 46   8/17/11 5:01p jrubio
69 * SW7346-456: fix coverity issues CID35192-CID35195
70 *
71 * 45   8/8/11 8:23p bandrews
72 * SW3548-1159: merge to main
73 *
74 * SW3548-1159/2   3/11/11 8:39p bandrews
75 * SW3548-1159: must reset firstPtsTsm when each decoder is restarted
76 *
77 * SW3548-1159/1   11/2/10 6:39p bandrews
78 * SW3548-1159: added non-TSM mode recovery methods and some options for
79 *  controlling ASTM better
80 *
81 * 44   8/8/11 6:24p bandrews
82 * SWDTV-7819: add default for tsm threshold adjustment
83 *
84 * 43   10/26/10 12:14p bandrews
85 * SW7125-642: reorder application of ASTM state
86 *
87 * 42   7/14/10 7:45p bandrews
88 * SW3548-1161: get default config for presentation and clock coupling
89 *
90 * 41   2/9/10 8:26p VISHK
91 * SW3548-1161: nexus_astm: expose all tunable params from astmlib
92 *
93 * 40   7/17/09 7:10p bandrews
94 * PR49215: astm dvr support
95 *
96 * 39   6/12/09 5:58p bandrews
97 * PR52472: Use phase error instead of computing PCR - STC directly
98 *
99 * 38   6/5/09 5:33p bandrews
100 * PR52503: Moved singleton counter/idgen to astmlib struct
101 *
102 * 37   4/30/09 3:37p bandrews
103 * PR51684: Default to false until more robust
104 *
105 * 36   2/6/09 2:16p bandrews
106 * PR50938: added debug for when ASTM starts
107 *
108 * 35   1/26/09 10:55a erickson
109 * PR51468: global variable naming convention
110 *
111 * 34   1/20/09 10:12p bandrews
112 * PR50938: merge
113 *
114 * PR50938/1   1/8/09 11:11p bandrews
115 * PR50938: Added capability to disable automatic lifecycle control
116 *
117 * 33   1/6/09 12:37a bandrews
118 * PR50848: Added static keyword to global state
119 *
120 * 32   12/31/08 1:05p jgarrett
121 * PR 50783: Adding runtime option to disable ASTM
122 *
123 * 32   12/31/08 1:03p jgarrett
124 * PR 50783: Adding runtime option to disable ASTM
125 *
126 * 31   12/17/08 3:28p bandrews
127 * PR49720: Added watchdog recovery to astm
128 *
129 * 30   12/17/08 2:37p bandrews
130 * PR50427: Disable ASTM in dependencies on disconnect of said
131 *  dependencies
132 *
133 * 29   12/12/08 6:13p bandrews
134 * PR50079: fixed test framework
135 *
136 * 28   12/8/08 4:36p bandrews
137 * PR41322: auto start astm from decoder start signal
138 *
139 * 27   12/8/08 2:53p bandrews
140 * PR49568: staticize the connect/disconnect functions
141 *
142 * 26   12/4/08 8:17p bandrews
143 * PR49489: Clean up
144 *
145 * 25   12/2/08 9:15p bandrews
146 * PR49489: Ensure defaults are applied to dependencies to allow user
147 *  overrides
148 *
149 * 24   12/1/08 3:21p bandrews
150 * PR49489: Propagate playback flag to decoder interfaces
151 *
152 * 23   11/26/08 2:38p bandrews
153 * PR49671: Fixed bug in setsettings
154 *
155 * 22   11/24/08 8:13p bandrews
156 * PR49527: Make Start return an error
157 *
158 * 21   11/24/08 5:58p katrep
159 * PR49539: compiler error
160 *
161 * 20   11/21/08 9:04p bandrews
162 * PR49539: Fixed
163 *
164 * 19   11/21/08 9:02p bandrews
165 * PR49535: Fixed
166 *
167 * 18   11/21/08 8:58p bandrews
168 * PR49536: Fixed
169 *
170 * 17   11/21/08 8:53p bandrews
171 * PR49568: Create/Destroy presenters in Create/Destroy (not SetSettings).
172 *  Allow disconnection of decoders.  Allow single audio decoder.
173 *
174 * 16   11/18/08 9:42p bandrews
175 * PR49213: Fixed debug message arg order
176 *
177 * 15   11/18/08 7:45p bandrews
178 * PR49212: ASTM overrides user settings, but it should not destroy them
179 *  when it does so
180 *
181 * 14   11/17/08 7:33p bandrews
182 * PR49213: Fix order of initialization of contexts and added ready flag
183 *  for SetSettings
184 *
185 * 13   9/18/08 4:18p erickson
186 * PR47111: fix warnings
187 *
188 * 12   9/18/08 3:29p erickson
189 * PR46838: merge
190 *
191 * PR46838/1   9/17/08 3:27p dyzhang
192 * PR46838: memory leak if do switch channel stress test(kylin will fault
193 *  after switch channel over 700 times). Astm presenter need to be
194 *  destoried when destorying the astm.
195 *
196 * 11   8/28/08 11:14a erickson
197 * PR46151: merge
198 *
199 * PR46151/2   8/27/08 5:17p dyzhang
200 * PR46151: fix a warning
201 *
202 * PR46151/1   8/27/08 4:58p dyzhang
203 * PR46151: _isr callbacks installed for astm in videodecoder,
204 *  audiodecoder and transport are installed when creating astm but not
205 *  uninstalled when destorying astm
206 *
207 * 10   4/11/08 9:53a erickson
208 * PR41246: convert BDBG_OBJECT_UNSET to BDBG_OBJECT_DESTROY if freeing
209 *  memory
210 *
211 * 9   4/3/08 2:40p bandrews
212 * PR40090: sync needs separate context for syslib callbacks and synclib
213 *  callbacks
214 *
215 * 8   4/2/08 11:31a erickson
216 * PR40198: fix DEBUG=n warning
217 *
218 * 7   3/31/08 12:33p erickson
219 * PR41073: check result of malloc and fail graciously
220 *
221 * 6   3/27/08 6:50p bandrews
222 * PR40090: upgraded tsm mode change messages to warnings
223 *
224 * 5   3/27/08 5:51p bandrews
225 * PR40090: default stc tsm mode for adaptive to stc master; fixed debug
226 *  print of video tsm pass
227 *
228 * 4   3/26/08 9:47p bandrews
229 * PR40090: stc channel must be passed to astm before video is started
230 *
231 * 3   3/26/08 5:11p bandrews
232 * PR40090: syslib needs context of at least module handle
233 *
234 * 2   3/24/08 10:53p bandrews
235 * PR40090: astm integration
236 *
237 * 1   3/24/08 9:30p bandrews
238 * PR40090: astm impl
239 **************************************************************************/
240#include "nexus_astm_module.h"
241#include "priv/nexus_core.h"
242#include "priv/nexus_syslib_framework.h"
243#include "priv/nexus_video_decoder_priv.h"
244#include "priv/nexus_audio_decoder_priv.h"
245#include "priv/nexus_stc_channel_priv.h"
246#include "priv/nexus_timebase_priv.h"
247#include "bastmlib.h"
248#if NEXUS_HAS_ASTM_TEST_SUPPORT
249#include "nexus_astm_test_extensions.h"
250#endif
251
252BDBG_MODULE(nexus_astm);
253
254static NEXUS_Error NEXUS_Astm_P_Start(NEXUS_AstmHandle astm);
255static void NEXUS_Astm_P_Stop(NEXUS_AstmHandle astm);
256static void NEXUS_Astm_P_TsmRecoveryAcquisitionTask(void * context);
257static void NEXUS_Astm_P_TsmRecoveryTrackingTimeoutHandler(void * context);
258
259NEXUS_ModuleHandle g_NEXUS_astmModule;
260
261static struct
262{
263    NEXUS_AstmModuleSettings settings;
264    NEXUS_SYSlib_ContextHandle syslibContext;
265} g_astm;
266
267void NEXUS_AstmModule_GetDefaultSettings(NEXUS_AstmModuleSettings *pSettings)
268{
269    BKNI_Memset(pSettings, 0, sizeof(*pSettings));
270}
271
272NEXUS_ModuleHandle NEXUS_AstmModule_Init(const NEXUS_AstmModuleSettings *pSettings)
273{
274    NEXUS_ModuleSettings moduleSettings;
275    NEXUS_SYSlib_ContextSettings syslibSettings;
276
277    BDBG_ASSERT(!g_NEXUS_astmModule);
278
279    BDBG_ASSERT(pSettings);
280    BDBG_ASSERT(pSettings->modules.videoDecoder);
281    BDBG_ASSERT(pSettings->modules.audio);
282    BDBG_ASSERT(pSettings->modules.transport);
283
284    /* init global module handle */
285    NEXUS_Module_GetDefaultSettings(&moduleSettings);
286    moduleSettings.priority = NEXUS_ModulePriority_eLow;
287    g_NEXUS_astmModule = NEXUS_Module_Create("astm", &moduleSettings);
288    if (!g_NEXUS_astmModule) {
289        return NULL;
290    }
291
292    g_astm.settings = *pSettings;
293
294    NEXUS_SYSlib_GetDefaultContextSettings_priv(&syslibSettings);
295    syslibSettings.module = NEXUS_MODULE_SELF;
296    NEXUS_SYSlib_CreateContext_priv(&g_astm.syslibContext, &syslibSettings);
297
298    return g_NEXUS_astmModule;
299}
300
301void NEXUS_AstmModule_Uninit()
302{
303    NEXUS_SYSlib_DestroyContext_priv(g_astm.syslibContext);
304    NEXUS_Module_Destroy(g_NEXUS_astmModule);
305    g_NEXUS_astmModule = NULL;
306}
307
308/****************************************
309* API functions
310***************/
311
312BDBG_OBJECT_ID(NEXUS_Astm);
313
314struct NEXUS_AstmDecoderStatus
315{
316    bool started;
317    uint32_t pts;
318    int32_t ptsStcDiff;
319    unsigned int decodedCount;
320    struct
321    {
322        unsigned int address;
323        unsigned int size;
324    } tsmLog;
325};
326
327struct NEXUS_AstmDecoderSettings
328{
329    int32_t ptsOffset;
330    bool tsm;
331};
332
333typedef void (*NEXUS_Astm_DecoderStatusAccessor_isr)(void * decoder, struct NEXUS_AstmDecoderStatus * status);
334typedef void (*NEXUS_Astm_DecoderStatusAccessor)(void * decoder, struct NEXUS_AstmDecoderStatus * status);
335typedef void (*NEXUS_Astm_DecoderSettingsMutator)(void * decoder, const struct NEXUS_AstmDecoderSettings * settings);
336typedef void (*NEXUS_Astm_DecoderSettingsAccessor)(void * decoder, struct NEXUS_AstmDecoderSettings * settings);
337
338/* Used to collect information to process callbacks from around the system */
339struct NEXUS_AstmContext
340{
341    NEXUS_AstmHandle astm;
342    NEXUS_StcChannelHandle stc;
343    bool started;
344    void * decoder;
345#ifdef BDBG_DEBUG_BUILD
346    const char * decoderName;
347#endif
348    NEXUS_Astm_DecoderStatusAccessor_isr getStatus_isr;
349    NEXUS_Astm_DecoderStatusAccessor getStatus;
350    NEXUS_Astm_DecoderSettingsAccessor getSettings;
351    NEXUS_Astm_DecoderSettingsMutator setSettings;
352    BASTMlib_Presenter_Handle presenter;
353    BKNI_EventHandle watchdogEvent;
354    NEXUS_EventCallbackHandle watchdogEventHandler;
355    BKNI_EventHandle lifecycleEvent;
356    NEXUS_EventCallbackHandle lifecycleEventHandler;
357
358    unsigned passEventCount;
359    unsigned lastDecodedCount;
360    NEXUS_TimerHandle tsmRecoveryAcquisitionTimer;
361    NEXUS_TimerHandle tsmRecoveryTrackingTimer;
362    unsigned ptsStcDiffAdjustmentThreshold;
363    unsigned tsmRecoveryAcquisitionPeriod;
364    unsigned tsmRecoveryTrackingTimeout;
365    BKNI_EventHandle tsmPassEvent;
366    NEXUS_EventCallbackHandle tsmPassEventHandler;
367    uint32_t maxAllowableFirstPtsStcDiff;
368    BKNI_EventHandle firstPtsEvent;
369    NEXUS_EventCallbackHandle firstPtsEventHandler;
370    bool firstPtsTsm;
371    bool firstPtsReceived;
372    uint32_t firstPts;
373    bool tsmThresholdAdjustment;
374    bool manageRateControl;
375    NEXUS_ModuleHandle module;
376};
377
378#define NEXUS_ASTM_PRESENTERS 3
379
380struct NEXUS_Astm
381{
382    BDBG_OBJECT(NEXUS_Astm)
383    NEXUS_AstmSettings settings;
384    NEXUS_TransportType transportType;
385    NEXUS_TimebaseHandle timebase;
386    struct NEXUS_AstmContext presenterContexts[NEXUS_ASTM_PRESENTERS];
387
388    /* syslib info */
389    BASTMlib_Handle lib;
390    BASTMlib_Status status;
391
392    bool ready;
393    bool started;
394    uint32_t lastPcr;
395    bool pcrReceived;
396};
397
398#if 0 /* old recovery scheme */
399#define NEXUS_ASTM_DEFAULT_PASS_EVENT_COUNT_THRESHOLD pcfg.uiPassEventCountThreshold
400#else /* new TSM recovery scheme */
401#define NEXUS_ASTM_DEFAULT_PASS_EVENT_COUNT_THRESHOLD 0
402#endif
403#define NEXUS_ASTM_DEFAULT_PTS_STC_DIFF_ADJ_THRESHOLD 90 /* 45 KHz ticks -> 2 ms */
404#define NEXUS_ASTM_DEFAULT_TSM_RECOVERY_ACQ_PERIOD 200 /* ms */
405#define NEXUS_ASTM_DEFAULT_TSM_RECOVERY_TRACKING_TIMEOUT 1000 /* ms */
406#define NEXUS_ASTM_DEFAULT_MAX_ALLOWABLE_VIDEO_FIRST_PTS_STC_DIFF 454500 /* 10.1 seconds, want this outside the avc spec */
407#define NEXUS_ASTM_DEFAULT_MAX_ALLOWABLE_AUDIO_FIRST_PTS_STC_DIFF 112500 /* 2.5 seconds, < 3 second live audio buffer */
408#define NEXUS_ASTM_P_SYNC_LIMIT 5000
409
410void NEXUS_Astm_GetDefaultSettings(NEXUS_AstmSettings *pSettings)
411{
412    BASTMlib_Config libcfg;
413    BASTMlib_Presenter_Config pcfg;
414    unsigned int i = 0;
415
416    BASTMlib_GetDefaultConfig(&libcfg);
417    BASTMlib_Presenter_GetDefaultConfig(&pcfg);
418   
419    BKNI_Memset(pSettings, 0, sizeof(*pSettings));
420    pSettings->enabled = true;
421    pSettings->enableAutomaticLifecycleControl = false; /* PR:50938 */ /* PR:51684 updated to false */
422    pSettings->syncLimit = NEXUS_ASTM_P_SYNC_LIMIT;
423    pSettings->stcMaster = NULL;
424    pSettings->clockCoupling = NEXUS_AstmClockCoupling_eAdaptive;
425    pSettings->stcSource = NEXUS_AstmStcSource_eAdaptive;
426    pSettings->presentationRateControl = NEXUS_AstmPresentationRateControl_eAdaptive;
427
428    /* clock coupling task default cfg */   
429    pSettings->clockCouplingConfig.initialAcquisitionTime = libcfg.sClockCoupling.uiInitialAcquisitionTime;
430    pSettings->clockCouplingConfig.processingFrequency = libcfg.sClockCoupling.uiProcessingFrequency;
431    pSettings->clockCouplingConfig.idealProcessingFrequency = libcfg.sClockCoupling.uiProcessingFrequency;
432    pSettings->clockCouplingConfig.settlingTime = libcfg.sClockCoupling.uiSettlingTime;
433
434    pSettings->clockCouplingConfig.minimumTimeBetweenEvents = libcfg.sClockCoupling.uiMinimumTimeBetweenEvents;
435    pSettings->clockCouplingConfig.deviationThreshold = libcfg.sClockCoupling.uiDeviationThreshold;
436    pSettings->clockCouplingConfig.deviantCountThreshold = libcfg.sClockCoupling.uiDeviantCountThreshold;
437    pSettings->clockCouplingConfig.idealCountThreshold = libcfg.sClockCoupling.uiIdealCountThreshold;
438
439    /* presentation task default cfg */
440    pSettings->presentationConfig.initialAcquisitionTime = libcfg.sPresentation.uiInitialAcquisitionTime;
441    pSettings->presentationConfig.processingFrequency = libcfg.sPresentation.uiProcessingFrequency;
442    pSettings->presentationConfig.tsmDisabledWatchdogTimeout = libcfg.sPresentation.uiTsmDisabledWatchdogTimeout;
443    pSettings->presentationConfig.settlingTime = libcfg.sPresentation.uiSettlingTime;
444
445    pSettings->videoPresenterConfig.minimumTimeBetweenEvents = pcfg.uiMinimumTimeBetweenEvents;
446    pSettings->videoPresenterConfig.failEventCountThreshold = pcfg.uiFailEventCountThreshold;
447    pSettings->videoPresenterConfig.passEventCountThreshold = NEXUS_ASTM_DEFAULT_PASS_EVENT_COUNT_THRESHOLD;
448    pSettings->videoPresenterConfig.ptsStcDiffAdjustmentThreshold = NEXUS_ASTM_DEFAULT_PTS_STC_DIFF_ADJ_THRESHOLD;
449    pSettings->videoPresenterConfig.tsmRecoveryAcquisitionPeriod = NEXUS_ASTM_DEFAULT_TSM_RECOVERY_ACQ_PERIOD;
450    pSettings->videoPresenterConfig.tsmRecoveryTrackingTimeout = NEXUS_ASTM_DEFAULT_TSM_RECOVERY_TRACKING_TIMEOUT;
451    pSettings->videoPresenterConfig.maxAllowableFirstPtsStcDiff = NEXUS_ASTM_DEFAULT_MAX_ALLOWABLE_VIDEO_FIRST_PTS_STC_DIFF;
452    pSettings->videoPresenterConfig.tsmThresholdAdjustment = false; /* default off for video */
453    pSettings->videoPresenterConfig.manageRateControl = true;
454   
455    for (i = 0; i < NEXUS_ASTM_AUDIO_DECODERS; i++)
456    {
457        pSettings->audioPresenterConfig[i].failEventCountThreshold = pcfg.uiFailEventCountThreshold;
458        pSettings->audioPresenterConfig[i].minimumTimeBetweenEvents = pcfg.uiMinimumTimeBetweenEvents;
459        pSettings->audioPresenterConfig[i].passEventCountThreshold = NEXUS_ASTM_DEFAULT_PASS_EVENT_COUNT_THRESHOLD;
460        pSettings->audioPresenterConfig[i].ptsStcDiffAdjustmentThreshold = NEXUS_ASTM_DEFAULT_PTS_STC_DIFF_ADJ_THRESHOLD;
461        pSettings->audioPresenterConfig[i].tsmRecoveryAcquisitionPeriod = NEXUS_ASTM_DEFAULT_TSM_RECOVERY_ACQ_PERIOD;
462        pSettings->audioPresenterConfig[i].tsmRecoveryTrackingTimeout = NEXUS_ASTM_DEFAULT_TSM_RECOVERY_TRACKING_TIMEOUT;
463        pSettings->audioPresenterConfig[i].maxAllowableFirstPtsStcDiff = NEXUS_ASTM_DEFAULT_MAX_ALLOWABLE_AUDIO_FIRST_PTS_STC_DIFF;
464        pSettings->audioPresenterConfig[i].tsmThresholdAdjustment = true; /* default on for audio */
465        pSettings->audioPresenterConfig[i].manageRateControl = true;
466    }
467}
468
469#ifdef BDBG_DEBUG_BUILD
470static const char * stcSourceStrings[] =
471{
472    "Adaptive",
473    "PCR",
474    "PTS",
475    NULL
476};
477#endif
478
479static NEXUS_Error NEXUS_Astm_P_ApplyStcSource(NEXUS_AstmHandle astm, NEXUS_AstmStcSource stcSource, void * stcMaster)
480{
481    NEXUS_Error rc = NEXUS_SUCCESS;
482    NEXUS_StcChannelAstmSettings stcChannelAstmSettings;
483    NEXUS_VideoDecoderAstmSettings videoDecoderAstmSettings;
484    NEXUS_AudioDecoderAstmSettings audioDecoderAstmSettings;
485    unsigned int i;
486
487    BDBG_WRN(("Stc source: %s", stcSourceStrings[stcSource]));
488
489    /* Adaptive always starts with stc source = clock reference */
490    if (stcSource == NEXUS_AstmStcSource_eAdaptive
491        || stcSource == NEXUS_AstmStcSource_eClockReference)
492    {
493        if (astm->settings.videoDecoder)
494        {
495            NEXUS_Module_Lock(g_astm.settings.modules.videoDecoder);
496            NEXUS_VideoDecoder_GetAstmSettings_priv(astm->settings.videoDecoder, &videoDecoderAstmSettings);
497            videoDecoderAstmSettings.enablePlayback = false;
498            videoDecoderAstmSettings.syncLimit = 0;
499            rc = NEXUS_VideoDecoder_SetAstmSettings_priv(astm->settings.videoDecoder, &videoDecoderAstmSettings);
500            NEXUS_Module_Unlock(g_astm.settings.modules.videoDecoder);
501            if (rc) goto err;
502        }
503        else
504        {
505            BDBG_MSG(("%d: video decoder was NULL", __LINE__));
506        }
507
508        NEXUS_Module_Lock(g_astm.settings.modules.audio);
509        for (i = 0; i < NEXUS_ASTM_AUDIO_DECODERS; i++)
510        {
511            if (astm->settings.audioDecoder[i])
512            {
513                NEXUS_AudioDecoder_GetAstmSettings_priv(astm->settings.audioDecoder[i], &audioDecoderAstmSettings);
514                audioDecoderAstmSettings.enablePlayback = false;
515                audioDecoderAstmSettings.syncLimit = 0;
516                rc = NEXUS_AudioDecoder_SetAstmSettings_priv(astm->settings.audioDecoder[i], &audioDecoderAstmSettings);
517            }
518            else
519            {
520                BDBG_MSG(("%d: audio decoder %d was NULL", __LINE__, i));
521            }
522            if (rc) break;
523        }
524        NEXUS_Module_Unlock(g_astm.settings.modules.audio);
525        if (rc) goto err;
526
527        if (astm->settings.stcChannel)
528        {
529            NEXUS_Module_Lock(g_astm.settings.modules.transport);
530            NEXUS_StcChannel_GetAstmSettings_priv(astm->settings.stcChannel, &stcChannelAstmSettings);
531            stcChannelAstmSettings.mode = NEXUS_StcChannelMode_ePcr;
532            stcChannelAstmSettings.syncLimit = 0;
533            rc = NEXUS_StcChannel_SetAstmSettings_priv(astm->settings.stcChannel, &stcChannelAstmSettings);
534            NEXUS_Module_Unlock(g_astm.settings.modules.transport);
535            if (rc) goto err;
536        }
537        else
538        {
539            BDBG_WRN(("Attempted to apply stc source state to a NULL stc channel"));
540        }
541    }
542    else if (stcSource == NEXUS_AstmStcSource_ePts)
543    {
544        if (astm->settings.videoDecoder)
545        {
546            NEXUS_Module_Lock(g_astm.settings.modules.videoDecoder);
547            NEXUS_VideoDecoder_GetAstmSettings_priv(astm->settings.videoDecoder, &videoDecoderAstmSettings);
548            if (stcMaster == astm->settings.videoDecoder)
549            {
550                BDBG_MSG(("Stc master: video"));
551                videoDecoderAstmSettings.syncLimit = astm->settings.syncLimit;
552            }
553            else
554            {
555                videoDecoderAstmSettings.syncLimit = 0;
556            }
557
558            videoDecoderAstmSettings.enablePlayback = true;
559           
560            rc = NEXUS_VideoDecoder_SetAstmSettings_priv(astm->settings.videoDecoder, &videoDecoderAstmSettings);
561            NEXUS_Module_Unlock(g_astm.settings.modules.videoDecoder);
562            if (rc) goto err;
563        }
564        else
565        {
566            BDBG_MSG(("%d: video decoder was NULL", __LINE__));
567        }
568
569        NEXUS_Module_Lock(g_astm.settings.modules.audio);
570        for (i = 0; i < NEXUS_ASTM_AUDIO_DECODERS; i++)
571        {
572            if (astm->settings.audioDecoder[i])
573            {
574                NEXUS_AudioDecoder_GetAstmSettings_priv(astm->settings.audioDecoder[i], &audioDecoderAstmSettings);
575                if (stcMaster == astm->settings.audioDecoder[i])
576                {
577                    BDBG_MSG(("Stc master: audio %d", i));
578                    audioDecoderAstmSettings.syncLimit = astm->settings.syncLimit;
579                }
580                else
581                {
582                    audioDecoderAstmSettings.syncLimit = 0;
583                }
584               
585                audioDecoderAstmSettings.enablePlayback = true;
586               
587                rc = NEXUS_AudioDecoder_SetAstmSettings_priv(astm->settings.audioDecoder[i], &audioDecoderAstmSettings);
588                if (rc) break;
589            }
590            else
591            {
592                BDBG_MSG(("%d: audio decoder %d was NULL", __LINE__, i));
593            }
594        }
595        NEXUS_Module_Unlock(g_astm.settings.modules.audio);
596        if (rc) goto err;
597
598        if (astm->settings.stcChannel)
599        {
600            NEXUS_Module_Lock(g_astm.settings.modules.transport);
601            NEXUS_StcChannel_GetAstmSettings_priv(astm->settings.stcChannel, &stcChannelAstmSettings);
602            stcChannelAstmSettings.mode = NEXUS_StcChannelMode_eAuto;
603            stcChannelAstmSettings.syncLimit = astm->settings.syncLimit;
604            rc = NEXUS_StcChannel_SetAstmSettings_priv(astm->settings.stcChannel, &stcChannelAstmSettings);
605            NEXUS_Module_Unlock(g_astm.settings.modules.transport);
606            if (rc) goto err;
607        }
608        else
609        {
610            BDBG_WRN(("Attempted to apply stc source state to a NULL stc channel"));
611        }
612    }
613
614    goto end;
615
616err:
617
618end:
619
620    return rc;
621}
622
623
624#ifdef BDBG_DEBUG_BUILD
625static const char * clockCouplingStrings[] =
626{
627    "Adaptive",
628    "Input clock",
629    "Internal clock",
630    NULL
631};
632#endif
633
634static NEXUS_Error NEXUS_Astm_P_ApplyClockCoupling(NEXUS_AstmHandle astm, NEXUS_AstmClockCoupling clockCoupling)
635{
636    NEXUS_Error rc = NEXUS_SUCCESS;
637    NEXUS_TimebaseAstmSettings timebaseAstmSettings;
638
639    if (astm->timebase)
640    {
641        BDBG_WRN(("Clock coupling: %s", clockCouplingStrings[clockCoupling]));
642
643        NEXUS_Module_Lock(g_astm.settings.modules.transport);
644        NEXUS_Timebase_GetAstmSettings_priv(astm->timebase, &timebaseAstmSettings);
645
646        switch (clockCoupling)
647        {
648            case NEXUS_AstmClockCoupling_eAdaptive:
649                /* Adaptive always starts with clock coupling = input -> fall through */
650            case NEXUS_AstmClockCoupling_eInputClock:
651                timebaseAstmSettings.clockCoupling = NEXUS_TimebaseClockCoupling_eInputClock;
652                break;
653            case NEXUS_AstmClockCoupling_eInternalClock:
654                timebaseAstmSettings.clockCoupling = NEXUS_TimebaseClockCoupling_eInternalClock;
655                break;
656            default:
657                break;
658        }
659
660        rc = NEXUS_Timebase_SetAstmSettings_priv(astm->timebase, &timebaseAstmSettings);
661        NEXUS_Module_Unlock(g_astm.settings.modules.transport);
662        if (rc) goto err;
663    }
664    else
665    {
666        BDBG_WRN(("Attempted to apply clock coupling state to an invalid timebase"));
667    }
668
669    goto end;
670
671err:
672
673end:
674
675    return rc;
676}
677
678#ifdef BDBG_DEBUG_BUILD
679static const char * presentationRateControlStrings[] =
680{
681    "Adaptive",
682    "Time stamp",
683    "Output clock",
684    NULL
685};
686#endif
687
688static void NEXUS_Astm_P_CancelPendingTimers(NEXUS_AstmHandle astm)
689{
690    unsigned int i;
691
692    for (i = 0; i < NEXUS_ASTM_PRESENTERS; i++)
693    {
694        if (astm->presenterContexts[i].tsmRecoveryAcquisitionTimer)
695        {
696            NEXUS_CancelTimer(astm->presenterContexts[i].tsmRecoveryAcquisitionTimer);
697            astm->presenterContexts[i].tsmRecoveryAcquisitionTimer = NULL;
698        }
699        if (astm->presenterContexts[i].tsmRecoveryTrackingTimer)
700        {
701            NEXUS_CancelTimer(astm->presenterContexts[i].tsmRecoveryTrackingTimer);
702            astm->presenterContexts[i].tsmRecoveryTrackingTimer = NULL;
703        }
704    }
705}
706
707static NEXUS_Error NEXUS_Astm_P_ApplyPresentationRateControl(NEXUS_AstmHandle astm, NEXUS_AstmPresentationRateControl presentationRateControl)
708{
709    NEXUS_Error rc = NEXUS_SUCCESS;
710    NEXUS_VideoDecoderAstmSettings videoDecoderAstmSettings;
711    NEXUS_AudioDecoderAstmSettings audioDecoderAstmSettings;
712    unsigned int i;
713
714    BDBG_WRN(("Presentation rate control: %s", presentationRateControlStrings[presentationRateControl]));
715
716    /* switching TSM modes means clearing/restarting TSM recovery tasks */
717    NEXUS_Astm_P_CancelPendingTimers(astm);
718
719    /* Adaptive always starts with presentation rate control = time stamp */
720    if (presentationRateControl == NEXUS_AstmPresentationRateControl_eAdaptive
721        || presentationRateControl == NEXUS_AstmPresentationRateControl_eTimeStamp)
722    {
723        if (astm->settings.videoDecoder && astm->settings.videoPresenterConfig.manageRateControl)
724        {
725            NEXUS_Module_Lock(g_astm.settings.modules.videoDecoder);
726            NEXUS_VideoDecoder_GetAstmSettings_priv(astm->settings.videoDecoder, &videoDecoderAstmSettings);
727            videoDecoderAstmSettings.enableTsm = true 
728                && astm->presenterContexts[0].firstPtsTsm; /* don't enable TSM if we've disabled it for buffering reasons */
729            videoDecoderAstmSettings.ptsOffset = 0;
730            rc = NEXUS_VideoDecoder_SetAstmSettings_priv(astm->settings.videoDecoder, &videoDecoderAstmSettings);
731            NEXUS_Module_Unlock(g_astm.settings.modules.videoDecoder);
732            if (rc) goto err;
733        }
734
735        NEXUS_Module_Lock(g_astm.settings.modules.audio);
736        for (i = 0; i < NEXUS_ASTM_AUDIO_DECODERS; i++)
737        {
738            if (astm->settings.audioDecoder[i] && astm->settings.audioPresenterConfig[i].manageRateControl)
739            {
740                NEXUS_AudioDecoder_GetAstmSettings_priv(astm->settings.audioDecoder[i], &audioDecoderAstmSettings);
741                audioDecoderAstmSettings.enableTsm = true
742                    && astm->presenterContexts[i + 1].firstPtsTsm; /* don't enable TSM if we've disabled it for buffering reasons */;
743                audioDecoderAstmSettings.ptsOffset = 0;
744                rc = NEXUS_AudioDecoder_SetAstmSettings_priv(astm->settings.audioDecoder[i], &audioDecoderAstmSettings);
745                if (rc) break;
746            }
747        }
748        NEXUS_Module_Unlock(g_astm.settings.modules.audio);
749        if (rc) goto err;
750    }
751    else if (presentationRateControl == NEXUS_AstmPresentationRateControl_eOutputClock)
752    {
753        if (astm->settings.videoDecoder && astm->settings.videoPresenterConfig.manageRateControl)
754        {
755            NEXUS_Module_Lock(g_astm.settings.modules.videoDecoder);
756            NEXUS_VideoDecoder_GetAstmSettings_priv(astm->settings.videoDecoder, &videoDecoderAstmSettings);
757            videoDecoderAstmSettings.enableTsm = false;
758            rc = NEXUS_VideoDecoder_SetAstmSettings_priv(astm->settings.videoDecoder, &videoDecoderAstmSettings);
759            NEXUS_Module_Unlock(g_astm.settings.modules.videoDecoder);
760            if (rc) goto err;
761
762            /* start timer tasks for non-TSM mode recovery */
763            astm->presenterContexts[0].tsmRecoveryAcquisitionTimer =
764                NEXUS_ScheduleTimer(astm->settings.videoPresenterConfig.tsmRecoveryAcquisitionPeriod, 
765                    &NEXUS_Astm_P_TsmRecoveryAcquisitionTask, &astm->presenterContexts[0]);
766        }
767
768        NEXUS_Module_Lock(g_astm.settings.modules.audio);
769        for (i = 0; i < NEXUS_ASTM_AUDIO_DECODERS; i++)
770        {
771            if (astm->settings.audioDecoder[i] && astm->settings.audioPresenterConfig[i].manageRateControl)
772            {
773                NEXUS_AudioDecoder_GetAstmSettings_priv(astm->settings.audioDecoder[i], &audioDecoderAstmSettings);
774                audioDecoderAstmSettings.enableTsm = false;
775                rc = NEXUS_AudioDecoder_SetAstmSettings_priv(astm->settings.audioDecoder[i], &audioDecoderAstmSettings);
776                if (rc) break;
777
778                /* start timer tasks for non-TSM mode recovery */
779                astm->presenterContexts[i + 1].tsmRecoveryAcquisitionTimer =
780                    NEXUS_ScheduleTimer(astm->settings.audioPresenterConfig[i].tsmRecoveryAcquisitionPeriod, 
781                        &NEXUS_Astm_P_TsmRecoveryAcquisitionTask, &astm->presenterContexts[i + 1]);
782            }
783        }
784        NEXUS_Module_Unlock(g_astm.settings.modules.audio);
785        if (rc) goto err;
786    }
787
788    goto end;
789
790err:
791
792end:
793    return rc;
794}
795
796#ifdef BDBG_DEBUG_BUILD
797static const char * tsmModeStrings[] =
798{
799    "STC master",
800    "video master",
801    "audio master",
802    "output master",
803    NULL
804};
805#endif
806
807static NEXUS_StcChannelTsmMode NEXUS_Astm_P_ComputeStcChannelTsmMode(
808    NEXUS_AstmHandle astm,
809    NEXUS_AstmStcSource stcSource,
810    void * stcMaster,
811    NEXUS_AstmPresentationRateControl presentationRateControl
812)
813{
814    NEXUS_StcChannelTsmMode tsmMode = NEXUS_StcChannelTsmMode_eMax;
815
816    if ((presentationRateControl == NEXUS_AstmPresentationRateControl_eAdaptive
817        && stcSource == NEXUS_AstmStcSource_eAdaptive)
818        ||
819        (presentationRateControl == NEXUS_AstmPresentationRateControl_eTimeStamp
820        && stcSource == NEXUS_AstmStcSource_eClockReference))
821    {
822        tsmMode = NEXUS_StcChannelTsmMode_eStcMaster;
823    }
824    else if (presentationRateControl == NEXUS_AstmPresentationRateControl_eTimeStamp
825        && stcSource == NEXUS_AstmStcSource_ePts)
826    {
827        if (stcMaster == astm->settings.videoDecoder)
828        {
829            tsmMode = NEXUS_StcChannelTsmMode_eVideoMaster;
830        }
831        else if (stcMaster == NULL)
832        {
833            tsmMode = NEXUS_StcChannelTsmMode_eStcMaster; /* FCFS PTS in playback mode */
834        }
835        else
836        {
837            unsigned int i;
838
839            for (i = 0; i < NEXUS_ASTM_AUDIO_DECODERS; i++)
840            {
841                if (stcMaster == astm->settings.audioDecoder[i])
842                {
843                    tsmMode = NEXUS_StcChannelTsmMode_eAudioMaster;
844                    break;
845                }
846            }
847        }
848    }
849    else if (presentationRateControl == NEXUS_AstmPresentationRateControl_eOutputClock)
850    {
851                unsigned int i;
852                bool manageVideoRateControl = true;
853                bool manageAudioRateControl = true;
854
855                manageVideoRateControl = astm->settings.videoPresenterConfig.manageRateControl;
856               
857                for (i = 0; i < NEXUS_ASTM_AUDIO_DECODERS; i++)
858                {
859                        /* if at least 1 audio channel does not allow rate control management, this will be false */
860                        manageAudioRateControl = manageAudioRateControl && 
861                                astm->settings.audioPresenterConfig[i].manageRateControl;
862                }
863
864                if (manageVideoRateControl && manageAudioRateControl)
865                {
866                        /* video and all audio channels allow rate control management, so output master mode */
867            tsmMode = NEXUS_StcChannelTsmMode_eOutputMaster;
868                }
869                else if (manageVideoRateControl && !manageAudioRateControl)
870                {
871                        /* at least one audio does not allow rate control management, but video allows it, so audio master mode */
872            tsmMode = NEXUS_StcChannelTsmMode_eAudioMaster;
873                }
874                else if (!manageVideoRateControl && manageAudioRateControl)
875                {
876                        /* video does not allow rate control management, but audio allows it, so video master mode */
877            tsmMode = NEXUS_StcChannelTsmMode_eVideoMaster;
878                }
879                else
880                {
881                        /* none of the presenters allow rate control management, leave as invalid Max setting */
882                        BDBG_WRN(("No presenters allow presentation rate control management"));
883                }
884    }
885
886    return tsmMode;
887}
888
889static NEXUS_Error NEXUS_Astm_P_ApplyStcChannelTsmMode(
890    NEXUS_AstmHandle astm,
891    NEXUS_StcChannelTsmMode tsmMode
892)
893{
894    NEXUS_Error rc = NEXUS_SUCCESS;
895    NEXUS_StcChannelAstmSettings stcChannelAstmSettings;
896
897    BDBG_WRN(("STC channel tsm mode: %s", tsmModeStrings[tsmMode]));
898
899    if (astm->settings.stcChannel)
900    {
901        NEXUS_Module_Lock(g_astm.settings.modules.transport);
902        NEXUS_StcChannel_GetAstmSettings_priv(astm->settings.stcChannel, &stcChannelAstmSettings);
903        stcChannelAstmSettings.tsmMode = tsmMode;
904        NEXUS_StcChannel_SetAstmSettings_priv(astm->settings.stcChannel, &stcChannelAstmSettings);
905        NEXUS_Module_Unlock(g_astm.settings.modules.transport);
906    }
907    else
908    {
909        BDBG_WRN(("Attempted to apply tsm mode to a NULL stc channel"));
910    }
911
912    return rc;
913}
914
915static BERR_Code NEXUS_Astmlib_P_PresentationStateChange(void * pvParm1, int iParm2)
916{
917    NEXUS_AstmHandle astm = (NEXUS_AstmHandle)pvParm1;
918    BERR_Code rc = BERR_SUCCESS;
919    NEXUS_Error nrc = NEXUS_SUCCESS;
920    NEXUS_AstmStcSource stcSource;
921    NEXUS_AstmPresentationRateControl presentationRateControl;
922    NEXUS_StcChannelTsmMode tsmMode;
923    void * stcMaster;
924
925    BSTD_UNUSED(iParm2);
926    BDBG_OBJECT_ASSERT(astm, NEXUS_Astm);
927
928    BASTMlib_GetStatus(astm->lib, &astm->status);
929
930    switch (astm->status.eStcSource)
931    {
932        case BASTMlib_StcSource_ePresenter:
933            stcSource = NEXUS_AstmStcSource_ePts;
934            break;
935        case BASTMlib_StcSource_eClockReference:
936        default:
937            stcSource = NEXUS_AstmStcSource_eClockReference;
938            break;
939    }
940
941    switch (astm->status.ePresentationRateControl)
942    {
943        case BASTMlib_PresentationRateControl_eOutputClock:
944            presentationRateControl = NEXUS_AstmPresentationRateControl_eOutputClock;
945            break;
946        case BASTMlib_PresentationRateControl_eTimeStamp:
947        default:
948            presentationRateControl = NEXUS_AstmPresentationRateControl_eTimeStamp;
949            break;
950    }
951
952    stcMaster = NULL;
953
954    if (astm->status.hStcMaster == astm->presenterContexts[0].presenter)
955    {
956        stcMaster = astm->settings.videoDecoder;
957    }
958    else
959    {
960        unsigned int i;
961
962        for (i = 0; i < NEXUS_ASTM_AUDIO_DECODERS; i++)
963        {
964            if (astm->status.hStcMaster == astm->presenterContexts[i + 1].presenter)
965            {
966                stcMaster = astm->settings.audioDecoder[i];
967            }
968        }
969    }
970
971    /* this will enable/disable TSM in the decoders.
972    we want to disable it first, but enable it last */
973    if (astm->settings.presentationRateControl == NEXUS_AstmPresentationRateControl_eAdaptive
974        && presentationRateControl == NEXUS_AstmPresentationRateControl_eOutputClock)
975    {
976        nrc = NEXUS_Astm_P_ApplyPresentationRateControl(astm, presentationRateControl);
977        if (nrc) goto err;
978    }
979
980    /* changing pcrlib tsm mode must happen before we switch between Pcr and Auto,
981    so we handle any interrupts accordingly */
982    /* if either stc source or presentation rate control are adaptive, it affects
983    the stc channel tsm mode */
984    if (astm->settings.stcSource == NEXUS_AstmStcSource_eAdaptive
985        || astm->settings.presentationRateControl == NEXUS_AstmPresentationRateControl_eAdaptive)
986    {
987        tsmMode = NEXUS_Astm_P_ComputeStcChannelTsmMode(astm, stcSource,
988            stcMaster, presentationRateControl);
989        if (tsmMode != NEXUS_StcChannelTsmMode_eMax)
990        {
991                nrc = NEXUS_Astm_P_ApplyStcChannelTsmMode(astm, tsmMode);
992                if (nrc) goto err;
993        }
994    }
995
996    /* this will enable/disable playback in the decoders and switch pcrlib between PCR and Auto
997    this must occur after we've picked which pcrlib mode we want, otherwise Auto may be
998    handled incorrectly */
999    /* only apply the settings for the ones that are adaptive */
1000    if (astm->settings.stcSource == NEXUS_AstmStcSource_eAdaptive)
1001    {
1002        nrc = NEXUS_Astm_P_ApplyStcSource(astm, stcSource, stcMaster);
1003        if (nrc) goto err;
1004    }
1005
1006    /* this will enable/disable TSM in the decoders.
1007    we want to disable it first, but enable it last */
1008    if (astm->settings.presentationRateControl == NEXUS_AstmPresentationRateControl_eAdaptive
1009        && presentationRateControl == NEXUS_AstmPresentationRateControl_eTimeStamp)
1010    {
1011        nrc = NEXUS_Astm_P_ApplyPresentationRateControl(astm, presentationRateControl);
1012        if (nrc) goto err;
1013    }
1014
1015    goto end;
1016
1017err:
1018
1019end:
1020
1021    return rc;
1022}
1023
1024static BERR_Code NEXUS_Astmlib_P_ClockCouplingStateChange(void * pvParm1, int iParm2)
1025{
1026    BERR_Code rc = BERR_SUCCESS;
1027    NEXUS_Error nrc = NEXUS_SUCCESS;
1028    NEXUS_AstmHandle astm = (NEXUS_AstmHandle)pvParm1;
1029    NEXUS_AstmClockCoupling clockCoupling;
1030
1031    BSTD_UNUSED(iParm2);
1032    BDBG_OBJECT_ASSERT(astm, NEXUS_Astm);
1033
1034    BASTMlib_GetStatus(astm->lib, &astm->status);
1035
1036    switch (astm->status.eClockCoupling)
1037    {
1038        case BASTMlib_ClockCoupling_eInternalClock:
1039            clockCoupling = NEXUS_AstmClockCoupling_eInternalClock;
1040            break;
1041        case BASTMlib_ClockCoupling_eInputClock:
1042        default:
1043            clockCoupling = NEXUS_AstmClockCoupling_eInputClock;
1044            break;
1045    }
1046
1047    if (astm->settings.clockCoupling == NEXUS_AstmClockCoupling_eAdaptive)
1048    {
1049        nrc = NEXUS_Astm_P_ApplyClockCoupling(astm, clockCoupling);
1050        if (nrc) goto err;
1051    }
1052
1053    goto end;
1054
1055err:
1056
1057end:
1058
1059    return rc;
1060}
1061
1062static void NEXUS_Astm_P_GetAudioSettings(void * decoder, struct NEXUS_AstmDecoderSettings * settings)
1063{
1064    NEXUS_AudioDecoderAstmSettings audioSettings;
1065
1066    if (decoder)
1067    {
1068        if (settings)
1069        {
1070            NEXUS_AudioDecoder_GetAstmSettings_priv((NEXUS_AudioDecoderHandle)decoder, &audioSettings);
1071            settings->ptsOffset = audioSettings.ptsOffset;
1072            settings->tsm = audioSettings.enableTsm;
1073        }
1074        else
1075        {
1076            BDBG_WRN(("GetAudioSettings NULL settings"));
1077        }
1078    }
1079    else
1080    {
1081        BDBG_WRN(("GetAudioSettings NULL decoder handle"));
1082    }
1083}
1084
1085static void NEXUS_Astm_P_SetAudioSettings(void * decoder, const struct NEXUS_AstmDecoderSettings * settings)
1086{
1087    NEXUS_AudioDecoderAstmSettings audioSettings;
1088
1089    if (decoder)
1090    {
1091        if (settings)
1092        {
1093            /* SW7335-1330: Coverity: 35222, UNINIT */
1094            /* 20111207 bandrews - can't init with memset, need to preserve callbacks and such from previous settings */
1095            NEXUS_AudioDecoder_GetAstmSettings_priv((NEXUS_AudioDecoderHandle)decoder, &audioSettings);
1096            audioSettings.ptsOffset = settings->ptsOffset;
1097            audioSettings.enableTsm = settings->tsm;
1098            if (NEXUS_AudioDecoder_SetAstmSettings_priv((NEXUS_AudioDecoderHandle)decoder, &audioSettings))
1099            {
1100                BDBG_WRN(("Error in NEXUS_AudioDecoder_SetAstmSettings_priv"));
1101                return;
1102            }
1103        }
1104        else
1105        {
1106            BDBG_WRN(("SetAudioSettings NULL settings"));
1107        }
1108    }
1109    else
1110    {
1111        BDBG_WRN(("SetAudioSettings NULL decoder handle"));
1112    }
1113}
1114
1115static void NEXUS_Astm_P_GetAudioStatus_isr(void * decoder, struct NEXUS_AstmDecoderStatus * status)
1116{
1117    NEXUS_AudioDecoderAstmStatus audioStatus;
1118
1119    if (decoder)
1120    {
1121        NEXUS_AudioDecoder_GetAstmStatus_isr((NEXUS_AudioDecoderHandle)decoder, &audioStatus);
1122        if (status)
1123        {
1124            status->started = audioStatus.started;
1125            status->pts = audioStatus.pts;
1126            status->ptsStcDiff = -audioStatus.ptsStcDiff; /* stc - pts is reported */
1127            status->tsmLog.address = audioStatus.tsmLog.address;
1128            status->tsmLog.size = audioStatus.tsmLog.size;
1129        }
1130    }
1131    else
1132    {
1133        BDBG_WRN(("GetAudioStatus_isr NULL decoder handle"));
1134    }
1135}
1136
1137static void NEXUS_Astm_P_GetAudioStatus(void * decoder, struct NEXUS_AstmDecoderStatus * status)
1138{
1139    NEXUS_AudioDecoderStatus audioStatus;
1140
1141    if (decoder)
1142    {
1143        BKNI_EnterCriticalSection();
1144        NEXUS_Astm_P_GetAudioStatus_isr(decoder, status);
1145        BKNI_LeaveCriticalSection();
1146        if (NEXUS_AudioDecoder_GetStatus((NEXUS_AudioDecoderHandle)decoder, &audioStatus))
1147        {
1148            BDBG_WRN(("Error in NEXUS_VideoDecoder_GetStatus "));
1149
1150        }
1151
1152        if (status && audioStatus.framesDecoded)
1153        {
1154            status->decodedCount = audioStatus.framesDecoded;
1155        }
1156    }
1157    else
1158    {
1159        BDBG_WRN(("GetAudioStatus NULL decoder handle"));
1160    }
1161}
1162
1163static void NEXUS_Astm_P_GetVideoSettings(void * decoder, struct NEXUS_AstmDecoderSettings * settings)
1164{
1165    NEXUS_VideoDecoderAstmSettings videoSettings;
1166
1167    if (decoder)
1168    {
1169        if (settings)
1170        {
1171            NEXUS_VideoDecoder_GetAstmSettings_priv((NEXUS_VideoDecoderHandle)decoder, &videoSettings);
1172            settings->ptsOffset = videoSettings.ptsOffset;
1173            settings->tsm = videoSettings.enableTsm;
1174        }
1175        else
1176        {
1177            BDBG_WRN(("GetVideoSettings NULL settings"));
1178        }
1179    }
1180    else
1181    {
1182        BDBG_WRN(("GetVideoSettings NULL decoder handle"));
1183    }
1184}
1185
1186static void NEXUS_Astm_P_SetVideoSettings(void * decoder, const struct NEXUS_AstmDecoderSettings * settings)
1187{
1188    NEXUS_VideoDecoderAstmSettings videoSettings;
1189
1190    if (decoder)
1191    {
1192        if (settings)
1193        {
1194            NEXUS_VideoDecoder_GetAstmSettings_priv((NEXUS_VideoDecoderHandle)decoder, &videoSettings);
1195            videoSettings.ptsOffset = settings->ptsOffset;
1196            videoSettings.enableTsm = settings->tsm;
1197            if ( NEXUS_VideoDecoder_SetAstmSettings_priv((NEXUS_VideoDecoderHandle)decoder, &videoSettings) )
1198            {
1199                BDBG_WRN(("Error in NEXUS_VideoDecoder_SetAstmSettings_priv "));
1200                return;
1201            }
1202        }
1203        else
1204        {
1205            BDBG_WRN(("SetVideoSettings NULL settings"));
1206        }
1207    }
1208    else
1209    {
1210        BDBG_WRN(("SetVideoSettings NULL decoder handle"));
1211    }
1212}
1213
1214static void NEXUS_Astm_P_GetVideoStatus_isr(void * decoder, struct NEXUS_AstmDecoderStatus * status)
1215{
1216    NEXUS_VideoDecoderAstmStatus videoStatus;
1217
1218    if (decoder)
1219    {
1220        NEXUS_VideoDecoder_GetAstmStatus_isr((NEXUS_VideoDecoderHandle)decoder, &videoStatus);
1221        if (status)
1222        {
1223            status->started = videoStatus.started;
1224            status->pts = videoStatus.pts;
1225            status->tsmLog.address = videoStatus.tsmLog.address;
1226            status->tsmLog.size = videoStatus.tsmLog.size;
1227        }
1228    }
1229    else
1230    {
1231        BDBG_WRN(("GetVideoStatus_isr NULL decoder handle"));
1232    }
1233}
1234
1235static void NEXUS_Astm_P_GetVideoStatus(void * decoder, struct NEXUS_AstmDecoderStatus * status)
1236{
1237    NEXUS_VideoDecoderStatus videoStatus;
1238
1239    if (decoder)
1240    {
1241        BKNI_EnterCriticalSection();
1242        NEXUS_Astm_P_GetVideoStatus_isr(decoder, status);
1243        BKNI_LeaveCriticalSection();
1244        if (NEXUS_VideoDecoder_GetStatus((NEXUS_VideoDecoderHandle)decoder, &videoStatus))
1245        {
1246            BDBG_WRN(("Error in NEXUS_VideoDecoder_GetStatus "));
1247        }
1248       
1249        if (status)
1250        {
1251            status->decodedCount = videoStatus.numDecoded;
1252            status->ptsStcDiff = videoStatus.ptsStcDifference;
1253        }
1254    }
1255    else
1256    {
1257        BDBG_WRN(("GetVideoStatus NULL decoder handle"));
1258    }
1259}
1260
1261static void NEXUS_Astm_P_TsmCallback_isr(struct NEXUS_AstmContext * context, bool pass)
1262{
1263    struct NEXUS_AstmDecoderStatus decoderStatus;
1264    BASTMlib_Presenter_Event event;
1265
1266    BKNI_Memset(&decoderStatus, 0, sizeof(struct NEXUS_AstmDecoderStatus));
1267    BKNI_Memset(&event, 0, sizeof(BASTMlib_Presenter_Event));
1268
1269    if (context)
1270    {
1271        if (context->astm)
1272        {
1273            if (context->astm->ready)
1274            {
1275                if (context->getStatus_isr)
1276                {
1277                    context->getStatus_isr(context->decoder, &decoderStatus);
1278                    event.uiPts = decoderStatus.pts;
1279                }
1280                else
1281                {
1282                    BDBG_WRN(("%s TSM callback NULL getStatus_isr function pointer", context->decoderName));
1283                }
1284
1285                if (context->stc)
1286                {
1287                    NEXUS_StcChannel_GetStc_isr(context->stc, &event.uiStc);
1288                }
1289                else
1290                {
1291                    BDBG_WRN(("%s TSM callback NULL STC channel handle", context->decoderName));
1292                }
1293
1294                event.bPass = pass;
1295
1296                BDBG_MSG(("%s TSM %s callback pts=%#x stc=%#x", context->decoderName, pass ? "PASS" : "FAIL", event.uiPts, event.uiStc));
1297
1298                if (context->presenter)
1299                {
1300                    BASTMlib_Presenter_EventHandler_isr(context->presenter, &event);
1301                }
1302                else
1303                {
1304                    BDBG_WRN(("%s TSM callback NULL presenter handle", context->decoderName));
1305                }
1306            }
1307            else
1308            {
1309                BDBG_MSG(("%s TSM callback (ASTM not ready)", context->decoderName));
1310            }
1311        }
1312        else
1313        {
1314            BDBG_WRN(("%s TSM callback NULL astm handle", context->decoderName));
1315        }
1316    }
1317    else
1318    {
1319        BDBG_WRN(("TSM callback NULL context"));
1320    }
1321}
1322
1323static void NEXUS_Astm_P_DecoderFirstPtsEventHandler(void * context)
1324{
1325    struct NEXUS_AstmContext * astmContext = (struct NEXUS_AstmContext * )context;
1326    NEXUS_StcChannelSettings stcChannelSettings;
1327    struct NEXUS_AstmDecoderSettings settings;
1328
1329    /* this event only happens when the first pts/stc diff is outside the allowable range */
1330   
1331    NEXUS_StcChannel_GetSettings(astmContext->astm->settings.stcChannel, &stcChannelSettings);
1332
1333    if (stcChannelSettings.mode == NEXUS_StcChannelMode_ePcr)
1334    {
1335        /* TODO: should manageRateControl apply to this? */
1336        BDBG_MSG(("First PTS event occurred in live mode, disabling TSM on offending decoder"));
1337        if (astmContext->getSettings && astmContext->setSettings)
1338        {
1339            astmContext->firstPtsTsm = false; /* save for later */
1340            NEXUS_Module_Lock(astmContext->module);
1341            astmContext->getSettings(astmContext->decoder, &settings);
1342            settings.tsm = false;
1343            settings.ptsOffset = 0;
1344            astmContext->setSettings(astmContext->decoder, &settings);
1345            NEXUS_Module_Unlock(astmContext->module);
1346        }
1347    }
1348    else
1349    {
1350        BDBG_MSG(("First PTS event occurred in playback mode, ignored"));
1351    }
1352}
1353
1354static bool NEXUS_Astm_P_PtsStcDiffCheck_isr(uint32_t firstPts, uint32_t lastPcr, uint32_t max)
1355{
1356    bool fail = false;
1357   
1358    BDBG_MSG(("first pts: %#x; last pcr: %#x; max allowable diff: %u", firstPts, lastPcr, max));
1359
1360    /* we only test the positive case */
1361    if (firstPts > lastPcr)
1362    {
1363        if (firstPts - lastPcr > max)
1364        {
1365            fail = true;
1366        }
1367    }
1368
1369    return fail;
1370}
1371
1372static void NEXUS_Astm_P_DecoderFirstPtsCallback_isr(void * context, int param)
1373{
1374    struct NEXUS_AstmContext * astmContext = (struct NEXUS_AstmContext * )context;
1375    struct NEXUS_AstmDecoderStatus status;
1376
1377    BSTD_UNUSED(param);
1378
1379    if (astmContext)
1380    {
1381        if (astmContext->maxAllowableFirstPtsStcDiff) /* don't bother checking if max = 0 */
1382        {
1383            BDBG_MSG(("%d: %s decoder first PTS callback", __LINE__, astmContext->decoderName));
1384
1385
1386            if (astmContext->getStatus_isr)
1387            {
1388                astmContext->getStatus_isr(astmContext->decoder, &status);
1389                astmContext->firstPts = status.pts;
1390                astmContext->firstPtsReceived = true;
1391
1392                if (astmContext->astm->pcrReceived)
1393                {
1394                    if (NEXUS_Astm_P_PtsStcDiffCheck_isr(astmContext->firstPts, astmContext->astm->lastPcr, astmContext->maxAllowableFirstPtsStcDiff))
1395                    {
1396                        BKNI_SetEvent(astmContext->firstPtsEvent);
1397                    }
1398                }
1399                else
1400                {
1401                    BDBG_MSG(("%s first PTS, no PCR yet, suspending pts/stc diff check", astmContext->decoderName));
1402                }
1403            }
1404            else
1405            {
1406                BDBG_WRN(("%d: decoder first PTS callback NULL getStatus_isr", __LINE__));
1407            }
1408        }
1409    }
1410    else
1411    {
1412        BDBG_WRN(("%d: decoder first PTS callback NULL context", __LINE__));
1413    }
1414}
1415
1416static void NEXUS_Astm_P_DecoderTsmPassEventHandler(void * context)
1417{
1418    struct NEXUS_AstmContext * astmContext = (struct NEXUS_AstmContext * )context;
1419
1420    /* if acq timer exists (it should) cancel it */
1421    if (astmContext->tsmRecoveryAcquisitionTimer)
1422    {
1423        NEXUS_CancelTimer(astmContext->tsmRecoveryAcquisitionTimer);
1424        astmContext->tsmRecoveryAcquisitionTimer = NULL;
1425    }
1426
1427    if (!astmContext->tsmRecoveryTrackingTimer)
1428    {
1429        struct NEXUS_AstmDecoderStatus status;
1430       
1431        if (astmContext->getStatus)
1432        {
1433            astmContext->getStatus(astmContext->decoder, &status);
1434            astmContext->lastDecodedCount = status.decodedCount;
1435        }
1436
1437        /* schedule track timer */     
1438        astmContext->tsmRecoveryTrackingTimer = 
1439            NEXUS_ScheduleTimer(astmContext->tsmRecoveryTrackingTimeout, 
1440                &NEXUS_Astm_P_TsmRecoveryTrackingTimeoutHandler, astmContext);
1441    }
1442}
1443
1444static void NEXUS_Astm_P_DecoderTsmPassCallback_isr(void * context, int param)
1445{
1446    struct NEXUS_AstmContext * astmContext = (struct NEXUS_AstmContext * )context;
1447
1448    BSTD_UNUSED(param);
1449
1450#if 0 /* don't do normal TSM pass anymore */
1451    NEXUS_Astm_P_TsmCallback_isr(astmContext, true);
1452#else
1453    if (astmContext)
1454    {
1455        BDBG_MSG(("%d: %s decoder TSM pass callback", __LINE__, astmContext->decoderName));
1456        /* count the pass event */
1457        astmContext->passEventCount++;
1458
1459        BKNI_SetEvent(astmContext->tsmPassEvent);
1460    }
1461    else
1462    {
1463        BDBG_WRN(("%d: decoder TSM pass callback NULL context", __LINE__));
1464    }
1465#endif
1466}
1467
1468static void NEXUS_Astm_P_DecoderTsmFailCallback_isr(void * context, int param)
1469{
1470    struct NEXUS_AstmContext * astmContext = (struct NEXUS_AstmContext * )context;
1471
1472    BSTD_UNUSED(param);
1473
1474    NEXUS_Astm_P_TsmCallback_isr(astmContext, false);
1475}
1476
1477static void NEXUS_Astm_P_DecoderTsmLogCallback_isr(void * context, int param)
1478{
1479    BSTD_UNUSED(context);
1480    BSTD_UNUSED(param);
1481    /* TODO */
1482}
1483
1484static void NEXUS_Astm_P_DecoderWatchdogCallback_isr(void * context, int param)
1485{
1486    struct NEXUS_AstmContext * astmContext = (struct NEXUS_AstmContext * )context;
1487
1488    BSTD_UNUSED(param);
1489
1490    if (astmContext)
1491    {
1492        BDBG_ERR(("%s watchdog callback", astmContext->decoderName));
1493
1494        BKNI_SetEvent(astmContext->watchdogEvent);
1495    }
1496}
1497
1498static void NEXUS_Astm_P_DecoderWatchdogEventHandler(void * context)
1499{
1500    struct NEXUS_AstmContext * astmContext = (struct NEXUS_AstmContext * )context;
1501
1502    /* if started, restart */
1503    if (astmContext->astm->started)
1504    {
1505        BDBG_ERR(("Auto-restarting"));
1506        NEXUS_Astm_P_Stop(astmContext->astm);
1507        NEXUS_Astm_P_Start(astmContext->astm);
1508    }
1509}
1510
1511static void NEXUS_Astm_P_DecoderLifecycleCallback_isr(void * context, int param)
1512{
1513    struct NEXUS_AstmDecoderStatus decoderStatus;
1514    struct NEXUS_AstmContext * astmContext = (struct NEXUS_AstmContext * )context;
1515
1516    BSTD_UNUSED(param);
1517
1518    BKNI_Memset(&decoderStatus, 0, sizeof(struct NEXUS_AstmDecoderStatus));
1519
1520    if (astmContext)
1521    {
1522        if (astmContext->getStatus_isr)
1523        {
1524            astmContext->getStatus_isr(astmContext->decoder, &decoderStatus);
1525            astmContext->started = decoderStatus.started;
1526            astmContext->firstPtsReceived = false;
1527            astmContext->firstPtsTsm = true;
1528
1529            BDBG_MSG(("%s lifecycle callback: %s", astmContext->decoderName, astmContext->started ? "started" : "stopped"));
1530
1531            BKNI_SetEvent(astmContext->lifecycleEvent);
1532        }
1533        else
1534        {
1535            BDBG_WRN(("%s lifecycle callback NULL getStatus_isr function pointer", astmContext->decoderName));
1536        }
1537    }
1538}
1539
1540static void NEXUS_Astm_P_DecoderLifecycleEventHandler(void * context)
1541{
1542    unsigned int i = 0;
1543    struct NEXUS_AstmContext * astmContext = (struct NEXUS_AstmContext * )context;
1544
1545    if (astmContext)
1546    {
1547        if (astmContext->astm)
1548        {
1549            /* PR50938 add ability to disable ALC */
1550            if (astmContext->astm->settings.enableAutomaticLifecycleControl)
1551            {
1552                if (astmContext->started)
1553                {
1554                    /* if one presenter is started, start ASTM */
1555                    if (!astmContext->astm->started)
1556                    {
1557                        BDBG_MSG(("Auto-starting"));
1558                        NEXUS_Astm_P_Start(astmContext->astm);
1559                    }
1560                }
1561                else /* this presenter was just stopped, check others */
1562                {
1563                    for (i = 0; i < NEXUS_ASTM_PRESENTERS; i++)
1564                    {
1565                        if (astmContext->astm->presenterContexts[i].started)
1566                        {
1567                            break;
1568                        }
1569                    }
1570
1571                    /* all presenters are stopped */
1572                    if (i == NEXUS_ASTM_PRESENTERS)
1573                    {
1574                        BDBG_MSG(("Auto-stopping"));
1575                        NEXUS_Astm_P_Stop(astmContext->astm);
1576                    }
1577                }
1578            }
1579
1580            /* if a decoder is being started, stc channel state should be valid
1581            for this session */
1582            /* PR:49215 playback support */
1583            if (astmContext->started)
1584            {
1585                BASTMlib_Config astmlibConfig;
1586                NEXUS_StcChannelSettings stcChannelSettings;
1587               
1588                NEXUS_StcChannel_GetSettings(astmContext->astm->settings.stcChannel, &stcChannelSettings);
1589
1590                if (stcChannelSettings.mode == NEXUS_StcChannelMode_ePcr)
1591                {
1592                    /* assumes pcr's should be available from xpt hw */
1593                    BDBG_MSG(("Decoder started with stc channel in PCR mode, assuming PCRs available"));
1594                    BASTMlib_GetConfig(astmContext->astm->lib, &astmlibConfig);
1595                    astmlibConfig.sPresentation.ePreferredStcSource = BASTMlib_StcSource_eClockReference;
1596                    astmlibConfig.sClockCoupling.ePreferredClockCoupling = BASTMlib_ClockCoupling_eInputClock;
1597                    BASTMlib_SetConfig(astmContext->astm->lib, &astmlibConfig);
1598                }
1599                else
1600                {
1601                    /* assumes pcr's should not be available from xpt hw */
1602                    BDBG_MSG(("Decoder started with stc channel in auto/host mode, assuming PCRs unavailable"));
1603                    BASTMlib_GetConfig(astmContext->astm->lib, &astmlibConfig);
1604                    astmlibConfig.sPresentation.ePreferredStcSource = BASTMlib_StcSource_ePresenter;
1605                    astmlibConfig.sClockCoupling.ePreferredClockCoupling = BASTMlib_ClockCoupling_eInternalClock;
1606                    BASTMlib_SetConfig(astmContext->astm->lib, &astmlibConfig);
1607                }
1608            }
1609
1610            /* TODO: need to reapply current ASTM settings to decoder on restart */
1611        }
1612    }
1613}
1614
1615static void NEXUS_Astm_P_TimebasePcrReceivedCallback_isr(void * context, int param)
1616{
1617    NEXUS_AstmHandle astm = (NEXUS_AstmHandle)context;
1618    NEXUS_TimebaseStatus status;
1619    BASTMlib_ClockReference_Event sEvent;
1620    unsigned int i = 0;
1621
1622    BSTD_UNUSED(param);
1623    BKNI_Memset(&sEvent, 0, sizeof(BASTMlib_ClockReference_Event));
1624
1625    if (astm && astm->ready)
1626    {
1627        NEXUS_Timebase_GetStatus_priv_isr(astm->timebase, &status);
1628        sEvent.uiClockReference = status.lastValue;
1629
1630                if (astm->status.eClockCoupling == BASTMlib_ClockCoupling_eInputClock)
1631                {
1632                        /* if input clock, then error is between stc and pcr */
1633                sEvent.uiStc = status.lastValue - status.lastError; /* error saturates
1634                    at 10 bits (instead of 32), but for our purposes this is okay */
1635            }
1636            else
1637            {
1638                /* if internal, then error is between stc and xtal, so need to just
1639                read STC.  This will be sensitive to high latency environments, but
1640                the worst case in high latency situation is that we measure bad
1641                PCR/STC jitter and stay in the state we are already in */
1642                NEXUS_StcChannel_GetStc_isr(astm->settings.stcChannel, &sEvent.uiStc);
1643            }
1644
1645        BDBG_MSG(("TimebasePcrReceived pcr=%#x stc=%#x", sEvent.uiClockReference, sEvent.uiStc));
1646
1647        BASTMlib_ClockReferenceEventHandler_isr(astm->lib, &sEvent);
1648
1649        astm->lastPcr = status.lastValue;
1650
1651        if (!astm->pcrReceived)
1652        {
1653            /* in case PCR comes after first PTS, need to check large first PTS condition here */
1654            for (i = 0; i < NEXUS_ASTM_PRESENTERS; i++)
1655            {
1656                if (astm->presenterContexts[i].firstPtsReceived && astm->presenterContexts[i].maxAllowableFirstPtsStcDiff) /* don't bother checking if max = 0 */
1657                {
1658                    if (NEXUS_Astm_P_PtsStcDiffCheck_isr(astm->presenterContexts[i].firstPts, astm->lastPcr, astm->presenterContexts[i].maxAllowableFirstPtsStcDiff))
1659                    {
1660                        BKNI_SetEvent(astm->presenterContexts[i].firstPtsEvent);
1661                    }
1662                }
1663            }
1664
1665        }
1666       
1667        astm->pcrReceived = true;
1668    }
1669    else
1670    {
1671        BDBG_MSG(("TimebasePcrReceived (ASTM not ready)"));
1672    }
1673}
1674
1675static void NEXUS_Astm_P_TsmRecoveryTrackingTimeoutHandler(void * context)
1676{
1677    struct NEXUS_AstmContext * astmContext = context;
1678    struct NEXUS_AstmDecoderStatus status;
1679
1680    if (astmContext)
1681    {
1682        astmContext->tsmRecoveryTrackingTimer = NULL;
1683       
1684        if (astmContext->getStatus)
1685        {
1686            astmContext->getStatus(astmContext->decoder, &status);
1687
1688            /* TODO: may need a threshold here */
1689            BDBG_MSG(("%d: tsm pass count (%u); decoded count (%u)", __LINE__, astmContext->passEventCount, status.decodedCount - astmContext->lastDecodedCount));
1690            if (status.decodedCount && (status.decodedCount <= astmContext->passEventCount + astmContext->lastDecodedCount))
1691            {
1692                BKNI_EnterCriticalSection();
1693                NEXUS_Astm_P_TsmCallback_isr(astmContext, true);
1694                BKNI_LeaveCriticalSection();
1695            }
1696            else
1697            {
1698                BDBG_MSG(("%d: reverting to acquisition stage", __LINE__));
1699
1700                /* revert to acquisition */
1701                astmContext->tsmRecoveryAcquisitionTimer = 
1702                    NEXUS_ScheduleTimer(astmContext->tsmRecoveryAcquisitionPeriod, 
1703                        &NEXUS_Astm_P_TsmRecoveryAcquisitionTask, astmContext);
1704            }
1705
1706            astmContext->lastDecodedCount = status.decodedCount;
1707            astmContext->passEventCount = 0;
1708        }
1709        else
1710        {
1711            BDBG_MSG(("%d: decoder status accessor was NULL", __LINE__));
1712        }
1713    }
1714}
1715
1716static void NEXUS_Astm_P_TsmRecoveryAcquisitionTask(void * context)
1717{
1718    struct NEXUS_AstmContext * astmContext = context;
1719    struct NEXUS_AstmDecoderSettings settings;
1720    struct NEXUS_AstmDecoderStatus status;
1721
1722    if (astmContext)
1723    {
1724        astmContext->tsmRecoveryAcquisitionTimer = NULL;
1725
1726        /* if we've disabled TSM for first PTS reasons, don't bother coming back */
1727        if (astmContext->firstPtsTsm) 
1728        {
1729            if (astmContext->getStatus)
1730            {
1731                astmContext->getStatus(astmContext->decoder, &status);
1732                astmContext->lastDecodedCount = status.decodedCount;
1733
1734                if (astmContext->getSettings && astmContext->setSettings)
1735                {
1736                    BDBG_MSG(("%d: %s pts/stc diff = %ld", __LINE__, astmContext->decoderName, status.ptsStcDiff));
1737
1738                    if (status.ptsStcDiff > (int32_t)astmContext->ptsStcDiffAdjustmentThreshold
1739                        || status.ptsStcDiff < -(int32_t)astmContext->ptsStcDiffAdjustmentThreshold)
1740                    {
1741                        NEXUS_Module_Lock(astmContext->module);
1742                        astmContext->getSettings(astmContext->decoder, &settings);
1743                        settings.ptsOffset += -status.ptsStcDiff; 
1744                        astmContext->setSettings(astmContext->decoder, &settings);
1745                        NEXUS_Module_Unlock(astmContext->module);
1746                        BDBG_MSG(("%d: %s ptsOffset = %ld", __LINE__, astmContext->decoderName, settings.ptsOffset));
1747                    }
1748                    else
1749                    {
1750                        BDBG_MSG(("%d: %s pts/stc diff within tolerance", __LINE__, astmContext->decoderName));
1751                    }
1752                }
1753                else
1754                {
1755                    BDBG_MSG(("%d: %s decoder settings mutator was NULL", __LINE__, astmContext->decoderName));
1756                }
1757            }
1758            else
1759            {
1760                BDBG_MSG(("%d: %s decoder status accessor was NULL", __LINE__, astmContext->decoderName));
1761            }
1762
1763            /* schedule the next recovery task acq instant */
1764            astmContext->tsmRecoveryAcquisitionTimer = 
1765                NEXUS_ScheduleTimer(astmContext->tsmRecoveryAcquisitionPeriod, 
1766                    &NEXUS_Astm_P_TsmRecoveryAcquisitionTask, astmContext);
1767        }
1768    }
1769}
1770
1771/**********************
1772*
1773* Main functions
1774*
1775***********************/
1776
1777NEXUS_AstmHandle NEXUS_Astm_Create(const NEXUS_AstmSettings *pSettings)
1778{
1779    BASTMlib_Settings settings;
1780    NEXUS_AstmHandle astm;
1781    BERR_Code rc;
1782    unsigned int i = 0;
1783    BASTMlib_Presenter_Settings presenterSettings;
1784
1785    astm = BKNI_Malloc(sizeof(*astm));
1786    if (!astm) {
1787        BERR_TRACE(NEXUS_OUT_OF_SYSTEM_MEMORY);
1788        return NULL;
1789    }
1790    BKNI_Memset(astm, 0, sizeof(*astm));
1791    BDBG_OBJECT_SET(astm, NEXUS_Astm);
1792    NEXUS_Astm_GetDefaultSettings(&astm->settings);
1793    astm->timebase = NULL;
1794
1795    BKNI_EnterCriticalSection();
1796    astm->ready = false;
1797    BKNI_LeaveCriticalSection();
1798
1799    BASTMlib_GetDefaultSettings(&settings);
1800
1801    /* map syslib/framework functions to base */
1802    settings.cbTimer.pfCreate = NEXUS_SYSlib_P_CreateTimer;
1803    settings.cbTimer.pfDestroy = NEXUS_SYSlib_P_DestroyTimer;
1804    settings.cbTimer.pfStart_isr = NEXUS_SYSlib_P_StartTimer_isr;
1805    settings.cbTimer.pfCancel_isr = NEXUS_SYSlib_P_CancelTimer_isr;
1806    settings.cbTimer.pvParm1 = g_astm.syslibContext;
1807    settings.cbTimer.iParm2 = 0; /* unused */
1808
1809    /* ASTMlib state change callbacks. They are all task time. You cannot make any change to ASTMlib during these callbacks. */
1810    settings.sClockCoupling.cbStateChange.pfDo = &NEXUS_Astmlib_P_ClockCouplingStateChange;
1811    settings.sClockCoupling.cbStateChange.pvParm1 = astm;
1812    settings.sClockCoupling.cbStateChange.iParm2 = 0; /* unused */
1813    settings.sPresentation.cbStateChange.pfDo = &NEXUS_Astmlib_P_PresentationStateChange;
1814    settings.sPresentation.cbStateChange.pvParm1 = astm;
1815    settings.sPresentation.cbStateChange.iParm2 = 0; /* unused */
1816
1817    rc = BASTMlib_Create(&astm->lib, &settings);
1818    if (rc) {BERR_TRACE(rc); goto error;}
1819
1820    BASTMlib_Presenter_GetDefaultSettings(&presenterSettings);
1821
1822    for (i = 0; i < NEXUS_ASTM_PRESENTERS; i++)
1823    {
1824        BASTMlib_Presenter_Create(astm->lib, &astm->presenterContexts[i].presenter, &presenterSettings);
1825        BKNI_CreateEvent(&astm->presenterContexts[i].watchdogEvent);
1826        BKNI_CreateEvent(&astm->presenterContexts[i].lifecycleEvent);
1827        BKNI_CreateEvent(&astm->presenterContexts[i].tsmPassEvent);
1828        BKNI_CreateEvent(&astm->presenterContexts[i].firstPtsEvent);
1829    }
1830
1831    BASTMlib_GetStatus(astm->lib, &astm->status);
1832
1833    rc = NEXUS_Astm_SetSettings(astm, pSettings);
1834    if (rc) {BERR_TRACE(rc); goto error;}
1835
1836    BKNI_EnterCriticalSection();
1837    astm->ready = true;
1838    BKNI_LeaveCriticalSection();
1839
1840    return astm;
1841
1842error:
1843    NEXUS_Astm_Destroy(astm);
1844    return NULL;
1845}
1846
1847void NEXUS_Astm_Destroy(NEXUS_AstmHandle astm)
1848{
1849    unsigned int i;
1850    NEXUS_AstmSettings settings;
1851
1852    BDBG_OBJECT_ASSERT(astm, NEXUS_Astm);
1853
1854    NEXUS_Astm_GetSettings(astm, &settings);
1855    settings.videoDecoder = NULL;
1856    settings.stcChannel = NULL;
1857    settings.stcMaster = NULL;
1858    for (i = 0; i < NEXUS_ASTM_AUDIO_DECODERS; i++)
1859    {
1860        settings.audioDecoder[i] = NULL;
1861    }
1862    NEXUS_Astm_SetSettings(astm, &settings);
1863
1864    /* destroy presenters */
1865    for (i = 0; i < NEXUS_ASTM_PRESENTERS; i++)
1866    {
1867        if (astm->presenterContexts[i].firstPtsEvent)
1868        {
1869            BKNI_DestroyEvent(astm->presenterContexts[i].firstPtsEvent);
1870        }
1871        if (astm->presenterContexts[i].tsmPassEvent)
1872        {
1873            BKNI_DestroyEvent(astm->presenterContexts[i].tsmPassEvent);
1874        }
1875        if (astm->presenterContexts[i].watchdogEvent)
1876        {
1877            BKNI_DestroyEvent(astm->presenterContexts[i].watchdogEvent);
1878        }
1879        if (astm->presenterContexts[i].lifecycleEvent)
1880        {
1881            BKNI_DestroyEvent(astm->presenterContexts[i].lifecycleEvent);
1882        }
1883        if (astm->presenterContexts[i].presenter)
1884        {
1885            BASTMlib_Presenter_Destroy(astm->presenterContexts[i].presenter);
1886        }
1887    }
1888
1889    BASTMlib_Destroy(astm->lib);
1890
1891    BDBG_OBJECT_DESTROY(astm, NEXUS_Astm);
1892    BKNI_Free(astm);
1893}
1894
1895void NEXUS_Astm_GetSettings(NEXUS_AstmHandle astm, NEXUS_AstmSettings *pSettings)
1896{
1897    BDBG_OBJECT_ASSERT(astm, NEXUS_Astm);
1898    *pSettings = astm->settings;
1899}
1900
1901#ifdef BDBG_DEBUG_BUILD
1902static const char * decoderNameStrings[] =
1903{
1904    "Video",
1905    "Audio 0",
1906    "Audio 1",
1907    NULL
1908};
1909#endif
1910
1911static void NEXUS_Astm_P_DisconnectVideoDecoder(NEXUS_AstmHandle astm)
1912{
1913    NEXUS_VideoDecoderAstmSettings astmSettings;
1914#ifdef BDBG_DEBUG_BUILD
1915    BASTMlib_Presenter_Settings presenterSettings;
1916#endif
1917    struct NEXUS_AstmContext * presenterContext;
1918
1919    presenterContext = &astm->presenterContexts[0];
1920
1921    NEXUS_UnregisterEvent(presenterContext->lifecycleEventHandler);
1922    NEXUS_UnregisterEvent(presenterContext->watchdogEventHandler);
1923    NEXUS_UnregisterEvent(presenterContext->tsmPassEventHandler);
1924    NEXUS_UnregisterEvent(presenterContext->firstPtsEventHandler);
1925
1926    NEXUS_Module_Lock(g_astm.settings.modules.videoDecoder);
1927    NEXUS_VideoDecoder_GetAstmSettings_priv(astm->settings.videoDecoder, &astmSettings);
1928    astmSettings.firstPts_isr = NULL;
1929    astmSettings.tsmPass_isr = NULL;
1930    astmSettings.tsmFail_isr = NULL;
1931    astmSettings.tsmLog_isr  = NULL;
1932    astmSettings.watchdog_isr  = NULL;
1933    astmSettings.lifecycle_isr  = NULL;
1934    astmSettings.callbackContext = NULL;
1935    astmSettings.enableAstm = false;
1936    astmSettings.ptsOffset = 0;
1937    (void)NEXUS_VideoDecoder_SetAstmSettings_priv(astm->settings.videoDecoder, &astmSettings);
1938    NEXUS_Module_Unlock(g_astm.settings.modules.videoDecoder);
1939
1940    presenterContext->decoder = NULL;
1941#ifdef BDBG_DEBUG_BUILD
1942    presenterContext->decoderName = NULL;
1943#endif
1944    presenterContext->astm = NULL;
1945    presenterContext->getStatus_isr = NULL;
1946    presenterContext->getStatus = NULL;
1947    presenterContext->setSettings = NULL;
1948    presenterContext->getSettings = NULL;
1949
1950    BASTMlib_RemovePresenter(astm->lib, presenterContext->presenter);
1951
1952#ifdef BDBG_DEBUG_BUILD
1953    BASTMlib_Presenter_GetSettings(presenterContext->presenter, &presenterSettings);
1954    presenterSettings.pcName = NULL;
1955    BASTMlib_Presenter_SetSettings(presenterContext->presenter, &presenterSettings);
1956#endif
1957
1958    astm->settings.videoDecoder = NULL;
1959}
1960
1961static NEXUS_Error NEXUS_Astm_P_ConnectVideoDecoder(NEXUS_AstmHandle astm, const NEXUS_AstmSettings * pSettings)
1962{
1963    NEXUS_Error rc = NEXUS_SUCCESS;
1964    BERR_Code mrc = BERR_SUCCESS;
1965    NEXUS_VideoDecoderAstmSettings astmSettings;
1966#ifdef BDBG_DEBUG_BUILD
1967    BASTMlib_Presenter_Settings presenterSettings;
1968#endif
1969    struct NEXUS_AstmContext * presenterContext;
1970
1971    presenterContext = &astm->presenterContexts[0];
1972
1973    presenterContext->lifecycleEventHandler = NEXUS_RegisterEvent(presenterContext->lifecycleEvent, &NEXUS_Astm_P_DecoderLifecycleEventHandler, presenterContext);
1974    presenterContext->watchdogEventHandler = NEXUS_RegisterEvent(presenterContext->watchdogEvent, &NEXUS_Astm_P_DecoderWatchdogEventHandler, presenterContext);
1975    presenterContext->tsmPassEventHandler = NEXUS_RegisterEvent(presenterContext->tsmPassEvent, &NEXUS_Astm_P_DecoderTsmPassEventHandler, presenterContext);
1976    presenterContext->firstPtsEventHandler = NEXUS_RegisterEvent(presenterContext->firstPtsEvent, &NEXUS_Astm_P_DecoderFirstPtsEventHandler, presenterContext);
1977
1978#ifdef BDBG_DEBUG_BUILD
1979    BASTMlib_Presenter_GetSettings(presenterContext->presenter, &presenterSettings);
1980    presenterContext->decoderName = presenterSettings.pcName = decoderNameStrings[0];
1981    BASTMlib_Presenter_SetSettings(presenterContext->presenter, &presenterSettings);
1982#endif
1983
1984    mrc = BASTMlib_AddPresenter(astm->lib, presenterContext->presenter);
1985    if (mrc) {rc = NEXUS_UNKNOWN; goto err;}
1986
1987    presenterContext->decoder = pSettings->videoDecoder;
1988    presenterContext->astm = astm;
1989    presenterContext->getStatus_isr = &NEXUS_Astm_P_GetVideoStatus_isr;
1990    presenterContext->getStatus = &NEXUS_Astm_P_GetVideoStatus;
1991    presenterContext->getSettings = &NEXUS_Astm_P_GetVideoSettings;
1992    presenterContext->setSettings = &NEXUS_Astm_P_SetVideoSettings;
1993    presenterContext->passEventCount = 0;
1994    presenterContext->ptsStcDiffAdjustmentThreshold = pSettings->videoPresenterConfig.ptsStcDiffAdjustmentThreshold;
1995    presenterContext->tsmRecoveryAcquisitionTimer = NULL;
1996    presenterContext->tsmRecoveryAcquisitionPeriod = pSettings->videoPresenterConfig.tsmRecoveryAcquisitionPeriod;
1997    presenterContext->tsmRecoveryTrackingTimer = NULL;
1998    presenterContext->tsmRecoveryTrackingTimeout = pSettings->videoPresenterConfig.tsmRecoveryTrackingTimeout;
1999    presenterContext->maxAllowableFirstPtsStcDiff = pSettings->videoPresenterConfig.maxAllowableFirstPtsStcDiff;
2000    presenterContext->tsmThresholdAdjustment = pSettings->videoPresenterConfig.tsmThresholdAdjustment;
2001    presenterContext->manageRateControl = pSettings->videoPresenterConfig.manageRateControl;
2002    presenterContext->firstPtsTsm = true;
2003    presenterContext->firstPtsReceived = false;
2004    presenterContext->module = g_astm.settings.modules.videoDecoder;
2005
2006    NEXUS_Module_Lock(g_astm.settings.modules.videoDecoder);
2007    NEXUS_VideoDecoder_GetAstmSettings_priv(pSettings->videoDecoder, &astmSettings);
2008    astmSettings.enableAstm = pSettings->enabled;
2009    astmSettings.enableTsm = true;
2010    astmSettings.enablePlayback = false;
2011    astmSettings.syncLimit = 0;
2012    astmSettings.ptsOffset = 0;
2013    astmSettings.firstPts_isr = &NEXUS_Astm_P_DecoderFirstPtsCallback_isr;
2014    astmSettings.tsmPass_isr = &NEXUS_Astm_P_DecoderTsmPassCallback_isr;
2015    astmSettings.tsmFail_isr = &NEXUS_Astm_P_DecoderTsmFailCallback_isr;
2016    astmSettings.tsmLog_isr = &NEXUS_Astm_P_DecoderTsmLogCallback_isr;
2017    astmSettings.watchdog_isr = &NEXUS_Astm_P_DecoderWatchdogCallback_isr;
2018    astmSettings.lifecycle_isr = &NEXUS_Astm_P_DecoderLifecycleCallback_isr;
2019    astmSettings.callbackContext = presenterContext;
2020    rc = NEXUS_VideoDecoder_SetAstmSettings_priv(pSettings->videoDecoder, &astmSettings);
2021    NEXUS_Module_Unlock(g_astm.settings.modules.videoDecoder);
2022    if (rc) goto err;
2023
2024    astm->settings.videoDecoder = pSettings->videoDecoder;
2025
2026err:
2027    return rc;
2028}
2029
2030static NEXUS_Error NEXUS_Astm_P_DisconnectAudioDecoder(NEXUS_AstmHandle astm, unsigned int index)
2031{
2032    NEXUS_Error rc = NEXUS_SUCCESS;
2033    NEXUS_AudioDecoderAstmSettings astmSettings;
2034#ifdef BDBG_DEBUG_BUILD
2035    BASTMlib_Presenter_Settings presenterSettings;
2036#endif
2037    unsigned int presenterIndex = index + 1;
2038    struct NEXUS_AstmContext * presenterContext;
2039
2040    if (index > 1)
2041    {
2042        rc = NEXUS_INVALID_PARAMETER;
2043        goto err;
2044    }
2045
2046    presenterContext = &astm->presenterContexts[presenterIndex];
2047
2048    NEXUS_UnregisterEvent(presenterContext->lifecycleEventHandler);
2049    NEXUS_UnregisterEvent(presenterContext->watchdogEventHandler);
2050    NEXUS_UnregisterEvent(presenterContext->tsmPassEventHandler);
2051    NEXUS_UnregisterEvent(presenterContext->firstPtsEventHandler);
2052
2053    NEXUS_Module_Lock(g_astm.settings.modules.audio);
2054    NEXUS_AudioDecoder_GetAstmSettings_priv(astm->settings.audioDecoder[index], &astmSettings);
2055    astmSettings.firstPts_isr = NULL;
2056    astmSettings.tsmPass_isr = NULL;
2057    astmSettings.tsmFail_isr = NULL;
2058    astmSettings.tsmLog_isr  = NULL;
2059    astmSettings.watchdog_isr  = NULL;
2060    astmSettings.lifecycle_isr  = NULL;
2061    astmSettings.callbackContext = NULL;
2062    astmSettings.enableAstm = false;
2063    astmSettings.ptsOffset = 0;
2064    (void)NEXUS_AudioDecoder_SetAstmSettings_priv(astm->settings.audioDecoder[index], &astmSettings);
2065    NEXUS_Module_Unlock(g_astm.settings.modules.audio);
2066
2067    presenterContext->decoder = NULL;
2068    presenterContext->astm = NULL;
2069    presenterContext->getStatus_isr = NULL;
2070    presenterContext->getStatus = NULL;
2071    presenterContext->getSettings = NULL;
2072    presenterContext->setSettings = NULL;
2073
2074    BASTMlib_RemovePresenter(astm->lib, presenterContext->presenter);
2075
2076#ifdef BDBG_DEBUG_BUILD
2077    BASTMlib_Presenter_GetSettings(presenterContext->presenter, &presenterSettings);
2078    presenterSettings.pcName = NULL;
2079    BASTMlib_Presenter_SetSettings(presenterContext->presenter, &presenterSettings);
2080#endif
2081
2082    astm->settings.audioDecoder[index] = NULL;
2083
2084err:
2085    return rc;
2086}
2087
2088static NEXUS_Error NEXUS_Astm_P_ConnectAudioDecoder(NEXUS_AstmHandle astm, unsigned int index, const NEXUS_AstmSettings * pSettings)
2089{
2090    NEXUS_Error rc = NEXUS_SUCCESS;
2091    BERR_Code mrc = BERR_SUCCESS;
2092    NEXUS_AudioDecoderAstmSettings astmSettings;
2093#ifdef BDBG_DEBUG_BUILD
2094    BASTMlib_Presenter_Settings presenterSettings;
2095#endif
2096    unsigned int presenterIndex = index + 1;
2097    struct NEXUS_AstmContext * presenterContext;
2098
2099    if (index > 1)
2100    {
2101        rc = NEXUS_INVALID_PARAMETER;
2102        goto err;
2103    }
2104
2105    presenterContext = &astm->presenterContexts[presenterIndex];
2106
2107    presenterContext->lifecycleEventHandler = NEXUS_RegisterEvent(presenterContext->lifecycleEvent, &NEXUS_Astm_P_DecoderLifecycleEventHandler, presenterContext);
2108    presenterContext->watchdogEventHandler = NEXUS_RegisterEvent(presenterContext->watchdogEvent, &NEXUS_Astm_P_DecoderWatchdogEventHandler, presenterContext);
2109    presenterContext->tsmPassEventHandler = NEXUS_RegisterEvent(presenterContext->tsmPassEvent, &NEXUS_Astm_P_DecoderTsmPassEventHandler, presenterContext);
2110    presenterContext->firstPtsEventHandler = NEXUS_RegisterEvent(presenterContext->firstPtsEvent, &NEXUS_Astm_P_DecoderFirstPtsEventHandler, presenterContext);
2111
2112#ifdef BDBG_DEBUG_BUILD
2113    BASTMlib_Presenter_GetSettings(presenterContext->presenter, &presenterSettings);
2114    presenterContext->decoderName = presenterSettings.pcName = decoderNameStrings[presenterIndex];
2115    BASTMlib_Presenter_SetSettings(presenterContext->presenter, &presenterSettings);
2116#endif
2117
2118    mrc = BASTMlib_AddPresenter(astm->lib, presenterContext->presenter);
2119    if (mrc) {rc = NEXUS_UNKNOWN; goto err;}
2120
2121    presenterContext->decoder = pSettings->audioDecoder[index];
2122    presenterContext->astm = astm;
2123    presenterContext->getStatus_isr = &NEXUS_Astm_P_GetAudioStatus_isr;
2124    presenterContext->getStatus = &NEXUS_Astm_P_GetAudioStatus;
2125    presenterContext->getSettings = &NEXUS_Astm_P_GetAudioSettings;
2126    presenterContext->setSettings = &NEXUS_Astm_P_SetAudioSettings;
2127    presenterContext->passEventCount = 0;
2128    presenterContext->ptsStcDiffAdjustmentThreshold = pSettings->audioPresenterConfig[index].ptsStcDiffAdjustmentThreshold;
2129    presenterContext->tsmRecoveryAcquisitionTimer = NULL;
2130    presenterContext->tsmRecoveryAcquisitionPeriod = pSettings->audioPresenterConfig[index].tsmRecoveryAcquisitionPeriod;
2131    presenterContext->tsmRecoveryTrackingTimer = NULL;
2132    presenterContext->tsmRecoveryTrackingTimeout = pSettings->audioPresenterConfig[index].tsmRecoveryTrackingTimeout;
2133    presenterContext->maxAllowableFirstPtsStcDiff = pSettings->audioPresenterConfig[index].maxAllowableFirstPtsStcDiff;
2134    presenterContext->firstPtsTsm = true;
2135    presenterContext->firstPtsReceived = false;
2136    presenterContext->tsmThresholdAdjustment = pSettings->audioPresenterConfig[index].tsmThresholdAdjustment;
2137    presenterContext->manageRateControl = pSettings->audioPresenterConfig[index].manageRateControl;
2138    presenterContext->module = g_astm.settings.modules.audio;
2139
2140    NEXUS_Module_Lock(g_astm.settings.modules.audio);
2141    NEXUS_AudioDecoder_GetAstmSettings_priv(pSettings->audioDecoder[index], &astmSettings);
2142    astmSettings.enableAstm = pSettings->enabled;
2143    astmSettings.enableTsm = true;
2144    astmSettings.enablePlayback = false;
2145    astmSettings.syncLimit = 0;
2146    astmSettings.ptsOffset = 0;
2147    astmSettings.firstPts_isr = &NEXUS_Astm_P_DecoderFirstPtsCallback_isr;
2148    astmSettings.tsmPass_isr = &NEXUS_Astm_P_DecoderTsmPassCallback_isr;
2149    astmSettings.tsmFail_isr = &NEXUS_Astm_P_DecoderTsmFailCallback_isr;
2150    astmSettings.tsmLog_isr = &NEXUS_Astm_P_DecoderTsmLogCallback_isr;
2151    astmSettings.watchdog_isr = &NEXUS_Astm_P_DecoderWatchdogCallback_isr;
2152    astmSettings.lifecycle_isr = &NEXUS_Astm_P_DecoderLifecycleCallback_isr;
2153    astmSettings.callbackContext = presenterContext;
2154    rc = NEXUS_AudioDecoder_SetAstmSettings_priv(pSettings->audioDecoder[index], &astmSettings);
2155    NEXUS_Module_Unlock(g_astm.settings.modules.audio);
2156    if (rc) goto err;
2157
2158    astm->settings.audioDecoder[index] = pSettings->audioDecoder[index];
2159
2160err:
2161    return rc;
2162}
2163
2164static void NEXUS_Astm_P_DisconnectTimebase(NEXUS_AstmHandle astm)
2165{
2166    NEXUS_TimebaseAstmSettings astmSettings;
2167
2168    NEXUS_Module_Lock(g_astm.settings.modules.transport);
2169    NEXUS_Timebase_GetAstmSettings_priv(astm->timebase, &astmSettings);
2170    astmSettings.enabled = false;
2171    astmSettings.pcrReceived_isr = NULL;
2172    (void)NEXUS_Timebase_SetAstmSettings_priv(astm->timebase, &astmSettings);
2173    NEXUS_Module_Unlock(g_astm.settings.modules.transport);
2174
2175    astm->timebase = NULL;
2176}
2177
2178static NEXUS_Error NEXUS_Astm_P_ConnectTimebase(NEXUS_AstmHandle astm, const NEXUS_AstmSettings * pSettings)
2179{
2180    NEXUS_Error rc = NEXUS_SUCCESS;
2181    NEXUS_StcChannelSettings stcChannelSettings;
2182    NEXUS_TimebaseAstmSettings astmSettings;
2183    NEXUS_StcChannelAstmStatus stcChannelAstmStatus;
2184
2185    NEXUS_StcChannel_GetSettings(pSettings->stcChannel, &stcChannelSettings);
2186   
2187    NEXUS_Module_Lock(g_astm.settings.modules.transport);
2188    NEXUS_StcChannel_GetAstmStatus_priv(pSettings->stcChannel, &stcChannelAstmStatus);
2189    NEXUS_Module_Unlock(g_astm.settings.modules.transport);
2190   
2191    astm->timebase = stcChannelAstmStatus.timebase;
2192
2193    switch (stcChannelSettings.mode)
2194    {
2195        case NEXUS_StcChannelMode_ePcr:
2196            if (stcChannelSettings.modeSettings.pcr.pidChannel)
2197            {
2198                NEXUS_PidChannelStatus pidChannelStatus;
2199                NEXUS_PidChannel_GetStatus(stcChannelSettings.modeSettings.pcr.pidChannel, &pidChannelStatus);
2200                astm->transportType = pidChannelStatus.transportType;
2201            }
2202            break;
2203        case NEXUS_StcChannelMode_eAuto:
2204            astm->transportType = stcChannelSettings.modeSettings.Auto.transportType;
2205            break;
2206        case NEXUS_StcChannelMode_eHost:
2207            astm->transportType = stcChannelSettings.modeSettings.host.transportType;
2208            break;
2209        default:
2210            BDBG_WRN(("ASTM transport type not set"));
2211            break;
2212    }
2213
2214    NEXUS_Module_Lock(g_astm.settings.modules.transport);
2215    NEXUS_Timebase_GetAstmSettings_priv(astm->timebase, &astmSettings);
2216    astmSettings.enabled = pSettings->enabled;
2217    astmSettings.clockCoupling = NEXUS_TimebaseClockCoupling_eInputClock;
2218    astmSettings.pcrReceived_isr = NEXUS_Astm_P_TimebasePcrReceivedCallback_isr;
2219    astmSettings.callbackContext = astm;
2220    rc = NEXUS_Timebase_SetAstmSettings_priv(astm->timebase, &astmSettings);
2221    NEXUS_Module_Unlock(g_astm.settings.modules.transport);
2222    if (rc) goto err;
2223
2224err:
2225    return rc;
2226}
2227
2228static void NEXUS_Astm_P_DisconnectStcChannel(NEXUS_AstmHandle astm)
2229{
2230    unsigned int i = 0;
2231    NEXUS_StcChannelAstmSettings astmSettings;
2232
2233    NEXUS_Module_Lock(g_astm.settings.modules.transport);
2234    NEXUS_StcChannel_GetAstmSettings_priv(astm->settings.stcChannel, &astmSettings);
2235    astmSettings.enabled = false;
2236    (void)NEXUS_StcChannel_SetAstmSettings_priv(astm->settings.stcChannel, &astmSettings);
2237    NEXUS_Module_Unlock(g_astm.settings.modules.transport);
2238
2239    /* 20081204 bandrews - apply STC channel to all video and audio decoder
2240    presenter contexts, in case they were set at a different time from the STC channel */
2241    for (i = 0; i < NEXUS_ASTM_PRESENTERS; i++)
2242    {
2243        astm->presenterContexts[i].stc = NULL;
2244    }
2245}
2246
2247static NEXUS_Error NEXUS_Astm_P_ConnectStcChannel(NEXUS_AstmHandle astm, const NEXUS_AstmSettings * pSettings)
2248{
2249    unsigned int i = 0;
2250    NEXUS_Error rc = NEXUS_SUCCESS;
2251    NEXUS_StcChannelAstmSettings astmSettings;
2252
2253    NEXUS_Module_Lock(g_astm.settings.modules.transport);
2254    NEXUS_StcChannel_GetAstmSettings_priv(pSettings->stcChannel, &astmSettings);
2255    astmSettings.enabled = pSettings->enabled;
2256    astmSettings.mode = NEXUS_StcChannelMode_ePcr;
2257    astmSettings.tsmMode = NEXUS_StcChannelTsmMode_eStcMaster;
2258    astmSettings.syncLimit = 0;
2259    rc = NEXUS_StcChannel_SetAstmSettings_priv(pSettings->stcChannel, &astmSettings);
2260    NEXUS_Module_Unlock(g_astm.settings.modules.transport);
2261    if (rc) goto err;
2262
2263    astm->settings.stcChannel = pSettings->stcChannel;
2264
2265    /* 20081204 bandrews - apply STC channel to all video and audio decoder
2266    presenter contexts, in case they were set at a different time from the STC channel */
2267    for (i = 0; i < NEXUS_ASTM_PRESENTERS; i++)
2268    {
2269        astm->presenterContexts[i].stc = pSettings->stcChannel;
2270    }
2271
2272err:
2273    return rc;
2274}
2275
2276NEXUS_Error NEXUS_Astm_SetSettings(NEXUS_AstmHandle astm, const NEXUS_AstmSettings *pSettings)
2277{
2278    BASTMlib_Config astmlibConfig;
2279    BASTMlib_Presenter_Config astmPresenterConfig;
2280    unsigned int i;
2281    NEXUS_Error rc = NEXUS_SUCCESS;
2282
2283    BDBG_OBJECT_ASSERT(astm, NEXUS_Astm);
2284
2285    if (!pSettings)
2286    {
2287        return NEXUS_INVALID_PARAMETER;
2288    }
2289
2290    BKNI_EnterCriticalSection();
2291    astm->ready = false;
2292    BKNI_LeaveCriticalSection();
2293
2294    if (pSettings->stcChannel != astm->settings.stcChannel)
2295    {
2296        /* disco timebase first, relies on STC channel, may change in future with mutable timebases */
2297        if (astm->timebase)
2298        {
2299            NEXUS_Astm_P_DisconnectTimebase(astm);
2300        }
2301
2302        if (astm->settings.stcChannel)
2303        {
2304            NEXUS_Astm_P_DisconnectStcChannel(astm);
2305        }
2306
2307        if (pSettings->stcChannel)
2308        {
2309            NEXUS_Astm_P_ConnectStcChannel(astm, pSettings);
2310
2311            /* need STC channel to connect timebase, this may change in future with mutable timebases */
2312            NEXUS_Astm_P_ConnectTimebase(astm, pSettings);
2313        }
2314    }
2315
2316    if (pSettings->videoDecoder != astm->settings.videoDecoder)
2317    {
2318        if (astm->settings.videoDecoder)
2319        {
2320            NEXUS_Astm_P_DisconnectVideoDecoder(astm);
2321        }
2322
2323        if (pSettings->videoDecoder)
2324        {
2325            NEXUS_Astm_P_ConnectVideoDecoder(astm, pSettings);
2326        }
2327    }
2328
2329    for (i = 0; i < NEXUS_ASTM_AUDIO_DECODERS; i++)
2330    {
2331        if (pSettings->audioDecoder[i] != astm->settings.audioDecoder[i])
2332        {
2333            if (astm->settings.audioDecoder[i])
2334            {
2335                NEXUS_Astm_P_DisconnectAudioDecoder(astm, i);
2336            }
2337
2338            if (pSettings->audioDecoder[i])
2339            {
2340                NEXUS_Astm_P_ConnectAudioDecoder(astm, i, pSettings);
2341            }
2342        }
2343    }
2344
2345    /* ASTMlib config */
2346    {
2347        BASTMlib_GetConfig(astm->lib, &astmlibConfig);     
2348
2349        if (astm->transportType == NEXUS_TransportType_eDssEs
2350            || astm->transportType == NEXUS_TransportType_eDssPes)
2351        {
2352            astmlibConfig.eStcRate = BASTMlib_ClockRate_e27Mhz;
2353            astmlibConfig.sClockCoupling.eClockReferenceDomain = BASTMlib_ClockRate_e27Mhz;
2354           
2355        }
2356        else
2357        {
2358            astmlibConfig.eStcRate = BASTMlib_ClockRate_e45Khz;
2359            astmlibConfig.sClockCoupling.eClockReferenceDomain = BASTMlib_ClockRate_e45Khz;
2360        }
2361
2362        astmlibConfig.sPresentation.hPreferredPresenter = NULL;
2363
2364        if (pSettings->stcMaster == pSettings->videoDecoder)
2365        {
2366            astmlibConfig.sPresentation.hPreferredPresenter = astm->presenterContexts[0].presenter;
2367        }
2368        else
2369        {
2370            for (i = 0; i < NEXUS_ASTM_AUDIO_DECODERS; i++)
2371            {
2372                if (pSettings->stcMaster == pSettings->audioDecoder[i])
2373                {
2374                    astmlibConfig.sPresentation.hPreferredPresenter = astm->presenterContexts[i + 1].presenter;
2375                    break;
2376                }
2377            }
2378        }
2379
2380        astmlibConfig.bEnabled = pSettings->enabled;
2381        astmlibConfig.sPresentation.uiInitialAcquisitionTime = pSettings->presentationConfig.initialAcquisitionTime;
2382        astmlibConfig.sPresentation.uiProcessingFrequency = pSettings->presentationConfig.processingFrequency;
2383        astmlibConfig.sPresentation.uiTsmDisabledWatchdogTimeout = pSettings->presentationConfig.tsmDisabledWatchdogTimeout;
2384        astmlibConfig.sPresentation.uiSettlingTime = pSettings->presentationConfig.settlingTime;
2385        astmlibConfig.sPresentation.ePreferredPresentationRateControl = pSettings->presentationConfig.preferredPresentationRateControl;
2386        astmlibConfig.sClockCoupling.uiMinimumTimeBetweenEvents = pSettings->clockCouplingConfig.minimumTimeBetweenEvents;
2387        astmlibConfig.sClockCoupling.uiDeviationThreshold = pSettings->clockCouplingConfig.deviationThreshold;
2388        astmlibConfig.sClockCoupling.uiDeviantCountThreshold = pSettings->clockCouplingConfig.deviantCountThreshold;
2389        astmlibConfig.sClockCoupling.uiIdealCountThreshold = pSettings->clockCouplingConfig.idealCountThreshold;
2390        astmlibConfig.sClockCoupling.uiInitialAcquisitionTime = pSettings->clockCouplingConfig.initialAcquisitionTime;
2391        astmlibConfig.sClockCoupling.uiProcessingFrequency = pSettings->clockCouplingConfig.processingFrequency;
2392        astmlibConfig.sClockCoupling.uiIdealProcessingFrequency = pSettings->clockCouplingConfig.idealProcessingFrequency;
2393        astmlibConfig.sClockCoupling.uiSettlingTime = pSettings->clockCouplingConfig.settlingTime;
2394       
2395        BASTMlib_SetConfig(astm->lib, &astmlibConfig);
2396    }
2397
2398    if (astm->settings.videoDecoder)
2399    {
2400        BASTMlib_Presenter_GetConfig(astm->presenterContexts[0].presenter, &astmPresenterConfig );
2401        astmPresenterConfig.uiMinimumTimeBetweenEvents = pSettings->videoPresenterConfig.minimumTimeBetweenEvents;   
2402        astmPresenterConfig.uiPassEventCountThreshold = pSettings->videoPresenterConfig.passEventCountThreshold;
2403        astmPresenterConfig.uiFailEventCountThreshold = pSettings->videoPresenterConfig.failEventCountThreshold;
2404        if (astm->transportType == NEXUS_TransportType_eDssEs || astm->transportType == NEXUS_TransportType_eDssPes)
2405        {
2406            astmPresenterConfig.ePtsDomain = BASTMlib_ClockRate_e27Mhz;
2407        }
2408        else
2409        {
2410            astmPresenterConfig.ePtsDomain = BASTMlib_ClockRate_e45Khz;
2411        }   
2412        BASTMlib_Presenter_SetConfig(astm->presenterContexts[0].presenter, &astmPresenterConfig );
2413    }
2414   
2415    for (i = 1; i <= NEXUS_ASTM_AUDIO_DECODERS; i++)
2416    {
2417        if (astm->settings.audioDecoder[i - 1])
2418        {
2419            BASTMlib_Presenter_GetConfig(astm->presenterContexts[i].presenter, &astmPresenterConfig );
2420            astmPresenterConfig.uiMinimumTimeBetweenEvents = pSettings->audioPresenterConfig[i].minimumTimeBetweenEvents;   
2421            astmPresenterConfig.uiPassEventCountThreshold = pSettings->audioPresenterConfig[i].passEventCountThreshold;
2422            astmPresenterConfig.uiFailEventCountThreshold = pSettings->audioPresenterConfig[i].failEventCountThreshold;
2423            if (astm->transportType == NEXUS_TransportType_eDssEs || astm->transportType == NEXUS_TransportType_eDssPes)
2424            {
2425                astmPresenterConfig.ePtsDomain = BASTMlib_ClockRate_e27Mhz;
2426            }
2427            else
2428            {
2429                astmPresenterConfig.ePtsDomain = BASTMlib_ClockRate_e45Khz;
2430            }
2431            BASTMlib_Presenter_SetConfig(astm->presenterContexts[i].presenter, &astmPresenterConfig );
2432        }
2433    }
2434
2435    BASTMlib_GetStatus(astm->lib, &astm->status);
2436
2437    /* need to copy this before applying settings */
2438    astm->settings.syncLimit = pSettings->syncLimit;
2439
2440    /* apply settings */
2441    {
2442        NEXUS_StcChannelTsmMode newTsmMode;
2443        NEXUS_StcChannelTsmMode oldTsmMode;
2444
2445        if (pSettings->clockCoupling != astm->settings.clockCoupling)
2446        {
2447            rc = NEXUS_Astm_P_ApplyClockCoupling(astm, astm->settings.clockCoupling);
2448            if (rc) goto err;
2449        }
2450
2451        if (pSettings->stcSource != astm->settings.stcSource || pSettings->stcMaster != astm->settings.stcMaster)
2452        {
2453            rc = NEXUS_Astm_P_ApplyStcSource(astm, pSettings->stcSource, pSettings->stcMaster);
2454            if (rc) goto err;
2455        }
2456
2457        if (pSettings->presentationRateControl != astm->settings.presentationRateControl)
2458        {
2459            rc = NEXUS_Astm_P_ApplyPresentationRateControl(astm, pSettings->presentationRateControl);
2460            if (rc) goto err;
2461        }
2462
2463        oldTsmMode = NEXUS_Astm_P_ComputeStcChannelTsmMode(astm, astm->settings.stcSource,
2464            astm->settings.stcMaster, astm->settings.presentationRateControl);
2465        newTsmMode = NEXUS_Astm_P_ComputeStcChannelTsmMode(astm, pSettings->stcSource,
2466            pSettings->stcMaster, pSettings->presentationRateControl);
2467        if (newTsmMode != oldTsmMode)
2468        {
2469            rc = NEXUS_Astm_P_ApplyStcChannelTsmMode(astm, newTsmMode);
2470            if (rc) goto err;
2471        }
2472    }
2473
2474    astm->settings = *pSettings;
2475
2476    BDBG_MSG(("ALC: %s", astm->settings.enableAutomaticLifecycleControl ? "enabled" : "disabled"));
2477
2478    goto end;
2479
2480err:
2481
2482end:
2483
2484    BKNI_EnterCriticalSection();
2485    astm->ready = true;
2486    BKNI_LeaveCriticalSection();
2487
2488    return 0;
2489}
2490
2491static NEXUS_Error NEXUS_Astm_P_Start(NEXUS_AstmHandle astm)
2492{
2493    NEXUS_Error rc = NEXUS_SUCCESS;
2494
2495    BDBG_OBJECT_ASSERT(astm, NEXUS_Astm);
2496
2497    if (!NEXUS_GetEnv("astm_disabled"))
2498    {
2499        BDBG_MSG(("ASTM starting"));
2500        rc = (NEXUS_Error)BASTMlib_Start(astm->lib);
2501    }
2502
2503    astm->started = true;
2504
2505    return rc;
2506}
2507
2508static void NEXUS_Astm_P_Stop(NEXUS_AstmHandle astm)
2509{
2510    BDBG_OBJECT_ASSERT(astm, NEXUS_Astm);
2511
2512    if (!NEXUS_GetEnv("astm_disabled"))
2513    {
2514        BDBG_MSG(("ASTM stopping"));
2515        BASTMlib_Stop(astm->lib);
2516    }
2517
2518    /* cancel any pending nexus timers */
2519    NEXUS_Astm_P_CancelPendingTimers(astm);
2520
2521    astm->pcrReceived = false;
2522    astm->started = false;
2523}
2524
2525NEXUS_Error NEXUS_Astm_Start(NEXUS_AstmHandle astm)
2526{
2527    NEXUS_Error rc = NEXUS_SUCCESS;
2528
2529    BDBG_OBJECT_ASSERT(astm, NEXUS_Astm);
2530
2531    if (!astm->settings.enableAutomaticLifecycleControl)
2532    {
2533        if (!astm->started)
2534        {
2535            NEXUS_Astm_P_Start(astm);
2536        }
2537        else
2538        {
2539            BDBG_WRN(("ASTM already started"));
2540            rc = NEXUS_INVALID_PARAMETER;
2541        }
2542    }
2543    else
2544    {
2545        BDBG_WRN(("You must disable automatic lifecycle control before manually starting ASTM."));
2546        rc = NEXUS_INVALID_PARAMETER;
2547    }
2548
2549    return rc;
2550}
2551
2552void NEXUS_Astm_Stop(NEXUS_AstmHandle astm)
2553{
2554    BDBG_OBJECT_ASSERT(astm, NEXUS_Astm);
2555
2556    if (!astm->settings.enableAutomaticLifecycleControl)
2557    {
2558        if (astm->started)
2559        {
2560            NEXUS_Astm_P_Stop(astm);
2561        }
2562        else
2563        {
2564            BDBG_WRN(("ASTM not started"));
2565        }
2566    }
2567    else
2568    {
2569        BDBG_WRN(("You must disable automatic lifecycle control before manually stopping ASTM."));
2570    }
2571}
2572
Note: See TracBrowser for help on using the repository browser.